public static void DuplicateSelected() { IEnumerable <GameObject> selectedObjs = Selection.GetFiltered(typeof(GameObject), SelectionMode.Editable | SelectionMode.TopLevel | SelectionMode.ExcludePrefab).Cast <GameObject>(); List <GameObject> newObjs = new List <GameObject>(); foreach (GameObject go in selectedObjs) { TreeCurve tc = go.GetComponent <TreeCurve>(); if (tc == null) { Debug.LogWarning("Selected object \"" + go.name + "\" isn't a tree and was ignored."); continue; } Transform tr = go.transform; GameObject go2 = GameObject.Instantiate <GameObject>(go); go2.name = go.name + " 2"; newObjs.Add(go2); Transform tr2 = go2.transform; tr2.position = tr.position; tr2.rotation = tr.rotation; tr2.localScale = tr.localScale; //Remove the reference to the original object's trunk/foliage meshes. foreach (TreeCurve tc2 in go2.GetComponentsInChildren <TreeCurve>().ToArray()) { tc2.GetComponent <MeshFilter>().sharedMesh = null; tc2.OnValidate(); } foreach (CurveFoliage cf in go2.GetComponentsInChildren <CurveFoliage>().ToArray()) { cf.GetComponent <MeshFilter>().sharedMesh = null; cf.OnValidate(); } } //Select the duplicates. Selection.objects = newObjs.ToArray(); }
/// <summary> /// Re-generates the foliage mesh. /// </summary> public void OnValidate() { //Make sure inputs are sane. VerticalAngle = Mathf.Clamp01(VerticalAngle); VerticalAngleVariance = Mathf.Max(0.0f, VerticalAngleVariance); MinPieces = Mathf.Max(MinPieces, 0); MaxPieces = Mathf.Max(MaxPieces, MinPieces); SpawnDistribution = Mathf.Max(0.00001f, SpawnDistribution); MinSpawnLength = Mathf.Clamp01(MinSpawnLength); MinSize = Mathf.Max(0.0f, MinSize); MaxSize = Mathf.Max(MinSize, MaxSize); if (myMF == null) { myMF = GetComponent <MeshFilter>(); } TreeCurve tc = transform.parent.GetComponent <TreeCurve>(); Vector3[] preC = tc.Curve.PreCalculateValues(); Rand.seed = Seed; //Calculate the position, normal/tangent, and size of each foliage quad. List <Piece> pieces = new List <Piece>(); int nPieces = Rand.Range(MinPieces, MaxPieces); pieces.Capacity = nPieces; for (int i = 0; i < nPieces; ++i) { float t = Mathf.Lerp(MinSpawnLength, 1.0f, Mathf.Pow(Rand.value, SpawnDistribution)); var posAndDerivative = tc.Curve.GetValueAndDerivative(t, preC); posAndDerivative.Derivative.Normalize(); Vector3 perp = posAndDerivative.Perpendicular.normalized; float sizeF = Rand.Range(MinSize, MaxSize); Vector2 size = new Vector2(sizeF, sizeF); Vector3 curveNormal = Quaternion.AngleAxis(Rand.Range(5.0f, 355.0f), posAndDerivative.Derivative) * perp; curveNormal = new Vector3(curveNormal.x, 0.0f, curveNormal.z).normalized; Piece p = new Piece(); p.Pos = posAndDerivative.Value + (size.y * 0.5f * curveNormal); p.Normal = Vector3.Cross(curveNormal, new Vector3(0.0f, 1.0f, 0.0f)).normalized; float angle = Mathf.Lerp(-90.0f, 90.0f, VerticalAngle + Rand.Range(-VerticalAngleVariance, VerticalAngleVariance)); p.Normal = Quaternion.AngleAxis(angle, curveNormal) * p.Normal; p.Tangent = curveNormal; p.Size = size; pieces.Add(p); } //Convert the "pieces" list into a mesh. if (MyMesh == null) { MyMesh = new Mesh(); } else { MyMesh.Clear(); } switch (Mode) { case MeshModes.Point: MyMesh.vertices = pieces.Select(p => p.Pos).ToArray(); MyMesh.normals = pieces.Select(p => p.Normal).ToArray(); MyMesh.tangents = pieces.Select(p => { return(new Vector4(p.Tangent.x, p.Tangent.y, p.Tangent.z, 1.0f)); }).ToArray(); MyMesh.uv = pieces.Select(p => p.Size).ToArray(); int i = -1; MyMesh.SetIndices(pieces.Select(p => { i += 1; return(i); }).ToArray(), MeshTopology.Points, 0); break; case MeshModes.Quad: Vector3[] poses = new Vector3[pieces.Count * 4], normals = new Vector3[pieces.Count * 4]; Vector4[] tangents = new Vector4[pieces.Count * 4]; Vector2[] uvs = new Vector2[pieces.Count * 4]; int[] indices = new int[pieces.Count * 6]; for (int j = 0; j < pieces.Count; ++j) { Piece p = pieces[j]; Vector3 bitangent = Vector3.Cross(p.Normal, p.Tangent).normalized; Vector3 deltaX = 0.5f * p.Tangent * p.Size.y, deltaY = 0.5f * bitangent * p.Size.x; int vIndex = j * 4, iIndex = j * 6; poses[vIndex] = p.Pos + (-deltaX + -deltaY); uvs[vIndex] = new Vector2(0.0f, 0.0f); poses[vIndex + 1] = p.Pos + (deltaX + -deltaY); uvs[vIndex + 1] = new Vector2(1.0f, 0.0f); poses[vIndex + 2] = p.Pos + (-deltaX + deltaY); uvs[vIndex + 2] = new Vector2(0.0f, 1.0f); poses[vIndex + 3] = p.Pos + (deltaX + deltaY); uvs[vIndex + 3] = new Vector2(1.0f, 1.0f); normals[vIndex] = p.Normal; normals[vIndex + 1] = p.Normal; normals[vIndex + 2] = p.Normal; normals[vIndex + 3] = p.Normal; Vector4 tang = new Vector4(p.Tangent.x, p.Tangent.y, p.Tangent.z, 1.0f); tangents[vIndex] = tang; tangents[vIndex + 1] = tang; tangents[vIndex + 2] = tang; tangents[vIndex + 3] = tang; indices[iIndex] = vIndex; indices[iIndex + 1] = vIndex + 1; indices[iIndex + 2] = vIndex + 3; indices[iIndex + 3] = vIndex; indices[iIndex + 4] = vIndex + 3; indices[iIndex + 5] = vIndex + 2; } MyMesh.vertices = poses; MyMesh.normals = normals; MyMesh.tangents = tangents; MyMesh.uv = uvs; MyMesh.SetIndices(indices, MeshTopology.Triangles, 0); break; default: throw new NotImplementedException(Mode.ToString()); } MyMesh.UploadMeshData(false); }
private static void AddBranchTo(TreeCurve root, TreeCurve toCopy) { GameObject go = new GameObject("Branch"); TreeCurve tc = go.AddComponent<TreeCurve>(); tc.DrawCurveGizmo = false; tc.Curve = new Curve(toCopy.Curve.Points.ToList()); tc.RadiusAlongCurve = new AnimationCurve(toCopy.RadiusAlongCurve.keys.ToArray()); tc.RadiusAroundCurve = new AnimationCurve(toCopy.RadiusAroundCurve.keys.ToArray()); tc.RadiusVarianceAlongCurve = new AnimationCurve(toCopy.RadiusVarianceAlongCurve.keys.ToArray()); if (root == toCopy) { tc.RadiusScale = toCopy.RadiusScale * 0.5f; } else { tc.RadiusScale = toCopy.RadiusScale; } tc.CurveDivisionsAlong = toCopy.CurveDivisionsAlong; tc.CurveDivisionsAround = toCopy.CurveDivisionsAround; tc.OnValidate(); MeshRenderer mrOld = toCopy.GetComponent<MeshRenderer>(); if (mrOld != null) { MeshRenderer mr = go.AddComponent<MeshRenderer>(); mr.sharedMaterial = mrOld.sharedMaterial; } //Add a mesh collider for ray-casting. myMC = root.GetComponent<MeshCollider>(); if (myMC == null) { myMC = root.gameObject.AddComponent<MeshCollider>(); } //Set the scale to be equal to the copy, or half of the copy if the copy is also the root. NewBranch = go.transform; NewBranch.localScale = toCopy.transform.localScale; NewBranch.parent = root.transform; }