Unity 2018 3.0地形优化与新增特性

Posted wolf96

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 2018 3.0地形优化与新增特性相关的知识,希望对你有一定的参考价值。

https://blogs.unity3d.com/cn/2018/10/10/2018-3-terrain-update-getting-started/

总览:

This update features improved tools and performance by taking better advantage of the GPU. It also adds support for the HD and LW render pipelines

 

1.法线贴图的Keyword由_TERRAIN_NORMAL_MAP变为_NORMALMAP

官方注释说明:

Since 2018.3 we changed from _TERRAIN_NORMAL_MAP to _NORMALMAP to save 1 keyword.

会节省一个keyword

 

2.GPU-instanced

On the performance side, we added a GPU-instanced render path for terrain. In most cases, instancing yields a dramatic reduction in the number of draw calls issuedMany of our tests saw more than a 50% reduction in CPU costs (though, of course, actual numbers will depend on your platform and use case).  You can choose this new render path by enabling ‘Draw Instanced’ in the Terrain settings:

When enabled, Unity transforms all of the heavy terrain data, like height maps and splat maps, into textures on the GPU. Instead of constructing a custom mesh for each terrain patch on the CPU, we can use GPU instancing to replicate a single mesh and sample the height map texture to produce the correct geometry. This reduces the terrain CPU workload by orders of magnitude, as a few instanced draw calls replace potentially thousands of custom mesh draws.

As a nice side effect, it also improves our load times! Not only can we skip building all of those custom meshes, but we can also use the GPU to build the basemap (pre-blended LOD texture); the GPU is much faster at that kind of thing.  This also means that if you have your own custom terrain shader, you can now override the ‘build basemap’ shader and generate matching basemap LOD textures.

Unity之前的做法是 constructing a custom mesh for each terrain patch on the CPU,也就是说一个地形相当于有许多mesh,信息存储在CPU中,

改进之后Unity在顶点shader里使用高度图和法线贴图还原地形的顶点位置和法线,这样可以做到地形的一些mesh做instanced rendering(将高度图和法线贴图作为vertex buffer做instanced ),也不需要CPU传大量数据到GPU生成地形

可以节省大量CPU时间和加载时间,并减少draw call

void SplatmapVert(inout appdata_full v, out Input data)



    UNITY_INITIALIZE_OUTPUT(Input, data);


#if defined(UNITY_INSTANCING_ENABLED) && !defined(SHADER_API_D3D11_9X)


    float2 patchVertex = v.vertex.xy;

    float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);


    float4 uvscale = instanceData.z * _TerrainHeightmapRecipSize;

    float4 uvoffset = instanceData.xyxy * uvscale;

    uvoffset.xy += 0.5f * _TerrainHeightmapRecipSize.xy;

    float2 sampleCoords = (patchVertex.xy * uvscale.xy + uvoffset.xy);


    float hm = UnpackHeightmap(tex2Dlod(_TerrainHeightmapTexture, float4(sampleCoords, 0, 0)));

    v.vertex.xz = (patchVertex.xy + instanceData.xy) * _TerrainHeightmapScale.xz * instanceData.z;  //(x + xBase) * hmScale.x * skipScale;

    v.vertex.y = hm * _TerrainHeightmapScale.y;

    v.vertex.w = 1.0f;

    v.texcoord.xy = (patchVertex.xy * uvscale.zw + uvoffset.zw);

    v.texcoord3 = v.texcoord2 = v.texcoord1 = v.texcoord;


    #ifdef TERRAIN_INSTANCED_PERPIXEL_NORMAL

        v.normal = float3(0, 1, 0); // TODO: reconstruct the tangent space in the pixel shader. Seems to be hard with surface shader especially when other attributes are packed together with tSpace.

        data.tc.zw = sampleCoords;

    #else

        float3 nor = tex2Dlod(_TerrainNormalmapTexture, float4(sampleCoords, 0, 0)).xyz;

        v.normal = 2.0f * nor - 1.0f;

    #endif

#endif

    v.tangent.xyz = cross(v.normal, float3(0,0,1));

    v.tangent.w = -1;

    data.tc.xy = v.texcoord;

#ifdef TERRAIN_BASE_PASS

    #ifdef UNITY_PASS_META

        data.tc.xy = v.texcoord * _MainTex_ST.xy + _MainTex_ST.zw;

    #endif

#else

    float4 pos = UnityObjectToClipPos(v.vertex);

    UNITY_TRANSFER_FOG(data, pos);

#endif



3.支持法线贴图强度

    #ifdef _NORMALMAP

        mixedNormal  = UnpackNormalWithScale(tex2D(_Normal0, uvSplat0), _NormalScale0) * splat_control.r;

        mixedNormal += UnpackNormalWithScale(tex2D(_Normal1, uvSplat1), _NormalScale1) * splat_control.g;

        mixedNormal += UnpackNormalWithScale(tex2D(_Normal2, uvSplat2), _NormalScale2) * splat_control.b;

        mixedNormal += UnpackNormalWithScale(tex2D(_Normal3, uvSplat3), _NormalScale3) * splat_control.a;

        mixedNormal.z += 1e-5f; // to avoid nan after normalizing

    #endif

4.fragment逐像素法线

Instancing also improves the appearance of terrain normals; we decouple the terrain mesh normals from the geometry by storing them in a normal map texture that is generated from the heightmap and sampled in the pixel shader. This means the normals are independent of the mesh LOD level. Consequently, you can increase the ‘pixel error rate’ to decrease vertex cost, with fewer artifacts.

Old per-vertex normals (left) and new per-pixel normals (right) – with identical triangle counts.

宏定义为TERRAIN_INSTANCED_PERPIXEL_NORMAL

在上面第2个特性GPU-instanced开启的情况下

上面也说到会有一张顶点的高度与一张法线贴图,开启TERRAIN_INSTANCED_PERPIXEL_NORMAL将在fragment shader中读取这张法线贴图,不开启会在vertex shader中读取这张法线贴图作为顶点法线(顶点插值会降低原有贴图细节)

GPU-instanced的情况下还是默认顶点法线

这样有个好处就是LOD顶点数降低的情况下,默认顶点法线会随着顶点减少而降低细节,而在fragment shader读取这张法线贴图则完全不会会影响细节,顶点法线效果不受LOD级别影响,但是多了一次读取贴图会增加一点GPU性能消耗

VS见特性2的代码,FS中:

#if defined(UNITY_INSTANCING_ENABLED) && !defined(SHADER_API_D3D11_9X) && defined(TERRAIN_INSTANCED_PERPIXEL_NORMAL)

        float3 geomNormal = normalize(tex2D(_TerrainNormalmapTexture, IN.tc.zw).xyz * 2 - 1);

        #ifdef _NORMALMAP

            float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));

            float3 geomBitangent = normalize(cross(geomTangent, geomNormal));

            mixedNormal = mixedNormal.x * geomTangent

                          + mixedNormal.y * geomBitangent

                          + mixedNormal.z * geomNormal;

        #else

            mixedNormal = geomNormal;

        #endif

        mixedNormal = mixedNormal.xzy;

    #endif

 

5.可编程GPU工具

详情:https://blogs.unity3d.com/cn/2018/10/10/2018-3-terrain-update-getting-started/

6.多地形

多地形无缝绘制,自动连接等等。详情:https://blogs.unity3d.com/cn/2018/10/10/2018-3-terrain-update-getting-started/

7. TerrainLayer Asset

相当于地形用材质球,修改参数相对便捷,可以多地形共用相同TerrainLayer

a script interface to provide shader-dependent custom GUI for the TerrainLayer asset.

还可以像shaderGUI一样编写TerrainLayer的GUI

8.Brush Asset

可以自定义画刷,可以调节falloff和半径

支持16bit单通道贴图(R16),以前是8biit单通道贴图,可以增加精度(高度图,画刷等)

参考:

https://blogs.unity3d.com/cn/2018/10/10/2018-3-terrain-update-getting-started/

-----by wolf96  2018/12/20

 

 

 

 

以上是关于Unity 2018 3.0地形优化与新增特性的主要内容,如果未能解决你的问题,请参考以下文章

10.Unity2018中的地形——Terrain(一)

Unity Shader ------ 纹理之法线纹理单张纹理及遮罩纹理的实现

(四)Unity纹理、贴图和材质

又一封神Unity插件SECTR地形优化的代码三段分享

又一封神Unity插件SECTR地形优化的代码三段分享

从片段着色器中的地形高程数据计算法线