static float TraverseMaxLength(TreeBranch branch) { float max = 0f; branch.Children.ForEach(c => { max = Mathf.Max(max, TraverseMaxLength(c)); }); return(branch.Length + max); }
static void Traverse(TreeBranch from, Action <TreeBranch> action) { if (from.Children.Count > 0) { from.Children.ForEach(child => { Traverse(child, action); }); } action(from); }
protected TreeBranch(List <TreeBranch> branches, int generation, int generations, Vector3 from, Vector3 tangent, Vector3 normal, Vector3 binormal, float length, float radius, float offset, TreeData data) { this.generation = generation; this.fromRadius = radius; this.toRadius = (generation == 0) ? 0f : radius *data.radiusAttenuation; this.from = from; var scale = Mathf.Lerp(1f, data.growthAngleScale, 1f - 1f * generation / generations); var rotation = Quaternion.AngleAxis(scale * data.RandomGrowthAngle, normal) * Quaternion.AngleAxis(scale * data.RandomGrowthAngle, binormal); this.to = from + rotation * tangent * length; this.length = length; this.offset = offset; segments = BuildSegments(data, fromRadius, toRadius, normal, binormal); branches.Add(this); children = new List <TreeBranch>(); if (generation > 0) { int count = data.RandomBranches; for (int i = 0; i < count; i++) { float ratio; if (count == 1) { // for zero division ratio = 1f; } else { ratio = Mathf.Lerp(0.5f, 1f, (1f * i) / (count - 1)); } var index = Mathf.FloorToInt(ratio * (segments.Count - 1)); var segment = segments[index]; Vector3 nt, nn, nb; if (ratio >= 1f) { // sequence branch nt = segment.Frame.Tangent; nn = segment.Frame.Normal; nb = segment.Frame.Binormal; } else { var rot = Quaternion.AngleAxis(i * 90f, tangent); nt = rot * tangent; nn = rot * normal; nb = rot * binormal; } var child = new TreeBranch( branches, this.generation - 1, generations, segment.Position, nt, nn, nb, length * Mathf.Lerp(1f, data.lengthAttenuation, ratio), radius * Mathf.Lerp(1f, data.radiusAttenuation, ratio), offset + length, data ); children.Add(child); } } }
static MeshObjectData CreateFoliage(TreeData data, TreeBranch Branch, int index) { MeshDraft m; switch (data.FoliageBasePrimitiveShape) { case TreeData.BasePrimitiveShapes.Dodecahedron: m = MeshDraft.Dodecahedron(0.5f); break; case TreeData.BasePrimitiveShapes.Icosahedron: m = MeshDraft.Icosahedron(0.5f, false); break; case TreeData.BasePrimitiveShapes.Prism: m = MeshDraft.Prism(0.5f, data.foliageSegments, 0.1f, false); break; case TreeData.BasePrimitiveShapes.Pyramid: m = MeshDraft.Pyramid(0.5f, data.foliageSegments, 0.5f, false); break; default: m = MeshDraft.Sphere(0.5f, data.foliageSegments, data.foliageSegments, false); break; } MeshObjectData plant = new MeshObjectData(); plant.vertices = m.vertices.ToArray(); plant.triangles = m.triangles.ToArray(); plant.tangents = m.tangents.ToArray(); plant.AutoWeldMesh(0.0001f, 0.4f); Vector3[] verts = plant.vertices; float currentNoise = data.noise; currentNoise *= 0.4f; Vector3 Pos = Branch.To; plant.position = Pos; int s = data.TreeSeed + index + Mathf.RoundToInt(Pos.x) + Mathf.RoundToInt(Pos.y) + Mathf.RoundToInt(Pos.z) + Mathf.RoundToInt(Branch.Length); Rand r = new Rand(s); for (int i = 0; i < verts.Length; i++) { verts[i].x += r.Range(-currentNoise, currentNoise); verts[i].y += r.Range(-currentNoise, currentNoise); verts[i].z += r.Range(-currentNoise, currentNoise); } plant.vertices = verts; plant.flatShade(); Color[] vertexColor = new Color[plant.vertices.Length]; Color CC = data.foliageColors[r.Range(0, data.foliageColors.Length)]; for (int c = 0; c < plant.vertices.Length; c++) { vertexColor[c] = CC; } plant.colors = vertexColor; return(plant); }
public static void Build(TreeThreadReturnData ReturnData) { TreeData data = ReturnData.TreeData; var root = new TreeBranch( data.generations, data.length, data.radius, data ); var vertices = new List <Vector3>(); var normals = new List <Vector3>(); var tangents = new List <Vector4>(); var uvs = new List <Vector2>(); var triangles = new List <int>(); List <MeshObjectData> Foliages = new List <MeshObjectData>(); Rand rand; int FolCheckCount = 0; float maxLength = TraverseMaxLength(root); Traverse(root, (branch) => { var offset = vertices.Count; var vOffset = branch.Offset / maxLength; var vLength = branch.Length / maxLength; for (int i = 0, n = branch.Segments.Count; i < n; i++) { var t = 1f * i / (n - 1); var v = vOffset + vLength * t; var segment = branch.Segments[i]; var N = segment.Frame.Normal; var B = segment.Frame.Binormal; for (int j = 0; j <= data.radialSegments; j++) { // 0.0 ~ 2π var u = 1f * j / data.radialSegments; float rad = u * PI2; float cos = Mathf.Cos(rad), sin = Mathf.Sin(rad); var normal = (cos * N + sin * B).normalized; vertices.Add(segment.Position + segment.Radius * normal); normals.Add(normal); var tangent = segment.Frame.Tangent; tangents.Add(new Vector4(tangent.x, tangent.y, tangent.z, 0f)); uvs.Add(new Vector2(u, v)); } } for (int j = 1; j <= data.heightSegments; j++) { for (int i = 1; i <= data.radialSegments; i++) { int a = (data.radialSegments + 1) * (j - 1) + (i - 1); int b = (data.radialSegments + 1) * j + (i - 1); int c = (data.radialSegments + 1) * j + i; int d = (data.radialSegments + 1) * (j - 1) + i; a += offset; b += offset; c += offset; d += offset; triangles.Add(a); triangles.Add(d); triangles.Add(b); triangles.Add(b); triangles.Add(d); triangles.Add(c); } } //plants if (branch.Children == null || branch.Children.Count == 0) { rand = new Rand(FolCheckCount + data.TreeSeed); float chance = rand.Range(0f, 100f); Debug.Log(chance); if (chance <= data.foliageChance) { Foliages.Add(CreateFoliage(data, branch, Foliages.Count + FolCheckCount)); } FolCheckCount++; } }); MeshObjectData TreeMeshData = new MeshObjectData(); TreeMeshData.vertices = vertices.ToArray(); TreeMeshData.triangles = triangles.ToArray(); TreeMeshData.position = ReturnData.TreePos; TreeMeshData.flatShade(); Color[] treecolor = new Color[TreeMeshData.vertices.Length]; for (int i = 0; i < TreeMeshData.vertices.Length; i++) { treecolor[i] = data.branchColor; } TreeMeshData.colors = treecolor; ReturnData.TreeBuildData = TreeMeshData; ReturnData.FoliagesBuildData = Foliages.ToArray(); ReturnData.ManagerCallBack(ReturnData); }