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 GenerateTorusAsset(CSGBrushMeshAsset brushMeshAsset, CSGTorusDefinition definition)
        {
            Vector3[] vertices = null;
            if (!GenerateTorusVertices(definition, ref vertices))
            {
                brushMeshAsset.Clear();
                return(false);
            }

            definition.Validate();
            var surfaces     = definition.surfaceAssets;
            var descriptions = definition.surfaceDescriptions;
            var tubeRadiusX  = (definition.tubeWidth * 0.5f);
            var tubeRadiusY  = (definition.tubeHeight * 0.5f);
            var torusRadius  = (definition.outerDiameter * 0.5f) - tubeRadiusX;


            var horzSegments = definition.horizontalSegments;
            var vertSegments = definition.verticalSegments;

            var horzDegreePerSegment = (definition.totalAngle / horzSegments);
            var vertDegreePerSegment = (360.0f / vertSegments) * Mathf.Deg2Rad;
            var descriptionIndex     = new int[2 + vertSegments];

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

            var circleVertices = new Vector2[vertSegments];

            var min             = new Vector2(float.PositiveInfinity, float.PositiveInfinity);
            var max             = new Vector2(float.NegativeInfinity, float.NegativeInfinity);
            var tubeAngleOffset = ((((vertSegments & 1) == 1) ? 0.0f : ((360.0f / vertSegments) * 0.5f)) + definition.tubeRotation) * Mathf.Deg2Rad;

            for (int v = 0; v < vertSegments; v++)
            {
                var vRad = tubeAngleOffset + (v * vertDegreePerSegment);
                circleVertices[v] = new Vector2((Mathf.Cos(vRad) * tubeRadiusX) - torusRadius,
                                                (Mathf.Sin(vRad) * tubeRadiusY));
                min.x = Mathf.Min(min.x, circleVertices[v].x);
                min.y = Mathf.Min(min.y, circleVertices[v].y);
                max.x = Mathf.Max(max.x, circleVertices[v].x);
                max.y = Mathf.Max(max.y, circleVertices[v].y);
                descriptionIndex[v + 2] = 2;
            }

            if (definition.fitCircle)
            {
                var center = (max + min) * 0.5f;
                var size   = (max - min) * 0.5f;
                size.x = tubeRadiusX / size.x;
                size.y = tubeRadiusY / size.y;
                for (int v = 0; v < vertSegments; v++)
                {
                    circleVertices[v].x  = (circleVertices[v].x - center.x) * size.x;
                    circleVertices[v].y  = (circleVertices[v].y - center.y) * size.y;
                    circleVertices[v].x -= torusRadius;
                }
            }

            var subMeshes  = new CSGBrushSubMesh[horzSegments];
            var horzOffset = definition.startAngle;

            for (int h = 1, p = 0; h < horzSegments + 1; p = h, h++)
            {
                var hDegree0        = (p * horzDegreePerSegment) + horzOffset;
                var hDegree1        = (h * horzDegreePerSegment) + horzOffset;
                var rotation0       = Quaternion.AngleAxis(hDegree0, Vector3.up);
                var rotation1       = Quaternion.AngleAxis(hDegree1, Vector3.up);
                var subMeshVertices = new Vector3[vertSegments * 2];
                for (int v = 0; v < vertSegments; v++)
                {
                    subMeshVertices[v + vertSegments] = rotation0 * circleVertices[v];
                    subMeshVertices[v] = rotation1 * circleVertices[v];
                }

                var subMesh = new CSGBrushSubMesh();
                CreateExtrudedSubMesh(subMesh, vertSegments, descriptionIndex, descriptionIndex, 0, 1, subMeshVertices, surfaces, descriptions);
                if (!subMesh.Validate())
                {
                    brushMeshAsset.Clear();
                    return(false);
                }
                subMeshes[h - 1] = subMesh;
            }

            brushMeshAsset.SubMeshes = subMeshes;

            brushMeshAsset.CalculatePlanes();
            brushMeshAsset.SetDirty();
            return(true);
        }