1. 程式人生 > >Unity Shader-法線貼圖(Normal)及其原理

Unity Shader-法線貼圖(Normal)及其原理

簡介

以前經常聽說“模型不好看啊,怎麼辦啊?”答曰“加法線”,”做了個高模,準備烘一下法線貼圖”,“有的美術特別屌,直接畫法線貼圖”.....法線貼圖到底是個什麼鬼,當年天真的我真的被這個圖形學的奇淫雜技忽悠了,然而畢竟本人還算有點刨根問底的精神,決定研究一下法線貼圖的原理以及Unity下的實現。本人才疏學淺,如有錯誤,歡迎指正。

法線貼圖是目前遊戲開發中最常見的貼圖之一。我們知道,一般情況下,模型面數越高,可以表現的細節越多,效果也越好。但是,由於面數多了,頂點數多了,計算量也就上去了,效果永遠是和效能成反比的。怎麼樣用盡可能簡單模型來做出更好的效果就成了大家研究的方向之一。紋理對映是最早的一種,通過紋理直接貼在模型表面,提供了一些細節,但是普通的紋理貼圖只是影響最終畫素階段輸出的顏色值,不能讓模型有一些凹凸之類的細節表現。而法線貼圖就是為了解決上面的問題,給我們提供了通過低面數模型來模擬高面數模型的效果,增加細節層次感,效果與高模相差不多,但是大大降低了模型的面數。

法線貼圖原理

要模擬一個圓球,要想越平滑,就需要更多的面數,否則會很容易地發現面和麵之間的明顯邊界。最早時的GPU是沒有fragement程式設計能力的,也就是說在這種情況下,在計算時需要逐頂點計算光照,然後每個畫素的顏色在各個頂點的顏色之間插值,也就是高洛德著色,這種情況下,面數決定一切效果,沒有什麼好辦法。而當畫素著色器出現之後,我們可以逐畫素來計算光照效果,這時候,在計算每個畫素的光照時,會計算這個畫素所在的面的法向量,而這個面的法向量也是由這個面周圍的頂點法線(也就是我們之前vertex shader中出現的normal)插值得來的,當然,如果面數很低,那麼效果也好不到哪裡去。但是,逐畫素計算光照時,我們每一個畫素都會根據該點的法向量來計算最終該點的光照結果,那麼,我們如果能夠改變這個法線的方向,不是就可以改變這個點的光照結果了呢
!那麼,把紋理取樣的思想用在這裡,我們直接用一張圖來儲存法線(或者法線偏移值,見下文),逐畫素計算時,在取樣diffuse貼圖的時候,再取樣一張法線的貼圖,就可以修改法線了,進而修改最終的效果。 為什麼法線貼圖會讓我們感覺有凹凸感呢?看下面一張圖,在現實世界中,你要相信你的眼睛,眼見為實還有點道理,在計算機世界中,一切以忽悠你為目的。在平面的情況下,我們感覺物體是凹陷還是凸起,很大一部分取決於這個面的亮度,像下面這張圖,有了這種亮度的對比,我們就很容易感覺這個按鈕有周圍的一圈凸起。


如果還是沒理解,再看一套圖片,同樣一張圖片,旋轉180度後的結果完全相反。不信可以去截圖放到MSPaint裡面轉一下試試,反正我是試了....

既然一個面的光照條件(亮度)的改變,就可以讓我們感覺這個面有凹凸感,那麼上面說的,通過改變法線來改變面上某點的光照條件,進而忽悠觀察者,讓他們感覺這個面有凹凸感的方法就行得通了。

假如下面是我們的低面數模型,上面是我們的高面數模型,上面的模型在計算光照時,由於面數多,每個面的法線方向不同,所以各個面的光照計算結果都不同,就有凹凸的感覺了,而下面的低模,只有一個面,整個面的光照條件都是一致的,就沒有凹凸的感覺了。我們如果把上面的高模的法線資訊儲存下來,類似紋理貼圖那樣,存在一張圖裡,再給低模使用,低模就可以有跟高模一樣的法線,進而在計算光照時達到和高模類似的效果,這也就是常說的烘法線的原理。

凹凸貼圖(Bump Map)

既然說了要研究法線貼圖,所以肯定要從老一輩的開始,首先來看一下凹凸貼圖(Bump Map)。Bump Map是最早的法線貼圖實現方式,這也是製作上最容易的一種模式,可以直接通過一張灰度圖,預設為黑色,越凸起的地方顏色越亮,這種就是可以直接在PhotoShop中畫的法線,但是這種法線貼圖的原理理解起來比較難,我只說一下我的理解,然後附上unity中的shader實現。這種技術現在貌似已經過時了,但是思想還是流傳下來了,而且這種畫灰度圖,或者通過灰度圖生成法線貼圖的方式現在仍然在使用,Unity就支援這種直接通過灰度圖生成法線貼圖。 首先,通過灰度圖來表現凹凸,那麼,我們怎樣判斷一個點處在凹凸的邊緣呢?答案是通過斜率,比如我要對(x,y)進行取樣,怎樣求這一點的斜率呢,學過數學的都知道,我們可以通過兩點確定一條直線,進而求出這條直線的斜率。那麼我們就可以對(x-1,y)和(x+1,y)兩點進行取樣,豎向也是一樣,通過(x,y-1)和(x,y+1)進行取樣,那麼,我們就可以獲得這一點上灰度值的變化,如果灰度值不變,說明該點不在邊緣,如果灰度值有改變,那麼說明該點在邊緣,那麼我們就可以根據這個斜率值來修改法線,進而修改光照結果。 我又掏出了我十分不熟練的PhotoShop,畫了一張傳說中的Bump Map,恩,感覺還不錯,目前RGB通道都有資訊,反正只是實驗,和shader對應就好了:
Bump Map型別的shader如下(僅僅是實驗基於灰度的Bump,完全不實用....)
//Bump Map
//by:puppet_master
//2016.12.13
Shader "ApcShader/BumpMap"
{
	//屬性
	Properties{
		_Diffuse("Diffuse", Color) = (1,1,1,1)
		_MainTex("Base 2D", 2D) = "white"{}
		_BumpMap("Bump Map", 2D) = "black"{}
		_BumpScale ("Bump Scale", Range(0.1, 30.0)) = 10.0
	}

	//子著色器	
	SubShader
	{
		Pass
		{
			//定義Tags
			Tags{ "RenderType" = "Opaque" }

			CGPROGRAM
			//引入標頭檔案
			#include "Lighting.cginc"
			//定義Properties中的變數
			fixed4 _Diffuse;
			sampler2D _MainTex;
			//使用了TRANSFROM_TEX巨集就需要定義XXX_ST
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float4 _BumpMap_TexelSize;
			float _BumpScale;

			//定義結構體:應用階段到vertex shader階段的資料
			struct a2v
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 texcoord : TEXCOORD0;
			};
			//定義結構體:vertex shader階段輸出的內容
			struct v2f
			{
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				//轉化紋理座標
				float2 uv : TEXCOORD1;
			};

			//定義頂點shader
			v2f vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				//把法線轉化到世界空間
				o.worldNormal = mul(v.normal, (float3x3)_World2Object);
				//通過TRANSFORM_TEX巨集轉化紋理座標,主要處理了Offset和Tiling的改變,預設時等同於o.uv = v.texcoord.xy;
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				return o;
			}

			//定義片元shader
			fixed4 frag(v2f i) : SV_Target
			{
				//unity自身的diffuse也是帶了環境光,這裡我們也增加一下環境光
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.xyz;
				//歸一化法線,即使在vert歸一化也不行,從vert到frag階段有差值處理,傳入的法線方向並不是vertex shader直接傳出的
				fixed3 worldNormal1 = normalize(i.worldNormal);
				//取樣bump貼圖,需要知道該點的斜率,xy方向分別求,所以對於一個點需要取樣四次
				fixed bumpValueU = tex2D(_BumpMap, i.uv + fixed2(-1.0 * _BumpMap_TexelSize.x, 0)).r - tex2D(_BumpMap, i.uv + fixed2(1.0 * _BumpMap_TexelSize.x, 0)).r;
				fixed bumpValueV = tex2D(_BumpMap, i.uv + fixed2(0, -1.0 * _BumpMap_TexelSize.y)).r - tex2D(_BumpMap, i.uv + fixed2(0, 1.0 * _BumpMap_TexelSize.y)).r;
				//用上面的斜率來修改法線的偏移值
				fixed3 worldNormal = fixed3(worldNormal1.x * bumpValueU * _BumpScale, worldNormal1.y * bumpValueV * _BumpScale, worldNormal1.z);

				//把光照方向歸一化
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				//根據半蘭伯特模型計算畫素的光照資訊
				fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
				//最終輸出顏色為lambert光強*材質diffuse顏色*光顏色
				fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz + ambient;
				//進行紋理取樣
				fixed4 color = tex2D(_MainTex, i.uv);
				return fixed4(diffuse * color.rgb, 1.0);
			}

			//使用vert函式和frag函式
			#pragma vertex vert
			#pragma fragment frag	

			ENDCG
		}

	}
		//前面的Shader失效的話,使用預設的Diffuse
		FallBack "Diffuse"
}
效果如下: 這個過程還是很有意思的,Unity為我們封裝了太多東西,尤其是surface shader,只需要一句unpacknormal,然後把輸出賦給o.normal就ok了,我們基本不需要做什麼,但是底層的實現對於學習來說還是很必要的。

法線貼圖(Normal Map)

隨著GPU的發展,Geforce3的出現,帶來了真正的Normal Mapping技術,也叫作Dot3 bump mapping。這種Normal Map就是我們現在在使用的法線貼圖技術。與之前通過灰度表現介面的凹凸程度,進而修改法線的方式完全不同,這種Normal Map直接將法線儲存到了法線貼圖中,也就是說,我們從法線貼圖讀取的法線直接就可以使用了,而不是需要像上面那樣,再通過灰度漸變值來修改法線。這種法線對於製作來說,沒有灰度圖那樣直白,但是卻是真正的法線貼圖技術,所謂烘焙法線,烘焙的就是這個。 雖然灰度圖不會直接被用於實時計演算法線了,但是在離線工具中卻提供了直接通過灰度圖生成法線的功能。Unity中就有這種功能:
我們把之前畫的那張灰度圖直接通過這種方式改成法線貼圖,從法線貼圖中我們就直接可以看到凹凸的效果了。在Unity裡實現法線貼圖的shader之前,首先看幾個問題,也是困擾了我一段時間的幾個問題。

法線貼圖是怎樣儲存的

既然法線貼圖中儲存的是法線的方向,也就是說是一個Vector3型別的變數,剛好和圖片的RGB格式不謀而合。但是向量畢竟要靈活得多,我們正常的RGBA貼圖,一個通道是8位,可以表示的大小在(0,255),那麼反過來除一下,貼圖中可以儲存的向量的精度就是0.0039,也就是說並不是真正意義上的浮點型別,精度要小得多,不過對於一般情況下,這種精度也足夠了。再一個問題,就是向量是有方向滴,而貼圖中只能儲存的都是正數,所以,還需要一個對映的過程。對映在圖形學中真是很多見呢,比如計算半蘭伯特光照時,就通過把(0,1)的光照區間轉化到了(0.5,1)提高了光的亮度,使效果更好。在法線貼圖中,可以用0代表向量中的-1,用255代表向量中的1,不過,在shader中,貼圖的顏色一般也是(0,1)區間,所以,我們在計算時只需要把從法線貼圖中取樣得到的法線值進行對映,將其從(0,1)區間轉化到(-1,1)區間。 這個步驟,Unity已經為我們完成了,我們在計演算法線的時候,只需要呼叫UnpackNormal這個函式就可以實現區間的重新對映。從UnityCG.cginc中可以看到UnpackNormal這個函式的實現:
inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal)
{
	fixed3 normal;
	normal.xy = packednormal.wy * 2 - 1;
	normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
	return normal;
}

inline fixed3 UnpackNormal(fixed4 packednormal)
{
#if defined(UNITY_NO_DXT5nm)
	return packednormal.xyz * 2 - 1;
#else
	return UnpackNormalDXT5nm(packednormal);
#endif
}
做法很簡單,乘2 減1大法好,轉化區間沒煩惱(什麼鬼....) 這裡,我們看到了兩個UnpackNormal的函式,下面的就是我們所說的直接轉化區間。而上面的那個函式,看定義來說,是為了專門解出DXT5nm格式的normal map,這種型別的normal map,只用儲存法向量中的兩個通道,然後解開的時候,需要計算一下,重新算出另一個向量方向。這樣可以實現的原理在於,儲存的向量是單位向量,長度一定的情況下,就可以通過sqrt(1 - x^2 - y^2)來求得,如下圖: 不過這是一種時間換空間的做法,以犧牲時間的代價,換來更好的壓縮比以及壓縮後的效果。關於DXT5nm,附上一篇參考文章:Normal Map的dds壓縮

為什麼法線貼圖儲存在切線空間

既然知道了法線可以儲存在貼圖中,我們就再來看一下,為什麼法線貼圖中一般都儲存的是切線空間,為什麼不儲存在世界空間或者模型空間。首先看一下世界空間,如果我們的法線貼圖儲存的世界空間的法線資訊,我們可以直接解出法線的值,在世界空間進行計算,是最直接並且計算效率最高的做法,但是世界空間的法線貼圖就跟當前環境之間耦合過大了,比如同樣的兩個模型,僅僅是旋轉方向不同,也需要兩張法線貼圖,這很明顯是多餘的,於是就有人想出了基於模型空間的法線,基於模型空間,在計算時,把模型空間的法線轉換到世界空間,雖然多了一步操作,但是同一個模型可以共用法線,不用考慮旋轉等問題。但是,人們感覺模型空間的法線貼圖跟模型的耦合度還是高,那就繼續解耦吧,於是基於切線空間的法線貼圖就誕生了。下圖為模型空間與切線空間法線。
所謂的切線空間,跟那些比較常見的座標系,比如世界座標,模型座標一樣,也是一個座標系,用三個基向量就可以表示。我們用模型上的一個點來看,這個點的有一個法線的方向,也就是這個點所在的面的法線的方向N,這個方向是確定的,我們可以用它作為Z軸。而剩下的兩個軸,剛好就在這個面上,互相垂直,但是這兩個軸的可選種類就多了,因為在這個面上任意兩個向量都可以表示這個面。目前最常用的方式是以該點的uv二維座標系表達該點的切線(tangent)和該點的次法線(binormal)所構成的切平面。它的法線既處處都垂直於它的表面。我們用展uv的方式,將紋理展開攤平,那麼所有的法線就都垂直於這個紋理平面,法線就是z軸,而uv set,準確地說是該點uv朝著下一個頂點uv的方向向量分別作為tangent和binormal軸,也就是x,y軸。但是這樣做有一個弊端,就是x軸和y軸之間不互相垂直,計算Tangent空間的公式如下: T = normalize(dx/du, dy/du, dz/du)
N = T × normalize(dx/dv, dy/dv, dz/dv)
B = N × T
很遺憾我們在在Unity裡面看不到全部原始碼,不過從shader的定義中可以看到B的求解以及TBN矩陣的構建過程:
// Declares 3x3 matrix 'rotation', filled with tangent space basis
#define TANGENT_SPACE_ROTATION \
	float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \
	float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal )
float3x3是行向量構建,可以參照這裡,然後我們就可以通過mul(rotation,v)把需要的向量從模型空間轉化到tangent空間。不過大部分內容Unity已經幫我們做好了,主要是TBN空間的建立,如果需要自己寫渲染器的話,這個是一個比較麻煩的過程,也有類似3DMax中匯出頂點tangent值中的做法,直接在匯出的時候將tangent空間資訊匯出,儲存在頂點中。 最後總結一下:tangent space下,其實跟我們上一節計算的斜率很像,我們計算斜率基本也是tangent值。而這裡T(x軸)使用normalize(dx/du, dy/du, dz/du),相當於計算了模型空間下x,y,z值隨著紋理u座標方向的斜率,換句話說,切線空間反映了模型空間座標xyz隨著紋理座標uv的變化率(坡度),這也正是normal map中要儲存的資訊,所以normal map中的內容正好可以使用切線空間進行儲存。

為什麼法線貼圖都是藍色的

既然我們知道了法線貼圖中儲存的是切線空間的法線。而法線貼圖所對應的表面,絕大部分的位置肯定是平滑的,只有需要凹凸變化的地方才會有變化,那麼大部分地方的法線方向不變,也就是在切線空間的(0,0,1),這個值按照上面介紹的對映關係,從(-1,1)區間變換到(0,1)區間:(0*0.5+0.5,0*0.5+0.5,1*0.5+0.5)= (0.5,0.5,1),再轉化為顏色的(0,255)區間,最終就變成了(127,127,255)。好了,開啟photoshop,看一下這個顏色值是什麼: 法線一般就是這個顏色嘛!那麼,其他的地方,如果有凹凸感,就需要調整法線的方向,那麼顏色就不一樣了。

Unity下法線貼圖Shader實現

解決了上面幾個問題之後,我們就可以看一下Unity Shader中實現法線貼圖的方式。光照模型仍然採用之前的半蘭伯特光照,vertex fragemnt shader實現(surface版本的就兩句話,也就不寫了):
//Bump Map
//by:puppet_master
//2016.12.14
Shader "ApcShader/NormalMap"
{
	//屬性
	Properties{
		_Diffuse("Diffuse", Color) = (1,1,1,1)
		_MainTex("Base 2D", 2D) = "white"{}
		_BumpMap("Bump Map", 2D) = "bump"{}
		_BumpScale ("Bump Scale", Range(0.1, 30.0)) = 10.0
	}

	//子著色器	
	SubShader
	{
		Pass
		{
			//定義Tags
			Tags{ "RenderType" = "Opaque" }

			CGPROGRAM
			//引入標頭檔案
			#include "Lighting.cginc"
			//定義Properties中的變數
			fixed4 _Diffuse;
			sampler2D _MainTex;
			//使用了TRANSFROM_TEX巨集就需要定義XXX_ST
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float _BumpScale;

			//定義結構體:vertex shader階段輸出的內容
			struct v2f
			{
				float4 pos : SV_POSITION;
				//轉化紋理座標
				float2 uv : TEXCOORD0;
				//tangent空間的光線方向
				float3 lightDir : TEXCOORD1;
			};

			//定義頂點shader
			v2f vert(appdata_tan v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				//這個巨集為我們定義好了模型空間到切線空間的轉換矩陣rotation,注意後面有個;
				TANGENT_SPACE_ROTATION;
				//ObjectSpaceLightDir可以把光線方向轉化到模型空間,然後通過rotation再轉化到切線空間
				o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
				//通過TRANSFORM_TEX巨集轉化紋理座標,主要處理了Offset和Tiling的改變,預設時等同於o.uv = v.texcoord.xy;
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				return o;
			}

			//定義片元shader
			fixed4 frag(v2f i) : SV_Target
			{
				//unity自身的diffuse也是帶了環境光,這裡我們也增加一下環境光
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.xyz;
				//直接解出切線空間法線
				float3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uv));
				//normalize一下切線空間的光照方向
				float3 tangentLight = normalize(i.lightDir);
				//根據半蘭伯特模型計算畫素的光照資訊
				fixed3 lambert = 0.5 * dot(tangentNormal, tangentLight) + 0.5;
				//最終輸出顏色為lambert光強*材質diffuse顏色*光顏色
				fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz + ambient;
				//進行紋理取樣
				fixed4 color = tex2D(_MainTex, i.uv);
				return fixed4(diffuse * color.rgb, 1.0);
			}

			//使用vert函式和frag函式
			#pragma vertex vert
			#pragma fragment frag	

			ENDCG
		}

	}
		//前面的Shader失效的話,使用預設的Diffuse
		FallBack "Diffuse"
}
結果:

總結

本篇文章簡單探究了一下bump map以及normal map的原理以及在Unity中的實現。法線貼圖可以很好地在低模上模擬高模的效果,雖然多采樣了一次貼圖,但是能模擬出數倍於模型本身面數的效果,極大地提升了實時渲染的效果。雖然法線貼圖也有一些弊端,因為法線貼圖只是給人造成一種凹凸的假象,所以在視角與物體平行時,看到的物體表面仍然是平的。並且還會有一些穿幫的現象,不過畢竟瑕不掩瑜,法線貼圖仍然是目前渲染中最常使用的技術之一。為了解決上面的問題,一些更加高階的貼圖技術,如視差貼圖和位移貼圖就誕生了。之後再研究這兩種更加高階一點的貼圖技術,本篇到此為止。上面給出了一些關於tangent空間求解的參考連結。最後再附上一些關於法線貼圖原理的參考。

相關推薦

Unity Shader-法線Normal及其原理

簡介 以前經常聽說“模型不好看啊,怎麼辦啊?”答曰“加法線”,”做了個高模,準備烘一下法線貼圖”,“有的美術特別屌,直接畫法線貼圖”.....法線貼圖到底是個什麼鬼,當年天真的我真的被這個圖形學的奇淫雜技忽悠了,然而畢竟本人還算有點刨根問底的精神,決定研究一下法線貼圖的原

Unity Shader 法線的實現

計算 變換 float minus include 的確 dal 反射 mode 這裏有一個細節,關於法線貼圖是有兩個不同的空間的,如下:   切線空間:法線貼圖顏色為偏藍色   模型空間:法線貼圖顏色為五顏六色 因此根據不同的空間變換位置方便一致計算。 1 // 法

unity3d 凹凸法線、置換

NormalMap 看來可以增加細節,但是它的缺點也很明顯。不過在說缺點之前,要提前說一句--NormalMap帶來的優勢是遠遠大於它的缺點的。因此仍然是個極好的東西,不要對它有偏見,特別是在我們後面介紹的更牛的技術前面,千萬不要。最大的也是最明顯的缺點應該就是它的視角問

Shader法線

法線貼圖,在切線空間下計算(Cubemap環境對映不可以用,要用世界空間下計算) 參考 《unity shader 入門精要》 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityOb

unity shader 反射

Shader "Unlit/reflex" { Properties { _MainTex ("Texture", 2D) = "white" {} _Cube("Cube", Cube) = "_Skybox"{} _Relect("反射度", Range(0, 1)

OpenGL深入探索——陰影

背景 陰影和光是緊密聯絡在一起的,因為如果你想要產生一個陰影就必須要光。有許多的技術可以生成陰影,在接下來的兩個章節中我們將學習其中的一種比較基礎簡單的技術-陰影貼圖。 當光柵化的時候,你會問這個畫素是否位於陰影中?讓我們換個問法,從光源到畫素的路徑是否中間經過其他物體?

unity shader 入門之路sublime編譯器

研究了半天,在同事的指點下入了sublime的坑,VS2015寫unity shader太難受了,沒有高亮,沒有報錯,沒有智慧感應,很不爽,換了sub之後問題就解決了。 一個新的shader  來

Unity Shader學習筆記】最基本的頂點片段著色器

分享一個基本的頂點片段著色器,可以實現紋理取樣。目前沒有加入光照和陰影效果。 這個Shader可以作為基本的模板,進行更加細節的修改與開發。這裡就簡單分享一下吧。 Shader "Unlit/unl

unity shader 入門之路Unity支援的語義

從應用階段傳遞模型資料給頂點著色器時Unity支援的常用語義 語義 描述 POSITION 模型空間中的頂點位置,通常是float4型別 NORMAL 頂點法線,通常是float3型別 TANGENT 頂點切線,通常是float4型別 TEXCOORDn,如TEXCO

第四章 開始Unity Shader學習之旅3

行處理 由於 ctx 渲染 ima arc bubuko 這一 vpd 1. 程序員的煩惱:Debug 調試(debug),大概是所有程序員的噩夢。而不幸的是,對一個Shader進行調試更是噩夢中的噩夢。這也是造成Shader難寫的原因之一——如果發現得到的效果不對,我們就

ShaderLab學習小結十五法線的簡單Shader

otl mvp truct 沒有 模型 視覺 有一個 rdb 值範圍 目標:賦予材質法線貼圖,並能響應光照的變化,體現出凹凸感。場景中只有一個主平行光找了一張法線貼圖(網上蕩的)在unity裏別忘了把這張圖設為normalmap先看一下,如果只是作為普通貼圖,賦在Diffu

Unity Shader-邊緣檢測效果基於顏色,基於深度法線,邊緣流光效果,轉場效果

前言 週末通關了一個小遊戲,流程很短,6個小時左右就通關,但是遊戲的畫風,視角,玩法都比較新奇,對了,遊戲的名字也很奇特《12 Is Better Than 6》(12比6好是有什麼梗嗎?)。 遊戲採用的是俯視角,人物在活著的時候基本只能看到個帽子,玩法類似很早玩的《

Unity ShaderShader中使用法線

首先我們在Unity中建立一個小球 然後通過"Create->Shader->Standard Surface Shader"建立一個表面著色器,並修改名字為Diffuse Bump 然後通過"Create->Material"建立一個材質,並修改名字為

Unity中的法線、漫反射及高光

我們都知道,一個三維場景的畫面的好壞,百分之四十取決於模型,百分之六十取決於貼圖,可見貼圖在畫面中所佔的重要性。在這裡我將列舉一些貼圖,並且初步闡述其概念,理解原理的基礎上製作貼圖,也就順手多了。 我在這裡主要列舉幾種UNITY3D中常用的貼圖,與大家分享,希望對大家有幫助。  

材質球換Material與ShareMaterial

sharedMaterial修改所有用到這個材質球的物體,material修改該物體第一個例項化的材質球,不會修改所有的用到該材質球的物體(工程中模型自帶一個,然後例項化出一個,模型換不了貼圖),詳細解釋參考http:

OpenCV-帶有深度資訊增強現實

OpenCV建立Mat矩陣並進行帶有深度資訊的貼圖 貼圖是一件很簡單得事情,我利用單目深度影象的演算法進行得到的深度圖資訊進行貼圖,也就是圖片會根據深度資訊進行該顯示的地方顯示,不該顯示的地方遮擋,聽

陰影Shadow mapping

陰影貼圖是一種使用深度紋理來為渲染陰影提供解決方案的多通道計算。它的關鍵是,就是用投射光源代替最終視口來觀察場景。通過移動視口到光源位置,可以觀察到這個位置每個東西都是明亮的,因為從光的角度來看是沒有陰影的。

Normal Map(法線)Ⅰ(轉)

http://blog.csdn.net/kongbu0622/article/details/38274999 這篇文章寫得非常好,轉自http://www.zwqxin.com/archives/shaderglsl/review-normal-map-bump-m

unity shader 較完整光照含有多光源陰影

效果圖: shader被附給了球。 燈光需要在屬性面板開啟陰影。 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Unlit/lightFull" {

立方體環境Cube Mapping之OpenGL原理

立方體紋理是一種特殊的紋理技術,它用6幅二維紋理影象構成一個以原點為中心的紋理立方體。對於每個片段,紋理座標(s, t, r)被當作方向向量看待,每個紋理單元都表示從原點所看到的紋理立方體上的影象。 一個典型的立方環境貼圖如下: