问题背景
在做地形模块时,需要根据实际地形高度画出世界相应的等高线,以及根据高度做颜色渐变,以及剖切功能。
解决方法
通过像素点在世界坐标系下的真实高度值来判断计算绘制等高线,剖切功能以及颜色渐变均有世界坐标实际高度值来判断,具体逻辑在代码中,这些均 在shder 中为的fragment阶段进行,
Shader代码
1 Shader "Custom/StratumFrontShader" { 2 Properties{ 3 _FristColir("MainColor", color) = (0,1,0,1) //第一种颜色:绿 4 _SecondColor("SecondColor", color) = (1,0,0,1) //第二种颜色:红 5 _Diffuse("Diffuse", Color) = (1,1,1,1) 6 7 _K("K", float) = 0.8 8 _P("P", float) = 0.8 9 } 10 SubShader { 11 pass { 12 CGPROGRAM 13 #pragma vertex vert 14 #pragma fragment frag 15 #include "unitycg.cginc" 16 #include "Lighting.cginc" 17 18 fixed4 _Diffuse; 19 uniform half _K; 20 uniform half _P; 21 22 //高低点颜色 23 fixed4 _FristColir; 24 fixed4 _SecondColor; 25 26 //高低点值 27 float _HighValue; 28 float _LowValue; 29 30 //是否显示等高线 31 float _IsShowContour=0; 32 33 //等高线密集比例 34 float _ContourScale=0.12; 35 36 //是否是同一颜色 37 float _IsSameColor=0; 38 39 //是否开启剖切 40 float clipping; 41 float3 clipPlanePosition; 42 float3 clipPlaneNormal; 43 44 45 struct v2f { 46 float4 pos:POSITION; 47 float y : TEXCOORD1; 48 fixed3 worldNormal: TEXCOORD2; 49 fixed3 worldPos: TEXCOORD3; 50 }; 51 52 v2f vert(appdata_base v) 53 { 54 v2f o; 55 o.pos = UnityObjectToClipPos(v.vertex); 56 o.worldNormal = UnityObjectToWorldNormal(v.normal); 57 o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz; 58 o.y = v.vertex.y; 59 return o; 60 } 61 fixed4 frag(v2f IN):COLOR 62 { 63 float y = IN.y; 64 65 //剖切逻辑 66 if ( clipping > 0.0 ) { 67 float r = dot( normalize( IN.worldPos - clipPlanePosition ), clipPlaneNormal ); 68 if ( r > 0.0 ) { 69 discard; 70 } 71 } 72 73 //等高线 74 float f = abs( frac( y * _ContourScale ) - 0.5 ); 75 float df = fwidth( y * _ContourScale ); 76 float g = smoothstep( -df * 2, df * 2, f ); 77 float3 lineCol = float3( 0.0, 0.0, 0.0 ); 78 79 //颜色随高度渐变 80 float h=saturate((_HighValue-y)/(_HighValue-_LowValue)); 81 h = _IsSameColor == 0 ? h : 0;//同一种颜色时为第一默认色 82 fixed3 col = lerp( _FristColir, _SecondColor, h ); 83 g = _IsShowContour == 0 ? g : 1; 84 col = lerp( lineCol, col, g ); 85 86 //光照 87 float3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); 88 float lightDot = clamp(dot(IN.worldNormal, worldLightDir), -1, 1); 89 lightDot = exp(-pow(_K* (1 - lightDot), _P)); 90 float3 diffuse = _LightColor0.rgb * col * lightDot; 91 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; 92 fixed3 color0=ambient + diffuse; 93 94 return (fixed4(color0,1)); 95 } 96 ENDCG 97 } 98 } 99 }
ps:剖切功能:在于实际坐标点与剖切面的夹角选择性剔除。渐变功能:根据高度区间变换做的混合,等高线:高度值根据设定参数计算,插值出等高线。
这里是我功能源代码,这里做了剖切和颜色渐变和光照,提供给大家做个参考吧。
效果如下: