• water effect(2)


    这节主要记录的是第二个Subshader的具体效果,相对于的vert200, vert300顶点着色器主要会对mesh中的顶点进行变换,主要函数是Gerstner,根据gpugems第一小节的描述,Gerstner wave function是对 sin() 次方运算的简化版,具体公式如下,下面的条件中默认初始值为0。

    其中A是坡度,即从低谷到高峰的高度值,W为波的频率值,即两个波峰之间的距离越小,W越大,D为波的方向向量,Q为控制波的程度。在unity中,WaterInclude.cginc的Gerstner函数主要用于波的混合计算的,其中计算顶点偏移量的公式如下。

    	//数字4代表4个波的混合,dirAB.xy代表A波方向,dir.zw指B波,dirCD.xy指C波,dirCD.zw指D波
    	half3 GerstnerOffset4 (half2 xzVtx, half4 steepness, half4 amp, half4 freq, half4 speed, half4 dirAB, half4 dirCD) 
    	{
    		half3 offsets;
    		//计算四个波的参数,对应于Gerstner中的Q*A*D
    		half4 AB = steepness.xxyy * amp.xxyy * dirAB.xyzw;
    		half4 CD = steepness.zzww * amp.zzww * dirCD.xyzw;
    		
    		//计算四个波的cos参数,对应于 W*D*(x,y)
    		half4 dotABCD = freq.xyzw * half4(dot(dirAB.xy, xzVtx), dot(dirAB.zw, xzVtx), dot(dirCD.xy, xzVtx), dot(dirCD.zw, xzVtx));
    		half4 TIME = _Time.yyyy * speed;
    		
    		half4 COS = cos (dotABCD + TIME);
    		half4 SIN = sin (dotABCD + TIME);
    		
    		偏移量的计算
    		offsets.x = dot(COS, half4(AB.xz, CD.xz));
    		offsets.z = dot(COS, half4(AB.yw, CD.yw));
    		offsets.y = dot(SIN, amp);
    
    		return offsets;			
    	}

    为片元着色器准备的发现信息也是通过对Gerstner函数进行x,y求偏导算出binormal和tangent,最后叉乘得出normal向量,具体的计算公式如下。

       接下来看看片元着色器,片元着色器相对于低质量的版本水面主要添加了天空盒的反射纹理混合和边缘混合。

    	half4 frag300( v2f_noGrab i ) : COLOR
    	{		
    	//计算出pixel的世界法线,这里边的基准向量不再用(0,1,0)表示,而是使用顶点着色器计算出来的法线向量。
    		half3 worldNormal = PerPixelNormal(_BumpMap, i.bumpCoords, normalize(VERTEX_WORLD_NORMAL), PER_PIXEL_DISPLACE);
    
    		half3 viewVector = normalize(i.viewInterpolator.xyz);
    
    //屏幕纹理的扭曲
    		half4 distortOffset = half4(worldNormal.xz * REALTIME_DISTORTION * 10.0, 0, 0);
    		half4 screenWithOffset = i.screenPos + distortOffset;
    		
    //利用相机计算出来的贴图来设置反射颜色。
    		#ifdef WATER_REFLECTIVE		
    			half4 rtReflections = tex2Dproj(_ReflectionTex, UNITY_PROJ_COORD(screenWithOffset));	
    		#endif
    		
    //与上一节类似,反射计算高光效果。
    		half3 reflectVector = normalize(reflect(viewVector, worldNormal));          
    		half3 h = normalize (_WorldLightDir.xyz + viewVector.xyz);
    		float nh = max (0, dot (worldNormal, -h));
    		float spec = max(0.0,pow (nh, _Shininess));	
    		
    //边缘混合,利用相机的纹理深度与当前pixel的纹理深度做对比,差距越小,edgeBlendFactors.x越小,
    //最后计算basecolor的alpha与edgeBlendFactors.x正相关;效果就是水面离水底越近,水面颜色越透明。
    		half4 edgeBlendFactors = half4(1.0, 0.0, 0.0, 0.0);
    		
    		#ifdef WATER_EDGEBLEND_ON
    			half depth = UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos)));
    			depth = LinearEyeDepth(depth);
    			edgeBlendFactors = saturate(_InvFadeParemeter * (depth-i.screenPos.z));		
    			edgeBlendFactors.y = 1.0-edgeBlendFactors.y;
    		#endif		
    		
    //与上一节类似,通过fresnel公式计算反射率。
    		worldNormal.xz *= _FresnelScale;		
    		half refl2Refr = Fresnel(viewVector, worldNormal, FRESNEL_BIAS, FRESNEL_POWER);
    		
    		half4 baseColor = _BaseColor;
    
    //先混合整体的环境纹理和反射颜色,然后再混合基础颜色。
    		#ifdef WATER_REFLECTIVE	
    			baseColor = lerp (baseColor, lerp (rtReflections,_ReflectionColor,_ReflectionColor.a), saturate(refl2Refr * 2.0));
    		#else
    			baseColor = lerp (baseColor, _ReflectionColor, saturate(refl2Refr * 2.0));		
    		#endif
    		
    		baseColor = baseColor + spec * _SpecularColor;
    		
    //计算最后改点的alpha值,与反射率和边缘程度相关。
    		baseColor.a = edgeBlendFactors.x * saturate(0.5 + refl2Refr * 1.0);
    		return baseColor;
    	}	

      

      最高质量的water effect主要是添加了 light extinction(消光技术,unity中只是简单的将波峰处的颜色消减为淡蓝色)和foam,在WaterInclude.cginc中ExtinctColor函数中,可以看到 extinction coefficient = (0.15,0.03,0.01),消减量与波高度正相关,我们可以看到高度值越大,对r,g两个分量的消减比b更多,淡蓝色效果越明显。

      关于foam的计算主要代码如下。

    	//计算foam纹理值
    	half4 foam = Foam(_ShoreTex, i.bumpCoords * 2.0);
    		
    	//_Foam.x为foam强度,_Foam.y为阈值,即i.viewInterpolator.w代表波的高度,即越接近波峰处,foam纹理在最终的pixel中越明显。
          baseColor.rgb += foam.rgb * _Foam.x * (edgeBlendFactors.y + saturate(i.viewInterpolator.w - _Foam.y));
  • 相关阅读:
    正则只能输入数字小数点后保留4位
    redis基础之安装和配置
    IDEA 2017下载及注册码
    springcloud zuul 使用zuulfilter 修改请求路径和响应头
    JPA 多表分页查询
    springboot整合JPA创建数据库表失败
    springboot整合fastjson 将null转成空字符串
    Go 结构体和map等数据结构转json字符串
    go项目找不到包问题
    设计模式--策略模式
  • 原文地址:https://www.cnblogs.com/VanHu/p/4895697.html
Copyright © 2020-2023  润新知