Пример #1
0
        private void populateMatrix(List <Face> faces, List <Face>[,,] matrix, Extent size)
        {
            Trace.TraceInformation("Partitioning Faces.");

            int xLength = matrix.GetLength(0);
            int yLength = matrix.GetLength(1);
            int zLength = matrix.GetLength(2);

            // World to cube ratios
            double xOffset = 0 - size.XMin;
            double xRatio  = xLength / (size.XSize);

            double yOffset = 0 - size.YMin;
            double yRatio  = yLength / (size.YSize);

            double zOffset = 0 - size.ZMin;
            double zRatio  = zLength / (size.ZSize);

            // Initialize matrix
            SpatialUtilities.EnumerateSpace(xLength, yLength, zLength,
                                            (x, y, z) => matrix[x, y, z] = new List <Face>());

            foreach (var face in faces)
            {
                List <int> used = new List <int>();

                for (int i = 0; i < 3; i++)
                {
                    Vertex vertex = VertexList[face.VertexIndexList[i] - 1];

                    int x = (int)Math.Floor((vertex.X + xOffset) * xRatio);
                    int y = (int)Math.Floor((vertex.Y + yOffset) * yRatio);
                    int z = (int)Math.Floor((vertex.Z + zOffset) * zRatio);

                    if (x == xLength)
                    {
                        x--;
                    }
                    if (y == yLength)
                    {
                        y--;
                    }
                    if (z == zLength)
                    {
                        z--;
                    }

                    int hash = x * 10000 + y * 100 + z;

                    if (!used.Contains(hash))
                    {
                        matrix[x, y, z].Add(face);
                        used.Add(hash);
                    }
                }
            }

            // Crop all the cubes
            SpatialUtilities.EnumerateSpace(xLength, yLength, zLength,
                                            (x, y, z) => CropCube(matrix[x, y, z], x, y, z, matrix, size));
        }
Пример #2
0
        private void CropCube(List <Face> chunkFaceList, int cubeX, int cubeY, int cubeZ, List <Face>[,,] matrix, Extent size)
        {
            double cubeHeight;
            double cubeWidth;
            double cubeDepth;

            cubeHeight = size.YSize / matrix.GetLength(1);
            cubeWidth  = size.XSize / matrix.GetLength(0);
            cubeDepth  = size.ZSize / matrix.GetLength(2);

            double yOffset = cubeHeight * cubeY;
            double xOffset = cubeWidth * cubeX;
            double zOffset = cubeDepth * cubeZ;

            Extent cubeExtent = new Extent
            {
                XMin = size.XMin + xOffset,
                YMin = size.YMin + yOffset,
                ZMin = size.ZMin + zOffset,
                XMax = size.XMin + xOffset + cubeWidth,
                YMax = size.YMin + yOffset + cubeHeight,
                ZMax = size.ZMin + zOffset + cubeDepth
            };

            Dictionary <Face, List <Vertex> > facesToRepair = new Dictionary <Face, List <Vertex> >();

            // Enumerate vertices for ones crossing bounds
            foreach (var face in chunkFaceList)
            {
                var vertices = FindOutOfBoundVertices(face, cubeExtent);

                if (vertices.Any())
                {
                    facesToRepair.Add(face, vertices);
                }
            }

            foreach (var face in facesToRepair.Keys)
            {
                // Type 1 - yields two triangles - 2 of the 3 vertices are in-bounds.
                if (facesToRepair[face].Count == 1)
                {
                    Vertex   croppedVertex = facesToRepair[face].First();
                    Vertex[] newVertices   = new Vertex[2];

                    // Find the vertices we are keeping
                    var      allVerts     = face.VertexIndexList.Select(i => VertexList[i - 1]);
                    Vertex[] homeVertices = allVerts.Except(new List <Vertex> {
                        croppedVertex
                    }).ToArray();

                    // First triangle, use existing face
                    var intersectionA = SpatialUtilities.CheckLineBox(
                        cubeExtent.MinCorner,
                        cubeExtent.MaxCorner,
                        new Vector3D(croppedVertex),
                        new Vector3D(homeVertices[0]));

                    var intersectionB = SpatialUtilities.CheckLineBox(
                        cubeExtent.MinCorner,
                        cubeExtent.MaxCorner,
                        new Vector3D(croppedVertex),
                        new Vector3D(homeVertices[1]));

                    if (intersectionA != null && intersectionB != null)
                    {
                        // Clone the face before we edit it, to use for the new face
                        var newFaceA = face.Clone();
                        var newFaceB = face.Clone();

                        // Update the UVs before the vertices so we can key off the original vertices
                        // New UV for NewVertexA / IntersectionA, which is a new point between homeVertices[0] and croppedVertex
                        var resultA = CalculateNewUV(face, croppedVertex, homeVertices[0], intersectionA);
                        newFaceA.UpdateTextureVertexIndex(resultA.OldIndex, resultA.NewIndex, false);

                        // New UV for NewVertexB / IntersectionB, which is a new point between homeVertices[1] and croppedVertex
                        var resultB = CalculateNewUV(newFaceB, croppedVertex, homeVertices[1], intersectionB);
                        newFaceB.UpdateTextureVertexIndex(resultB.OldIndex, resultB.NewIndex, false);

                        // Now update the vertices
                        // Add a new vertex and update the existing face
                        int length     = VertexList.Count();
                        var NewVertexA = new Vertex {
                            Index = length + 1, X = intersectionA.X, Y = intersectionA.Y, Z = intersectionA.Z
                        };
                        VertexList.Add(NewVertexA);
                        newFaceA.UpdateVertexIndex(croppedVertex.Index, length + 1, false);

                        // Replace original face with newFaceA
                        chunkFaceList.Add(newFaceA);
                        chunkFaceList.Remove(face);

                        // Add another new vertex for the net-new face
                        length++;
                        var NewVertexB = new Vertex {
                            Index = length + 1, X = intersectionB.X, Y = intersectionB.Y, Z = intersectionB.Z
                        };
                        VertexList.Add(NewVertexB);

                        // Add the net-new face
                        // TODO: Almost certainly leaving the face and vertex list incorrect for future cubes
                        // Won't really know until I do a run and see what is broken...
                        chunkFaceList.Add(newFaceB);
                        newFaceB.UpdateVertexIndex(homeVertices[0].Index, length, false);
                        newFaceB.UpdateVertexIndex(croppedVertex.Index, length + 1, false);
                    }
                }
                // Type 2 - yields single triangle - 1 of the 3 vertices are in-bounds.
                else if (facesToRepair[face].Count == 2)
                {
                    Vertex[] croppedVertices = facesToRepair[face].ToArray();
                    Vertex[] newVertices     = new Vertex[2];

                    // Find the vertex we are keeping
                    var    allVerts   = face.VertexIndexList.Select(i => VertexList[i - 1]);
                    Vertex homeVertex = allVerts.Except(croppedVertices).First();

                    // Create new face
                    bool doReplacement = false;
                    var  newFace       = face.Clone();

                    for (int i = 0; i < 2; i++)
                    {
                        var croppedVertex = new Vector3D(croppedVertices[i]);

                        // Figure out where this line intersects the cube
                        var intersection = SpatialUtilities.CheckLineBox(
                            cubeExtent.MinCorner,
                            cubeExtent.MaxCorner,
                            new Vector3D(croppedVertices[i]),
                            new Vector3D(homeVertex));

                        if (intersection != null)
                        {
                            doReplacement = true;

                            var result = CalculateNewUV(face, croppedVertices[i], homeVertex, intersection);

                            newFace.UpdateTextureVertexIndex(result.OldIndex, result.NewIndex, false);

                            // Add the new vertex
                            int length = VertexList.Count();
                            VertexList.Add(new Vertex {
                                Index = length + 1, X = intersection.X, Y = intersection.Y, Z = intersection.Z
                            });

                            // Update the new face vertex
                            newFace.UpdateVertexIndex(croppedVertices[i].Index, length + 1, false);
                        }
                    }

                    if (doReplacement)
                    {
                        chunkFaceList.Add(newFace);
                        chunkFaceList.Remove(face);
                    }
                }
            }
        }