public static bool GenerateRevolvedShapeAsset(CSGBrushMeshAsset brushMeshAsset, CSGRevolvedShapeDefinition definition)
        {
            definition.Validate();
            var surfaces     = definition.surfaceAssets;
            var descriptions = definition.surfaceDescriptions;


            var shapeVertices       = new List <Vector2>();
            var shapeSegmentIndices = new List <int>();

            GetPathVertices(definition.shape, definition.curveSegments, shapeVertices, shapeSegmentIndices);

            Vector2[][] polygonVerticesArray;
            int[][]     polygonIndicesArray;

            if (!Decomposition.ConvexPartition(shapeVertices, shapeSegmentIndices,
                                               out polygonVerticesArray,
                                               out polygonIndicesArray))
            {
                brushMeshAsset.Clear();
                return(false);
            }

            // TODO: splitting it before we do the composition would be better
            var polygonVerticesList = polygonVerticesArray.ToList();

            for (int i = polygonVerticesList.Count - 1; i >= 0; i--)
            {
                SplitPolygon(polygonVerticesList, i);
            }

            var subMeshes = new List <CSGBrushSubMesh>();

            var horzSegments         = definition.revolveSegments;           //horizontalSegments;
            var horzDegreePerSegment = definition.totalAngle / horzSegments;


            // TODO: make this work when intersecting rotation axis
            //			1. split polygons along rotation axis
            //			2. if edge lies on rotation axis, make sure we don't create infinitely thin quad
            //					collapse this quad, or prevent this from happening
            // TODO: share this code with torus generator
            for (int p = 0; p < polygonVerticesList.Count; p++)
            {
                var polygonVertices = polygonVerticesList[p];
//				var segmentIndices		= polygonIndicesArray[p];
                var shapeSegments = polygonVertices.Length;

                var vertSegments     = polygonVertices.Length;
                var descriptionIndex = new int[2 + vertSegments];

                descriptionIndex[0] = 0;
                descriptionIndex[1] = 1;

                for (int v = 0; v < vertSegments; v++)
                {
                    descriptionIndex[v + 2] = 2;
                }

                var horzOffset = definition.startAngle;
                for (int h = 1, pr = 0; h < horzSegments + 1; pr = h, h++)
                {
                    var hDegree0        = (pr * horzDegreePerSegment) + horzOffset;
                    var hDegree1        = (h * horzDegreePerSegment) + horzOffset;
                    var rotation0       = Quaternion.AngleAxis(hDegree0, Vector3.forward);
                    var rotation1       = Quaternion.AngleAxis(hDegree1, Vector3.forward);
                    var subMeshVertices = new Vector3[vertSegments * 2];
                    for (int v = 0; v < vertSegments; v++)
                    {
                        subMeshVertices[v + vertSegments] = rotation0 * new Vector3(polygonVertices[v].x, 0, polygonVertices[v].y);
                        subMeshVertices[v] = rotation1 * new Vector3(polygonVertices[v].x, 0, polygonVertices[v].y);
                    }

                    var subMesh = new CSGBrushSubMesh();
                    if (!CreateExtrudedSubMesh(subMesh, vertSegments, descriptionIndex, descriptionIndex, 0, 1, subMeshVertices, surfaces, descriptions))
                    {
                        continue;
                    }

                    if (!subMesh.Validate())
                    {
                        brushMeshAsset.Clear();
                        return(false);
                    }
                    subMeshes.Add(subMesh);
                }
            }

            brushMeshAsset.SubMeshes = subMeshes.ToArray();

            brushMeshAsset.CalculatePlanes();
            brushMeshAsset.SetDirty();
            return(true);
        }
예제 #2
0
        public static bool GenerateExtrudedShapeAsset(CSGBrushMeshAsset brushMeshAsset, Curve2D shape, Path path, int curveSegments, CSGSurfaceAsset[] surfaceAssets, ref SurfaceDescription[] surfaceDescriptions)
        {
            var shapeVertices       = new List <Vector2>();
            var shapeSegmentIndices = new List <int>();

            GetPathVertices(shape, curveSegments, shapeVertices, shapeSegmentIndices);

            Vector2[][] polygonVerticesArray;
            int[][]     polygonIndicesArray;

            if (!Decomposition.ConvexPartition(shapeVertices, shapeSegmentIndices,
                                               out polygonVerticesArray,
                                               out polygonIndicesArray))
            {
                return(false);
            }

            // TODO: make each extruded quad split into two triangles when it's not a perfect plane,
            //			split it to make sure it's convex

            // TODO: make it possible to smooth (parts) of the shape

            // TODO: make materials work well
            // TODO: make it possible to 'draw' shapes on any surface

            // TODO: make path work as a spline, with subdivisions
            // TODO:	make this work well with twisted rotations
            // TODO: make shape/path subdivisions be configurable / automatic



            var subMeshes = new List <CSGBrushSubMesh>();

            for (int p = 0; p < polygonVerticesArray.Length; p++)
            {
                var polygonVertices = polygonVerticesArray[p];
                var segmentIndices  = polygonIndicesArray[p];
                var shapeSegments   = polygonVertices.Length;

                for (int s = 0; s < path.segments.Length - 1; s++)
                {
                    var pathPointA       = path.segments[s];
                    var pathPointB       = path.segments[s + 1];
                    int subSegments      = 1;
                    var offsetQuaternion = pathPointB.rotation * Quaternion.Inverse(pathPointA.rotation);
                    var offsetEuler      = offsetQuaternion.eulerAngles;
                    if (offsetEuler.x > 180)
                    {
                        offsetEuler.x = 360 - offsetEuler.x;
                    }
                    if (offsetEuler.y > 180)
                    {
                        offsetEuler.y = 360 - offsetEuler.y;
                    }
                    if (offsetEuler.z > 180)
                    {
                        offsetEuler.z = 360 - offsetEuler.z;
                    }
                    var maxAngle = Mathf.Max(offsetEuler.x, offsetEuler.y, offsetEuler.z);
                    if (maxAngle != 0)
                    {
                        subSegments = Mathf.Max(1, (int)Mathf.Ceil(maxAngle / 5));
                    }

                    if ((pathPointA.scale.x / pathPointA.scale.y) != (pathPointB.scale.x / pathPointB.scale.y) &&
                        (subSegments & 1) == 1)
                    {
                        subSegments += 1;
                    }

                    for (int n = 0; n < subSegments; n++)
                    {
                        var matrix0 = PathPoint.Lerp(ref path.segments[s], ref path.segments[s + 1], n / (float)subSegments);
                        var matrix1 = PathPoint.Lerp(ref path.segments[s], ref path.segments[s + 1], (n + 1) / (float)subSegments);

                        // TODO: this doesn't work if top and bottom polygons intersect
                        //			=> need to split into two brushes then, invert one of the two brushes
                        var invertDot = Vector3.Dot(matrix0.MultiplyVector(Vector3.forward).normalized, (matrix1.MultiplyPoint(shapeVertices[0]) - matrix0.MultiplyPoint(shapeVertices[0])).normalized);

                        if (invertDot == 0.0f)
                        {
                            continue;
                        }

                        Vector3[] vertices;
                        if (invertDot < 0)
                        {
                            var m = matrix0; matrix0 = matrix1; matrix1 = m;
                        }
                        if (!GetExtrudedVertices(polygonVertices, matrix0, matrix1, out vertices))
                        {
                            continue;
                        }

                        var subMesh = new CSGBrushSubMesh();
                        CreateExtrudedSubMesh(subMesh, shapeSegments, segmentIndices, 0, 1, vertices, surfaceAssets, surfaceDescriptions);
                        subMeshes.Add(subMesh);
                    }
                }
            }

            brushMeshAsset.SubMeshes = subMeshes.ToArray();
            brushMeshAsset.CalculatePlanes();
            brushMeshAsset.OnValidate();
            brushMeshAsset.SetDirty();
            return(true);
        }