iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 22
0
自我挑戰組

初見Unity Shader系列 第 22

不是真的反射

文章內使用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
		}
	}
}

以下為結果:

假的!

這是一個非常老的反射場景的方法,但可以看的出來上面的作法並不是「真正的」反射場景,而是利用單純貼圖做出反射的效果。

Reference


上一篇
立方體貼圖、Skybox、環境貼圖
下一篇
極.簡單頂點動畫
系列文
初見Unity Shader30

尚未有邦友留言

立即登入留言