Shader "chicai/7"{ Properties{ _Specular("Specular",Color)=(1,1,1,1) _Glass("Glass",Range(8,20))=8 _MainTex("MainTex",2D)="white"{} _NormalTex("NormalTex",2D)="white"{} _NormalIndexd("AoTuQiangDu",float)=1 } SubShader{ Pass{ Tags{"RenderMode"="ForwardBase"} CGPROGRAM fixed4 _Diffuse; fixed4 _Specular; float _Glass; sampler2D _MainTex; float4 _MainTex_ST; sampler2D _NormalTex; float4 _NormalTex_ST; float _NormalIndexd; #include "Lighting.cginc" #pragma vertex vert #pragma fragment frag struct a2v{ float4 vertex:POSITION; float3 normal:NORMAL; float4 tangent:TANGENT; float4 texcoord:TEXCOORD0; }; struct v2f{ float4 position:SV_POSITION; fixed3 nor:COLOR0; fixed3 lightDir:COLOR1; fixed3 viewDir:COLOR2; float4 uv:TEXCOORD0; }; v2f vert(a2v v){ v2f f; f.position = UnityObjectToClipPos(v.vertex); f.nor = normalize(mul(unity_ObjectToWorld,v.normal)); TANGENT_SPACE_ROTATION; f.lightDir = normalize(mul(rotation,ObjSpaceLightDir(v.vertex))).xyz; f.viewDir = normalize(mul(rotation,ObjSpaceViewDir(v.vertex))).xyz; f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; f.uv.zw = v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw; return f; } fixed4 frag(v2f f):SV_Target{ fixed3 tangentNormal = UnpackNormal(tex2D(_NormalTex,f.uv.wz)); tangentNormal.xy = tangentNormal.xy * _NormalIndexd; tangentNormal = normalize(tangentNormal); fixed3 texCol = tex2D(_MainTex,f.uv);//计算改uv上贴图的颜色,当物体本身颜色——Diffuse fixed3 diffuseCol = _LightColor0.rgb * texCol * (dot(tangentNormal,f.lightDir)/2+0.5); fixed3 aveDir = normalize(f.lightDir+f.viewDir); fixed3 specularCol = _LightColor0.rgb * _Specular * pow(max(dot(aveDir,tangentNormal),0),_Glass); fixed3 allColor = diffuseCol + specularCol; return fixed4(allColor,1); } ENDCG } } }
Unity属性中添加法线贴图属性和凹凸强度系数
_NormalTex("NormalTex",2D)="white"{} _NormalIndexd("AoTuQiangDu",float)=1
CG声明对应的变量和平移缩放变量
sampler2D _NormalTex; float4 _NormalTex_ST; float _NormalIndexd;
引进切线到顶点函数float4 tangent:TANGENT;
使用传入片元的uv参数的xy传递贴图uv坐标,zw传递法线贴图的uv坐标
f.uv.zw = v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw;
转变视野方向和光线方向到切线空间
TANGENT_SPACE_ROTATION;//一个宏,计算出rotation f.lightDir = normalize(mul(rotation,ObjSpaceLightDir(v.vertex))).xyz; f.viewDir = normalize(mul(rotation,ObjSpaceViewDir(v.vertex))).xyz;
片元中得出相应的法线
fixed3 tangentNormal = UnpackNormal(tex2D(_NormalTex,f.uv.wz));//像素图片(0-255)转化为方向的(-1,1) tangentNormal.xy = tangentNormal.xy * _NormalIndexd; tangentNormal = normalize(tangentNormal);
Shader "chicai/6"{ Properties{ _Specular("Specular",Color)=(1,1,1,1) _Glass("Glass",Range(8,20))=8 _MainTex("MainTex",2D)="white"{} } SubShader{ Pass{ Tags{"RenderMode"="ForwardBase"} CGPROGRAM fixed4 _Diffuse; fixed4 _Specular; float _Glass; sampler2D _MainTex; float4 _MainTex_ST; #include "Lighting.cginc" #pragma vertex vert #pragma fragment frag struct a2v{ float4 vertex:POSITION; float3 normal:NORMAL; float4 texcoord:TEXCOORD0; }; struct v2f{ float4 position:SV_POSITION; fixed3 nor:COLOR0; fixed3 lightDir:COLOR1; fixed3 viewDir:COLOR2; float2 uv:TEXCOORD0; }; v2f vert(a2v o){ v2f f; f.position = UnityObjectToClipPos(o.vertex); f.nor = normalize(mul(unity_ObjectToWorld,o.normal)); f.lightDir = normalize(WorldSpaceLightDir(o.vertex)); f.viewDir = normalize(WorldSpaceViewDir(o.vertex)); f.uv = o.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; return f; } fixed4 frag(v2f f):SV_Target{ fixed3 texCol = tex2D(_MainTex,f.uv);//计算该uv上贴图的颜色,当物体本身颜色——Diffuse fixed3 diffuseCol = _LightColor0.rgb * texCol * (dot(f.nor,f.lightDir)/2+0.5); fixed3 aveDir = normalize(f.lightDir+f.viewDir);//光照方向和视野方向的平分线 fixed3 specularCol = _LightColor0.rgb * _Specular * pow(max(dot(aveDir,f.nor),0),_Glass); fixed3 allColor = diffuseCol + specularCol; return fixed4(allColor,1); } ENDCG } } }
首先,Unity变量:
_MainTex("MainTex",2D)="white"{}
对应CG变量:
sampler2D _MainTex; float4 _MainTex_ST;//固定,变量名_ST,xy分量表示贴图的缩放,zw分量表示贴图的偏移
顶点函数传入uv纹理坐标 float4 texcoord:TEXCOORD0;
计算出含偏移缩放等的纹理坐标给片元
float2 uv:TEXCOORD0; f.uv = o.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;//乘缩放,+偏移 f.uv = TRANSFORM_TEX(v.texcoord, _MainTex_ST);//内置的方法转换uv,等同于上面一行
找出对应uv坐标对应的纹理颜色充当漫反射自身颜色
// 摄像机方向(视角方向) float3 WorldSpaceViewDir(float4 v) // 根据模型空间中的顶点坐标 得到 (世界空间)从这个点到摄像机的观察方向 float3 UnityWorldSpaceViewDir(float4 v) // 世界空间中的顶点坐标==》世界空间从这个点到摄像机的观察方向 float3 ObjSpaceViewDir(float4 v) // 模型空间中的顶点坐标==》模型空间从这个点到摄像机的观察方向 // 光源方向 float3 WorldSpaceLightDir(float4 v) // 模型空间中的顶点坐标==》世界空间中从这个点到光源的方向 float3 UnityWorldSpaceLightDir(float4 v) // 世界空间中的顶点坐标==》世界空间中从这个点到光源的方向 float3 ObjSpaceLightDir(float4 v) // 模型空间中的顶点坐标==》模型空间中从这个点到光源的方向 // 方向转换 float3 UnityObjectToWorldNormal(float3 norm) // 把法线方向 模型空间==》世界空间 float3 UnityObjectToWorldDir(float3 dir) // 把方向 模型空间=》世界空间 float3 UnityWorldToObjectDir(float3 dir) // 把方向 世界空间=》模型空间
公式:Specular = 直射光 * pow( max(cosβ,0) ,范围系数)
β角指的是法线和x的夹角,x指的是直射光和视野方向的平分线
公式的改变就只有夹角不同,这个效果的反光范围会比较大
//计算高光 fixed3 reflectDir = normalize( reflect(-lightDir,normalDir) ); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex)); fixed3 specularColor = _LightColor0.rgb * _Specular * (pow( max( dot(reflectDir,viewDir) ,0),_Gloss) ); f.color = diffuseColor + specularColor;
主要计算两个方向,反射光的方向和视野方向
_Specular是自定义属性,为高光颜色
反射光方向主要用reflect()方法得到,两个参数为入射光的方向和法线
视野方向用摄像机位置-点的位置来得到。
公式:specular = 直射光 * pow( max(cosβ,0) ,范围系数)
β角指的是反射光的方向和该点到相机(视野)方向的夹角。
使用兰伯特光照模型计算的模型背面颜色都是全黑色这样子不好。所有演变了一个半兰伯特模型
公式:diffuse = 直射光颜色 * ( cosβ * 0.5 + 0.5)
cosβ的范围为[-1,1],乘于0.5后为[-0.5,0.5],在加上0.5后就变成[0,1]了,刚好满足颜色的范围。
颜色之间相乘,表示融合两种颜色
颜色之间相加,表示加强