1. 程式人生 > >Unity 製作燈罩 雙面材質背面不受光照影響的解決方法

Unity 製作燈罩 雙面材質背面不受光照影響的解決方法

     最近開發一個Unity專案主要是打算模擬一下燈效果,本以為把一個光源放入我們的燈的模型中就可以完美解決問題,然而當開始操作的時候,真的是困難重重,套在模型裡面的點光源根本無法照亮外面的模型!

     

     我們可以發現,這個光源可以在外面照亮這個立方體,而無法從裡面照亮立方體。 

     百度了一下之後,也沒有發現過多的資訊,大多數的做法還是選擇高亮表面,然後旁邊加幾個點光源照亮表面(設定layer,只照亮燈的部分),一開始,我也是這麼弄得,但是我的專案就是為了表現燈的,所以不免有對燈的亮度的調節,而且有的燈的模型面太多了根本就沒法實現正常的模擬,畢竟在外面找一個類圓形的物體肯定會導致照的不均勻的,而且光源過多的話對系統消耗也有不小的影響。於是,我決定一定要研究一下這個燈的發光效果,目標就是實現光源從裡面照亮整個燈罩!

      所以,這樣的話,我們的目標就明確了,就是要立方體的背面可以被照亮,但是為什麼立方體外面可以被照亮然而內部不可以被照亮呢?

      其實每一個模型都是有一個面的,也就是正面和反面,預設的情況下,我們的圖形渲染和光照影響都是隻會在正面有效果的,這樣做是為了節省資源,畢竟背面的話,我們也看不見何必再消耗資源去渲染它呢?現在網上有很多關於雙面材質的解決方案,最簡單的做法就是在Shader裡面加入一個cull off,也就是關閉剔除渲染(表達的有點不清楚,這個意思就是cull back 的話就是不渲染背面,cull front的話就是不渲染正面),所以你添加了cull off的話就是兩面都渲染,也就是實現了雙面材質。

    

      以上的效果是當光源照正面的時候,我們發現這個plane的兩邊都被照亮了,下面我們來看看,照背面會怎麼樣?

     我們可以發現,當光源照到背面的時候,兩面都沒有光照的效果。

     Google了一下之後,發現了一片文章解決了我的疑惑,這篇文章講的真心不錯,強烈推薦讀一讀:http://danielbrauer.com/files/rendering-double-sided-geometry.html。其實,正面之所以被光照影響是因為,當前的模型上面的法線和光照的方向是相反的,所謂法線,大家初中物理就應該接觸過吧,就是很據入射光計算反射光的中間的那條線。在Unity3D中,光照效果的漫反射也是根據這個計算的,之所以背面不接受光照,是因為法線方向和光線方向平行當然就計算不出反射光線的方向

,也就反射不回來,所以我們也看不到它。那麼,這樣的話,我們的工作就明確了,只要把法線方向變為和原來的相反,那麼模型的背面也就有效果啦~

下面貼一下,Shader的程式碼(這個Shader是我根據Unity自帶的自發光高光Shader改的雙面材質背面受光照影響):

Shader "Happy/TwoSideShader" {
Properties {
	_Color ("Main Color", Color) = (1,1,1,1)
	_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
	_Shininess ("Shininess", Range (0.01, 3)) = 1
	_Parallax ("Height", Range (0.005, 0.08)) = 0.02
	_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
	_Illum ("Illumin (A)", 2D) = "white" {}
	_BumpMap ("Normalmap", 2D) = "bump" {}
	_ParallaxMap ("Heightmap (A)", 2D) = "black" {}
}
SubShader {
	Tags { "RenderType"="Opaque" }
	LOD 600
	cull off
CGPROGRAM
#pragma surface surf BlinnPhong
#pragma target 3.0

sampler2D _MainTex;
sampler2D _BumpMap;
sampler2D _ParallaxMap;
sampler2D _Illum;
fixed4 _Color;
float _Parallax;
half _Shininess;
struct Input {
	float2 uv_MainTex;
	float2 uv_BumpMap;
	float2 uv_Illum;
	float3 viewDir;
};

void surf (Input IN, inout SurfaceOutput o) {
	half h = tex2D (_ParallaxMap, IN.uv_BumpMap).w;
	float2 offset = ParallaxOffset (h, _Parallax, IN.viewDir);
	IN.uv_MainTex += offset;
	IN.uv_BumpMap += offset;
	IN.uv_Illum += offset;

	fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
	fixed4 c = tex * _Color;
	o.Albedo = c.rgb;
	o.Gloss = tex.a;
	o.Emission = c.rgb * tex2D(_Illum, IN.uv_Illum).a;
	o.Specular = _Shininess;
	o.Alpha = c.a;
	o.Normal = -UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
FallBack "Legacy Shaders/Self-Illumin/Bumped Specular"
CustomEditor "LegacyIlluminShaderGUI"
}

     其實,單單實現燈罩的話沒必要使用雙面材質,可以把這個Shader裡面的cull off去掉,這次為了做一個這樣的效果也是花費不少的時間,最終的解決方法也是如此的簡單,看來還事Shader的基礎不紮實!有時間還得好好研究一下~