前言:一个简单的Unity使用顶点片段着色器的镜面反射的例子,虽然很简单却很实用----在使用多个pass时,移植性比表面着色器的移植性要好。
Shader "Custom/NormSpecular" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Bump ("Bump", 2D) = "bump" {}
_Specular ("Specular", Range(1.0, 500.0)) = 250.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
Pass {
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
uniform float4x4 _LightMatrix0; // 引入光矩阵
sampler2D _MainTex;
sampler2D _Bump;
float _Specular;
float _Gloss;
float4 _MainTex_ST;
struct a2v {
float4 vertex : POSITION; // 输入的模型顶点信息
fixed3 normal : NORMAL; // 输入的法线信息
fixed4 texcoord : TEXCOORD0; // 输入的坐标纹理集
fixed4 tangent : TANGENT; // 切线信息
};
struct v2f {
float4 pos : POSITION; // 输出的顶点信息
fixed2 uv : TEXCOORD0; // 输出的UV信息
fixed3 lightDir: TEXCOORD1; // 输出的光照方向
fixed3 viewDir : TEXCOORD2; // 输出的摄像机方向
fixed3 _LightCoord : TEXCOORD3; // 光照坐标
fixed4 _ShadowCoord : TEXCOORD4; // 阴影坐标
fixed3 vertexLighting:TEXCOORDS5;//顶点光照强度
};
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
// 创建一个正切空间的旋转矩阵,TANGENT_SPACE_ROTATION由下面两行组成
//TANGENT_SPACE_ROTATION;
float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal );
// 将顶点的光方向,转到切线空间
// 该顶点在对象坐标中的光方向向量,乘以切线空间旋转矩阵
o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
// 该顶点在摄像机坐标中的方向向量,乘以切线空间旋转矩阵
o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex));
// 将照明信息给像素着色器,应该是用于下面片段中光衰弱atten的计算
// TRANSFER_VERTEX_TO_FRAGMENT(o); // 由下面两行组成
// 顶点转到世界坐标,再转到光坐标
o._LightCoord = mul(_LightMatrix0, mul(_Object2World, v.vertex)).xyz;
o._ShadowCoord = mul(unity_World2Shadow[0], mul(_Object2World, v.vertex));
o.vertexLighting = fixed3(0.0,0.0,0.0);
o.vertexLighting = Shade4PointLights(unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0,
unity_LightColor[0].rgb,unity_LightColor[1].rgb,unity_LightColor[2].rgb,unity_LightColor[3].rgb,
unity_4LightAtten0,mul(_Object2World,v.vertex),normalize(mul(float4(v.normal,0.0),_World2Object).xyz));
return o;
}
fixed4 frag(v2f i) : COLOR {
// 对主纹理进行采样
fixed4 texColor = tex2D(_MainTex, i.uv);
// 对法线图进行采样
fixed3 norm = UnpackNormal(tex2D(_Bump, i.uv));
// 光衰弱,卧槽,里面封装了比较深,暂时看不进去,就不拆开了
fixed atten = LIGHT_ATTENUATION(i);
// 求漫反射
// 公式:漫反射色 = 光颜色*N,L的余弦值(取大于0的),所以夹角越小亮度越小
fixed3 Diff = dot (normalize(norm), normalize(i.lightDir));//半角向量
fixed3 HalfVector = normalize(i.lightDir + i.viewDir);
fixed NdotH = max(0,dot(norm,HalfVector));
fixed specularpower = pow(NdotH,_Specular)*sign(Diff);
Diff = saturate(Diff);
// 计算反射高光
// 公式:反射高光 = 光颜色 * 【(反射光向量,摄像机方向向量)的余弦值】的【高光指数_Specular】次方 * 光泽度
fixed4 fragColor;
fragColor.rgb = texColor.rgb*(((Diff+specularpower)*_LightColor0.rgb)*(atten*Diff*2)+i.vertexLighting);
fragColor.a = texColor.a;
return fragColor;
}
ENDCG
}
}
FallBack "Diffuse"
}
Unity5.2.3下编译通过