我们先按照前文的方法,制作一个Cubemap。
然后复制一个最简单的立方体反射shader:
Shader "Custom/Reflection/Normal" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_MainTint ("Main Tint", Color) = (1,1,1,1)
_CubeMap ("CubeMap", CUBE) = "" {}
_ReflAmount ("Reflection Amount", Range(0.01, 1)) = 0.5
}
SubShader {
Tags { "RenderType"="Opaque"}
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
fixed4 _MainTint;
samplerCUBE _CubeMap;
fixed _ReflAmount;
struct Input {
float2 uv_MainTex;
float3 worldRefl;
};
void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
o.Emission = texCUBE(_CubeMap, IN.worldRefl).rgb * _ReflAmount;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
Properties里增加:
_NormalMap ("Normal Map", 2D) = "bump" {}
sampler2D _NormalMap;
struct Input {
float2 uv_MainTex;
float2 uv_NormalMap;
float3 worldRefl;
INTERNAL_DATA
};
修改surf方法:
void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
fixed3 n = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
o.Normal = n;
o.Emission = texCUBE(_CubeMap, WorldReflectionVector(IN, o.Normal)).rgb * _ReflAmount;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
这时候,如果我们把INTERNAL_DATA注释掉的话,Unity会报错:
Shader error in 'Custom/Reflection/NormalMap': Surface shader Input structure needs INTERNAL_DATA for this WorldNormalVector or WorldReflectionVector usage at line 36 (on glcore)
挑选一个Normal Map作为输入,例如这张:
得到效果:
如果我们不修改o.Emission这一句,还是使用原来的值:
// o.Emission = texCUBE(_CubeMap, WorldReflectionVector(IN, o.Normal)).rgb * _ReflAmount;
o.Emission = texCUBE(_CubeMap, IN.worldRefl).rgb * _ReflAmount;
因为法线不对应,所以无法形成发射效果。
我们还是从基础的立方体反射开始:
Shader "Custom/Reflection/BlinnPhong" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_MainTint ("Main Tint", Color) = (1,1,1,1)
_CubeMap ("CubeMap", CUBE) = "" {}
_ReflAmount ("Reflection Amount", Range(0.01, 1)) = 0.5
}
SubShader {
Tags { "RenderType"="Opaque"}
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
fixed4 _MainTint;
samplerCUBE _CubeMap;
fixed _ReflAmount;
struct Input {
float2 uv_MainTex;
float3 worldRefl;
};
void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
o.Emission = texCUBE(_CubeMap, IN.worldRefl).rgb * _ReflAmount;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
_RimPower ("Fresnel Falloff", Range(0.1, 3)) = 2
_SpecColor ("Specular Color", Color) = (1,0,0,1)
_SpecPower ("Specular Power", Range(0, 1)) = 0.2
half _RimPower;
fixed _SpecPower;
float3 viewDir;
void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
half rim = saturate(dot(o.Normal, normalize(IN.viewDir)));
rim = 1.0 - rim;
rim = pow(rim, _RimPower);
o.Emission = texCUBE(_CubeMap, IN.worldRefl).rgb * _ReflAmount * rim;
o.Specular = _SpecPower;
o.Gloss = 1.0;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
如果注释掉这一行:
rim = 1.0 - rim;
我们知道,rim是计算了法线向量与视图向量之间的点积(数值越大表示接收到的视线越多),而1-rim就正好翻转了这个值,也就是说背向摄像机的面反射效果更明显。