GPUTerrain简单实现

本文介绍了使用GPU驱动实现地形绘制的优化技术,包括基于Hiz的剔除和深度预处理,以减少DrawCall并提高效率。同时,详细阐述了处理不同mip级别地形接缝问题的方法,通过顶点退化避免缝隙产生,确保地形平滑过渡。文中还提到了Unity中的实现代码示例和阴影绘制的类似剔除策略。
摘要由CSDN通过智能技术生成

简介

在看了狗哥老司机MaxwellGeng等大佬关于GPUDriven的实现,就参考Ubisoft实现一个简单的GPUDriven的Terrain的绘制

因为地形绘制时需要的数据不需要一直更新,所以只要在一开始传入地形的HeightMap和NormalMap之后,剩下的绘制操作基本不太需要传入其他大量的数据,非常适合GPUDriven。

使用GPUDriven的好处是可以在很少的几次DrawCall就可以绘制出整个地形场景,而且可以剔除掉不需要的面片,减少绘制的压力。

做GPUDrivenTerrain需要注意

  • Hiz的生成,地表mesh的拆分与剔除
  • 不同mip的mesh的临接的接缝处理
  • 在GPU上实现的地形数据结构,以及灯光的处理(我没有去实现)

实现流程

  1. 使用一个64*64大小的mesh作为Instance的对象,可以通过四叉树把当前的地形切分,分成3级
  2. 使用上一帧的depth计算出的Hiz和上一帧的ViewProjection的Matrix对当前帧的做一次Cull
  3. 用第2步剪裁的结果绘制出深度,并生成当前深度的Hiz
  4. 通过第3步生成的Hiz和当前帧的ViewProjection的Matrix再次对第2步剪裁后剩下的部分再做一次Cull
  5. 对第4步得到的新的深度重新计算Hiz,作为本帧最终的Hiz,同时也作为下一帧的输入Hiz
  6. 通过剔除操作得到需要绘制的mesh的ID和

我们在Unity上实现的时候,场景跟地形分开绘制,具体实现代码如下

// 0、绘制得到Opaque的深度图
m_DepthPrepass.Setup(cameraTargetDescriptor, new RenderTargetIdentifier(m_DepthRenderTarget));
EnqueuePass(m_DepthPrepass);

// 1、根据上一帧的Hiz和VP先剔除掉有可能被遮挡的地块,在Opaque的深度图上继续绘制深度
m_TerrainDepthPrepass.Setup(new RenderTargetIdentifier(m_DepthRenderTarget), m_HizRenderTarget, _VPPrevFrame);
EnqueuePass(m_TerrainDepthPrepass);

// 2、使用新的depth计算Hiz
m_HizPass.Setup(new RenderTargetIdentifier(m_DepthRenderTarget), m_HizRenderTarget);
EnqueuePass(m_HizPass);

// 3、使用新的Hiz做剔除,绘制剩下的其实还存在的小块
m_TerrainDepthPrepass.Setup(new RenderTargetIdentifier(m_DepthRenderTarget), m_HizRenderTarget, _VPPrevFrame);
EnqueuePass(m_TerrainDepthPrepass);

// 4、计算当前帧的depth计算Hiz,以便下一帧使用
m_HizPass.Setup(new RenderTargetIdentifier(m_DepthRenderTarget), m_HizRenderTarget);
EnqueuePass(m_HizPass);

// 正常绘制场景
EnqueuePass(m_RenderOpaqueForwardPass);

// 正常绘制地形
m_GPUTerrainPass.Setup(BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.CameraTarget);
EnqueuePass(m_GPUTerrainPass);

对于绘制阴影也是跟上面同样的剔除方法,只不过光源作为相机的位置和方向而已,跟正常的shadowmap绘制没有太大区别。

Game相机绘制的GPUDriven地形真实绘制的mesh以及不同的LOD

接缝处理

参考狗哥老司机和Ubisoft介绍的,通过对mesh进行退化,可以防止不同mip等级的mesh之间相连接的时候会出现缝隙,通过把在小mip的一个点移动到已知的点的位置上,而这个移动的距离就存在mesh的color属性中。

使用的mesh是直接狗哥老司机的项目中的在顶点的color上设置了偏移值的mesh,右边是存到了alpha通道上,所以看不见
使用的
在实际绘制的时候,如下图所示,不同mip的mesh连接到一块儿的时候如果不做偏移的处理是这样的,小的mip会有一个顶点在大的mip边上,这样在根据heightmap对顶点的位置做偏移的时候,就会导致该边上多出来的这个顶点凸出去,而且产生缝隙
在这里插入图片描述
处理的方法就是提前在在不同mip临接的边上,对低mip的mesh多出来的这个顶点做退化处理,这点跟Ubisoft提到的用greedy的方法预填充场景对象的mesh方法一样,要对mesh重合或者不同mip临接的顶点做退化处理,其实就是把这个顶点偏移一定的距离,使其与mesh内部的顶点重合。

不同mip连接的地方退化的mesh顶点
做了顶点偏移处理后的mesh如上图所示,不同mip的mesh相接的地方就不会出现接缝

Unity版本的实现请看 https://gitee.com/alienity/GPUDrivenTerrain

引用

[1] https://zhuanlan.zhihu.com/p/335325149

[2] https://zhuanlan.zhihu.com/p/352850047

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值