|
[md]## Culling
> 根据相机视椎体对视椎体外的草进行裁剪,从而优化数据量。
> 具体实现可以简述为,把草的位置坐标转换到相机裁剪空间,得到float4的clipPos,因为裁剪空间可视范围内的坐标范围在[-w,w]之间,所以通过裁剪空间的坐标点数据可以判断草是否在视野中。
***GrassComputeScript***中加入如下代码
```csharp
...
private int[] argsBufferReset = new int[] { 0, 1, 0, 0 };
//相机
private Camera m_MainCamera;
...
private void OnEnable() {
// 如果已经初始化,先清理旧数据
if (m_Initialized) {
OnDisable();
}
//获取相机
m_MainCamera = Camera.main;
...
}
...
private void SetGrassDataUpdate() {
// 每帧更新的数据
...
if (m_MainCamera != null) {
//计算VP矩阵,用于草转换到裁剪空间
Matrix4x4 v = m_MainCamera.worldToCameraMatrix;
Matrix4x4 p = m_MainCamera.projectionMatrix;
Matrix4x4 vp = p * v;
//传入矩阵
m_InstantiatedComputeShader.SetMatrix("_VPMatrix", vp);
}
else
m_MainCamera = Camera.main;
}
...
```
***GrassCompute.compute***中加入如下代码
```cpp
...
[numthreads(128, 1, 1)]
void Main(uint3 id : SV_DispatchThreadID) {
...
float3 worldPos = mul(_LocalToWorld, float4(sv.positionOS, 1)).xyz;
//转换到裁剪空间
float4 absPosCS = abs(mul(_VPMatrix, float4(worldPos, 1)));
//判断是否在视锥外,放在此处判断的点是C#传进来的点,目前是mesh顶点位置,
//因此会把整批草都裁掉,也可以放在处理整批草的里面进行处理,
//但是要注意裁剪后要正确添加到_IndirectArgsBuffer[0].numVerticesPerInstance里
if (absPosCS.z > absPosCS.w || absPosCS.y > absPosCS.w * 1.5 ||
absPosCS.x > absPosCS.w * 1.1) {
return;
}
...
...
```
***效果***
![grassCulling](https://cdn.laojiong.site/grassCulling.gif)
## LOD
> 根据相机距离,对草的数量进行裁剪,从而优化数据量。
> 具体实现为,计算当前计算位置点与相机的距离,根据优化的参数计算裁剪比例,剔除部分数量。
***GrassComputeScript***中加入如下代码
```csharp
...
// LOD
[Header("LOD")]
public float minFadeDistance = 40;
public float maxFadeDistance = 60;
...
...
private void SetGrassDataBase() {
// 非每帧更新的数据
...
m_InstantiatedComputeShader.SetFloat("_MinFadeDist", minFadeDistance);
m_InstantiatedComputeShader.SetFloat("_MaxFadeDist", maxFadeDistance);
}
private void SetGrassDataUpdate() {
// 每帧更新的数据
...
if (m_MainCamera != null) {
//传入相机位置
m_InstantiatedComputeShader.SetVector("_CameraPositionWS",
m_MainCamera.transform.position);
...
}
...
}
```
***GrassCompute.compute***中修改如下代码
```cpp
...
float4 absPosCS = abs(mul(_VPMatrix, float4(worldPos, 1)));
if (absPosCS.z > absPosCS.w || absPosCS.y > absPosCS.w * 1.5 || absPosCS.x > absPosCS.w * 1.1) {
return;
}
// 根据相机距离计算裁剪比例,用于计算一批次草的数量
float distanceFromCamera = distance(worldPos, _CameraPositionWS);
float distanceFade = 1 - saturate((distanceFromCamera - _MinFadeDist) / (_MaxFadeDist - _MinFadeDist));
...
DrawVertex drawVertices[GRASS_NUM_VERTICES_PER_BLADE];
int fadeBladerCount = numBladesPerVertex * distanceFade;
for (int j = 0; j < fadeBladerCount; ++j) {
...
}
...
const int addVertexCount = numTrianglesPerBlade * fadeBladerCount;
for (int i = 0; i < addVertexCount; i++)
{
InterlockedAdd(_IndirectArgsBuffer[0].numVerticesPerInstance,3);
}
...
```
***效果***
![grassLOD](https://cdn.laojiong.site/grassLOD.gif)
下一篇,最后一篇将介绍编辑器刷草工具。
[/md] |
|