近期的一些进展ww

刚取得一些进展于是丢上来www还在制作中。

大概是一个渲染树的东西,不过也不全是w

上面的图大概是“进化过程”。前面的没什么好说的,主要说下Tree3(单说树枝的绘制方法,不讨论这个分形结构有多丑):

它是这样构成的:

首先,把整个树枝分为几段,每一段是一个小“圆柱”(会有各种扭曲但是一定对应着圆形的截面)。在这里我把它分成了10段,圆形截面用六边形近似。

这根树枝的长度是固定的。根据这个长度求得每段的长度,先把每段抽象成一条线段,那么整个树枝就是一条折线。

每段的粗细程度自底向上减小,并带一点噪波(我把根部那一段做了加粗处理)。

长度固定。然后是旋转(生长方向):

产生两个PerlinNoise,简记为noiseA和noiseP。

生长方向在前一段的基础上,做如下操作:

  1) 先确定转轴:旋转轴以垂直于前一段生长方向的单位向量为基础(tangent),绕前一段生长方向旋转noiseP度。

  2) 这一段的生长方向就是前一段的生长方向绕上一步确定的转轴旋转noiseA度。

大概就是这样,之后考虑加入重力和“径向扭曲”来营造真实感。当然还是先把分形结构改一下www

在研究了一会SpeedTree之后改的这些。不得不说学到了好多东西w

(植物在微重力环境下的生长: http://global.jaxa.jp/article/special/kibo/takahashi_e.html

下面是代码(用Unity写的,为了之后各种东西写着也方便,想做一个小demo):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Assets.FractalSystemCore.NodeInherits
{
    public class TreeSplineNode
    {
        public Vector3 positionLocal = Vector3.zero;
        public Quaternion rotationGlobal = Quaternion.identity;
        public Vector3 tangentGlobal = Vector3.zero;
        public float radius;
    }

    public enum BranchType
    {
        Trank,
        Branch,
        Root,
        Leaves
    }

    //这里所有旋转为Global,位置为local。
    class TreeVer3_CycWithSpline : FractalSystemNode
    {
        public int circleFragments = 6, nodes = 10;
        public float radiusRate = 0.025f, height = 1.0f;

        List<TreeSplineNode> spline = new List<TreeSplineNode>();

        BranchType branchType = BranchType.Trank;

        #region 形态处理函数

        public void UpdateSpline()
        {
            int i = 0;

            float startRadius, endRadius;
            startRadius = radiusRate * growRate;

            if(branchType == BranchType.Leaves)
            {
                return;
            }
            if(branchType == BranchType.Trank)
            {
                endRadius = startRadius * 0.15f;
            }
            else
            {
                endRadius = startRadius * 0.02f;
            }

            Vector3 startPos = centerPos;
            Quaternion q = rotation;
            float lengthStep = height * growRate / (spline.Count);

            /*
            在样条线上加一个PerlinNoise,两层(一层是幅度一层是相位)

            转轴旋转平面垂直于上一个节点的生长方向,从0开始旋转noiseP度;
            然后绕转轴旋转noiseA度。
            */

            int noiseStep = spline.Count / 4;
            float noiseAmpl = 8;//(height * growRate) / 6.0;

            float[] noiseA = MathCore.PerlinNoise(spline.Count, noiseStep, noiseAmpl, 0);
            float[] noiseP = MathCore.PerlinNoise(spline.Count, noiseStep, 180, 0);//相位先设定为2pi

            //样条线
            //第一个点和当前node的数据一致
            spline[i].positionLocal = centerPos;
            spline[i].rotationGlobal = rotation;
            spline[i].tangentGlobal = (rotation * new Vector3(1, 0, 0));//假定切线在x轴
            spline[i].radius = startRadius;

            //如果是主干,根部加粗
            if(branchType == BranchType.Trank)
            {
                spline[i].radius *= 2.0f;
            }

            for (i = 1; i < spline.Count; i++)
            {
                //位置是由上一个node的生长方向决定的
                spline[i].positionLocal = spline[i - 1].positionLocal + spline[i - 1].rotationGlobal * new Vector3(0, lengthStep, 0);

                //当前旋转方向由噪声决定
                //先让这个节点的方向和上一个节点的方向保持一致
                spline[i].rotationGlobal = spline[i - 1].rotationGlobal;
                spline[i].tangentGlobal = spline[i - 1].tangentGlobal;

                //再处理旋转
                //转轴
                Vector3 rotateAxis = Quaternion.AngleAxis(noiseP[i], spline[i - 1].rotationGlobal * new Vector3(0, lengthStep, 0)) * spline[i - 1].tangentGlobal;
                rotateAxis.Normalize();

                //旋转
                Quaternion quaternion = Quaternion.AngleAxis(noiseA[i], rotateAxis);
                spline[i].rotationGlobal = quaternion * spline[i].rotationGlobal;
                spline[i].tangentGlobal = quaternion * spline[i].tangentGlobal;

                //处理当前结点截面的大小
                spline[i].radius = ((endRadius - startRadius) * (i / ((float)spline.Count)) + startRadius) * Random.Range(0.9f, 1.1f);
            }
        }

        #endregion

        public override void Express(
            Vector3[] vertices,
            ref int verticesCount,
            int[] indices,
            ref int indicesCount,
            Vector3[] normals,
            ref int normalsCount,
            Vector2[] uvs,
            ref int uvsCount,
            Vector2[] uv2s,
            ref int uv2sCount,
            Vector4[] tangents,
            ref int tangentsCount,
            ref FractalRenderState state
            )
        {
            /*

            按圆柱表面坐标系上点的坐标给点标号。圆为横轴,高为纵轴。

            顶点(x,y)坐标:
                rad = x * (2f * Mathf.PI / circleFragments);
Vertex =        (cos(rad) * radius, y * heightStep, sin(rad) * radius);

            顶点(x,y)法线:
                rad = x * (2f * Mathf.PI / circleFragments);
Normal =        (cos(rad), 0, sin(rad))

            构成整个子结构的面:
                for(x = 0; x < circleFragments - 1; x++)
                    for(y = 0; y < heightFragments - 1; y++)
Indices =               ( x, y ) ( x + 1, y + 1 ) ( x + 1, y ); ( x, y ) ( x , y + 1 ) ( x + 1, y + 1 )
                
                不封口。反正也看不见(
            */

            //int vert = 0, x, y;
            //float radius = radiusRate * growRate, heightStep = height * growRate / (spline.Count);
            //float rad;

            //添加样条线节点
            for(int i = 0; i < nodes; i++)
            {
                spline.Add(new TreeSplineNode());
            }

            //先处理样条线的形态
            UpdateSpline();
            //施加重力
            //施加径向扭曲力

            //绘制
            int vert = 0, x, index;
            float rad, radiusReal;

            #region Vertices & Normals

            for (index = 0; index < spline.Count; index++)
            {
                for (x = 0; x < circleFragments; x++)
                {
                    radiusReal = spline[index].radius * Random.Range(0.9f, 1.1f);

                    rad = x * (2f * Mathf.PI / circleFragments);

                    vertices[verticesCount + (x + index * circleFragments)] =
                        state.centerPos + (spline[index].rotationGlobal * new Vector3(
                            Mathf.Cos(rad) * radiusReal,
                            0,
                            Mathf.Sin(rad) * radiusReal)) + spline[index].positionLocal;

                    normals[verticesCount + (x + index * circleFragments)] = spline[index].rotationGlobal * new Vector3(
                        Mathf.Cos(rad),
                        0,
                        Mathf.Sin(rad));

                    vert++;
                }
            }

            #endregion

            #region Indices

            for (x = 0; x < circleFragments - 1; x++)
                for (index = 0; index < (spline.Count - 1); index++)
                {
                    //Indices = ( x, y ) ( x + 1, y + 1 ) ( x + 1, y ); ( x, y ) ( x , y + 1 ) ( x + 1, y + 1 )
                    indices[indicesCount++] = verticesCount + (x + index * circleFragments);
                    indices[indicesCount++] = verticesCount + (x + 1 + (index + 1) * circleFragments);
                    indices[indicesCount++] = verticesCount + (x + 1 + index * circleFragments);
                    indices[indicesCount++] = verticesCount + (x + index * circleFragments);
                    indices[indicesCount++] = verticesCount + (x + (index + 1) * circleFragments);
                    indices[indicesCount++] = verticesCount + (x + 1 + (index + 1) * circleFragments);
                }

            for (index = 0; index < (spline.Count - 1); index++)
            {
                //Indices = ( x, y ) ( x + 1, y + 1 ) ( x + 1, y ); ( x, y ) ( x , y + 1 ) ( x + 1, y + 1 )
                indices[indicesCount++] = verticesCount + (x + index * circleFragments);
                indices[indicesCount++] = verticesCount + (0 + (index + 1) * circleFragments);
                indices[indicesCount++] = verticesCount + (0 + index * circleFragments);
                indices[indicesCount++] = verticesCount + (x + index * circleFragments);
                indices[indicesCount++] = verticesCount + (x + (index + 1) * circleFragments);
                indices[indicesCount++] = verticesCount + (0 + (index + 1) * circleFragments);
            }

            #endregion

            verticesCount += vert;
            normalsCount += vert;
            //indicesCount已经在上面加过了

            state.centerPos += spline[spline.Count - 1].positionLocal;
            state.rotation = Quaternion.identity;
        }

        static float panStepStart = 60f;
        static float panStepStop = 120f;
        static float panOffsetMax = 60f;
        static float tiltStart = 20f;
        static float tiltEnd = 70f;

        /*
            生长率控制,在这里生长率为和这个树枝与主干的夹角(tilt)线性相关的一个量和一个加性高斯噪声叠加而成。start与end定义出这个线性相关量(与tilt相对应),noiseRad定义出噪声的方差(功率)。
        */
        static float growRateStart = 0.6f;
        static float growRateEnd = 0.8f;
        static float growNoiseRad = 0.04f;

        public override void generateChildren()
        {
            float nowDeg = 0f, offset = Random.Range(0f, panOffsetMax);

            while (nowDeg < 360.0f)
            {
                nowDeg += Random.Range(panStepStart, panStepStop);
                float tilt = Random.Range(tiltStart, tiltEnd);

                FractalSystemNode node = new TreeVer3_CycWithSpline();
                node.rotation = Quaternion.AngleAxis(tilt,
                    Quaternion.AngleAxis(offset, Vector3.up) * Quaternion.AngleAxis(nowDeg, Vector3.up) * new Vector3(0, 0, 1)) * rotation;

                node.centerPos = new Vector3(0, 0, 0);

                //与旋转角度的余弦线性相关
                node.growRate = growRate * (((Mathf.Cos(tiltStart / 180.0f * Mathf.PI) - Mathf.Cos(tilt / 180.0f * Mathf.PI)) / (Mathf.Cos(tiltStart / 180.0f * Mathf.PI) - Mathf.Cos(tiltEnd / 180.0f * Mathf.PI))) *
                    ((growRateEnd) - (growRateStart)) + growRateStart + Random.Range(-growNoiseRad, growNoiseRad));

                node.globalRotation = node.rotation;// * globalRotation;
                node.centerPos = node.centerPos + globalPos;

                //朝向下方的惩罚(得不到光照etc.)
                Vector3 final = node.globalRotation * Vector3.up;
                if (final.y < 0.1f)
                {
                    float factor = (0.1f - final.y) / 1.1f;
                    node.growRate *= ((factor - 1) * (factor - 1)) * 0.4f + 0.6f;
                }

                child.Add(node);
            }
        }
    }
}

 最新的www

原文地址:https://www.cnblogs.com/betairy-linkzeldagg/p/5376656.html