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