自动编译shader-组装片段
基本思路是会有一个feature类,不同的shader启用不同feature,按feature来组装写好的片段,需要的property和define写进去。当然函数主体是一样的,只是不同的define控制的分支。
一般地形shader特性——混合,雪,湿,积水,tess,parallax,macromap等
雪量在DoSnow里,基本思路是用height和ao来生成一个snowAmount,这个snowAmount来lerp颜色法线等等
1 | float DoSnow(inout MegaSplatLayer o, float2 uv, float3 worldNormal, half snowHeightFade, float puddleHeight, half surfPorosity, float camDist) |
浅溪在DoPuddle里,会有泡沫和水波涟漪的计算,另外还会用法线重采样原有地形贴图造成折射效果
1 | float DoPuddles(inout MegaSplatLayer o, float2 uv, half3 waterNormFoam, half puddleLevel, half2 flowDir, half porosity, float3 worldNormal) |
熔岩在DoLava里
1 | float DoLava(inout MegaSplatLayer o, float2 uv, half lavaLevel, half2 flowDir) |
支持一个pass 256张贴图,使用TextureArray,在顶点上存Id。但是per pixel怎么读取id呢,一差值就傻了啊
巧妙用了一个mask的方式
每个顶点上存两个index,分别是这里混合的两层贴图的id,然后还会存一个顶点色。对于某一个三角形,三个vertex存的颜色分别是(1,0,0), (0,1,0), (0,0,1).
之后vertex shader里来做插值。这里假设顶点色存的是上图的颜色,UV3的x是第一层id,UV3的y是第二层id,UV3的z是两层的混合强度
1 | struct Input{ |
之后再surf/frag里面这样就可以了,用Input的index0除以vertexWeights,就得到了这个pixel所在的三角形,三个顶点处的ID,就可以来用它采样texturearray
1 | void surf(Input IN, inout SurfaceOutoutStandard o){ |
神奇的事情发生在顶点插值计算的时候,vertexWeights的通道特性决定了index0的xyz分别是该pixel所在的三角面上三个vertex的id,于是用这个id正好和vertexWeights进行混合
1 | struct Input |
1 | o.weights = i.color.rgb; |
weights是在一个三角面的三个顶点分别是红绿蓝,三个顶点处id不一样,valuesSecond和valuesMain获取的是这个pixel上三角面的三个id
同一个pixel是两个贴图混合的,混合度是valueSecond.a = i.texcoord3.x
InitLayerParams里面i0为应该是走非terrain,下面的,要除以si.weight
1 | LayerParams InitLayerParams(SplatInput si, float3 values, half2 texScale) |
Input.weight还要compute一下,最后是SAMPLETEXARRAY出来的颜色,uv参数用的是params.uv0 uv1 uv2,所以上面i0 i1 i2就是id了
1 | MegaSplatLayer SampleLayer(inout LayerParams params, SplatInput si) |