刚取得一些进展于是丢上来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