untiy shader 水的模拟

思路:
:用脚本抓取反射texture;
:让水面法线贴图随时间移动;
:把法线贴图上的法线值(纹理空间)转换为世界空间中的法线值;
:用水面世界空间中的法线计算水面漫反射;
:用水面世界空间中的法线计算水面高光;
:用水面世界空间中的法线扭曲水面倒影和水底折射;
:shader用菲尼尔配置好反射和折射的关系;

详细思路在shader代码里,已经注释好。
untiy shader 水的模拟
untiy shader 水的模拟

Shader "LJFShader/water"
{
	Properties
	{
		_BaseColor("BaseColor", color) = (1,1,1,1)
		_MainTex ("Texture", 2D) = "white" {}
		_ReflectionTex("ReflectionTex", 2D) = ""{}
		_Bias("Bias", Range(0.000000,1.000000)) = 0
		_Scale("Scale", Range(0.000000,1.000000)) = 0
		_Pow("Pow", Range(0,5)) = 1
	}
	SubShader
	{
		//抓取的时候执行的队列往后靠一靠
		Tags { "RenderType"="Opaque"  "queue"="transparent"}
		LOD 100

		grabpass{}

		Pass 
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			#include "UnityCG.cginc"

			/*
			struct appdata//输入顶点着色器的数据
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};
			*/

			struct v2f//顶点着色器输出的数据,也是片段作色器的输入数据
			{
				float2 uv : TEXCOORD0;
				float4 proj:TEXCOORD1;//投影纹理坐标
				float4 vertex : SV_POSITION;
				float3 L:TEXCOORD2;//关于光的向量
				float3 V:TEXCOORD3;
				float4 refl:TEXCOORD4;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _GrabTexture;
			float4 _BaseColor;//水的主颜色
			sampler2D _ReflectionTex;
			float _Bias, _Scale, _Pow;
			
			v2f vert (appdata_tan v)//appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);

				//o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.uv = TRANSFORM_TEX(v.texcoord.xy, _MainTex);

				o.proj = ComputeGrabScreenPos(o.vertex);
				o.refl = ComputeScreenPos(o.vertex);//非抓取,直接使用屏幕坐标

				//o.L = WorldSpaceLightDir(v.vertex);//用模型本地坐标计算出 世界空间 中的模型顶点指向光的向量

				//物体空间中的光照方向 把光向量由世界空间变到切线空间
				o.L = ObjSpaceLightDir(v.vertex);

				//物体空间中的视向量 把视向量由世界空间转变到切线空间(物体空间)
				o.V = ObjSpaceViewDir(v.vertex);

				TANGENT_SPACE_ROTATION;//宏定义,得到rotation矩阵

				//rotation为旋转的矩阵 - 把向量转变到切线空间的矩阵
				//使用rotation矩阵去变换物体空间中的光向量
				o.L = mul(rotation, o.L);//把光向量变换到切线空间 
				o.V = mul(rotation, o.V);//变换到切线空间


				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// sample the texture
				fixed4 col1 = tex2D(_MainTex, i.uv + float2(_Time.x,0));
				fixed4 col2 = tex2D(_MainTex, float2(1-i.uv.y, i.uv.x) + float2(_Time.x,0));

				fixed4 col = (col1 + col2) / 2;//法线的颜色值

				//把颜色值转变为法线 --- 此法线是来自法线纹理 - 存在于纹理空间,并不是顶点中的法线
				float3 N = normalize( UnpackNormal(col) );

				//与水面法线的点积--得到夹角的大小
				float off_xy = dot(N,float3(0,1,0));//结果在1和-1之间

				//二维向量加一个标量,意味着给每一个分量加上这个标量
				//乘0.1是为了缩小夹角变化范围
				i.proj.xy += off_xy * 0.1;

				//采样 抓取的通道的颜色
				fixed4 gcol = tex2Dproj(_GrabTexture, i.proj);

				//漫反射系数
				float diff = max(0, dot(N, normalize(i.L))); 

				//半角向量
				float3 H = normalize(normalize(i.L) + normalize(i.V));
				//高光反射 高光系数
				float spec = pow(max(0,dot(N, H)), 128);


				//gcol.rgb *= diff * _BaseColor.rgb;
				//gcol.rgb += spec * _LightColor0.rgb;
				//float4 diffColor = diff * _BaseColor;
				//diffColor.rgb += spec * _LightColor0.rgb;

				i.refl.xy += off_xy * 0.1;//扭曲倒影
				fixed4 reflCol = tex2Dproj(_ReflectionTex, i.refl) + spec * _LightColor0;
				
				float fresnel = _Bias + _Scale * pow(1+dot(N, -normalize(i.V)), _Pow);


				fixed4 finalColor = lerp( gcol, reflCol, fresnel);

				return finalColor;
			}
			ENDCG
		}
	}
}