示例#1
0
        public static void GenerateCuboid(Cuboid shapeDesc, Transform transform, Vector2 texScale, bool insideOut, out IList <CSGVertex> vertices, out IList <uint> indices)
        {
            CSGPlane[] planes = new CSGPlane[6];

            #region Construct Non-Transformed Planes
            Plane       facePlane;
            CSGVertex[] faceVertices;
            Vector3     faceNormal;

            // Top face
            faceNormal   = Vector3.UP;
            facePlane    = new Plane(faceNormal, shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontTopLeft));
            faceVertices = new[] {
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackTopLeft),
                    faceNormal,
                    new Vector2(0f, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackTopRight),
                    faceNormal,
                    new Vector2(shapeDesc.Width / texScale.X, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontTopRight),
                    faceNormal,
                    new Vector2(shapeDesc.Width / texScale.X, shapeDesc.Depth / texScale.Y)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontTopLeft),
                    faceNormal,
                    new Vector2(0f, shapeDesc.Depth / texScale.Y)
                    ),
            };
            planes[0] = new CSGPlane(facePlane, faceVertices);

            // Bottom face
            faceNormal   = Vector3.DOWN;
            facePlane    = new Plane(faceNormal, shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontBottomLeft));
            faceVertices = new[] {
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontBottomRight),
                    faceNormal,
                    new Vector2(0f, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomRight),
                    faceNormal,
                    new Vector2(0f, shapeDesc.Depth / texScale.Y)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomLeft),
                    faceNormal,
                    new Vector2(shapeDesc.Width / texScale.X, shapeDesc.Depth / texScale.Y)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontBottomLeft),
                    faceNormal,
                    new Vector2(shapeDesc.Width / texScale.X, 0f)
                    ),
            };
            planes[1] = new CSGPlane(facePlane, faceVertices);

            // Front face
            faceNormal   = Vector3.BACKWARD;
            facePlane    = new Plane(faceNormal, shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontBottomLeft));
            faceVertices = new[] {
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontTopLeft),
                    faceNormal,
                    new Vector2(0f, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontTopRight),
                    faceNormal,
                    new Vector2(shapeDesc.Width / texScale.X, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontBottomRight),
                    faceNormal,
                    new Vector2(shapeDesc.Width / texScale.X, shapeDesc.Height / texScale.Y)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontBottomLeft),
                    faceNormal,
                    new Vector2(0f, shapeDesc.Height / texScale.Y)
                    ),
            };
            planes[2] = new CSGPlane(facePlane, faceVertices);

            // Back face
            faceNormal   = Vector3.FORWARD;
            facePlane    = new Plane(faceNormal, shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomLeft));
            faceVertices = new[] {
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackTopRight),
                    faceNormal,
                    new Vector2(0f, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackTopLeft),
                    faceNormal,
                    new Vector2(shapeDesc.Width / texScale.X, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomLeft),
                    faceNormal,
                    new Vector2(shapeDesc.Width / texScale.X, shapeDesc.Height / texScale.Y)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomRight),
                    faceNormal,
                    new Vector2(0f, shapeDesc.Height / texScale.Y)
                    ),
            };
            planes[3] = new CSGPlane(facePlane, faceVertices);

            // Left face
            faceNormal   = Vector3.LEFT;
            facePlane    = new Plane(faceNormal, shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomLeft));
            faceVertices = new[] {
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackTopLeft),
                    faceNormal,
                    new Vector2(0f, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontTopLeft),
                    faceNormal,
                    new Vector2(shapeDesc.Depth / texScale.X, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontBottomLeft),
                    faceNormal,
                    new Vector2(shapeDesc.Depth / texScale.X, shapeDesc.Height / texScale.Y)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomLeft),
                    faceNormal,
                    new Vector2(0f, shapeDesc.Height / texScale.Y)
                    ),
            };
            planes[4] = new CSGPlane(facePlane, faceVertices);

            // Right face
            faceNormal   = Vector3.RIGHT;
            facePlane    = new Plane(faceNormal, shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomRight));
            faceVertices = new[] {
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontTopRight),
                    faceNormal,
                    new Vector2(0f, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackTopRight),
                    faceNormal,
                    new Vector2(shapeDesc.Depth / texScale.X, 0f)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.BackBottomRight),
                    faceNormal,
                    new Vector2(shapeDesc.Depth / texScale.X, shapeDesc.Height / texScale.Y)
                    ),
                new CSGVertex(
                    shapeDesc.GetCorner(Cuboid.CuboidCorner.FrontBottomRight),
                    faceNormal,
                    new Vector2(0f, shapeDesc.Height / texScale.Y)
                    ),
            };
            planes[5] = new CSGPlane(facePlane, faceVertices);
            #endregion

            for (int i = 0; i < planes.Length; ++i)
            {
                planes[i] = planes[i].Transform(transform, shapeDesc.CenterPoint);
            }

            CreateVBAndIB(planes, out vertices, out indices, insideOut);
        }
        private static unsafe CSGPlane[] GeneratePlanes(CurveDesc shapeDesc, Transform transform, Vector2 texScale, CurveSegment[] segments)
        {
            float depthPerSegment = shapeDesc.StartingCuboid.Depth / shapeDesc.NumSegments;

            CSGPlane[] planes = new CSGPlane[shapeDesc.NumSegments * 8 + 2];

            #region UV Planes
            Vector2 invTexScale = 1f / texScale;
            float   minX, minY, minZ, maxX, maxY, maxZ;
            minX = minY = minZ = Single.MaxValue;
            maxX = maxY = maxZ = Single.MinValue;
            Action <Vector3> testAction = vec => {
                if (vec.X < minX)
                {
                    minX = vec.X;
                }
                if (vec.X > maxX)
                {
                    maxX = vec.X;
                }
                if (vec.Y < minY)
                {
                    minY = vec.Y;
                }
                if (vec.Y > maxY)
                {
                    maxY = vec.Y;
                }
                if (vec.Z < minZ)
                {
                    minZ = vec.Z;
                }
                if (vec.Z > maxZ)
                {
                    maxZ = vec.Z;
                }
            };
            foreach (var segment in segments)
            {
                testAction(segment.FrontTopLeft);
                testAction(segment.BackTopLeft);
                testAction(segment.FrontBottomLeft);
                testAction(segment.BackBottomLeft);
                testAction(segment.FrontTopRight);
                testAction(segment.BackTopRight);
                testAction(segment.FrontBottomRight);
                testAction(segment.BackBottomRight);
            }
            float xMid = minX + (maxX - minX) * 0.5f;
            float yMid = minY + (maxY - minY) * 0.5f;
            float zMid = minZ + (maxZ - minZ) * 0.5f;
            #endregion

            for (int segmentIndex = 0, planeIndex = 0; segmentIndex < shapeDesc.NumSegments; ++segmentIndex)
            {
                CurveSegment segment = segments[segmentIndex];

                Plane       facePlane;
                CSGVertex[] faceVertices;
                Vector3     faceNormal;

                #region Back
                if (segmentIndex == 0)
                {
                    facePlane    = Plane.FromPoints(segment.BackBottomLeft, segment.BackTopRight, segment.BackBottomRight);
                    faceNormal   = facePlane.Normal;
                    faceVertices = new[] {
                        new CSGVertex(
                            segment.BackBottomLeft,
                            faceNormal,
                            new Vector2(segment.BackBottomLeft.X - xMid, segment.BackBottomLeft.Y - yMid).Scale(invTexScale)
                            ),
                        new CSGVertex(
                            segment.BackBottomRight,
                            faceNormal,
                            new Vector2(segment.BackBottomRight.X - xMid, segment.BackBottomRight.Y - yMid).Scale(invTexScale)
                            ),
                        new CSGVertex(
                            segment.BackTopRight,
                            faceNormal,
                            new Vector2(segment.BackTopRight.X - xMid, segment.BackTopRight.Y - yMid).Scale(invTexScale)
                            ),
                        new CSGVertex(
                            segment.BackTopLeft,
                            faceNormal,
                            new Vector2(segment.BackTopLeft.X - xMid, segment.BackTopLeft.Y - yMid).Scale(invTexScale)
                            ),
                    };
                    planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);
                }
                #endregion

                #region Top
                facePlane    = Plane.FromPoints(segment.BackTopLeft, segment.FrontTopLeft, segment.FrontTopRight);
                faceNormal   = facePlane.Normal;
                faceVertices = new[] {
                    new CSGVertex(
                        segment.BackTopLeft,
                        faceNormal,
                        new Vector2(segment.BackTopLeft.X - xMid, segment.BackTopLeft.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.FrontTopLeft,
                        faceNormal,
                        new Vector2(segment.FrontTopLeft.X - xMid, segment.FrontTopLeft.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.FrontTopRight,
                        faceNormal,
                        new Vector2(segment.FrontTopRight.X - xMid, segment.FrontTopRight.Z - zMid).Scale(invTexScale)
                        ),
                };
                planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);

                facePlane    = Plane.FromPoints(segment.FrontTopRight, segment.BackTopRight, segment.BackTopLeft);
                faceNormal   = facePlane.Normal;
                faceVertices = new[] {
                    new CSGVertex(
                        segment.FrontTopRight,
                        faceNormal,
                        new Vector2(segment.FrontTopRight.X - xMid, segment.FrontTopRight.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.BackTopRight,
                        faceNormal,
                        new Vector2(segment.BackTopRight.X - xMid, segment.BackTopRight.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.BackTopLeft,
                        faceNormal,
                        new Vector2(segment.BackTopLeft.X - xMid, segment.BackTopLeft.Z - zMid).Scale(invTexScale)
                        ),
                };
                planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);
                #endregion

                #region Bottom
                facePlane    = Plane.FromPoints(segment.FrontBottomRight, segment.FrontBottomLeft, segment.BackBottomLeft);
                faceNormal   = facePlane.Normal;
                faceVertices = new[] {
                    new CSGVertex(
                        segment.FrontBottomRight,
                        faceNormal,
                        new Vector2(segment.FrontBottomRight.X - xMid, segment.FrontBottomRight.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.FrontBottomLeft,
                        faceNormal,
                        new Vector2(segment.FrontBottomLeft.X - xMid, segment.FrontBottomLeft.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.BackBottomLeft,
                        faceNormal,
                        new Vector2(segment.BackBottomLeft.X - xMid, segment.BackBottomLeft.Z - zMid).Scale(invTexScale)
                        ),
                };
                planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);

                facePlane    = Plane.FromPoints(segment.BackBottomLeft, segment.BackBottomRight, segment.FrontBottomRight);
                faceNormal   = facePlane.Normal;
                faceVertices = new[] {
                    new CSGVertex(
                        segment.BackBottomLeft,
                        faceNormal,
                        new Vector2(segment.BackBottomLeft.X - xMid, segment.BackBottomLeft.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.BackBottomRight,
                        faceNormal,
                        new Vector2(segment.BackBottomRight.X - xMid, segment.BackBottomRight.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.FrontBottomRight,
                        faceNormal,
                        new Vector2(segment.FrontBottomRight.X - xMid, segment.FrontBottomRight.Z - zMid).Scale(invTexScale)
                        ),
                };
                planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);
                #endregion

                #region Left
                facePlane    = Plane.FromPoints(segment.BackBottomLeft, segment.FrontBottomLeft, segment.FrontTopLeft);
                faceNormal   = facePlane.Normal;
                faceVertices = new[] {
                    new CSGVertex(
                        segment.BackBottomLeft,
                        faceNormal,
                        new Vector2(segment.BackBottomLeft.Y - yMid, segment.BackBottomLeft.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.FrontBottomLeft,
                        faceNormal,
                        new Vector2(segment.FrontBottomLeft.Y - yMid, segment.FrontBottomLeft.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.FrontTopLeft,
                        faceNormal,
                        new Vector2(segment.FrontTopLeft.Y - yMid, segment.FrontTopLeft.Z - zMid).Scale(invTexScale)
                        ),
                };
                planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);

                facePlane    = Plane.FromPoints(segment.FrontTopLeft, segment.BackTopLeft, segment.BackBottomLeft);
                faceNormal   = facePlane.Normal;
                faceVertices = new[] {
                    new CSGVertex(
                        segment.FrontTopLeft,
                        faceNormal,
                        new Vector2(segment.FrontTopLeft.Y - yMid, segment.FrontTopLeft.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.BackTopLeft,
                        faceNormal,
                        new Vector2(segment.BackTopLeft.Y - yMid, segment.BackTopLeft.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.BackBottomLeft,
                        faceNormal,
                        new Vector2(segment.BackBottomLeft.Y - yMid, segment.BackBottomLeft.Z - zMid).Scale(invTexScale)
                        ),
                };
                planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);
                #endregion

                #region Right
                facePlane    = Plane.FromPoints(segment.FrontTopRight, segment.FrontBottomRight, segment.BackBottomRight);
                faceNormal   = facePlane.Normal;
                faceVertices = new[] {
                    new CSGVertex(
                        segment.FrontTopRight,
                        faceNormal,
                        new Vector2(segment.FrontTopRight.Y - yMid, segment.FrontTopRight.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.FrontBottomRight,
                        faceNormal,
                        new Vector2(segment.FrontBottomRight.Y - yMid, segment.FrontBottomRight.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.BackBottomRight,
                        faceNormal,
                        new Vector2(segment.BackBottomRight.Y - yMid, segment.BackBottomRight.Z - zMid).Scale(invTexScale)
                        ),
                };
                planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);

                facePlane    = Plane.FromPoints(segment.BackBottomRight, segment.BackTopRight, segment.FrontTopRight);
                faceNormal   = facePlane.Normal;
                faceVertices = new[] {
                    new CSGVertex(
                        segment.BackBottomRight,
                        faceNormal,
                        new Vector2(segment.BackBottomRight.Y - yMid, segment.BackBottomRight.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.BackTopRight,
                        faceNormal,
                        new Vector2(segment.BackTopRight.Y - yMid, segment.BackTopRight.Z - zMid).Scale(invTexScale)
                        ),
                    new CSGVertex(
                        segment.FrontTopRight,
                        faceNormal,
                        new Vector2(segment.FrontTopRight.Y - yMid, segment.FrontTopRight.Z - zMid).Scale(invTexScale)
                        ),
                };
                planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);
                #endregion

                #region Front
                if (segmentIndex == segments.Length - 1)
                {
                    facePlane    = Plane.FromPoints(segment.FrontBottomRight, segment.FrontTopLeft, segment.FrontBottomLeft);
                    faceNormal   = facePlane.Normal;
                    faceVertices = new[] {
                        new CSGVertex(
                            segment.FrontBottomRight,
                            faceNormal,
                            new Vector2(segment.FrontBottomRight.X - xMid, segment.FrontBottomRight.Y - yMid).Scale(invTexScale)
                            ),
                        new CSGVertex(
                            segment.FrontBottomLeft,
                            faceNormal,
                            new Vector2(segment.FrontBottomLeft.X - xMid, segment.FrontBottomLeft.Y - yMid).Scale(invTexScale)
                            ),
                        new CSGVertex(
                            segment.FrontTopLeft,
                            faceNormal,
                            new Vector2(segment.FrontTopLeft.X - xMid, segment.FrontTopLeft.Y - yMid).Scale(invTexScale)
                            ),
                        new CSGVertex(
                            segment.FrontTopRight,
                            faceNormal,
                            new Vector2(segment.FrontTopRight.X - xMid, segment.FrontTopRight.Y - yMid).Scale(invTexScale)
                            )
                    };
                    planes[planeIndex++] = new CSGPlane(facePlane, faceVertices);
                }
                #endregion
            }

            for (int i = 0; i < planes.Length; ++i)
            {
                planes[i] = planes[i].Transform(transform, shapeDesc.StartingCuboid.CenterPoint);
            }

            return(planes);
        }
示例#3
0
        private static IList <uint> TriangulatePlane(CSGPlane plane, bool insideOut)
        {
            CSGVertexConnectionGraph connectionGraph = new CSGVertexConnectionGraph();

            // Add the initial connections
            Ray[] initialConnectionRays = new Ray[plane.NumVertices];
            for (uint i = 0U; i < plane.NumVertices; ++i)
            {
                connectionGraph.AddConnection(plane[i], plane[(i + 1) % plane.NumVertices]);
                initialConnectionRays[i] = Ray.FromStartAndEndPoint(plane[i].Position, plane[(i + 1) % plane.NumVertices].Position);
            }

            // Add the algorithmic connections
            for (uint a = 0U; a < plane.NumVertices; ++a)
            {
                for (uint b = 0U; b < plane.NumVertices; ++b)
                {
                    if (a == b)
                    {
                        continue;
                    }
                    CSGVertex vertA = plane[a];
                    CSGVertex vertB = plane[b];

                    // Skip existing connections
                    if (connectionGraph.CheckForConnection(vertA, vertB))
                    {
                        continue;
                    }

                    // Is a triangle formable by drawing a connection between A and B?
                    if (!connectionGraph
                        .GetConnections(vertA)
                        .Select(conn => conn.B)
                        .Intersect(connectionGraph.GetConnections(vertB).Select(conn => conn.B))
                        .Any())
                    {
                        continue;
                    }

                    // Does the connection go outside the polygon? If so, it's no good.
                    CSGConnection potentialConnection = new CSGConnection(vertA, vertB);
                    Vector3       connectionCentre    = potentialConnection.Ray.StartPoint + (potentialConnection.Ray.EndPoint.Value - potentialConnection.Ray.StartPoint) / 2f;
                    if (connectionCentre != plane.Center)
                    {
                        Ray connectionToCentreRay = new Ray(connectionCentre, plane.Center - connectionCentre);
                        if ((initialConnectionRays.Count(ray => {
                            Vector3?potentialIntersection = ray.IntersectionWith(connectionToCentreRay);
                            // We check that we're not intersecting the start point because that means this ray is going through a vertex;
                            // so by rejecting intersections through the start point we're not accidentally bumping the number of edge crossings
                            // by 2
                            return(potentialIntersection.HasValue && potentialIntersection != ray.StartPoint);
                        }) & 1) == 0)
                        {
                            continue;
                        }
                    }

                    // Does the connection intersect any other connection? If it does, we would have to create more vertices, so ignore it.
                    if (connectionGraph.GetAllConnections().Any(conn => {
                        Vector3?intersectionPoint = conn.Ray.IntersectionWith(potentialConnection.Ray);
                        if (intersectionPoint.HasValue)
                        {
                            float minDist = Math.Min(
                                Vector3.DistanceSquared(intersectionPoint.Value, potentialConnection.A.Position),
                                Vector3.DistanceSquared(intersectionPoint.Value, potentialConnection.B.Position)
                                );
                            if (minDist > MathUtils.FlopsErrorMargin)
                            {
                                return(true);
                            }
                            return(conn == potentialConnection);
                        }

                        return(false);
                    }))
                    {
                        continue;
                    }

                    // Add this connection.
                    connectionGraph.AddConnection(potentialConnection);
                }
            }

            // Compose the triangles by looking for three-cycles
            List <CSGTriangle> formulatedTriangles = new List <CSGTriangle>();

            for (uint v = 0U; v < plane.NumVertices; ++v)
            {
                CSGVertex sourceVertex = plane[v];
                IEnumerable <CSGConnection> primaryConnections = connectionGraph.GetConnections(sourceVertex, true);

                foreach (CSGConnection primary in primaryConnections)
                {
                    IEnumerable <CSGConnection> secondaryConnections = connectionGraph.GetConnections(primary.B, true)
                                                                       .Where(sConn => sConn.B != sourceVertex && primaryConnections.Any(pConn => pConn.B == sConn.B));

                    // Now we have a set of triangles (source -> pConn.B -> sConn.B), let's find the ones we haven't already
                    // added and add those!
                    foreach (CSGConnection secondary in secondaryConnections)
                    {
                        CSGTriangle potentialTriangle = new CSGTriangle(v, plane.IndexOf(secondary.A), plane.IndexOf(secondary.B));
                        if (!formulatedTriangles.Contains(potentialTriangle))
                        {
                            formulatedTriangles.Add(potentialTriangle);
                        }
                    }
                }
            }

            List <uint> result = new List <uint>();

            foreach (CSGTriangle triangle in formulatedTriangles)
            {
                Vector3 aPos           = plane[triangle.A].Position;
                Vector3 bPos           = plane[triangle.B].Position;
                Vector3 triCentre      = (aPos + bPos + plane[triangle.C].Position) / 3f;
                bool    triIsClockwise = plane.Plane.Normal.Dot(Vector3.Cross(aPos - triCentre, bPos - triCentre)) > 0f;
                if (insideOut)
                {
                    triIsClockwise = !triIsClockwise;
                }

                result.Add(triangle.A);

                if (triIsClockwise)
                {
                    result.Add(triangle.B);
                    result.Add(triangle.C);
                }
                else
                {
                    result.Add(triangle.C);
                    result.Add(triangle.B);
                }
            }

            return(result);
        }
        public static void GeneratePlane(IList <Vector3> coplanarPoints, Transform transform, Vector2 texScale, bool doubleSided, out IList <CSGVertex> vertices, out IList <uint> indices)
        {
            if (coplanarPoints.Count < 2)
            {
                throw new ArgumentException("Must supply at least 3 points.", "coplanarPoints");
            }
            CSGPlane[] planes = new CSGPlane[2];

            Vector3 barycentre = Vector3.ZERO;

            coplanarPoints.ForEach(point => barycentre += point);
            barycentre /= coplanarPoints.Count;
            CSGVertex[] csgVertices;
            Plane       plane            = Plane.FromPoints(coplanarPoints[0], coplanarPoints[1], coplanarPoints[2]);
            Vector3     uvX              = (coplanarPoints[0] - barycentre).ToUnit();
            Vector3     uvY              = uvX.Cross(plane.Normal);
            Vector2     invTexDimensions = new Vector2(1f / texScale.X, 1f / texScale.Y);

            #region Plane A
            csgVertices = new CSGVertex[coplanarPoints.Count];
            plane       = -plane;
            for (int i = 0; i < coplanarPoints.Count; ++i)
            {
                Vector3 centreOffset = coplanarPoints[i] - barycentre;

                csgVertices[csgVertices.Length - (i + 1)] = new CSGVertex(
                    coplanarPoints[i],
                    plane.Normal,
                    new Vector2(centreOffset.Dot(uvX), centreOffset.Dot(uvY)).Scale(invTexDimensions)
                    );
            }

            planes[0] = new CSGPlane(plane, csgVertices, barycentre);
            #endregion

            #region Plane B
            if (doubleSided)
            {
                csgVertices = new CSGVertex[coplanarPoints.Count];
                for (int i = 0; i < coplanarPoints.Count; ++i)
                {
                    Vector3 centreOffset = coplanarPoints[i] - barycentre;

                    csgVertices[i] = new CSGVertex(
                        coplanarPoints[i],
                        plane.Normal,
                        new Vector2(centreOffset.Dot(uvX), centreOffset.Dot(uvY)).Scale(invTexDimensions)
                        );
                }

                planes[1] = new CSGPlane(plane, csgVertices, barycentre);
            }
            #endregion

            for (int i = 0; i < (doubleSided ? 2 : 1); ++i)
            {
                planes[i] = planes[i].Transform(transform, planes[i].Center);
            }

            CreateVBAndIB(planes.Take(doubleSided ? 2 : 1).ToList(), out vertices, out indices, false);
        }
示例#5
0
        public static void GenerateCone(Cone shapeDesc, Transform transform, Vector2 texScale, uint extrapolation, bool insideOut, out IList <CSGVertex> vertices, out IList <uint> indices)
        {
            if (extrapolation < 3U)
            {
                throw new ArgumentOutOfRangeException("extrapolation", extrapolation, "Value must be at least 3.");
            }
            if (shapeDesc.TopRadius < MathUtils.FlopsErrorMargin && shapeDesc.BottomRadius < MathUtils.FlopsErrorMargin)
            {
                throw new ArgumentException("Cone is too thin.", "shapeDesc");
            }

            uint numCircularFaces = (shapeDesc.TopRadius > 0f ? 1U : 0U) + (shapeDesc.BottomRadius > 0f ? 1U : 0U);

            CSGPlane[] planes = new CSGPlane[numCircularFaces + extrapolation];

            Vector3[] topPoints            = new Vector3[extrapolation];
            Vector3[] bottomPoints         = new Vector3[extrapolation];
            float     radiusCoveredPerFace = MathUtils.TWO_PI / extrapolation;
            float     radialOffset         = 0f;

            for (uint i = 0U; i < extrapolation; ++i, radialOffset += radiusCoveredPerFace)
            {
                Vector3 rotVec = (Vector3.FORWARD * Quaternion.FromAxialRotation(Vector3.DOWN, radialOffset)).ToUnit();
                topPoints[i]    = shapeDesc.TopCenter + shapeDesc.TopRadius * rotVec;
                bottomPoints[i] = shapeDesc.BottomCenter + shapeDesc.BottomRadius * rotVec;
            }
            Vector2 invTexScale = new Vector2(1f / texScale.X, 1f / texScale.Y);

            #region Side planes
            float topCirc    = new Circle(Vector2.ZERO, shapeDesc.TopRadius).Circumference;
            float bottomCirc = new Circle(Vector2.ZERO, shapeDesc.BottomRadius).Circumference;

            for (uint side = 0; side < extrapolation; ++side)
            {
                uint    advSide = (side + 1) % extrapolation;
                Vector3 normal  = bottomPoints[side] + (bottomPoints[advSide] - bottomPoints[side]) * 0.5f - shapeDesc.BottomCenter;
                if (normal == Vector3.ZERO)
                {
                    normal = topPoints[side] + (topPoints[advSide] - topPoints[side]) * 0.5f - shapeDesc.TopCenter;
                }
                normal = normal != Vector3.ZERO ? normal.ToUnit() : Vector3.UP;

                List <CSGVertex> sideVertices = new List <CSGVertex>();

                Vector2 sideTexPoint =
                    Vector3.Distance(shapeDesc.TopCenter, topPoints[side]) > Vector3.Distance(shapeDesc.BottomCenter, bottomPoints[side])
                                        ? new Vector2(topPoints[side].X, topPoints[side].Z) : new Vector2(bottomPoints[side].X, bottomPoints[side].Z);
                float sideTexU = MathUtils.NormalizeRadians(
                    Vector2.AngleBetween(Vector2.UP, sideTexPoint),
                    MathUtils.RadianNormalizationRange.PositiveFullRange
                    ) / MathUtils.TWO_PI;
                Vector2 advSideTexPoint =
                    Vector3.Distance(shapeDesc.TopCenter, topPoints[advSide]) > Vector3.Distance(shapeDesc.BottomCenter, bottomPoints[advSide])
                                        ? new Vector2(topPoints[advSide].X, topPoints[advSide].Z) : new Vector2(bottomPoints[advSide].X, bottomPoints[advSide].Z);
                float advSideTexU = MathUtils.NormalizeRadians(
                    Vector2.AngleBetween(Vector2.UP, advSideTexPoint),
                    MathUtils.RadianNormalizationRange.PositiveFullRange
                    ) / MathUtils.TWO_PI;

                if (shapeDesc.TopRadius > 0f)
                {
                    sideVertices.Add(
                        new CSGVertex(topPoints[advSide], normal, new Vector2(advSideTexU * topCirc, 0f).Scale(invTexScale))
                        );

                    sideVertices.Add(
                        new CSGVertex(topPoints[side], normal, new Vector2(sideTexU * topCirc, 0f).Scale(invTexScale))
                        );

                    sideVertices.Add(
                        new CSGVertex(bottomPoints[side], normal, new Vector2(sideTexU * bottomCirc, shapeDesc.Height).Scale(invTexScale))
                        );

                    if (shapeDesc.BottomRadius > 0f)
                    {
                        sideVertices.Add(
                            new CSGVertex(bottomPoints[advSide], normal, new Vector2(advSideTexU * bottomCirc, shapeDesc.Height).Scale(invTexScale))
                            );
                    }
                }
                else
                {
                    sideVertices.Add(
                        new CSGVertex(topPoints[side], normal, new Vector2(sideTexU * topCirc, 0f).Scale(invTexScale))
                        );

                    sideVertices.Add(
                        new CSGVertex(bottomPoints[side], normal, new Vector2(sideTexU * bottomCirc, shapeDesc.Height).Scale(invTexScale))
                        );

                    sideVertices.Add(
                        new CSGVertex(bottomPoints[advSide], normal, new Vector2(advSideTexU * bottomCirc, shapeDesc.Height).Scale(invTexScale))
                        );
                }

                planes[side] = new CSGPlane(new Plane(normal, topPoints[side]), sideVertices.ToArray());
            }
            #endregion

            #region Top and bottom planes
            if (shapeDesc.TopRadius > 0f)
            {
                planes[extrapolation] = new CSGPlane(new Plane(Vector3.UP, shapeDesc.TopCenter), topPoints.Select(point => {
                    Vector2 uv = new Vector2(
                        point.X - shapeDesc.TopCenter.X,
                        point.Z - shapeDesc.TopCenter.Z
                        ).Scale(invTexScale);
                    return(new CSGVertex(point, Vector3.UP, uv));
                }).ToArray());
            }
            if (shapeDesc.BottomRadius > 0f)
            {
                planes[extrapolation + numCircularFaces - 1U] = new CSGPlane(new Plane(Vector3.DOWN, shapeDesc.BottomCenter), bottomPoints.Reverse().Select(point => {
                    Vector2 uv = new Vector2(
                        point.X - shapeDesc.BottomCenter.X,
                        point.Z - shapeDesc.BottomCenter.Z
                        ).Scale(invTexScale);
                    return(new CSGVertex(point, Vector3.DOWN, uv));
                }).ToArray());
            }
            #endregion


            for (int i = 0; i < planes.Length; ++i)
            {
                // Translate by half the height to make the centre/origin the centre of the shape
                planes[i] = planes[i].Transform(transform.TranslateBy(Vector3.UP * (shapeDesc.Height * 0.5f)), new Vector3(shapeDesc.BottomCenter, y: shapeDesc.BottomCenter.Y + shapeDesc.Height / 2f));
            }

            CreateVBAndIB(planes, out vertices, out indices, insideOut);
        }