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); }
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); }