public void GenerateCrystal() { //Debug.Log("Generating crystal"); List <Vector3> vertices = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <int> tris = new List <int>(); for (int lobe = 0; lobe < numCrystals; lobe++) { // compute lobe parameters given randomness int lobeNumCenters = Mathf.Max(1, (int)(numCenters - randomness * numCenters * NextRandomFloat)); int lobeNumSides = Mathf.Max(MinNumSides, (int)(numCenters - randomness * numCenters * NextRandomFloat)); float lobeScale = 1f - 0.75f * randomness * NextRandomFloat; // limit maximum randomness on scale float lobeWidth = lobeScale * crystalWidth * (1f - randomness + 2f * randomness * NextRandomFloat); float lobeLength = lobeScale * crystalLength * (1f - randomness + 2f * randomness * NextRandomFloat); float maxRotation = 2f * Mathf.PI / lobeNumSides; Vector3 lobeRoot = 0.25f * randomness * new Vector3(-1f + 2f * NextRandomFloat, 0, -1f + 2f * NextRandomFloat); //Debug.Log("Generating a crystal lobe " + lobe); Vector3 lobeDir = Samplers.SampleRandomCosineHemisphere(NextRandomFloat, NextRandomFloat); Quaternion rotation = Quaternion.LookRotation(lobeDir); List <Vector3> sides = new List <Vector3>(); for (int j = 0; j < lobeNumCenters; j++) { float ratio = lobeNumCenters == 1 ? 0.5f: 1f * j / (lobeNumCenters - 1); Vector3 centerPos = lobeRoot + lobeLength * lobeDir * EvaluateDensityCurve(ratio); for (int side = 0; side < lobeNumSides; side++) { float angle = maxRotation * side; Vector3 sideDir = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)); //todo rotate to crystalDir Vector3 sidePos = centerPos + lobeWidth * sideDir * crystalSizeCurve.Evaluate(ratio); //sidePos = rotation * sidePos; sides.Add(sidePos); } } Vector3 crystalTop = lobeRoot + lobeLength * lobeDir; //Debug.Log("ROOT: " + lobeRoot); //Debug.Log("SIDES: " + sides.Count); //foreach (var v in sides) // Debug.Log(v); //Debug.Log("TOP: " + crystalTop); int index, s1, s2, s3; // generate triangles for the sides for (int j = 0; j < lobeNumCenters - 1; j++) { for (int side = 0; side < lobeNumSides; side++) { index = j * lobeNumSides + side; s1 = index; bool b = (side + 1) % lobeNumSides == 0; // need to generate 2 triangles per side for (int tri = 0; tri < 2; tri++) { if (tri == 0) // triangle 1 { s2 = b ? index + lobeNumSides : index + lobeNumSides; s3 = b ? index + 1 : index + lobeNumSides + 1; } else // triangle 2 { s2 = b ? index + 1 : index + lobeNumSides + 1; s3 = b ? index - lobeNumSides + 1 : index + 1; } //Debug.Log("Indices" + s1 + " " + s2 + " " + s3); List <Vector3> verticesLocal = new List <Vector3>() { sides[s1], sides[s2], sides[s3] }; MeshTriAdder.AddTriangle(new Vector3Int(0, 1, 2), verticesLocal, vertices, tris, false); } } } bool isBottom = true; Vector3 v1; // bottom and top triangles for (int c = 0; c < 2; c++) { if (isBottom) { v1 = lobeRoot; index = 0; // index is now used as an offset for the vertex indices } else { v1 = crystalTop; index = (lobeNumCenters - 1) * lobeNumSides; } for (int j = 0; j < lobeNumSides; j++) { if (isBottom) { s2 = index + j; s3 = (index + 1 + j) % lobeNumSides; } else { s2 = index + (1 + j) % lobeNumSides; s3 = index + j; } List <Vector3> verticesLocal = new List <Vector3>() { v1, sides[s2], sides[s3] }; MeshTriAdder.AddTriangle(new Vector3Int(0, 1, 2), verticesLocal, vertices, tris, false); } isBottom = false; } } Mesh mesh = new Mesh(); mesh.Clear(); mesh.subMeshCount = 2; mesh.SetVertices(vertices); mesh.SetTriangles(tris.ToArray(), 0); Vector2[] uvs = Unwrapping.GeneratePerTriangleUV(mesh); mesh.SetUVs(0, new List <Vector2>(uvs)); mesh.RecalculateNormals(); mesh.RecalculateBounds(); // assign back to meshFilter MeshFilter meshFilter = GetComponent <MeshFilter>(); //mesh.Optimize(); meshFilter.mesh = mesh; }