// TODO: could probably figure out "inverse" from direction of topY compared to bottomY public static Vector3[] GetConeFrustumVertices(CSGCircleDefinition definition, float topHeight, float rotation, int segments, ref Vector3[] vertices, bool inverse = false) { var rotate = Quaternion.AngleAxis(rotation, Vector3.up); var bottomAxisX = rotate * Vector3.right * definition.diameterX * 0.5f; var bottomAxisZ = rotate * Vector3.forward * definition.diameterZ * 0.5f; var topY = Vector3.up * topHeight; var bottomY = Vector3.up * definition.height; if (vertices == null || vertices.Length != segments + 1) { vertices = new Vector3[segments + 1]; } float angleOffset = ((segments & 1) == 1) ? 0.0f : ((360.0f / segments) * 0.5f); vertices[0] = topY; for (int v = 0; v < segments; v++) { var r = (((v * 360.0f) / (float)segments) + angleOffset) * Mathf.Deg2Rad; var s = Mathf.Sin(r); var c = Mathf.Cos(r); var bottomVertex = (bottomAxisX * c) + (bottomAxisZ * s); bottomVertex += bottomY; var vi = inverse ? (segments - v) : (v + 1); vertices[vi] = bottomVertex; } return(vertices); }
public static bool GenerateCylinderSubMesh(CSGBrushSubMesh subMesh, CSGCircleDefinition bottom, float topHeight, float rotation, int sides, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions) { CSGCircleDefinition top; top.diameterX = bottom.diameterX; top.diameterZ = bottom.diameterZ; top.height = topHeight; return(GenerateConicalFrustumSubMesh(subMesh, bottom, top, rotation, sides, surfaceAssets, surfaceDescriptions)); }
public static bool GenerateConeAsset(CSGBrushMeshAsset brushMeshAsset, CSGCircleDefinition bottom, float topHeight, float rotation, int sides, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions) { CSGCircleDefinition top; top.diameterX = 0; top.diameterZ = 0; top.height = topHeight; return(GenerateConicalFrustumAsset(brushMeshAsset, bottom, top, rotation, sides, surfaceAssets, surfaceDescriptions)); }
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 Vector3[] GetConicalFrustumVertices(CSGCircleDefinition bottom, CSGCircleDefinition top, float rotation, int segments, ref Vector3[] vertices) { if (top.height > bottom.height) { var temp = top; top = bottom; bottom = temp; } var rotate = Quaternion.AngleAxis(rotation, Vector3.up); var topAxisX = rotate * Vector3.right * top.diameterX * 0.5f; var topAxisZ = rotate * Vector3.forward * top.diameterZ * 0.5f; var bottomAxisX = rotate * Vector3.right * bottom.diameterX * 0.5f; var bottomAxisZ = rotate * Vector3.forward * bottom.diameterZ * 0.5f; var topY = Vector3.up * top.height; var bottomY = Vector3.up * bottom.height; // TODO: handle situation where diameterX & diameterZ are 0 (only create one vertex) if (vertices == null || vertices.Length != segments * 2) { vertices = new Vector3[segments * 2]; } float angleOffset = ((segments & 1) == 1) ? 0.0f : ((360.0f / segments) * 0.5f); for (int v = 0; v < segments; v++) { var r = (((v * 360.0f) / (float)segments) + angleOffset) * Mathf.Deg2Rad; var s = Mathf.Sin(r); var c = Mathf.Cos(r); var topVertex = (topAxisX * c) + (topAxisZ * s); var bottomVertex = (bottomAxisX * c) + (bottomAxisZ * s); topVertex += topY; bottomVertex += bottomY; vertices[v] = topVertex; vertices[v + segments] = bottomVertex; } return(vertices); }
public static bool GenerateConicalFrustumAsset(CSGBrushMeshAsset brushMeshAsset, 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)) { brushMeshAsset.Clear(); return(false); } if (surfaceAssets.Length != 3 || surfaceDescriptions.Length != segments + 2) { brushMeshAsset.Clear(); return(false); } var subMesh = new CSGBrushSubMesh(); if (!GenerateConicalFrustumSubMesh(subMesh, bottom, top, rotation, segments, surfaceAssets, surfaceDescriptions)) { brushMeshAsset.Clear(); return(false); } brushMeshAsset.SubMeshes = new CSGBrushSubMesh[] { subMesh }; brushMeshAsset.CalculatePlanes(); brushMeshAsset.SetDirty(); return(true); }