private bool GenerateSphere(float radius, int splits, CSGModel parentModel, CSGBrush brush, out ControlMesh controlMesh, out Shape shape) { if (prevSplits != splits || prevIsHemisphere != IsHemiSphere || splitControlMesh == null || splitShape == null) { splitControlMesh = null; splitShape = null; BrushFactory.CreateCubeControlMesh(out splitControlMesh, out splitShape, Vector3.one); var axi = new Vector3[] { MathConstants.upVector3, MathConstants.leftVector3, MathConstants.forwardVector3 }; List<int> intersectedEdges = new List<int>(); float step = 1.0f / (float)(splits + 1); float offset; for (int i = 0; i < axi.Length; i++) { var normal = axi[i]; offset = 0.5f - step; while (offset > 0.0f) { ControlMeshUtility.CutMesh(splitControlMesh, splitShape, new CSGPlane(-normal, -offset), ref intersectedEdges); if (i != 0 || !IsHemiSphere) { ControlMeshUtility.CutMesh(splitControlMesh, splitShape, new CSGPlane(normal, -offset), ref intersectedEdges); } offset -= step; } if (i != 0 || !IsHemiSphere) { if ((splits & 1) == 1) ControlMeshUtility.CutMesh(splitControlMesh, splitShape, new CSGPlane(normal, 0), ref intersectedEdges); } } if (IsHemiSphere) { var cuttingPlane = new CSGPlane(MathConstants.upVector3, 0); intersectedEdges.Clear(); if (ControlMeshUtility.CutMesh(splitControlMesh, splitShape, cuttingPlane, ref intersectedEdges)) { var edge_loop = ControlMeshUtility.FindEdgeLoop(splitControlMesh, ref intersectedEdges); if (edge_loop != null) { if (ControlMeshUtility.SplitEdgeLoop(splitControlMesh, splitShape, edge_loop)) { Shape foundShape; ControlMesh foundControlMesh; ControlMeshUtility.FindAndDetachSeparatePiece(splitControlMesh, splitShape, cuttingPlane, out foundControlMesh, out foundShape); } } } } // Spherize the cube for (int i = 0; i < splitControlMesh.Vertices.Length; i++) { Vector3 v = splitControlMesh.Vertices[i] * 2.0f; float x2 = v.x * v.x; float y2 = v.y * v.y; float z2 = v.z * v.z; Vector3 s; s.x = v.x * Mathf.Sqrt(1f - (y2 * 0.5f) - (z2 * 0.5f) + ((y2 * z2) / 3.0f)); s.y = v.y * Mathf.Sqrt(1f - (z2 * 0.5f) - (x2 * 0.5f) + ((z2 * x2) / 3.0f)); s.z = v.z * Mathf.Sqrt(1f - (x2 * 0.5f) - (y2 * 0.5f) + ((x2 * y2) / 3.0f)); splitControlMesh.Vertices[i] = s;//(splitControlMesh.Vertices[i] * 0.75f) + (splitControlMesh.Vertices[i].normalized * 0.25f); } if (!ControlMeshUtility.Triangulate(null, splitControlMesh, splitShape)) { Debug.LogWarning("!ControlMeshUtility.IsConvex"); controlMesh = null; shape = null; return false; } ControlMeshUtility.FixTexGens(splitControlMesh, splitShape); if (!ControlMeshUtility.IsConvex(splitControlMesh, splitShape)) { Debug.LogWarning("!ControlMeshUtility.IsConvex"); controlMesh = null; shape = null; return false; } ControlMeshUtility.UpdateTangents(splitControlMesh, splitShape); prevSplits = splits; prevIsHemisphere = IsHemiSphere; } if (splitControlMesh == null || splitShape == null || !splitControlMesh.Valid) { Debug.LogWarning("splitControlMesh == null || splitShape == null || !splitControlMesh.IsValid"); controlMesh = null; shape = null; return false; } controlMesh = splitControlMesh.Clone(); shape = splitShape.Clone(); /* float angle_offset = GeometryUtility.SignedAngle(gridTangent, delta / sphereRadius, buildPlane.normal); angle_offset -= 90; angle_offset += sphereOffset; angle_offset *= Mathf.Deg2Rad; Vector3 p1 = MathConstants.zeroVector3; for (int i = 0; i < realSplits; i++) { var angle = ((i * Mathf.PI * 2.0f) / (float)realSplits) + angle_offset; p1.x = (Mathf.Sin(angle) * sphereRadius); p1.z = (Mathf.Cos(angle) * sphereRadius); } */ for (int i = 0; i < controlMesh.Vertices.Length; i++) { var vertex = controlMesh.Vertices[i]; vertex *= radius; controlMesh.Vertices[i] = vertex; } for (int i = 0; i < shape.Surfaces.Length; i++) { var plane = shape.Surfaces[i].Plane; plane.d *= radius; shape.Surfaces[i].Plane = plane; } bool smoothShading = SphereSmoothShading; if (!sphereSmoothingGroup.HasValue && smoothShading) { sphereSmoothingGroup = SurfaceUtility.FindUnusedSmoothingGroupIndex(); } for (int i = 0; i < shape.TexGenFlags.Length; i++) { shape.TexGens[i].SmoothingGroup = smoothShading ? sphereSmoothingGroup.Value : 0; } var defaultTexGen = new TexGen(); defaultTexGen.Scale = MathConstants.oneVector3; //defaultTexGen.Color = Color.white; var fakeSurface = new Surface(); fakeSurface.TexGenIndex = 0; var defaultMaterial = CSGSettings.DefaultMaterial; for (var s = 0; s < shape.Surfaces.Length; s++) { var texGenIndex = shape.Surfaces[s].TexGenIndex; var axis = GeometryUtility.SnapToClosestAxis(shape.Surfaces[s].Plane.normal); var rotation = Quaternion.FromToRotation(axis, MathConstants.backVector3); var matrix = Matrix4x4.TRS(MathConstants.zeroVector3, rotation, MathConstants.oneVector3); SurfaceUtility.AlignTextureSpaces(matrix, false, ref shape.TexGens[texGenIndex], ref shape.TexGenFlags[texGenIndex], ref shape.Surfaces[s]); shape.TexGens[texGenIndex].RenderMaterial = defaultMaterial; } return true; }