static int TriangleCompareFunction(TriangleGraph elementA, TriangleGraph elementB, int axis) { float valueA = (axis == 0) ? elementA.Centroid.X : (axis == 1) ? elementA.Centroid.Y : elementA.Centroid.Z; float valueB = (axis == 0) ? elementB.Centroid.X : (axis == 1) ? elementB.Centroid.Y : elementB.Centroid.Z; if (valueA < valueB) return -1; if (valueA > valueB) return 1; return 0; }
public void GenerateGeometry(ref byte[] DensityField, byte IsoValue, int DensityFieldWidth, int DensityFieldHeight, int DensityFieldDepth, int Width, int Height, int Depth, int xOrigin, int yOrigin, int zOrigin, Vector3 ratio, Matrix transform) { DestroyBuffers(); List<VertexPN> _vertices = new List<VertexPN>(); List<ushort> _indices = new List<ushort>(); SortedList<int, ushort> _edgeToIndices = new SortedList<int, ushort>(); collisionGraph.Clear(); int width = DensityFieldWidth; int sliceArea = width * DensityFieldHeight; byte[] DensityCache = new byte[8]; Vector3[] VectorCache = new Vector3[8]; for (int z = zOrigin; z < zOrigin + Depth; z++) { for (int y = yOrigin; y < yOrigin + Height; y++) { int dIdx = z * sliceArea + y * width + xOrigin; VectorCache[0] = new Vector3(xOrigin, y, z) * ratio - Vector3.One; VectorCache[3] = new Vector3(xOrigin, y + 1, z) * ratio - Vector3.One; VectorCache[4] = new Vector3(xOrigin, y, z + 1) * ratio - Vector3.One; VectorCache[7] = new Vector3(xOrigin, y + 1, z + 1) * ratio - Vector3.One; DensityCache[0] = DensityField[dIdx]; DensityCache[3] = DensityField[dIdx + width]; DensityCache[4] = DensityField[dIdx + sliceArea]; DensityCache[7] = DensityField[dIdx + sliceArea + width]; for (int x = xOrigin + 1; x <= xOrigin + Width; x++) { dIdx = z * sliceArea + y * width + x; VectorCache[1] = new Vector3(x, y, z) * ratio - Vector3.One; VectorCache[2] = new Vector3(x, y + 1, z) * ratio - Vector3.One; VectorCache[5] = new Vector3(x, y, z + 1) * ratio - Vector3.One; VectorCache[6] = new Vector3(x, y + 1, z + 1) * ratio - Vector3.One; DensityCache[1] = DensityField[dIdx]; DensityCache[2] = DensityField[dIdx + width]; DensityCache[5] = DensityField[dIdx + sliceArea]; DensityCache[6] = DensityField[dIdx + sliceArea + width]; /* Determine the index into the edge table which tells us which vertices are inside of the surface */ int cubeindex = 0; if (DensityCache[0] > IsoValue) cubeindex |= 1; if (DensityCache[1] > IsoValue) cubeindex |= 2; if (DensityCache[2] > IsoValue) cubeindex |= 4; if (DensityCache[3] > IsoValue) cubeindex |= 8; if (DensityCache[4] > IsoValue) cubeindex |= 16; if (DensityCache[5] > IsoValue) cubeindex |= 32; if (DensityCache[6] > IsoValue) cubeindex |= 64; if (DensityCache[7] > IsoValue) cubeindex |= 128; /* Cube is entirely in/out of the surface */ if (cubeindex != 0 && cubeindex != 255) { /*0-r 1-r+x 2-r+x+y 3-r+y 4-r+z 5-r+x+z 6-r+x+y+z 7-r+y+z */ //Now lets generate some normal vectors! Vector3[] NormalCache = new Vector3[8]; NormalCache[0] = ComputeNormal(ref DensityField, DensityFieldWidth, DensityFieldHeight, DensityFieldDepth, x - 1, y, z); NormalCache[1] = ComputeNormal(ref DensityField, DensityFieldWidth, DensityFieldHeight, DensityFieldDepth, x, y, z); NormalCache[2] = ComputeNormal(ref DensityField, DensityFieldWidth, DensityFieldHeight, DensityFieldDepth, x, y + 1, z); NormalCache[3] = ComputeNormal(ref DensityField, DensityFieldWidth, DensityFieldHeight, DensityFieldDepth, x - 1, y + 1, z); NormalCache[4] = ComputeNormal(ref DensityField, DensityFieldWidth, DensityFieldHeight, DensityFieldDepth, x - 1, y, z + 1); NormalCache[5] = ComputeNormal(ref DensityField, DensityFieldWidth, DensityFieldHeight, DensityFieldDepth, x, y, z + 1); NormalCache[6] = ComputeNormal(ref DensityField, DensityFieldWidth, DensityFieldHeight, DensityFieldDepth, x, y + 1, z + 1); NormalCache[7] = ComputeNormal(ref DensityField, DensityFieldWidth, DensityFieldHeight, DensityFieldDepth, x - 1, y + 1, z + 1); for (int i = 0; VoxelHelper.NewTriangleTable2[cubeindex, i] != -1; i += 3) { int[] edgeIndices = new int[3]; for (int j = 0; j < 3; j++) { int idx = GetEdgeId(DensityFieldWidth, DensityFieldHeight, x, y, z, VoxelHelper.NewTriangleTable2[cubeindex, i + j]); edgeIndices[j] = idx; if(!collisionGraph.ContainsKey(idx)) collisionGraph.Add(idx, new List<TriangleGraph>()); if (!_edgeToIndices.ContainsKey(idx)) { _edgeToIndices.Add(idx, (ushort)_vertices.Count); _vertices.Add(GenerateVertex(VoxelHelper.NewTriangleTable2[cubeindex, i + j], VectorCache, NormalCache, DensityCache, IsoValue)); } _indices.Add(_edgeToIndices[idx]); } ushort id0 = _indices[_indices.Count - 3]; ushort id1 = _indices[_indices.Count - 2]; ushort id2 = _indices[_indices.Count - 1]; Vector3 v0 = Vector3.Transform(_vertices[id0].Position, transform); Vector3 v1 = Vector3.Transform(_vertices[id1].Position, transform); Vector3 v2 = Vector3.Transform(_vertices[id2].Position, transform); TriangleGraph graph = new TriangleGraph(id0, id1, id2, v0, v1, v2); for (int j = 0; j < edgeIndices.Length; j++) collisionGraph[edgeIndices[j]].Add(graph); PrimitiveCount++; } } //Swap our caches VectorCache[0] = VectorCache[1]; VectorCache[3] = VectorCache[2]; VectorCache[4] = VectorCache[5]; VectorCache[7] = VectorCache[6]; DensityCache[0] = DensityCache[1]; DensityCache[3] = DensityCache[2]; DensityCache[4] = DensityCache[5]; DensityCache[7] = DensityCache[6]; } } } verts = _vertices.ToArray(); ib = _indices.ToArray(); if (verts.Length > 0) { renderElement.VertexCount = verts.Length; renderElement.VertexBuffer = new VertexBuffer(GFX.Device, verts.Length * VertexPN.SizeInBytes, BufferUsage.WriteOnly); renderElement.VertexBuffer.SetData<VertexPN>(verts); } if (ib.Length > 0) { renderElement.IndexBuffer = new IndexBuffer(GFX.Device, ib.Length * sizeof(ushort), BufferUsage.WriteOnly, IndexElementSize.SixteenBits); renderElement.IndexBuffer.SetData<ushort>(ib); renderElement.PrimitiveCount = PrimitiveCount; } collisionTree = new KDTree<TriangleGraph>(TriangleCompareFunction); for (int i = 0; i < collisionGraph.Values.Count; i++) { List<TriangleGraph> entries = collisionGraph.Values[i]; collisionTree.AddElementRange(entries.ToArray(), false); } collisionTree.BuildTree(); CanRender = (PrimitiveCount > 0); }
static int CompareCollisionNodesKD(TriangleGraph nodeA, TriangleGraph nodeB, int axis) { float nodeAValue = (axis == 0) ? nodeA.Centroid.X : (axis == 1) ? nodeA.Centroid.Y : nodeA.Centroid.Z; float nodeBValue = (axis == 0) ? nodeB.Centroid.X : (axis == 1) ? nodeB.Centroid.Y : nodeB.Centroid.Z; if (nodeAValue < nodeBValue) return -1; if (nodeAValue > nodeBValue) return 1; return 0; }