文章內使用Unity 2019 LTS
我們需要兩個材質,一個是環境貼圖的,另一個是物體反射的貼圖。
環境貼圖的立方體貼圖在昨天Day21做過了,關於物體反射的,請依下面的步驟新增一個:
Create -> Legacy -> CubeMap
依照昨天的立方體貼圖,把六張貼圖附加上去,勾選Readable,素材可以到以下這個網站尋找:
請注意在附加CubeMap的時候,請先把FaceSize調整好,這關係到CubeMap的解析度,若在附加貼圖過後,再調整,解析度會是先前的,並要求重新附加。
Shader "Learning/Reflection" {
Properties {
_BaseColor ("Color", Color) = (1, 1, 1, 1)
_ReflectColor ("Reflection Color", Color) = (1, 1, 1, 1)
_ReflectAmount ("Reflect Amount", Range(0, 1)) = 1
// 新屬性! 立方體貼圖
_Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {}
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry"}
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _ReflectColor;
fixed _ReflectAmount;
samplerCUBE _Cubemap;
struct v2f {
float4 pos : SV_POSITION;
float3 worldPos : TEXCOORD0;
fixed3 worldNormal : TEXCOORD1;
fixed3 worldViewDir : TEXCOORD2;
fixed3 worldRefl : TEXCOORD3;
};
v2f vert(appdata_base v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);
// 計算反射向量
o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 worldViewDir = normalize(i.worldViewDir);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal, worldLightDir));
// CubeMap是利用方向向量進行取樣,不是uv座標
fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb * _ReflectColor.rgb;
fixed3 color = ambient + lerp(diffuse, reflection, _ReflectAmount);
return fixed4(color, 1.0);
}
ENDCG
}
}
}
以下為結果:
這是一個非常老的反射場景的方法,但可以看的出來上面的作法並不是「真正的」反射場景,而是利用單純貼圖做出反射的效果。