上一章里,我們學習了HLSL主要的語法元素。現(xiàn)在,唯一沒有講解的只剩下函數(shù)了,包括如何聲明與定義函數(shù),如何在shader中使用函數(shù)。函數(shù)是高級語言中的重要組成部分,它在shader中也同樣扮演了重要角色。HLSL語法允許使用兩種類型的函數(shù)。內(nèi)置(或固有)函數(shù)為shader提供了一個預定義函數(shù)庫,同時也為特定著色構(gòu)架提供了某些特殊指令。
當然,你可以創(chuàng)建自定義函數(shù)。自定義函數(shù)可以用來把shader組織為一個整體,也可以用來打包部分希望重用的功能。
接下來的幾節(jié)里,我將會討論兩種類型的函數(shù),在最后還會講解如何用函數(shù)定義shader。先來看看HLSL提供的豐富內(nèi)置函數(shù)庫吧。
內(nèi)置函數(shù)
HLSL著色語言包含了一系列廣泛的,內(nèi)置,或固有函數(shù)。這些函數(shù)在開發(fā)shader時相當有用。它們提供了從數(shù)學計算到紋理采樣等廣泛的功能。先依次瀏覽一下這些函數(shù)。
表 3-1 HLSL內(nèi)置函數(shù)
abs 計算輸入值的絕對值。
acos 返回輸入值反余弦值。
all 測試非0值。
any 測試輸入值中的任何非零值。
asin 返回輸入值的反正弦值。
atan 返回輸入值的反正切值。
atan2 返回y/x的反正切值。
ceil 返回大于或等于輸入值的最小整數(shù)。
clamp 把輸入值限制在[min, max]范圍內(nèi)。
clip 如果輸入向量中的任何元素小于0,則丟棄當前像素。
cos 返回輸入值的余弦。
cosh 返回輸入值的雙曲余弦。
cross 返回兩個3D向量的叉積。
ddx 返回關于屏幕坐標x軸的偏導數(shù)。
ddy 返回關于屏幕坐標y軸的偏導數(shù)。
degrees 弧度到角度的轉(zhuǎn)換
determinant 返回輸入矩陣的值。
distance 返回兩個輸入點間的距離。
dot 返回兩個向量的點積。
exp 返回以e為底數(shù),輸入值為指數(shù)的指數(shù)函數(shù)值。
exp2 返回以2為底數(shù),輸入值為指數(shù)的指數(shù)函數(shù)值。
faceforward 檢測多邊形是否位于正面。
floor 返回小于等于x的最大整數(shù)。
fmod 返回a / b的浮點余數(shù)。
frac 返回輸入值的小數(shù)部分。
frexp 返回輸入值的尾數(shù)和指數(shù)
fwidth 返回 abs ( ddx (x) + abs ( ddy(x))。
isfinite 如果輸入值為有限值則返回true,否則返回false。
isinf 如何輸入值為無限的則返回true。
isnan 如果輸入值為NAN或QNAN則返回true。
ldexp frexp的逆運算,返回 x * 2 ^ exp。
len / lenth 返回輸入向量的長度。
lerp 對輸入值進行插值計算。
lit 返回光照向量(環(huán)境光,漫反射光,鏡面高光,1)。
log 返回以e為底的對數(shù)。
log10 返回以10為底的對數(shù)。
log2 返回以2為底的對數(shù)。
max 返回兩個輸入值中較大的一個。
min 返回兩個輸入值中較小的一個。
modf 把輸入值分解為整數(shù)和小數(shù)部分。
mul 返回輸入矩陣相乘的積。
normalize 返回規(guī)范化的向量,定義為 x / length(x)。
pow 返回輸入值的指定次冪。
radians 角度到弧度的轉(zhuǎn)換。
reflect 返回入射光線i對表面法線n的反射光線。
refract 返回在入射光線i,表面法線n,折射率為eta下的折射光線v。
round 返回最接近于輸入值的整數(shù)。
rsqrt 返回輸入值平方根的倒數(shù)。
saturate 把輸入值限制到[0, 1]之間。
sign 計算輸入值的符號。
sin 計算輸入值的正弦值。
sincos 返回輸入值的正弦和余弦值。
sinh 返回x的雙曲正弦。
smoothstep 返回一個在輸入值之間平穩(wěn)變化的插值。
sqrt 返回輸入值的平方根。
step 返回(x >= a)? 1 : 0。
tan 返回輸入值的正切值。
fanh 返回輸入值的雙曲線切線。
transpose 返回輸入矩陣的轉(zhuǎn)置。
tex1D* 1D紋理查詢。
tex2D* 2D紋理查詢。
tex3D* 3D紋理查詢。
為了貼近實際,舉個例子來展示如何使用這些函數(shù)吧。假設你需要把紋理映射到一個像素上,并且使用方向光來照亮這個像素。要完成這個任務,必須先計算光源對像素顏色的貢獻,然后查找紋理顏色,最后把這兩個顏色混合起來。首先,為了計算方向光的貢獻,需要計算像素法線和光源方向的點積。使用dot函數(shù)可以很方便的完成這一步計算:
LightIntensity = dot ( LightDirection , PixelNormal);
這里可能會出現(xiàn)一點小小的問題,如果像素法線背對著光源方向,那么得到的亮度將為負值。必須保證亮度在0和1之間,以避免這種效果。怎么做呢?很幸運,saturate函數(shù)能完成這個任務,修改上面的代碼:
LightIntensity = saturate ( dot ( LightDirection , PixelNormal ) );
在把燈光顏色添加到物體上之前,還需要從紋理中獲得像素的顏色。假設像素已經(jīng)包含了適當?shù)募y理坐標并且有一張簡單的2D紋理,那么紋理采樣的代碼如下:
PixelColor = tex2D ( objectTexture , TextureCoord ) ;
最后一步,就是對燈光和像素顏色進行混合。這里,我們需要燈光顏色,燈光亮度以及像素顏色作為參數(shù)。計算很簡單,但你應該注意shader構(gòu)架的矢量天性是如何對顏色中的所有分量同時起作用的。
FinalColor = ( LightColor * LightIntensity) * PixelColor ;
這個例子雖然簡單,但是它展示了HLSL的強大威力,僅僅使用三行代碼就能完成簡單的光照。在進入下一個主題之前,需要指出根據(jù)完成功能的不同,內(nèi)建函數(shù)可以接收不同的參數(shù)。另外,由于硬件性能的不同,部分內(nèi)建函數(shù)并不是在所有頂點和像素著色器版本上都可用。