public static bool GenerateConicalFrustumSubMesh(CSGBrushSubMesh subMesh, CSGCircleDefinition bottom, CSGCircleDefinition top, float rotation, int segments, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions) { if (segments < 3 || (top.height - bottom.height) == 0 || (bottom.diameterX == 0 && top.diameterX == 0) || (bottom.diameterZ == 0 && top.diameterZ == 0)) { subMesh.Clear(); return(false); } if (surfaceAssets.Length < 3 || surfaceDescriptions.Length < segments + 2) { subMesh.Clear(); return(false); } // TODO: handle situation where diameterX & diameterZ are 0 (only create one vertex) if (top.diameterX == 0) { var vertices = new Vector3[segments + 1]; GetConeFrustumVertices(bottom, top.height, rotation, segments, ref vertices, inverse: false); // TODO: the polygon/half-edge part would be the same for any extruded shape and should be re-used CreateConeSubMesh(subMesh, segments, null, vertices, surfaceAssets, surfaceDescriptions); } else if (bottom.diameterX == 0) { var vertices = new Vector3[segments + 1]; GetConeFrustumVertices(top, bottom.height, rotation, segments, ref vertices, inverse: true); // TODO: the polygon/half-edge part would be the same for any extruded shape and should be re-used CreateConeSubMesh(subMesh, segments, null, vertices, surfaceAssets, surfaceDescriptions); } else { if (top.height > bottom.height) { var temp = top; top = bottom; bottom = temp; } var vertices = new Vector3[segments * 2]; GetConicalFrustumVertices(bottom, top, rotation, segments, ref vertices); // TODO: the polygon/half-edge part would be the same for any extruded shape and should be re-used CreateExtrudedSubMesh(subMesh, segments, null, 0, 1, vertices, surfaceAssets, surfaceDescriptions); } return(true); }
public static bool GenerateSphereSubMesh(CSGBrushSubMesh subMesh, Vector3 diameterXYZ, float offsetY, bool generateFromCenter, Matrix4x4 transform, int horzSegments, int vertSegments, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions) { if (diameterXYZ.x == 0 || diameterXYZ.y == 0 || diameterXYZ.z == 0) { subMesh.Clear(); return(false); } var brushMesh = BrushMeshFactory.CreateSphere(diameterXYZ, offsetY, generateFromCenter, horzSegments, vertSegments); subMesh.HalfEdges = brushMesh.halfEdges; subMesh.Vertices = brushMesh.vertices; subMesh.Polygons = new CSGBrushSubMesh.Polygon[brushMesh.polygons.Length]; for (int i = 0; i < brushMesh.polygons.Length; i++) { subMesh.Polygons[i] = new CSGBrushSubMesh.Polygon { surfaceID = i, edgeCount = brushMesh.polygons[i].edgeCount, firstEdge = brushMesh.polygons[i].firstEdge, surfaceAsset = i < surfaceAssets.Length ? surfaceAssets[i] : surfaceAssets[0], description = i < surfaceDescriptions.Length ? surfaceDescriptions[i] : surfaceDescriptions[0], }; } return(true); }
// TODO: clean up public static bool GenerateSegmentedSubMesh(CSGBrushSubMesh subMesh, int horzSegments, int vertSegments, Vector3[] segmentVertices, bool topCap, bool bottomCap, int topVertex, int bottomVertex, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions) { // FIXME: hack, to fix math below .. vertSegments++; //if (bottomCap || topCap) // vertSegments++; int triangleCount, quadCount, capCount, extraVertices; capCount = 0; triangleCount = 0; extraVertices = 0; if (topCap) { capCount += 1; } else { extraVertices += 1; triangleCount += horzSegments; } if (bottomCap) { capCount += 1; } else { extraVertices += 1; triangleCount += horzSegments; } quadCount = horzSegments * (vertSegments - 2); var vertexCount = (horzSegments * (vertSegments - 1)) + extraVertices; var assetPolygonCount = triangleCount + quadCount + capCount; var halfEdgeCount = (triangleCount * 3) + (quadCount * 4) + (capCount * horzSegments); if (segmentVertices.Length != vertexCount) { Debug.LogError("segmentVertices.Length (" + segmentVertices.Length + ") != expectedVertexCount (" + vertexCount + ")"); subMesh.Clear(); return(false); } var vertices = segmentVertices; var polygons = new CSGBrushSubMesh.Polygon[assetPolygonCount]; var halfEdges = new BrushMesh.HalfEdge[halfEdgeCount]; var twins = new int[horzSegments]; var edgeIndex = 0; var polygonIndex = 0; var startVertex = extraVertices; var startSegment = topCap ? 1 : 0; var lastVertSegment = vertSegments - 1; var endSegment = bottomCap ? lastVertSegment : vertSegments; if (topCap) { var polygonEdgeCount = horzSegments; for (int h = 0, p = horzSegments - 1; h < horzSegments; p = h, h++) { var currEdgeIndex = edgeIndex + (horzSegments - 1) - h; halfEdges[currEdgeIndex] = new BrushMesh.HalfEdge { twinIndex = -1, vertexIndex = startVertex + (horzSegments - 1) - p }; twins[h] = currEdgeIndex; } polygons[polygonIndex] = new CSGBrushSubMesh.Polygon { surfaceID = polygonIndex, firstEdge = edgeIndex, edgeCount = polygonEdgeCount, description = surfaceDescriptions[0], surfaceAsset = surfaceAssets[0] }; edgeIndex += polygonEdgeCount; polygonIndex++; } for (int v = startSegment; v < endSegment; v++) { var startEdge = edgeIndex; for (int h = 0, p = horzSegments - 1; h < horzSegments; p = h, h++) { var n = (h + 1) % horzSegments; int polygonEdgeCount; if (v == 0) // top { // 0 // * // ^ \ // p1 /0 1\ n0 // / 2 v // *<------* // 2 t 1 polygonEdgeCount = 3; var p1 = (p * 3) + 1; var n0 = (n * 3) + 0; halfEdges[edgeIndex + 0] = new BrushMesh.HalfEdge { twinIndex = p1, vertexIndex = topVertex }; halfEdges[edgeIndex + 1] = new BrushMesh.HalfEdge { twinIndex = n0, vertexIndex = startVertex + (horzSegments - 1) - h }; halfEdges[edgeIndex + 2] = new BrushMesh.HalfEdge { twinIndex = -1, vertexIndex = startVertex + (horzSegments - 1) - p }; twins[h] = edgeIndex + 2; } else if (v == lastVertSegment) // bottom { // 0 t 1 // *------>* // ^ 1 / // p2 \0 2/ n0 // \ v // * // 2 polygonEdgeCount = 3; var p2 = startEdge + (p * 3) + 2; var n0 = startEdge + (n * 3) + 0; var t = twins[h]; halfEdges[twins[h]].twinIndex = edgeIndex + 1; halfEdges[edgeIndex + 0] = new BrushMesh.HalfEdge { twinIndex = p2, vertexIndex = startVertex + (horzSegments - 1) - p }; halfEdges[edgeIndex + 1] = new BrushMesh.HalfEdge { twinIndex = t, vertexIndex = startVertex + (horzSegments - 1) - h }; halfEdges[edgeIndex + 2] = new BrushMesh.HalfEdge { twinIndex = n0, vertexIndex = bottomVertex }; } else { // 0 t3 1 // *------>* // ^ 1 | // p1 |0 2| n0 // | 3 v // *<------* // 3 t1 2 polygonEdgeCount = 4; var p1 = startEdge + (p * 4) + 2; var n0 = startEdge + (n * 4) + 0; var t = twins[h]; halfEdges[twins[h]].twinIndex = edgeIndex + 1; halfEdges[edgeIndex + 0] = new BrushMesh.HalfEdge { twinIndex = p1, vertexIndex = startVertex + (horzSegments - 1) - p }; halfEdges[edgeIndex + 1] = new BrushMesh.HalfEdge { twinIndex = t, vertexIndex = startVertex + (horzSegments - 1) - h }; halfEdges[edgeIndex + 2] = new BrushMesh.HalfEdge { twinIndex = n0, vertexIndex = startVertex + (horzSegments - 1) - h + horzSegments }; halfEdges[edgeIndex + 3] = new BrushMesh.HalfEdge { twinIndex = -1, vertexIndex = startVertex + (horzSegments - 1) - p + horzSegments }; twins[h] = edgeIndex + 3; } polygons[polygonIndex] = new CSGBrushSubMesh.Polygon { surfaceID = polygonIndex, firstEdge = edgeIndex, edgeCount = polygonEdgeCount, description = surfaceDescriptions[0], surfaceAsset = surfaceAssets[0] }; edgeIndex += polygonEdgeCount; polygonIndex++; } if (v > 0) { startVertex += horzSegments; } } if (bottomCap) { var polygonEdgeCount = horzSegments; for (int h = 0; h < horzSegments; h++) { var currEdgeIndex = edgeIndex + h; halfEdges[twins[h]].twinIndex = currEdgeIndex; halfEdges[currEdgeIndex] = new BrushMesh.HalfEdge { twinIndex = twins[h], vertexIndex = startVertex + (horzSegments - 1) - h }; } polygons[polygonIndex] = new CSGBrushSubMesh.Polygon { surfaceID = polygonIndex, firstEdge = edgeIndex, edgeCount = polygonEdgeCount, description = surfaceDescriptions[0], surfaceAsset = surfaceAssets[0] }; } subMesh.Polygons = polygons; subMesh.HalfEdges = halfEdges; subMesh.Vertices = vertices; return(true); }
public static bool GenerateHemisphereSubMesh(CSGBrushSubMesh subMesh, Vector3 diameterXYZ, Matrix4x4 transform, int horzSegments, int vertSegments, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions) { if (diameterXYZ.x == 0 || diameterXYZ.y == 0 || diameterXYZ.z == 0) { subMesh.Clear(); return(false); } var bottomCap = true; var topCap = false; var extraVertices = ((!bottomCap) ? 1 : 0) + ((!topCap) ? 1 : 0); var rings = (vertSegments) + (topCap ? 1 : 0); var vertexCount = (horzSegments * rings) + extraVertices; var topVertex = 0; var bottomVertex = (!topCap) ? 1 : 0; var radius = new Vector3(diameterXYZ.x * 0.5f, diameterXYZ.y, diameterXYZ.z * 0.5f); var heightY = radius.y; float topY, bottomY; if (heightY < 0) { topY = 0; bottomY = heightY; } else { topY = heightY; bottomY = 0; } var vertices = new Vector3[vertexCount]; if (!topCap) { vertices[topVertex] = transform.MultiplyPoint(Vector3.up * topY); // top } if (!bottomCap) { vertices[bottomVertex] = transform.MultiplyPoint(Vector3.up * bottomY); // bottom } var degreePerSegment = (360.0f / horzSegments) * Mathf.Deg2Rad; var angleOffset = ((horzSegments & 1) == 1) ? 0.0f : 0.5f * degreePerSegment; var vertexIndex = extraVertices; if (heightY < 0) { for (int h = horzSegments - 1; h >= 0; h--, vertexIndex++) { var hRad = (h * degreePerSegment) + angleOffset; vertices[vertexIndex] = transform.MultiplyPoint(new Vector3(Mathf.Cos(hRad) * radius.x, 0.0f, Mathf.Sin(hRad) * radius.z)); } } else { for (int h = 0; h < horzSegments; h++, vertexIndex++) { var hRad = (h * degreePerSegment) + angleOffset; vertices[vertexIndex] = transform.MultiplyPoint(new Vector3(Mathf.Cos(hRad) * radius.x, 0.0f, Mathf.Sin(hRad) * radius.z)); } } for (int v = 1; v < rings; v++) { var segmentFactor = ((v - (rings / 2.0f)) / rings) + 0.5f; // [0.0f ... 1.0f] var segmentDegree = (segmentFactor * 90); // [0 .. 90] var segmentHeight = Mathf.Sin(segmentDegree * Mathf.Deg2Rad) * heightY; var segmentRadius = Mathf.Cos(segmentDegree * Mathf.Deg2Rad); // [0 .. 0.707 .. 1 .. 0.707 .. 0] for (int h = 0; h < horzSegments; h++, vertexIndex++) { vertices[vertexIndex].x = vertices[h + extraVertices].x * segmentRadius; vertices[vertexIndex].y = segmentHeight; vertices[vertexIndex].z = vertices[h + extraVertices].z * segmentRadius; } } return(GenerateSegmentedSubMesh(subMesh, horzSegments, vertSegments, vertices, bottomCap, topCap, bottomVertex, topVertex, surfaceAssets, surfaceDescriptions)); }