public static void Tessellate(VoxelMeshComponent component, NativeList <PackedIndex> componentIndices, NativeList <VoxelMeshComponentVertex> componentVertices, Matrix4x4 transform, NativeList <float3> vertices, int freeTriIndex, NativeList <int> triIndices, NativeList <float3> normals, NativeList <int> materials, NativeDeduplicationCache dedupeCache) { float3 triangleFanCenter; if (component.Feature) { triangleFanCenter = component.FeatureVertex; } else { triangleFanCenter = float3.zero; int vertexCount = 0; for (int i = component.Index; i < component.Index + component.Size; i++) { triangleFanCenter += (float3)componentVertices[componentIndices[i]].Position; vertexCount++; } triangleFanCenter *= 1f / vertexCount; } if (component.RegularFeature) { var sharpSections = new NativeList <SharpSection>(Allocator.Temp); var sharpSectionNormals = new NativeList <float3>(Allocator.Temp); FindSharpComponentSections(component, componentIndices, componentVertices, sharpSections, sharpSectionNormals); for (int i = component.Index; i < component.Index + component.Size; i++) { PackedIndex packedIndex1 = componentIndices[i]; VoxelMeshComponentVertex meshVertex1 = componentVertices[packedIndex1]; float3 v1 = meshVertex1.Position; float3 n1 = meshVertex1.Normal; int m1 = meshVertex1.Material; PackedIndex packedIndex2 = componentIndices[component.Index + ((i + 1 - component.Index) % component.Size)]; VoxelMeshComponentVertex meshVertex2 = componentVertices[packedIndex2]; float3 v2 = meshVertex2.Position; float3 n2 = meshVertex2.Normal; int m2 = meshVertex2.Material; float3 faceAverageNormal = float3.zero; if (packedIndex1.IsNormalSet) { faceAverageNormal += n1 / math.length(v1 - triangleFanCenter); } if (packedIndex2.IsNormalSet) { faceAverageNormal += n2 / math.length(v2 - triangleFanCenter); } faceAverageNormal = math.normalize(faceAverageNormal); float3 triangleFanCenterNormal = float3.zero; bool triangleFanCenterNormalSet = false; //Find the normal of the section we're in for (int count = sharpSections.Length, j = 0; j < count; j++) { SharpSection section = sharpSections[j]; if (i >= section.startIndex && i < section.endIndex) { triangleFanCenterNormal = sharpSectionNormals[j]; triangleFanCenterNormalSet = true; } } if (!triangleFanCenterNormalSet) { triangleFanCenterNormal = faceAverageNormal; } var outV2 = transform.MultiplyPoint(triangleFanCenter); var outN2 = transform.MultiplyVector(triangleFanCenterNormal); var outV1 = transform.MultiplyPoint(v1); float3 outN1; if (packedIndex1.IsNormalSet) { outN1 = transform.MultiplyVector(n1); } else { outN1 = outN2; } if (Deduplicate(outV1, outN1, m1, freeTriIndex, dedupeCache, out int outI1)) { triIndices.Add(outI1); } else { vertices.Add(outV1); normals.Add(outN1); materials.Add(m1); triIndices.Add(freeTriIndex); freeTriIndex++; } if (Deduplicate(outV2, outN2, m1, freeTriIndex, dedupeCache, out int outI2)) { triIndices.Add(outI2); } else { vertices.Add(outV2); normals.Add(outN2); materials.Add(m1); triIndices.Add(freeTriIndex); freeTriIndex++; } var outV3 = transform.MultiplyPoint(v2); float3 outN3; if (packedIndex2.IsNormalSet) { outN3 = transform.MultiplyVector(n2); } else { outN3 = outN2; } if (Deduplicate(outV3, outN3, m2, freeTriIndex, dedupeCache, out int outI3)) { triIndices.Add(outI3); } else { vertices.Add(outV3); normals.Add(outN3); materials.Add(m2); triIndices.Add(freeTriIndex); freeTriIndex++; } } DisposeManaged(sharpSections); DisposeManaged(sharpSectionNormals); } else { float3 fullAverageNormal = float3.zero; for (int i = component.Index; i < component.Index + component.Size; i++) { PackedIndex packedIndex = componentIndices[i]; if (packedIndex.IsNormalSet) { VoxelMeshComponentVertex meshVertex = componentVertices[packedIndex]; fullAverageNormal += meshVertex.Normal / math.length(meshVertex.Position - triangleFanCenter); } } fullAverageNormal = math.normalize(fullAverageNormal); for (int i = component.Index; i < component.Index + component.Size; i++) { PackedIndex packedIndex1 = componentIndices[i]; VoxelMeshComponentVertex meshVertex1 = componentVertices[packedIndex1]; float3 v1 = meshVertex1.Position; float3 n1 = meshVertex1.Normal; int m1 = meshVertex1.Material; PackedIndex packedIndex2 = componentIndices[component.Index + ((i + 1 - component.Index) % component.Size)]; VoxelMeshComponentVertex meshVertex2 = componentVertices[packedIndex2]; float3 v2 = meshVertex2.Position; float3 n2 = meshVertex2.Normal; int m2 = meshVertex2.Material; float3 faceAverageNormal = float3.zero; if (packedIndex1.IsNormalSet) { faceAverageNormal += n1 / math.length(v1 - triangleFanCenter); } if (packedIndex2.IsNormalSet) { faceAverageNormal += n2 / math.length(v2 - triangleFanCenter); } faceAverageNormal = math.normalize(faceAverageNormal); var outV1 = transform.MultiplyPoint(v1); float3 outN1; if (packedIndex1.IsNormalSet) { outN1 = transform.MultiplyVector(n1); } else { outN1 = transform.MultiplyVector(faceAverageNormal); } if (Deduplicate(outV1, outN1, m1, freeTriIndex, dedupeCache, out int outI1)) { triIndices.Add(outI1); } else { vertices.Add(outV1); normals.Add(outN1); materials.Add(m1); triIndices.Add(freeTriIndex); freeTriIndex++; } var outV2 = transform.MultiplyPoint(triangleFanCenter); var outN2 = transform.MultiplyVector(fullAverageNormal); if (Deduplicate(outV2, outN2, m1, freeTriIndex, dedupeCache, out int outI2)) { triIndices.Add(outI2); } else { vertices.Add(outV2); normals.Add(outN2); materials.Add(m1); triIndices.Add(freeTriIndex); freeTriIndex++; } var outV3 = transform.MultiplyPoint(v2); float3 outN3; if (packedIndex2.IsNormalSet) { outN3 = transform.MultiplyVector(n2); } else { outN3 = transform.MultiplyVector(faceAverageNormal); } if (Deduplicate(outV3, outN3, m2, freeTriIndex, dedupeCache, out int outI3)) { triIndices.Add(outI3); } else { vertices.Add(outV3); normals.Add(outN3); materials.Add(m2); triIndices.Add(freeTriIndex); freeTriIndex++; } } } }
public static void Tessellate <TColorMap>(NativeList <VoxelMeshComponent> components, NativeList <PackedIndex> componentIndices, NativeList <VoxelMeshComponentVertex> componentVertices, Matrix4x4 transform, NativeList <float3> vertices, NativeList <int> triIndices, NativeList <float3> normals, NativeList <int> materials, TColorMap materialColors, NativeList <Color32> colors, NativeDeduplicationCache dedupeCache) where TColorMap : struct, IMaterialColorMap { var newMaterials = new NativeList <int>(Allocator.Temp); for (int count = components.Length, i = 0; i < count; i++) { Tessellate(components[i], componentIndices, componentVertices, transform, vertices, vertices.Length, triIndices, normals, newMaterials, dedupeCache); } materials.AddRange(newMaterials); for (int count = newMaterials.Length, i = 0; i < count; i++) { colors.Add(materialColors.GetColor(newMaterials[i])); } DisposeManaged(newMaterials); }
private static bool Deduplicate(float3 position, float3 normal, int material, int freeTriIndex, NativeDeduplicationCache dedupeCache, out int dedupedTriIndex) { //TODO Find sensible value const float quantization = 1024f; int hash = HashVertex(position, normal, material, quantization); if (!dedupeCache.table.TryGetValue(hash, out int index)) { index = -1; } if (index >= 0) { int nodeIndex = index; DedupedVertexNode node = dedupeCache.nodes[nodeIndex]; while (true) { DedupedVertex deduped = node.vertex; if (IsVertexEqual(position, normal, material, deduped.position, deduped.normal, deduped.material, quantization)) { //Equal vertex found, return index dedupedTriIndex = deduped.triIndex; return(true); } if (node.next >= 0) { nodeIndex = node.next; node = dedupeCache.nodes[nodeIndex]; } else { //Hash contained but no equal vertex, append new node to linked list dedupeCache.nodes[nodeIndex] = new DedupedVertexNode(deduped, dedupeCache.nodes.Length); dedupeCache.nodes.Add(new DedupedVertexNode(new DedupedVertex(position, normal, material, freeTriIndex))); break; } } } else { //Hash not yet contained, add a new initial node Assert.IsTrue(dedupeCache.table.TryAdd(hash, dedupeCache.nodes.Length)); dedupeCache.nodes.Add(new DedupedVertexNode(new DedupedVertex(position, normal, material, freeTriIndex))); } dedupedTriIndex = freeTriIndex; return(false); }