水 shader
_WaveMap(“Normal”)
_Tiling
_WaveBumpScale
_WavaBumpSpeed() 水流动的方向
_DeepTex 获取深度 r通道(深度因素) g透明度因素(用深度图计算软边的时候需要) 用实时软边的话,透明度用_Color0.a
_Color0 反射颜色 a通道控制透明度
_Color1 折射颜色 a 通道控制折射的强度// 最基本的颜色通过Fresnel来混合两个基本颜色
//fixed fresnel = pow(saturate(dot(viewDir, bump)), 0.3);
fixed fresnel = saturate(dot(viewDir, bump));
fixed3 finalColor = lerp(_Color0,_Color1,fresnel);出自
fixed fresnel = _FresnelScale + (1 - _FresnelScale) * pow(1 - dot(worldView, worldNormal), 5);
lerp(diffuse, reflection, saturate(fresnel))也有版本color0和color1分别为深色、浅色,根据深度混合
折射:
vs里,计算坐标:
o.pos = UnityObjectToClipPos(v.vertex);// 屏幕位置
o.scrPos = ComputeScreenPos(o.pos);
函数具体分析可见:https://chengkehan.github.io/ComputeScreenPos.htmlunity注释:Computes texture coordinate for doing a screenspace-mapped texture sample. Input is clip space position.
COMPUTE_EYEDEPTH(o.scrPos.z);// grabUV
o.uvgrab =ComputeGrabScreenPos(o.pos);
unity注释:Computes texture coordinate for sampling a GrabPass texure. Input is clip space position.
冯乐乐书说:我们通过内置的ComputeGrabScreenPos函数来得到对应被抓取的屏幕图像的采样坐标。可以在UnityCG.cginc文件中看到其定义:他的主要代码和ComputeScreenPos基本类似,最大的不同是针对平台差异造成的采样坐标问题inline float4 ComputeGrabScreenPos (float4 pos) {
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
float4 o = pos * 0.5f;
o.xy = float2(o.x, o.y*scale) + o.w;
o.zw = pos.zw;
return o;
}
inline float4 ComputeNonStereoScreenPos(float4 pos) {
float4 o = pos * 0.5f;
#if defined(UNITY_HALF_TEXEL_OFFSET)
o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w * _ScreenParams.zw;
#else
o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;
#endif
o.zw = pos.zw;
return o;
}inline float4 ComputeScreenPos (float4 pos) {
float4 o = ComputeNonStereoScreenPos(pos);
#ifdef UNITY_SINGLE_PASS_STEREO
o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
#endif
return o;
}fs中,bump是法线空间,在法线空间下计算折射偏移
i.uvgrab.xy += bump.xy * _DistortionFactor * i.uvgrab.w * _GrabTexture_TexelSize.xy;
fixed3 grapColor = tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
水折射偏移 grapColor即为折射光颜色。然后将2种颜色混合后的结构与折射颜色混合
软边 获取深度(实时软边还是用深度图)
遇到bug,有的地方sceneZ小于objectZ,发现是由于没有深度贴图的原因。
half4 projTC = UNITY_PROJ_COORD(i.scrPos);
#ifdef USE_SOFTEDGE
// 边缘查找
//float sceneZ = LinearEyeDepth (tex2Dproj(_LastCameraDepthTexture, UNITY_PROJ_COORD(i.scrPos)).r);
//srcPosRe.x *=_ScreenParams.x/_ScreenParams.y;
float sceneZ = LinearEyeDepth (tex2Dproj(_LastCameraDepthTexture, projTC).r);
float objectZ = i.scrPos.z;
// 通过深度混合扭曲后的GrapTexture
depthFactor = saturate((sceneZ - objectZ) / _DepthFactor);//saturate(objectZ / _DepthFactor);
#else
fixed3 waterMap =tex2D(_MainTex, TRANSFORM_TEX(i.uv.xy, _MainTex)).rgb;
depthFactor = saturate(waterMap.r+_InvRanges.y);
_Color0.a *=saturate(waterMap.g*_InvRanges.z +_InvRanges.x);
#endif
高光相关
_SpecColor
_Shininess 高光相关反射
_Cubemap
_CubemapInstensity
实时反射 _ReflectionTex
fixed3 reflDir = reflect(-viewDir, bump);
fixed3 reflCol;
fixed3 reflection1 =texCUBE(_Cubemap, reflDir).rgb *_CubemapInstensity;
half refDis = _RefDisFactor * projTC.w * _ReflectionTex_TexelSize.xy;
projTC.x += bump.x *refDis;
//projTC.y += 0.5*bump.y *refDis;
fixed4 reflection2 = tex2Dproj(_ReflectionTex, projTC);
reflCol =lerp(reflection1.rgb,reflection2.rgb,reflection2.a*depthFactor);
//天空盒和实时反射贴图 通过深度和反射贴图的a通道混合
非实时反射
reflCol =texCUBE(_Cubemap, reflDir).rgb *_CubemapInstensity;
然后计算 反射的比例
finalColor +=reflCol*_ReflectVal*depthFactor;
finalCol += spec;
然后 finalCol *= _InvRanges.w.
加雾效 透明度是_Color0.a.
输出
几部分混合:
1. color0和color1用viewDotN混合;
2. 将GrabCol和得到的通过depthFactor混合;
3. 反射和已有相加,反射的强度用depthFactor和_ReflectVal控制;cubemap和实时反射用depthFactor和实时反射贴图的a通道控制。
4. 最后加上高光反射。
原来的水的版本:
(1)深度计算:
// Calculate the depth difference at the current pixel
float depth = tex2Dproj(_CameraDepthTexture, IN.proj0).r;
depth = LinearEyeDepth(depth);
depth -= IN.proj0.z;
深度和几个参数都有关系(ranges的x控制透明度、高光强度,折射偏移、折射和反射混合的菲涅尔,y控制两个颜色混合的参数,z控制折射的混合,折射也被y控制)
// Calculate the color tint
half4 col;
col.rgb = lerp(_Color1.rgb, _Color0.rgb, ranges.y);
col.a = ranges.x;
// Initial material properties
o.Alpha = col.a;
o.Specular = col.a;
o.Gloss = _Shininess;
IN.proj0.xy += o.Normal.xy * 0.5;
half3 reflection = tex2Dproj(_ReflectionTex, IN.proj0).rgb;
reflection = lerp(reflection * col.rgb, reflection, fresnel * _ReflectionTint);
//反射还用到ReflectionTint控制。
//折射用ranges.z 和ranges。控制
// High-quality refraction uses the grab pass texture
IN.proj1.xy += o.Normal.xy * _GrabTexture_TexelSize.xy * (20.0 * IN.proj1.z * col.a);
half3 refraction = tex2Dproj(_GrabTexture, IN.proj1).rgb;
refraction = lerp(refraction, refraction * col.rgb, ranges.z);
// Color the refraction based on depth
refraction = lerp(lerp(col.rgb, col.rgb * refraction, ranges.y), refraction, ranges.y);
//折射和反射的混合也和深度有关
// Always assume 20% reflection right off the bat, and make the fresnel fade out slower so there is more refraction overall
fresnel = fresnel fresnel;
fresnel = (0.8 * fresnel + 0.2) * col.a;
// Calculate the initial material color
o.Albedo = lerp(refraction, reflection, fresnel) + foam;