Beispiel #1
0
        // 木の枝を再帰的に辿り、全長の長さ(根元から枝先に至るまでの長さ)を返す
        static float TraverseMaxLength(TreeBranch branch)
        {
            float max = 0f;

            branch.Children.ForEach(c => {
                max = Mathf.Max(max, TraverseMaxLength(c));
            });
            return(branch.Length + max);
        }
Beispiel #2
0
 // 木の枝を再帰的に辿る
 // 到達した枝に対してAction<TreeBranch> actionコールバックを実行する
 static void Traverse(TreeBranch from, Action <TreeBranch> action)
 {
     if (from.Children.Count > 0)
     {
         from.Children.ForEach(child => {
             Traverse(child, action);
         });
     }
     action(from);
 }
Beispiel #3
0
        public TreeBranch(
            int generation,
            int generations,
            Vector3 from,
            Vector3 tangent,
            Vector3 normal,
            Vector3 binormal,
            float length,
            float radius,
            float offset,
            float rotation_b, // binormal の回転量 ::TEST
            bool haveChildren,
            TreeData data
            )
        {
            this.generation = generation;

            this.fromRadius = radius;

            // 枝先である場合は先端の太さが0になる
            this.toRadius = (generation == 0) ? 0f : radius *data.radiusAttenuation;

            this.from = from;

            // 枝先ほど分岐する角度が大きくなる
            var scale = Mathf.Lerp(1f, data.growthAngleScale, 1f - 1f * generation / generations);

            // normal方向の回転
            var qn = Quaternion.AngleAxis(scale * data.GetRandomGrowthAngle(), normal);

            this.binormalRotaion = rotation_b;
            // binormal方向の回転
            var qb = Quaternion.AngleAxis(scale * binormalRotaion, binormal);

            // 枝先が向いているtangent方向にqn * qbの回転をかけつつ、枝先の位置を決める
            this.to = from + (qn * qb) * tangent * length;

            this.length = length;
            this.offset = offset;

            // モデル生成に必要な節を構築
            segments = BuildSegments(data, fromRadius, toRadius, normal, binormal);

            segmentForChild = segments[segments.Count - 1];
            // 子を生成するときはこの フレネフレームを使う 先端から伸ばす

            children = new List <TreeBranch>();

            if (generation > 0 && fromRadius <= 0.5f && haveChildren)
            {
                // 分岐する数を取得
                int count = data.GetRandomBranches();
                for (int i = 0; i < count; i++)
                {
                    float ratio; // [0.0 ~ 1.0]
                    if (count == 1)
                    {
                        // 分岐数が1である場合(0除算を回避)
                        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];

                    // 分岐元の節が持つベクトルをTreeBranchに渡すことで滑らかな分岐を得る
                    Vector3 nt = segment.Frame.Tangent;
                    Vector3 nn = segment.Frame.Normal;
                    Vector3 nb = segment.Frame.Binormal;

                    var child = new TreeBranch(
                        this.generation - 1,
                        generations,
                        segment.Position,
                        nt,
                        nn,
                        nb,
                        this.length * Mathf.Lerp(1f, data.lengthAttenuation, ratio), // -> length
                        radius / 2,                                                  // -> fromRadius
                        offset + length,                                             // -> offset
                        rotation_b,
                        false,
                        data
                        );

                    children.Add(child);
                }
            }
        }
Beispiel #4
0
        public Mesh Build(TreeData data, int generations, float length, float radius)
        {
            data.Setup();
            generations = data.lsystem.MaxLength;
            var root = new TreeBranch(
                generations,
                length,
                radius,
                data
                );

            /*
             * TreeBranch 再帰させないで,枝を一本生成して返すっていう風にする.対象となってる treebranch を持つようにして
             * それの子に枝を追加するかどうかみたいなのを作って行けばいい.
             * 子に追加するためには,親の情報を渡すようにすればいい.root だけは作った方がいいかな.結局ランダム性があるんだkら
             * 生成してみないとワカらないよね.
             */

            string generator = data.lsystem.S_Brackets; //

            Debug.Log("Length is : " + generator.Length + " generator is: " + generator);
            var parent = root;
            List <TreeBranch> parents    = new List <TreeBranch>(); // 親をスタックしていく
            List <float>      rotations  = new List <float>();
            float             rotation_b = 0f;

            branchNum = 0;
            for (int i = 1; i < generator.Length; i++)   // root は除く

            {
                if (generator[i] == 'F')
                {
                    TreeBranch newBranch = new TreeBranch(
                        parent.Generation - 1,
                        generations,
                        parent.To,
                        parent.SegmentForChild.Frame.Tangent,
                        parent.SegmentForChild.Frame.Normal,
                        parent.SegmentForChild.Frame.Binormal,
                        parent.Length * data.lengthAttenuation,
                        parent.ToRadius,
                        parent.Offset + parent.Length,
                        rotation_b,
                        true,
                        data
                        );
                    if (newBranch.FromRadius <= 0.01f)
                    {
                        continue;
                    }
                    if (newBranch.FromRadius <= 0.5f)
                    {
                        branchDetail++; // TODO: もっと条件を追加する
                    }
                    if (Vector3.Distance(root.SegmentForChild.Position, parent.SegmentForChild.Position) > treeHeight)
                    {
                        // 見たいのは相対的な評価ならこれでも大丈夫
                        treeHeight = parent.SegmentForChild.Position.y; // (単純な高さじゃなくて,どれぐらい伸びたのかというのが正しい)
                    }
                    parent.Children.Add(newBranch);
                    branchNum++;
                    parent = newBranch;
                }
                else if (generator[i] == '+')
                {
                    rotation_b = data.lsystem.Angle; // TODO: method 使う
                    spreadDeg++;                     // FIXME: 今は回転したら広がっているとしている
                }
                else if (generator[i] == '-')
                {
                    rotation_b = -data.lsystem.Angle;
                    spreadDeg++;
                }
                else if (generator[i] == '[')
                {
                    parents.Add(parent);
                    rotations.Add(rotation_b);
                }
                else if (generator[i] == ']')
                {
                    // ']' の時
                    // parent を pop する
                    if (parents.Count <= 0)
                    {
                        Debug.LogError("At Close Bracket, somethin is wrong, maybe it's rule");
                    }
                    parent = parents[parents.Count - 1];
                    parents.RemoveAt(parents.Count - 1);
                    // 親の回転より回転を元に戻す
                    // -> 親がもともと曲がっててて,それに対して F はその曲がったまま伸びるため
                    rotation_b = rotations[rotations.Count - 1];
                    rotations.RemoveAt(rotations.Count - 1);
                }
            }
            Debug.Log(branchNum);

            data.lsystem.SetEvalInfo(treeHeight, spreadDeg, branchNum, data.radiusAttenuation, branchDetail);

            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>();

            // 木の全長を取得
            // 枝の長さを全長で割ることで、uv座標の高さ(uv.y)が
            // 根元から枝先に至るまで[0.0 ~ 1.0]で変化するように設定する
            float maxLength = TraverseMaxLength(root);

            // 再帰的に全ての枝を辿り、一つ一つの枝に対応するMeshを生成する
            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);
                    }
                }
            });

            var mesh = new Mesh();

            mesh.vertices = vertices.ToArray();
            Debug.Log("vertices's count: " + vertices.Count);
            mesh.normals   = normals.ToArray();
            mesh.tangents  = tangents.ToArray();
            mesh.uv        = uvs.ToArray();
            mesh.triangles = triangles.ToArray();
            mesh.RecalculateBounds();


            return(mesh);
        }