2018-03-17

基礎紋理

最基本的紋理采樣用到的Unity Shader 內置方法:

UNITY_MATRIX_MVP 當前的模型觀察投影矩陣:用于將頂點/方向矢量從模型空間變換到裁剪空間。

模型空間下的頂點紋理坐標 float4 vertex:POSITION;

變換到裁剪空間下頂點紋理坐標 float4 pos:SV_POSITION;

pos = mul(UNITY_MATRIX_MVP, vertex);

_Object2World 當前的模型矩陣:用于將頂點/方向矢量從模型空間變換到世界空間

模型空間下的頂點紋理坐標 float4 vertex:POSITION;

世界空間下的頂點紋理坐標 float3 worldPos:TEXCOORD1;

worldPos = mul(_Object2World,vertex).xyz;

UnityObjectToWorldNormal?把法線從模型空間轉換到世界空間

模型空間下的法線 float3 normal:NORMAL

世界空間下的法線 float3 worldNormal:TEXCOORD0;

worldNormal =? UnityObjectToWorldNormal(normal);

WorldSpaceLightDir 輸入一個模型空間中的頂點位置,返回世界空間中從該點到光源的光照方向。沒有被歸一化

float3 WorldSpaceLightDir(float4 v);

UnityWorldSpaceLightDir 輸入一個世界空間中的頂點位置,返回世界空間中從該點到光源的光照方向。沒有被歸一化(Unity內置函數相比WorldSpaceLightDir 多了對方向矢量進行了一次坐標空間變換)

float3 UnityWorldSpaceLightDir(float3 v);

世界空間下的頂點紋理坐標 float3 worldPos:TEXCOORD1;

fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldPos));

cg的tex2D函數對紋理進行采樣。它的第一個參數是需要被采樣的紋理,第二個參數是一個float2類型的紋理坐標,它將返回計算得到的紋素值。

fixed4 _Color;

sampler2D _MainTex;

float4 _MainTex_ST;

fixed4 _Specular;

float _Gloss;

float4 texcoord:TEXCOORD0;

float2 uv:TEXCOORD2;

uv=texcoord.xy*_MainTex_ST+_MainTex_ST.zw;

或者

uv=TRANSFORM_TEX(texcoord,_MainTex);

fixed3 albedo = tex2D(_MainTex,uv).rgb*_Color.rgb;(材質的反射率albedo)

fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;(Unity的內置變量UNITY_LIGHTMODEL_AMBIENT環境光與材質的反射率albedo相乘得到ambient)

fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));(計算漫反射光照:_LightColor0光源的顏色和強度)

float3 UnityWorldSpaceViewDir(float4 v) 輸入一個世界空間中的頂點位置,返回世界空間中從該點到攝像機的觀察方向

fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));

fixed3 halfDir = normalize(worldLightDir + viewDir);(Blinn光照模型)

fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(worldNormal,halfDir)),_Glass);(高光反射模型計算)

return fixed4(ambient + diffuse +? specular,1.0);(最終得到漫反射時使用紋理中的紋素值)


紋理的屬性

TextureType:Texture、Normal?map、Cubemap

Wrap Mode:Repeat(這種模式下,如果紋理坐標超過1,那么它的整數部分將會被舍棄,而直接使用小數部分進行采樣,這樣的結果是紋理將會不斷重復)、Clamp(這種模式下,如果紋理坐標大于1,那么將會被截取到1,如果小于0,那么將會被截取到0)。

Filter Mode:紋理由于變換而產生拉伸時將會采用哪種濾波模式。Filter Mode?支持3種模式:Point,Bilinear?以及Trilinear。(濾波效果依次提升,但需要消耗的性能也依次增大。)

紋理縮小的過程比放大更加復雜一些,此時原紋理中的多個像素將會對應一個目標像素。紋理縮放更加復雜的原因在于我們往往需要處理抗鋸齒問題,一個最常使用的方法就是使用多級漸遠紋理(mipmapping)技術。


凹凸映射

紋理的另一種常見的應用就是凹凸映射(bump?mapping)。凹凸映射的目的是使用一張紋理來修改模型表面的法線,以便為模型提供更多的細節。

有兩種主要的方法可以用來進行凹凸映射:一種方法是使用一張高度紋理(height?map)來模擬表面位移(displacement),然后得到一個修改后的法線值,這種方法也被稱為高度映射(height?mapping);另一種方法則是使用一張法線紋理(normal?map)來直接存儲表面法線,這種方法又被稱為法線映射(normal?mapping)

高度紋理,即使用一張高度圖來實現凹凸映射。高度圖中存儲的是強度值(intensity),它用于表示模型表面局部的海拔高度。因此,顏色越淺表明該位置的表面越向外凸起,而顏色越深表明該位置越向里凹。這種方法的好處是非常直觀,我們可以從高度圖中明確地知道一個模型表面的凹凸情況,但缺點是計算更加復雜,在實時計算時不能直接得到表面法線,而是需要由像素的灰度值計算而得,因此需要消耗更多的性能。高度圖通常會和法線映射一起使用,用于給出表面凹凸的額外信息。也就是說,我們通常會使用法線映射來修改光照。

法線紋理?中存儲的就是表面的法線方向。由于法線方向的分量范圍在[-1,1],而像素的分量范圍為[0,1],因此我們需要做一個映射,通常使用的映射就是:

????????????????????????????????????????????????????????pixel = (normal+1)/ 2

這就要求,我們在shader中對法線紋理進行紋理采樣后,還需要對結果進行一次反映射的過程,以得到原先的法線方向。反映射的過程實際就是使用上面映射函數的逆函數:

????????????????????????????????????????????????????????normal =?pixel * 2 - 1

法線紋理中存儲的法線方向所在的坐標空間:

對于模型頂點自帶的法線,它們是定義在模型空間中的,因此一種直接的想法就是將修改后的模型空間中的表面法線存儲在一張紋理中,這種紋理被稱為是模型空間的法線紋理(object-space-normal?map)

在實際制作中,我們往往會采用另一種坐標空間,即模型頂點的切線空間(tangent?space)來存儲法線。對于模型的每個頂點,它都有一個屬于自己的切線空間,這個切線空間的原點就是該頂點本身,而z軸是頂點的法線方向(n),x軸是頂點的切線方向(t),而y軸可由法線和切線叉積而得,也被稱為是副切線或副法線。這種紋理被稱為是切線空間的法線紋理(tangent-space-normal-map)


漸變紋理

遮罩紋理

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容