QQ登录

只需一步,快速开始

 找回密码
 定下契约(新注册)

QQ登录

只需一步,快速开始

查看: 457|回复: 0
收起左侧

[原创] 草(二)Unity移动端可用的草海,Culling&LOD

[复制链接]

Tech Artist

Rank: 16

UID
60078
宝石
0 粒
金币
29 枚
节操
3 斤
灵石
0 块
精力
49 ℃
发表于 2021-10-20 14:03:09 | 显示全部楼层 |阅读模式

你这样只看不注册,真的大丈夫?~

您需要 登录 才可以下载或查看,没有账号?定下契约(新注册)

x
[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]

本版积分规则

    切换繁體
    Archiver|手机版|小黑屋|

GMT+8, 2023-2-6 04:46 , Processed in 0.105887 second(s), 30 queries .

沪ICP备2021020632号-1

快速回复 返回顶部 返回列表