基礎(chǔ)紋理
最基本的紋理采樣用到的Unity Shader 內(nèi)置方法:
UNITY_MATRIX_MVP 當(dāng)前的模型觀察投影矩陣:用于將頂點/方向矢量從模型空間變換到裁剪空間友存。
模型空間下的頂點紋理坐標(biāo) float4 vertex:POSITION;
變換到裁剪空間下頂點紋理坐標(biāo) float4 pos:SV_POSITION;
pos = mul(UNITY_MATRIX_MVP, vertex);
_Object2World 當(dāng)前的模型矩陣:用于將頂點/方向矢量從模型空間變換到世界空間
模型空間下的頂點紋理坐標(biāo) float4 vertex:POSITION;
世界空間下的頂點紋理坐標(biāo) float3 worldPos:TEXCOORD1;
worldPos = mul(_Object2World,vertex).xyz;
UnityObjectToWorldNormal?把法線從模型空間轉(zhuǎn)換到世界空間
模型空間下的法線 float3 normal:NORMAL
世界空間下的法線 float3 worldNormal:TEXCOORD0;
worldNormal =? UnityObjectToWorldNormal(normal);
WorldSpaceLightDir 輸入一個模型空間中的頂點位置蛇券,返回世界空間中從該點到光源的光照方向。沒有被歸一化
float3 WorldSpaceLightDir(float4 v);
UnityWorldSpaceLightDir 輸入一個世界空間中的頂點位置售滤,返回世界空間中從該點到光源的光照方向。沒有被歸一化(Unity內(nèi)置函數(shù)相比WorldSpaceLightDir 多了對方向矢量進(jìn)行了一次坐標(biāo)空間變換)
float3 UnityWorldSpaceLightDir(float3 v);
世界空間下的頂點紋理坐標(biāo) float3 worldPos:TEXCOORD1;
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldPos));
cg的tex2D函數(shù)對紋理進(jìn)行采樣。它的第一個參數(shù)是需要被采樣的紋理,第二個參數(shù)是一個float2類型的紋理坐標(biāo)混蔼,它將返回計算得到的紋素值。
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;(材質(zhì)的反射率albedo)
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;(Unity的內(nèi)置變量UNITY_LIGHTMODEL_AMBIENT環(huán)境光與材質(zhì)的反射率albedo相乘得到ambient)
fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));(計算漫反射光照:_LightColor0光源的顏色和強(qiáng)度)
float3 UnityWorldSpaceViewDir(float4 v) 輸入一個世界空間中的頂點位置惭嚣,返回世界空間中從該點到攝像機(jī)的觀察方向
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(這種模式下料按,如果紋理坐標(biāo)超過1奄侠,那么它的整數(shù)部分將會被舍棄卓箫,而直接使用小數(shù)部分進(jìn)行采樣,這樣的結(jié)果是紋理將會不斷重復(fù))垄潮、Clamp(這種模式下烹卒,如果紋理坐標(biāo)大于1,那么將會被截取到1弯洗,如果小于0旅急,那么將會被截取到0)。
Filter Mode:紋理由于變換而產(chǎn)生拉伸時將會采用哪種濾波模式牡整。Filter Mode?支持3種模式:Point藐吮,Bilinear?以及Trilinear。(濾波效果依次提升逃贝,但需要消耗的性能也依次增大谣辞。)
紋理縮小的過程比放大更加復(fù)雜一些,此時原紋理中的多個像素將會對應(yīng)一個目標(biāo)像素沐扳。紋理縮放更加復(fù)雜的原因在于我們往往需要處理抗鋸齒問題泥从,一個最常使用的方法就是使用多級漸遠(yuǎn)紋理(mipmapping)技術(shù)。
凹凸映射
紋理的另一種常見的應(yīng)用就是凹凸映射(bump?mapping)沪摄。凹凸映射的目的是使用一張紋理來修改模型表面的法線躯嫉,以便為模型提供更多的細(xì)節(jié)。
有兩種主要的方法可以用來進(jìn)行凹凸映射:一種方法是使用一張高度紋理(height?map)來模擬表面位移(displacement)杨拐,然后得到一個修改后的法線值祈餐,這種方法也被稱為高度映射(height?mapping);另一種方法則是使用一張法線紋理(normal?map)來直接存儲表面法線哄陶,這種方法又被稱為法線映射(normal?mapping)
高度紋理帆阳,即使用一張高度圖來實現(xiàn)凹凸映射。高度圖中存儲的是強(qiáng)度值(intensity)奕筐,它用于表示模型表面局部的海拔高度舱痘。因此变骡,顏色越淺表明該位置的表面越向外凸起,而顏色越深表明該位置越向里凹芭逝。這種方法的好處是非常直觀塌碌,我們可以從高度圖中明確地知道一個模型表面的凹凸情況,但缺點是計算更加復(fù)雜旬盯,在實時計算時不能直接得到表面法線台妆,而是需要由像素的灰度值計算而得,因此需要消耗更多的性能胖翰。高度圖通常會和法線映射一起使用接剩,用于給出表面凹凸的額外信息。也就是說萨咳,我們通常會使用法線映射來修改光照懊缺。
而法線紋理?中存儲的就是表面的法線方向。由于法線方向的分量范圍在[-1,1]培他,而像素的分量范圍為[0,1]鹃两,因此我們需要做一個映射,通常使用的映射就是:
????????????????????????????????????????????????????????pixel = (normal+1)/ 2
這就要求舀凛,我們在shader中對法線紋理進(jìn)行紋理采樣后俊扳,還需要對結(jié)果進(jìn)行一次反映射的過程,以得到原先的法線方向猛遍。反映射的過程實際就是使用上面映射函數(shù)的逆函數(shù):
????????????????????????????????????????????????????????normal =?pixel * 2 - 1
法線紋理中存儲的法線方向所在的坐標(biāo)空間:
對于模型頂點自帶的法線馋记,它們是定義在模型空間中的,因此一種直接的想法就是將修改后的模型空間中的表面法線存儲在一張紋理中懊烤,這種紋理被稱為是模型空間的法線紋理(object-space-normal?map)梯醒。
在實際制作中,我們往往會采用另一種坐標(biāo)空間奸晴,即模型頂點的切線空間(tangent?space)來存儲法線冤馏。對于模型的每個頂點,它都有一個屬于自己的切線空間寄啼,這個切線空間的原點就是該頂點本身逮光,而z軸是頂點的法線方向(n),x軸是頂點的切線方向(t)墩划,而y軸可由法線和切線叉積而得涕刚,也被稱為是副切線或副法線。這種紋理被稱為是切線空間的法線紋理(tangent-space-normal-map)乙帮。