码迷,mamicode.com
首页 > 其他好文 > 详细

water effect(2)

时间:2015-10-20 21:18:13      阅读:273      评论:0      收藏:0      [点我收藏+]

标签:

这节主要记录的是第二个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;
	}	

  最后最高质量的效果主要是foam的添加,具体分析下一节再阐述。

water effect(2)

标签:

原文地址:http://www.cnblogs.com/VanHu/p/4895697.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!