You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

162 lines
5.3 KiB

using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering
{
// Helper class to render the visible mesh using custom materials.
// If possible, the mesh for each view will be combined into one mesh to reduce draw calls.
internal class XRVisibleMesh
{
XRPass m_Pass;
Mesh m_CombinedMesh;
int m_CombinedMeshHashCode;
static readonly ProfilingSampler k_VisibleMeshProfilingSampler = new ProfilingSampler("XR Visible Mesh");
internal XRVisibleMesh(XRPass xrPass)
{
m_Pass = xrPass;
}
internal void Dispose()
{
if (m_CombinedMesh)
{
CoreUtils.Destroy(m_CombinedMesh);
m_CombinedMesh = null;
}
}
internal bool hasValidVisibleMesh
{
get
{
if (IsVisibleMeshSupported())
{
if (m_Pass.singlePassEnabled)
return m_CombinedMesh != null;
else
return m_Pass.GetVisibleMesh() != null;
}
return false;
}
}
internal void RenderVisibleMeshCustomMaterial(CommandBuffer cmd, float occlusionMeshScale, Material material, MaterialPropertyBlock materialBlock, int shaderPass, bool yFlip = false)
{
if (IsVisibleMeshSupported())
{
using (new ProfilingScope(cmd, k_VisibleMeshProfilingSampler))
{
Vector3 scale = new Vector3(occlusionMeshScale, yFlip ? occlusionMeshScale : -occlusionMeshScale, 1.0f);
Mesh VisMesh = m_Pass.singlePassEnabled ? m_CombinedMesh : m_Pass.GetVisibleMesh(0);
cmd.DrawMesh(VisMesh, Matrix4x4.Scale(scale), material, 0, shaderPass, materialBlock);
}
}
}
internal void UpdateCombinedMesh()
{
if (IsVisibleMeshSupported() && m_Pass.singlePassEnabled && TryGetVisibleMeshCombinedHashCode(out var hashCode))
{
if (m_CombinedMesh == null || hashCode != m_CombinedMeshHashCode)
{
CreateVisibleMeshCombined();
m_CombinedMeshHashCode = hashCode;
}
}
else
{
m_CombinedMesh = null;
m_CombinedMeshHashCode = 0;
}
}
bool IsVisibleMeshSupported()
{
return m_Pass.enabled && m_Pass.occlusionMeshScale > 0.0f;
}
bool TryGetVisibleMeshCombinedHashCode(out int hashCode)
{
hashCode = 17;
for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId)
{
Mesh mesh = m_Pass.GetVisibleMesh(viewId);
if (mesh != null)
{
hashCode = hashCode * 23 + mesh.GetHashCode();
}
else
{
hashCode = 0;
return false;
}
}
return true;
}
// Create a new mesh that contains the visible data from all views
// This essentially fetches the mesh vertices from XRPass.GetVisibleMesh(viewId=0,1)
// and combines them into one mesh.
void CreateVisibleMeshCombined()
{
CoreUtils.Destroy(m_CombinedMesh);
m_CombinedMesh = new Mesh();
m_CombinedMesh.indexFormat = IndexFormat.UInt16;
int combinedVertexCount = 0;
uint combinedIndexCount = 0;
for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId)
{
Mesh mesh = m_Pass.GetVisibleMesh(viewId);
Debug.Assert(mesh != null);
Debug.Assert(mesh.subMeshCount == 1);
Debug.Assert(mesh.indexFormat == IndexFormat.UInt16);
combinedVertexCount += mesh.vertexCount;
combinedIndexCount += mesh.GetIndexCount(0);
}
Vector3[] vertices = new Vector3[combinedVertexCount];
ushort[] indices = new ushort[combinedIndexCount];
int vertexStart = 0;
int indexStart = 0;
for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId)
{
Mesh mesh = m_Pass.GetVisibleMesh(viewId);
var meshIndices = mesh.GetIndices(0);
// Encode the viewId into the z channel
{
mesh.vertices.CopyTo(vertices, vertexStart);
for (int i = 0; i < mesh.vertices.Length; i++)
vertices[vertexStart + i].z = viewId;
}
// Combine indices into one buffer
for (int i = 0; i < meshIndices.Length; i++)
{
int newIndex = vertexStart + meshIndices[i];
Debug.Assert(meshIndices[i] < ushort.MaxValue);
indices[indexStart + i] = (ushort)newIndex;
}
vertexStart += mesh.vertexCount;
indexStart += meshIndices.Length;
}
m_CombinedMesh.vertices = vertices;
m_CombinedMesh.SetIndices(indices, MeshTopology.Triangles, 0);
}
}
}