Uploaded by 蔡昀辰

sandboxDemoProfile

advertisement
实现逻辑
Runtime Terrain
GPU Driven Terrain 以一张高度图为Source直接在GPU端进行视锥剔除,LOD计算以及T junction
Terrain进行了分块,由n个Section构成Component,n个Component构成地形,Component是碰撞更新单位,Section是
LOD与剔除单位,在最高LOD下,section是一块由两个三角面拼成的方形,方块数以2^n增长
SolveSectionBound
SolveSectionLOD
DoFrustumCull
Result
BuildInstanceData
indirectDraw
DrawVertex
构建高度图
对2D spline采样退化成Polygon并传入GPU,由GPU计算perpixel SDF,并通过SDF绘制不同种类spline的高度图,最
终降得到的三张高度图进行blend,得到用于地形的最终高度图
mountainHegihtMap
spline(bezierCurve)
退化
polygon
GPU
SDF
heightMap
lakeHegihtMap
riverHegihtMap
Code
terrain.SolveBound(cs, cmd);
terrain.SolveLOD(cs, cmd, cameraPos, screenMultiple);
terrain.BuildDrawElements(cs, cmd, _frustumPlanes);
terrain.SetupTerrainConstant(terrain.terrainMaterial);
terrain.SetupTerrainTexture(terrain.terrainMaterial);
terrain.SetupTerrainBuffer(terrain.terrainMaterial);
terrain.DrawTerrain(terrain.terrainMaterial, cmd, isWireFrameMode);
Result
terrainHeightMap
构建分区信息以及湿度
通过上一步得到的各种类spline的高度图,分批进行区域求解,分区规则如下
高山可以切断矮山的区域
河流可以切断山面的区域,切断的所有区域共享河的湿度
湖可以切断山面的区域,切断的所有区域共享湖的湿度
lakeHeightMap
riverHeightMap
lakeArea
riverArea
mountainHeightMap
unionSet
mountainArea
unionSetWithMark
unionSetWithMark
Code
public void BuildHumidityAndArea(TerrainBuilder terrainBuilder, TerrainEcoSystemConfig
ecoConfig)
{
// init
float[] humidityCache = new float[UnionSet.DataArray.Length];
NativeArray<uint> markBuffer = new NativeArray<uint>(UnionSet.DataArray.Length,
Allocator.TempJob);
BuildUnionSetGlobalParam.Builder = terrainBuilder;
BuildUnionSetGlobalParam.TargetUnionSet = UnionSet;
CleanUp();
// mountain pass
BuildMountainUnionSet(markBuffer, terrainBuilder);
BuildMarkBuffer(markBuffer);
SolveRiverHumidity(humidityCache, terrainBuilder);
// river pass
UnionSet.Reset();
BuildRiverUnionSet(markBuffer, terrainBuilder);
BuildMarkBuffer(markBuffer);
SolveLakeHumidity(humidityCache, terrainBuilder);
// lake pass
UnionSet.Reset();
BuildLakeUnionSet(markBuffer, terrainBuilder);
// final pass
BuildIndexDicAndAreaMember();
SolveFinalHumidity(humidityCache, terrainBuilder);
RefreshAreaEcologicalIndex(ecoConfig);
// clean up
markBuffer.Dispose();
}
Result
植被生成
利用上一步形成的区域以湿度信息,通过区域高度决定每个区域所属的生态,并为所有区域生成植物
植物拥有排斥圈(即在一定距离内不得生成该植物),生态具有植物的生成密度,用来控制该区域内植物的生成数量
为了解决排斥圈问题,会在初始化时使用possion disk法生成一系列采样点,然后在生产植被时,从这些点中拣选想
生成的植被
possionDiskSample
edgeCull
terrainSDF
areaCull
areaData
randomAreaPlant
PossionDiskSample
性能热点
SDF构建
使用GPU进行Polygon的SDF构建,一条spline需要PerPixel跑一遍全图SDF
并查集构建
为了提取区域信息,需要通过回读下来的高度图构建并查集来分出区域信息,mountain,river,lake一共需要跑三
遍并查集构建
PossionDiskSample
对于每一个生态的每一种植物,需要烘焙一组点用于后续的生成,由于只需要在初始化的时候做一次,所以开销相
对并不严重
CollisonUpdate
每次刷新地形之后,需要对地形的碰撞进行更新
离屏RT
目前必须的离屏RT有9张,包括 3张高度RT 1张SDF 1张湿度信息 1张最终高度图 1张最终Normal 1张mountain normal
1张烘焙的网格贴图
实机Profile
环境: RTX 3060 10850K
分辨率: 1080P
高度图分辨率: 1024 x 1024
打包设置: il2cpp,development build,release,incremental GC,D3D11
测试场景: 上文截图中的场景
修改地形时出现的性能尖峰
第一个尖峰是由GPU构建SDF造成的,在两帧后,回读完毕,CPU开始更新碰撞,湿度,植被信息,此时出现第二
个尖峰
第一个尖峰
第二个尖峰
更新碰撞 54ms
计算区域信息 157ms
生成植物 60ms
Download