HLSL有關的基礎知識

2021-09-30 06:05:22 字數 4565 閱讀 3484

主要是最近在學習xna中有關一些效果的東西,發現了官網上的2d的一些fx效果相當好。其**給出如下鏈結 然後就查了一下hlsl這個範例裡面的fx還都不算太難,可以理解。

乙個簡單的hlsl程式,返回乙個材質的各點的顏色。

sampler s0 : register(s0);

float4 main(float2 tex : texcoord0) : color

hlsl,顏色表示。

使用mpc的custom shader,由於在mpc中需要使用hlsl編寫shader,所以首先要了解hlsl裡面的顏色表示法,hlsl中,尤其是mpc中,顏色基本都是使 用xrgb表示(x代表保留位),一般將其表示為乙個四維向量,資料型別是float4。比如float4 color;,那麼接下來就可以用color.x,color.y,color.z,來分別訪問r,g,b三個分量了。

眾所周知,對於24位,或者32位影象來說來說,rgb每個通道都是8位,轉化為10進製就是0-255的整數,不過在hlsl中情況不同,0對應的是 float(0.0)而255對應的是float(1.0),所以白色表示不再是(255,255,255)而是float3(1.0,1.0,1.0) 或者float4(1.0,1.0,1.0,1.0)。

程式解釋

第一行定義了乙個sampler,將pixel shader暫存器s0與我們定義的sampler s0繫結,在mpc中,暫存器s0就是影片影象所對應的紋理。

float4 main(float2 tex : texcoord0) : color,它代表的意思是,輸出乙個float4變數,將這個float4變數作為color(作為render target 0中的顏色,關於render target,後面會解釋)。這個函式有乙個輸入引數,就是作為0號紋理座標(texcoord0)的float2型別的tex。

hlsl中的最簡單的2d紋理對映函式是tex2d(s,t);兩個引數,第乙個是乙個sampler,它代表的是目標紋理和紋理過濾,定址方式,第二個 引數是乙個float2,也就是紋理座標uv。它返回乙個顏色值float4,這就是:紋理s中,紋理座標t處的顏色之意。

在這裡就需要說明作為輸入的texcoord0的內容了,在mpc中,我們知道原紋理要經過shader處理後寫入乙個新的同樣大小的紋理中,所以事實上 它繪製了乙個full rect quad(全區域矩形)並把新的紋理作為該次繪製的輸出物件(即繪製的東西就不顯示於螢幕上,而繪製到該紋理中)。

練習下看**:

變亮20%

sampler s0 : register(s0);

float4 main(float2 tex : texcoord0) : color

常用mul函式

上面color0*float4(0.2,0.2,0.2,0.0)是對位相乘。即:

color1 = color0*scale;

則代表color1.x = color0.x*scale.x;

color1.y = color0.y*scale.y;

color1.z = color0.z*scale.z;

color1.w = color0.w*scale.w;

如果需要得到向量點積,需要用mul(x,y);

比如float lum = mul(color0.xyz,float3(0.3,0.59,0.11) );其中color0.xyz表示以color0的xyz元素構成的乙個3維向量,lum = color0.x*0.3 + color0.y*0.59 + color0.z*0.11;

讀**練習:

灰度轉換shader

sampler s0 : register(s0);

float4 main(float2 tex : texcoord0) : color

hlsl的ps版本的問題

會用color0+color0*float4(0.2,0.2,0.2,0.0)而不是color0*float4(1.2,1.2,1.2,1.0) 是由於ps版本問題。版本越高,hlsl就越靈活,當然,硬體功能要求也就越強。對於ps1.x來說,常量暫存器不能儲存超過1的數值,所以如果用 float4(1.2,1.2,1.2,1.0)執行時會直接當作float4(1.0,1.0,1.0,1.0)處理,也可以說,是hlsl編譯器比較 弱智,不能自動轉化為color0+color0*float4(0.2,0.2,0.2,0.0)。

(所以會看到wow為每個ps版本寫了不同的**。)

如何獲得相鄰畫素

如下圖,設原紋理大小為m*n個texel,於是每個texel的uv尺寸為(1.0/m,1.0/n),所以可以通過將tex偏移再tex2d來取得相鄰處的texel。

add——vec1+vec2——向量對位相加

mul——vec1*vec2——向量對位相乘

mad——vec1*vec2+vec3——向量對位乘加

dp3——vec1.x*vec2.x+vec1.y*vec2.y+vec1.z*vec2.z——向量點積

等運算,而標量單元負責的是諸如

pow——scar1^scar2——標量冪運算

rcp——1.0/scar1——標量倒數運算

rsq——1.0/sqrt(scar1)——標量方根倒數

log——log2(scar1)——2為底的對數 等等

而紋理單元,執行的自然是

texld——紋理取樣函式

在mpc的hlsl編譯目標(compile target)選項中,有意義的包括ps_1_1,ps_1_3,ps_1_4,ps_2_0,ps_3_0。hlsl code的結構複雜度、指令的複雜性、指令數多寡決定了它最低需要的編譯目標。

ps_1_1和ps_1_3在實際應用中差別甚微。都屬於限制非常大的編譯目標,主要限制是:

1: 最大指令數目限制嚴重,不能超過8條算術指令(儘管其實可以不超過3維的向量運算與標量運算併發(co-issue)所以最多是16條算術指令,但是不用 指望hlsl編譯器能夠強大到如此程度)和4條紋理指令(ps1.1-1.3的紋理指令其實比較複雜,屬於組合功能方式,但是在mpc中基本用不上)

2:無複雜運算指令,諸如rcp,rsq,log,pow等全部沒有

3:暫存器數值範圍很窄,比如float s1 = 1.5 * s2;就會自動變成float s1 = 1.0 * s2;(也就是1.5超出了範圍),只能寫成float s1 = s2+0.5*s2;才能正確編譯

4:無dependent texture read。而tex基本可以認為無法操作

5:分支什麼的就基本不用指望了。除了像if(s1>0.0)else這種極其簡單的。

ps_1_1級別的硬體,比較流行的是nvidia geforce 3

ps_1_3級別的硬體,比較流行的是nvidia geforce 4ti

ps_1_4比ps_1_3適應性廣一些包括

1:最大指令數限制有所鬆動,算術指令翻倍,紋理指令翻2倍。

2:支援一定限度的dependent texture read(1級),tex可以進行一定程度的操作

ps_1_4級別的硬體,比較流行的是ati radeon8500,9000-9200

事實上,由於ps1.x屬於定點數結構,所以有一些移位指令可以使用,比如mul_x2,add_x2代表將結果相加後左移一位,相當於乘二。這也是為何第六節的第四個程式有ps1.x版本的原因。不過說到底,ps1.x不是為hlsl準備的。

ps_2_0是hlsl誕生時的預設編譯物件

1:支援絕大多數的hlsl函式。

2:64條算術指令,32條紋理指令,最多4級的dependent texture read

3:全部浮點流水線,資料範圍精度增強。

4:儘管ps_2_0沒有硬體支援的動態分支,不過可以實現一定程度的分支,只不過每個分支都要跑一遍。也就是效率不會很高

ps_2_0級別的硬體包括nvidia geforcefx系列(ps_2_a)ati radeon 9500及以上x700以下(ps_2_0)x700,x800,x850系列(ps_2_b)

ps_3_0是當前pc上的最高pixel shader版本

1:比ps_2_0增加了一些指令

2:硬體支援分支,迴圈

3:最大指令數大大增加,不再有紋理算術指令數量分配的限制

4:dependent texture read級數沒有限制

ps_3_0級別硬體包括nvidia geforce 6系列,7系列,ati radeon x1***系列

所以,編寫hlsl請考慮自身硬體的功能等級。

以下是一些簡單的提公升效能的考慮

1:如果可以,使用ps1.x編譯物件能獲得最佳效能,如果該hlsl code不能使用ps1.x編譯物件,那麼請使用可用的最高ps版本的編譯物件,如geforce6系列就請使用ps_3_0編譯物件。

2:在許可的情況下儘量減少使用複雜運算指令,諸如pow,sin,cos,asin,acos,sqrt等。

3:對於nvidia geforce fx和6系列,推薦將float(fp32)替換為half(fp16)以提高效能。

4:對於向量來說,選擇需要的最小維數,比如能用float3(half3)就不要用float4(half4),能用標量就不要用向量

5:動態分支不要太多,除非你用的是x1800xt……

有關於PHP的基礎知識

1 l 長字串表示,必須放在 主要是 其次是也可以不使用heredoc.l l可以直接解析php變數。但是不可以直接解析運算 2 字串的注意事項 l在雙引號內,輸出是變數的值。如 echo 的年齡是24歲 l 在單引號內,輸出的是變數的名稱,而不是值。l 在雙引號內,如果乙個變數名後跟乙個非空字元,...

雜湊表有關的基礎知識(1)

補充知識 namespace的格式基本格式是 namespace exp 有點類似於類,但完全是兩種不同的型別。為了在namespace外使用namespace內的變數我們使用 操作符,如下 exp a exp b 使用namespace可以有效的避免重定義的問題 include using nam...

有關 交流電 的基礎知識

通常波形為正弦曲線,在乙個週期內的執行平均值為零 交流電可以有效傳輸電力。正余弦交流電的峰值與振幅相對應,而有效值大小則由相同時間內產生相當焦耳熱的直流電的大小來等效。交流電峰值與均方根值 有效值 的關係為 假設使用單相電連線到純電阻負載 根據三角恒等式,可以得知功率 p 的振盪頻率是電壓 v 頻率...