您的位置:首页 > 科技 > 能源 > 北京企业官网建设_显而易见的解决方案 企业解决方案_网页设计参考网站_企业网站营销的典型案例

北京企业官网建设_显而易见的解决方案 企业解决方案_网页设计参考网站_企业网站营销的典型案例

2024/9/24 3:30:19 来源:https://blog.csdn.net/Mr_Dongzheng/article/details/142302522  浏览:    关键词:北京企业官网建设_显而易见的解决方案 企业解决方案_网页设计参考网站_企业网站营销的典型案例
北京企业官网建设_显而易见的解决方案 企业解决方案_网页设计参考网站_企业网站营销的典型案例

1.Using Blender to create a single grass clump

首先blender与unity的坐标轴不同,z轴向上,不是y轴

通过小键盘的数字键可以快速切换视图,选中物体以后按下小键盘的点可以将物体聚焦于屏幕中心

首先我们创建一个平面,宽度为0.2m,然后切换到正交前视图,复制两个平面。shift+D可以复制面

接着将上下两个面旋转45°至中间面的中心。先按下R然后按下Y可以绕y轴旋转,然后按G键可以移动面

然后切换到正交顶视图(数字键7)

将两个复制的面分别向左向右旋转10.5°左右

最后加上材质和贴图以后的效果就是下面这样

然后就可以保存退出Blender了,后面我们在unity中批量产出这个grass

2. Using instancing to cover a surface with grass

首先就是定义草的类,包含了草的位置,摆动角度

 struct GrassClump{public Vector3 position;public float lean;public float noise;public GrassClump( Vector3 pos){position.x = pos.x;position.y = pos.y;position.z = pos.z;lean = 0;noise = Random.Range(0.5f, 1);if (Random.value < 0.5f) noise = -noise;}}

接着还有全局的草的密度,大小,最大摆动角度

 [Range(0,1)]public float density = 0.8f;[Range(0.1f,3)]public float scale = 0.2f;[Range(10, 45)]public float maxLean = 25;

然后就是初始化草丛的位置信息,生成一个 ComputeBuffer 来存储这些位置数据,并通过计算着色器来模拟草丛的摆动效果。

获取附加的 MeshFilter 组件中的网格边界,bounds.extents 返回边界框的一半大小(每个轴的范围的一半)

MeshFilter mf = GetComponent<MeshFilter>();
Bounds bounds = mf.sharedMesh.bounds;
Vector3 clumps = bounds.extents;

使用对象的缩放值(transform.localScale)和一个密度因子来调整草丛的分布范围,主要是 x 和 z 轴 。并且计算草丛的总数量

Vector3 vec = transform.localScale / 0.1f * density;clumps.x *= vec.x;clumps.z *= vec.z;int total = (int)clumps.x * (int)clumps.z;

获取计算着色器中的内核 LeanGrass,并计算每个线程组的大小。groupSize 是用于处理草丛的线程组数,而 count 则是实际生成的草丛总数 

kernelLeanGrass = shader.FindKernel("LeanGrass");
shader.GetKernelThreadGroupSizes(kernelLeanGrass, out threadGroupSize, out _, out _);
groupSize = Mathf.CeilToInt((float)total / (float)threadGroupSize);
int count = groupSize * (int)threadGroupSize;

随机生成 count 个草丛的 pos 位置。这个位置基于网格的边界和中心生成,使用 TransformPoint 将局部坐标转换为全局坐标 (世界坐标)

clumpsArray = new GrassClump[count];for (int i = 0; i < count; i++)
{Vector3 pos = new Vector3(Random.value * bounds.extents.x * 2 - bounds.extents.x + bounds.center.x,0,Random.value * bounds.extents.z * 2 - bounds.extents.z + bounds.center.z);pos = transform.TransformPoint(pos);clumpsArray[i] = new GrassClump(pos);
}

创建了一个 ComputeBuffer 来存储所有的草丛位置信息,并将 clumpsArray 赋值到缓冲区中。 

clumpsBuffer = new ComputeBuffer(count, SIZE_GRASS_CLUMP);
clumpsBuffer.SetData(clumpsArray);

将缓冲区 clumpsBuffer 绑定到计算着色器的 clumpsBuffer 参数,并将草丛最大倾斜角度 maxLean 传递给着色器。 

shader.SetBuffer(kernelLeanGrass, "clumpsBuffer", clumpsBuffer);
shader.SetFloat("maxLean", maxLean * Mathf.PI / 180);
timeID = Shader.PropertyToID("time");

 通过 argsArray 设置绘制调用的参数(索引数量和实例数量),并使用 ComputeBuffer 类型为 IndirectArguments 创建一个缓冲区,用于 DrawMeshInstancedIndirect 函数的调用

  • argsArray[0] = mesh.GetIndexCount(0);

    • 这行代码获取的是 mesh 的索引数量,也就是用来渲染的几何体有多少个顶点索引。每个网格都有其顶点、法线、UV 等信息,而索引决定了如何连接这些顶点来形成三角形。
    • IndirectArguments 绘制时,第一个参数就是表示绘制网格时使用的顶点索引数量。
  • argsArray[1] = (uint)count;

    • count 是实例化对象的数量。通过 Graphics.DrawMeshInstancedIndirect 方法可以在一次绘制调用中实例化多个对象。
    • 这里第二个参数表示要绘制的实例化网格的数量
argsArray[0] = mesh.GetIndexCount(0);
argsArray[1] = (uint)count;
argsBuffer = new ComputeBuffer(1, 5 * sizeof(uint), ComputeBufferType.IndirectArguments);
argsBuffer.SetData(argsArray);

然后看一下我们的计算着色器

很简短,就是设置了个倾斜角度,方便后续在表面shader中进行旋转

[numthreads(THREADGROUPSIZE,1,1)]
void LeanGrass (uint3 id : SV_DispatchThreadID)
{GrassClump clump = clumpsBuffer[id.x];clump.lean = sin(time + clump.noise) * maxLean * clump.noise;clumpsBuffer[id.x] = clump;
}

接着继续编写表面着色器

首先是设置每个草丛的位置以及旋转平移矩阵

        void setup(){#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLEDGrassClump clump = clumpsBuffer[unity_InstanceID];_Position = clump.position;_Matrix = create_matrix(clump.position, clump.lean);#endif}

然后是创建矩阵函数,这是一个绕z轴旋转的矩阵

  float4x4 create_matrix(float3 pos, float theta){float c = cos(theta);float s = sin(theta);return float4x4(c,-s, 0, pos.x,s, c, 0, pos.y,0, 0, 1, pos.z,0, 0, 0, 1);}

最后就是顶点函数的设置

首先乘上缩放系数,然后计算经过旋转和平移的顶点位置,接着计算只经过平移的位置,最后根据uv的y值来插值坐标,也就是高度越高,弯曲幅度越大

 void vert(inout appdata_full v, out Input data){UNITY_INITIALIZE_OUTPUT(Input, data);#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLEDv.vertex.xyz *= _Scale;float4 rotatedVertex = mul(_Matrix, v.vertex);v.vertex.xyz += _Position;v.vertex = lerp(v.vertex, rotatedVertex, v.texcoord.y);#endif}

最终效果:

3. Bending blades of grass

这次我们要自己通关代码创建一个草的mesh,并且设置顶点位置,法线,uv,索引。

下面几个图分别是这几个属性的图解。

这里面设置顶点索引要按照逆时针的顺序是因为unity会按照逆时针顺序的三角形认定为正面,防止它被背面剔除

代码:

 Mesh Blade{get{Mesh mesh;if (blade != null){mesh = blade;}else{mesh = new Mesh();float height = 0.2f;float rowHeight = height / 4;float halfWidth = height / 10;//1. Use the above variables to define the vertices arrayVector3[] vertices ={new Vector3(-halfWidth, 0, 0),new Vector3( halfWidth, 0, 0),new Vector3(-halfWidth, rowHeight, 0),new Vector3( halfWidth, rowHeight, 0),new Vector3(-halfWidth*0.9f, rowHeight*2, 0),new Vector3( halfWidth*0.9f, rowHeight*2, 0),new Vector3(-halfWidth*0.8f, rowHeight*3, 0),new Vector3( halfWidth*0.8f, rowHeight*3, 0),new Vector3( 0, rowHeight*4, 0)};//2. Define the normals array, hint: each vertex uses the same normalVector3 normal = new Vector3(0, 0, -1);Vector3[] normals ={normal,normal,normal,normal,normal,normal,normal,normal,normal};//3. Define the uvs arrayVector2[] uvs ={new Vector2(0,0),new Vector2(1,0),new Vector2(0,0.25f),new Vector2(1,0.25f),new Vector2(0,0.5f),new Vector2(1,0.5f),new Vector2(0,0.75f),new Vector2(1,0.75f),new Vector2(0.5f,1)};//4. Define the indices arrayint[] indices =
{0,1,2,1,3,2,//row 12,3,4,3,5,4,//row 24,5,6,5,7,6,//row 36,7,8//row 4};//5. Assign the mesh properties using the arrays//   for indices use//   mesh.SetIndices( indices, MeshTopology.Triangles, 0 );mesh.vertices = vertices;mesh.normals = normals;mesh.uv = uvs;mesh.SetIndices(indices, MeshTopology.Triangles, 0);}return mesh;}}

 接下来加入风向的影响

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com