• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當自強而不息

            像素著色器入門(1)

            像素著色器是一段執行在圖形卡的GPU上的程序,它運行在對每個像素進行光柵化處理時。(不像頂點著色器,Direct3D不會以軟件模擬像素著色器的功能。)實際上它替換了固定功能管線的多紋理化階段(the multitexturing stage),并賦予我們直接操縱單獨的像素和訪問每個像素的紋理坐標的能力。這種對像素和紋理坐標的直接訪問使我們可以達成各種特效,例如:多紋理化(multitexturing)、每像素光照(per pixel lighting)、景深(depth of field)、云狀物模擬(cloud simulation)、焰火模擬(fire simulation)、高級陰影技術(sophisticated shadowing technique)。

            圖形卡支持的像素著色器的版本可以通過D3DCAPS9結構的PixelShaderVersion成員和D3DPS_VERSION宏進行檢查。下列代碼片斷展示了這點:

            // If the device's supported version is less than version 2.0

            if( caps.PixelShaderVersion < D3DPS_VERSION(2, 0) )

                 // Then pixel shader version 2.0 is not supported on this device.

             

            18.1多紋理化概覽

            多紋理化(Multitexturing)可能是用像素著色器實現的最簡單的技巧了。

            多紋理化后面的概念有一點和混合(blending)相關,可以將正要被光柵化的像素與之前寫入后臺緩沖的像素進行混合來達成一種特效。我們延伸這種相同的思想到多紋理化中(multiple texture)。也就是說,我們一次使用幾個紋理,然后定義這些紋理如何被混合在一起,以達到一種特殊效果。多紋理化的一個通常的用法是執行光照。作為在頂點處理階段使用Direct3D的光照模型的替代,我們使用一種叫做“光照圖”(light map)的特殊紋理貼圖(texture map),它編碼(encode)表面是如何被光照的。例如,假設我們希望一盞聚光燈(spotlight)照在一個大木箱上,我們要么定義一個D3DLIGHT9結構的聚光燈,要么將代表木箱的紋理貼圖與代表聚光燈的光照映射混合在一起,如圖18.1所示。

            注意:結果圖像依賴于紋理被混合的方式。在固定功能管線的多紋理化階段,混合方程式被紋理渲染狀態(texture render state)控制。用像素著色器,我們能以可編程的方式在代碼中寫出混合函數的簡單表達式。這使我們可以用任何我們想要的方式混合紋理。

            混合多個紋理(本例中是兩個)來照亮木箱比起Direct3D的光照來有兩個好處:

            光照是是預先在聚光燈的光照貼圖里計算好的。因此,光照不需要在運行時被計算,這節省了處理時間。當然,只有靜態對象和靜態燈光的光照可以被預先計算。

            因為光照圖是預先計算好的,我們能夠使用比Direct3D的(光照)模型多的多的更加精確的和成熟的光照模型。(更好的光照可以產生更真實的場景。)

            備注:多紋理化階段的典型應用是實現靜態對象的完全光照引擎(full lighting engine)。例如,我們可以用一個紋理貼圖保存對象的顏色,比如木箱的紋理貼圖。然后我們可以用一個散射光照貼圖(diffuse light map)保存散射表面著色(diffuse surface shade),一個單獨的鏡面光照貼圖保存鏡面表面著色,一個霧狀物貼圖(fog map)保存覆蓋在表面的霧狀物的總量,還有可以用一個細節貼圖(detail map)保存小的、高訪問率的表面的細節。當所有這些紋理被組合起來,只需到這些預先計算的紋理中檢索,就可以有效的照亮、著色并且增加細節到場景中去。

            注意:聚光燈光照貼圖在很基礎的光照貼圖中是一個價值不高(trivial)的例子。一般的的程序通過給定的場景和光源來生成光照貼圖。

             

            18.1.1 允許多個紋理

            回憶一下,紋理是用IDirect3DDevice9::SetTexture方法設置,而采樣器狀態(sampler state)是用IDirect3DDevice9::SetSamplerState方法設置,原型如下:

            HRESULT IDirect3DDevice9::SetTexture(

                 DWORD Stage, // specifies the texture stage index

                 IDirect3DBaseTexture9 *pTexture

            );

             

            HRESULT IDirect3DDevice9::SetSamplerState(

                 DWORD Sampler, // specifies the sampler stage index

                 D3DSAMPLERSTATETYPE Type,

                 DWORD Value

            );

             

            注意:一個特定的采樣器階段索引I關聯第i個紋理階段(texture stage)。即第i個采樣器階段指定采樣器狀態是第i集(set)紋理。

            紋理/采樣器階段索引標識了我們希望設置的紋理/采樣器的紋理/采樣器階段。因此,我們可以允許多個紋理并通過使用不同的階段索引設置其相應的采樣器狀態。例如,假設我們要允許三個紋理,我們像這樣使用階段0,1和2:

            // Set first texture and corresponding sampler states.

            Device->SetTexture(0, Tex1);

            Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

            Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

            Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

             

            // Set second texture and corresponding sampler states.

            Device->SetTexture(1, Tex2);

            Device->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

            Device->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

            Device->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

             

            // Set third texture and corresponding sampler states.

            Device->SetTexture(2, Tex3);

            Device->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

            Device->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

            Device->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

            這段代碼使用Tex1, Tex2和Tex3,并設置每個紋理的過濾模式。

             

            18.1.2 多紋理坐標

            對于每個3D三角形,我們應該在紋理上定義一個三角形以映射該3D三角形。我們通過對每個頂點增加紋理坐標完成映射。因此,每三個頂點定義一個三角形,它對應于紋理上的三角形。

            現在使用多紋理,每三個頂點定義一個三角形,我們需要在每個被使用的紋理上定義一個相應的三角形。通過給每個頂點增加額外的一套紋理坐標——每個頂點一套,對應于每個使用的紋理。舉個例子,如果我們混合三個紋理到一起,那么每個頂點必須有三套紋理坐標以索引到三個使用的紋理。因此,一個包含三個紋理的多紋理化頂點結構看起來可能像這樣:

            struct MultiTexVertex

            {

                 MultiTexVertex(float x, float y, float z,

                                float u0, float v0,

                                float u1, float v1,

                                float u2, float v2)

                 {

                      _x =  x;   _y = y; _z = z;

                      _u0 = u0;  _v0 = v0;

                      _u1 = u1;  _v1 = v1;

                      _u2 = u2;  _v2 = v2;

                 }

             

                 float _x, _y, _z;

                 float _u0, _v0; // Texture coordinates for texture at stage 0.

                 float _u1, _v1; // Texture coordinates for texture at stage 1.

                 float _u2, _v2; // Texture coordinates for texture at stage 2.

             

                 static const DWORD FVF;

            };

            const DWORD MultiTexVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX3;

             

            注意,指定自由頂點格式標記D3DFVF_TEX3表明頂點結構包含3套紋理坐標。固定功能管線支持最多8套紋理坐標。如果多于8套,你必須使用頂點聲明和可編程頂點管線。

            注意:在新版本像素著色器中,我們可以使用一套紋理坐標集來索引多個紋理,并因此消除了對多個紋理坐標的需要。當然這得假設每個紋理階段使用相同的紋理坐標。如果每個階段的紋理坐標不同,則我們仍然需要多紋理坐標。

             

            18.2像素著色器輸入和輸出

            有兩樣東西要輸入到像素著色器:顏色和紋理坐標。兩樣都是以每像素為單位的。

            注意:頂點顏色是在圖元的面(face of primitive)間進行插值的。

            每個像素的紋理坐標就是簡單的 (u , v) ,它指定了紋理的哪個圖素被映射到像素上。在輸入到像素著色器前,Direct3D根據頂點顏色和頂點紋理坐標,為每個像素計算顏色和紋理坐標。輸入到像素著色器的顏色和紋理坐標的數值依賴于頂點著色器輸出的顏色和紋理坐標的數值。例如,如果一個頂點著色器輸出了兩個顏色和三個紋理坐標,那么Direct3D將會為每個像素計算兩個顏色和三個紋理坐標并且把它們把它們輸入到像素著色器。我們使用帶語意的語法(semantic syntax)映射輸入顏色和紋理坐標進我們的著色器程序的變量里。用前面的例子,我們可以這樣寫:

            struct PS_INPUT

            {

                 vector c0 : COLOR0;

                 vector c1 : COLOR1;

                 float2 t0 : TEXCOORD0;

                 float2 t1 : TEXCOORD1;

                 float2 t2 : TEXCOORD2;

            };

             

            對于輸出,像素著色器只輸出一個計算過的該像素的顏色值:

            struct PS_OUTPUT

            {

                 vector finalPixelColor : COLOR0;

            };

             

             

            18.3使用像素著色器的步驟

            下面的列表概述了創建和使用像素著色器的必要步驟:

            1.        編寫并編譯像素著色器

            2.        創建一個IDirect3DPixelShader9接口來代表基于已編譯代碼的像素著色器

            3.        用IDirect3DDevice9::SetPixelShader方法允許該像素著色器

            當然,用完頂點著色器之后我們必須銷毀它。

             

            18.3.1 編寫并編譯像素著色器

            我們用與編譯頂點著色器一樣的方式編譯像素著色器。首先,我們必須編寫一個像素著色器程序, 我們用HLSL編寫我們的著色器。一旦寫好著色器代碼,我們就可以用D3DXCompileShaderFromFile函數編譯該著色器了,這個函數返回一個ID3DXBuffer指針,它包含已編譯的著色器代碼。

            注意:因為我們使用的是像素著色器,所以要記得把編譯目標改成像素著色器目標(比如:ps_2_0),而不是頂點著色器目標(比如:vs_2_0)。編譯目標通過D3DXCompileShaderFromFile函數的一個參數指定。

             

            18.3.2 創建像素著色器

            一旦我們編譯了著色器代碼,我們就可以獲得一個IDirect3DPixelShader的接口指針,它代表一個像素著色器,使用下面的方法:

            HRESULT IDirect3DDevice9::CreatePixelShader(

                  CONST DWORD *pFunction,

                  IDirect3DPixelShader9** ppShader

            );

            pFunction——已編譯著色器代碼的指針

            ppShader——返回一個IDirect3DPixelShader9接口的指針

            例如,假設變量shader是一個包含已編譯著色器代碼的ID3DXBuffer接口指針。那么要獲得IDirect3DPixelShader9接口,我們應該寫:

            IDirect3DPixelShader9* MultiTexPS = 0;

            hr = Device->CreatePixelShader( (DWORD*)shader->GetBufferPointer(), &MultiTexPS);

            注意:重申一遍,D3DXCompileShaderFromFile是一個可以返回已編譯著色器代碼(shader)的函數。

             

            18.3.3 建立像素著色器

            在我們獲得一個代表我們的像素著色器的IDirect3DPixelShader9接口的指針之后,我們可以使用下面的方法使用它:

            HRESULT IDirect3DDevice9::SetPixelShader(

                  IDirect3DPixelShader9* pShader

            );

            這個方法只接受一個參數,我們通過它傳遞一個我們希望使用的指向像素著色器的指針。

            Device->SetPixelShader(MultiTexPS);

             

            18.3.4 銷毀像素著色器

            和其它所有Direct3D接口一樣,要清除這些接口,我們必須在使用完畢后調用它們的Release方法。

            d3d::Release<IDirect3DPixelShader9*>(MultiTexPS);


            posted on 2008-04-11 12:38 lovedday 閱讀(2324) 評論(0)  編輯 收藏 引用

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            韩国三级大全久久网站| 国产激情久久久久影院老熟女免费 | 国产欧美一区二区久久| 亚洲国产精品无码久久一线| 久久综合久久美利坚合众国| 久久久久久国产精品美女 | 色99久久久久高潮综合影院| 青青草国产精品久久| 91精品国产综合久久婷婷| 丰满少妇高潮惨叫久久久| 国产产无码乱码精品久久鸭 | 国产精品成人99久久久久 | 亚洲熟妇无码另类久久久| 国产亚洲精品久久久久秋霞 | 久久精品国产亚洲77777| 亚洲AV无码久久精品蜜桃| 亚洲国产另类久久久精品黑人 | 一级做a爱片久久毛片| 国产成人精品久久亚洲高清不卡| segui久久国产精品| 久久本道久久综合伊人| 无码8090精品久久一区| 亚洲女久久久噜噜噜熟女| 久久精品国产亚洲av高清漫画| 99久久精品国产麻豆| 99久久免费国产精品| 亚洲AⅤ优女AV综合久久久| 精品无码久久久久国产动漫3d| 麻豆亚洲AV永久无码精品久久| 99久久免费国产精品热| 国产精品一区二区久久精品无码 | 理论片午午伦夜理片久久| 久久久久久综合网天天| 国产69精品久久久久777| 女同久久| 粉嫩小泬无遮挡久久久久久| 91性高湖久久久久| 婷婷五月深深久久精品| 国产午夜精品理论片久久 | 亚洲欧美精品伊人久久| 亚洲午夜精品久久久久久浪潮|