• <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>

            永遠(yuǎn)也不完美的程序

            不斷學(xué)習(xí),不斷實(shí)踐,不斷的重構(gòu)……

            常用鏈接

            統(tǒng)計(jì)

            積分與排名

            好友鏈接

            最新評論

            零距離接觸HLSL 一(轉(zhuǎn)載)

             

            人一旦停下來不做事情,就會變得懶惰。自從停止寫《Direct3D 快速上手》后,就老不想寫東西,這些天一直都在想著要寫一些關(guān)于游戲引擎的文章,遲遲未敢動手,因?yàn)橛X得這個(gè)主題實(shí)在比較大,自己水平有限,寫不好還要被人笑話。為了督促自己再次像個(gè)陀螺轉(zhuǎn)起來,開始寫一些關(guān)于HLSL以及Shader的東西,當(dāng)然,我學(xué)這個(gè)也不久,只能講到一些膚淺的東西,意在拋磚引玉。

            這里我假設(shè)你已經(jīng)明白以寫有關(guān)流水線的基本得知識,以及明白為什么要使用Shader這之類的基本的問題,我就不多花時(shí)間介紹這些基本得知識,相關(guān)的知識大家可以在MSDN的網(wǎng)站上看到,以及很多有名的樹上都有詳細(xì)的介紹,例如《Microsoft DirectX 9 Programmable Graphics Pipeline

            好那我們就開始。這里我不再使用C#作為編寫程序的語言,雖然我很喜歡它,但是考慮到用Shader的目的就是為了效率,那在語言的選擇上自然選擇C++,編譯工具選用VC.Net

            在以后的文章中,我或許會提到Cg這個(gè)語言,這個(gè)微軟和NVIDIA聯(lián)合開發(fā)的一門語言,其實(shí)和HLSL只不過是叫了2個(gè)不同的名字罷了,完全可以兼容運(yùn)行。

            作為第一章,還是弄一點(diǎn)比較簡單的例子,這個(gè)例子里面我們著重探討的是Vertex Shader以及PS的語法,以及怎么把它們運(yùn)用到DirectX的程序中去,這個(gè)例子沒有任何的實(shí)用性,It is only a sample.

            以下是運(yùn)行圖例:


             

             

             

             

             

             


            首先看看我們程序的結(jié)構(gòu):

            int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

            LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

            void init(void); //初始化所有資源

            void shutDown(void); //釋放資源

            void render(void);   //渲染函數(shù)

            void initShader( void ); //初始化Shader

            很簡單對吧,其實(shí)也可以用微軟提供給我們的DX的框架,這個(gè)看個(gè)人的喜好了。

            我們先來看看Vertex Shader

            建立一個(gè)新的文件,存為vertex_shad.vsh,然后輸入:

            float4x4 worldViewProj;

             

            struct VS_INPUT

            {

                 float3 position : POSITION; //位置

                 float4 color0    : COLOR0;    //顏色

                 float2 texcoord0 : TEXCOORD0; //紋理坐標(biāo)

            };

             

            struct VS_OUTPUT

            {

                 float4 hposition : POSITION;

                 float4 color0    : COLOR0;

                 float2 texcoord0 : TEXCOORD0;

            };

             

            VS_OUTPUT main( VS_INPUT IN ) //入口函數(shù)

            {

                 VS_OUTPUT OUT;

                 float4 v = float4( IN.position.x,IN.position.y, IN.position.z,1.0f );

                OUT.hposition = mul( v, worldViewProj ); //矩陣變換

                OUT.color0    = IN.color0; //輸出的顏色=輸入的顏色

                OUT.texcoord0 = IN.texcoord0; //復(fù)制紋理坐標(biāo)

             

                return OUT;

            }

            這里首先定義了2個(gè)結(jié)構(gòu),都分別定義了位置,顏色,和紋理坐標(biāo)。這里我們看到程序里面使用了很多我們沒見過的數(shù)據(jù)類型,這是HLSL內(nèi)置的數(shù)據(jù)結(jié)構(gòu),例如float4x4

            我們注意下float4這個(gè)類型,它是一個(gè)有4個(gè)向量的浮點(diǎn)類型,你可以把它理解為一個(gè)浮點(diǎn)的數(shù)組,當(dāng)然嚴(yán)格的說,這里應(yīng)該是壓縮數(shù)組。

                float3 position : POSITION; //位置

            這一句話聲明了一個(gè)float3的變量,變量的名字叫做position,這里我們看到在后面還有一個(gè)冒號和POSITION,這個(gè)冒號和其后的POSRITION叫做“語義”。語義的作用相當(dāng)于在HLSL出現(xiàn)以前的Shader中用到的寄存器,這里我們指明了把position這個(gè)變量將與流水線的POSRITION寄存器相連接。在其后的COLOR0, TEXCOORD0也是一樣的意思。

            我們看到Shader的入口函數(shù)main,這個(gè)函數(shù)有一個(gè)參數(shù)和一個(gè)返回值,都是我們在Shader的開頭定義的結(jié)構(gòu)。

                OUT.hposition = mul( v, worldViewProj ); //矩陣變換

            我們將向量和矩陣相乘,這樣得到的仍然是一個(gè)向量,這個(gè)向量就是經(jīng)過我們的透視變換的向量。這里之所以要進(jìn)行這個(gè)變換是為了讓所有的定點(diǎn)都在視區(qū)內(nèi)并且在選轉(zhuǎn)的時(shí)候符合透視。

            在將所有的返回值賦值完成后,程序返回。

            接下來我們建立pixel_shader.psh文件,這是pixelShader文件:

            struct VS_OUTPUT

            {

                 float4 hposition : POSITION;

                 float4 color0    : COLOR0;

                 float2 texcoord0 : TEXCOORD0;

            };

            struct PS_OUTPUT

            {

                 float4 color : COLOR;

            };

            sampler testTexture; //樣本對象

             

            PS_OUTPUT main( VS_OUTPUT IN )

            {

                 PS_OUTPUT OUT;

                     OUT.color = tex2D( testTexture, IN.texcoord0 ) + IN.color0; // Add texel color to vertex color

             

                 return OUT;

            }

            相對于VS來說PS的代碼簡單很多,程序聲明了一個(gè)樣本對象,然后在PS的入口程序中用到了tex2D函數(shù),這個(gè)函數(shù)可以用制定的紋理坐標(biāo)集存取不同類型的樣本并返回一個(gè)向量結(jié)果。

            OUT.color = tex2D( testTexture, IN.texcoord0 ) + IN.color0; 的結(jié)果是把顏色疊加在原來紋理的地方。

             

            我們該看看我們的主程序了,這里我只介紹最重要的initShader

            void initShader( void )

            {

                 D3DXCreateTextureFromFile( g_pd3dDevice, "test.bmp", &g_pTexture );

                 D3DVERTEXELEMENT9 declaration[] =

                 {

                     { 0, 0, D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },

                     { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,    0 },

                     { 0, 16, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },

                     D3DDECL_END()

                 };

             

                 g_pd3dDevice->CreateVertexDeclaration( declaration, &g_pVertexDeclaration );

             

                 HRESULT hr;

                 LPD3DXBUFFER pCode;

                 DWORD dwShaderFlags = 0;

                 LPD3DXBUFFER pBufferErrors = NULL;

             

                 // Assemble the vertex shader from the file

                 hr = D3DXCompileShaderFromFile( "vertex_shader.vsh", NULL, NULL, "main",

                     "vs_1_1", dwShaderFlags, &pCode,

                     &pBufferErrors, &g_pConstantTableVS );

             

                 if( FAILED(hr) )

                 {

                     LPVOID pCompilErrors = pBufferErrors->GetBufferPointer();

                     MessageBox(NULL, (const char*)pCompilErrors, "Vertex Shader Compile Error",

                          MB_OK|MB_ICONEXCLAMATION);

                 }

             

                 // Create the vertex shader

                 g_pd3dDevice->CreateVertexShader( (DWORD*)pCode->GetBufferPointer(),

                     &g_pVertexShader );

                 pCode->Release();

             

                 //

                 // Create a HLSL based pixel shader.

                 //

             

                 // Assemble the vertex shader from the file

                 hr = D3DXCompileShaderFromFile( "pixel_shader.psh", NULL, NULL, "main",

                     "ps_1_1", dwShaderFlags, &pCode,

                     &pBufferErrors, &g_pConstantTablePS );

             

                 if( FAILED(hr) )

                 {

                     LPVOID pCompilErrors = pBufferErrors->GetBufferPointer();

                     MessageBox(NULL, (const char*)pCompilErrors, "Pixel Shader Compile Error",

                          MB_OK|MB_ICONEXCLAMATION);

                 }

             

                 // Create the vertex shader

                 g_pd3dDevice->CreatePixelShader( (DWORD*)pCode->GetBufferPointer(),

                     &g_pPixelShader );

                 pCode->Release();

            }

            一開始我們定義了一個(gè)D3DVERTEXELEMENT9結(jié)構(gòu),這個(gè)結(jié)構(gòu)的作用是描述頂點(diǎn)數(shù)據(jù)的用途等等屬性:

            typedef struct _D3DVERTEXELEMENT9 {

                WORD Stream; //Stream number

               WORD Offset; //數(shù)據(jù)的偏移量

                BYTE Type;   //種類,也是一個(gè)結(jié)構(gòu),詳細(xì)情況查閱MSDN

                BYTE Method; //制定方格化的操作,為default時(shí),值將被拷貝如寄存器

                BYTE Usage;   //用途

                BYTE UsageIndex; //修改用途,允許用戶指定多種用途

            } D3DVERTEXELEMENT9

             

            接下來,我們就要建立一個(gè)VertexDeclaration

            HRESULT CreateVertexDeclaration( 
            CONST D3DVERTEXELEMENT9* pVertexElements,
            Direct3DVertexDeclaration9** ppDecl
            );

            然后我們從文件中讀入Shader的信息。PS的讀入和VS如出一轍。我們看看渲染的部分。

            void render( void )

            {

                g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,

                                     D3DCOLOR_COLORVALUE(0.0f,1.0f,0.0f,1.0f), 1.0f, 0 );

                g_pd3dDevice->BeginScene();

                 D3DXMATRIX matTrans;

                 D3DXMATRIX matRot;

             

                 D3DXMatrixTranslation( &matTrans, 0.0f, 0.0f, 4.0f );

                 D3DXMatrixRotationYawPitchRoll( &matRot,

                     D3DXToRadian(g_fSpinX),

                     D3DXToRadian(g_fSpinY),

                     0.0f );

                 g_matWorld = matRot * matTrans;

             

                 D3DXMatrixIdentity( &g_matView );

             

                 if( g_bUseShaders == true )

                 {

                     //

                     // Use vertex and pixel shaders...

                     //

             

                     D3DXMATRIX worldViewProjection = g_matWorld * g_matView * g_matProj;

                     g_pConstantTableVS->SetMatrix( g_pd3dDevice, "worldViewProj", &worldViewProjection );

             

                     g_pd3dDevice->SetVertexDeclaration( g_pVertexDeclaration );

                     g_pd3dDevice->SetVertexShader( g_pVertexShader );

             

                    

                     g_pd3dDevice->SetTexture( 0, g_pTexture );

                     g_pd3dDevice->SetPixelShader( g_pPixelShader );

             

                     g_pd3dDevice->SetFVF( Vertex::FVF_Flags );

                     g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0,sizeof(Vertex) );

                     g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

             

                     g_pd3dDevice->SetVertexShader( NULL );

                     g_pd3dDevice->SetPixelShader( NULL );

                 }

                 else

                 {

                     //

                     // Render the normal way...

                     //

             

                     g_pd3dDevice->SetTransform( D3DTS_WORLD, &g_matWorld );

             

                     g_pd3dDevice->SetTexture( 0, g_pTexture );

                     g_pd3dDevice->SetFVF( Vertex::FVF_Flags );

                     g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0,sizeof(Vertex) );

                     g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

                 }

             

             

                g_pd3dDevice->EndScene();

             

                g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

            }

             

            g_pConstantTableVS->SetMatrix( g_pd3dDevice, "worldViewProj", &worldViewProjection );

            這一句將視覺矩陣和我們在Vertex Shader中定義的矩陣關(guān)聯(lián)起來。然后我們通過

            g_pd3dDevice->SetVertexDeclaration( g_pVertexDeclaration );

                     g_pd3dDevice->SetVertexShader( g_pVertexShader );

            來通知程序,所有的頂點(diǎn)的處理都要由我們的頂點(diǎn)Shader來處理,頂點(diǎn)Shader中用到的所有頂點(diǎn)的一些屬性都在VertexDeclaration中聲明了。然后建立頂點(diǎn)的Shader

            在建立完VS,紋理,PS后,執(zhí)行畫圖指令,最后我們需要釋放Shader,恢復(fù)固定流水線的功能。g_pd3dDevice->SetVertexShader( NULL );g_pd3dDevice->SetPixelShader( NULL );

             

            好了,這里我們的程序就完成了,接下來的日子里面,我將盡力為大家講解一些Shader的有用的特性,呵呵呵,當(dāng)然,這里我沒有說,不是所有的顯卡都支持Shader的,所以你需要在程序中判斷你顯卡所支持的類型,這里我不再多些,2句話就可以搞定。

            By sssa2000

            5/15/2005

            posted on 2008-08-07 17:59 狂爛球 閱讀(571) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            国产高潮国产高潮久久久91 | 伊人久久大香线蕉精品| 久久这里都是精品| 亚洲国产香蕉人人爽成AV片久久| 91久久精品电影| 久久亚洲中文字幕精品一区四| 国产香蕉97碰碰久久人人| 国产999精品久久久久久| 成人精品一区二区久久久| 国产99久久九九精品无码| 国产无套内射久久久国产| 久久国产乱子伦精品免费午夜| 国产精品嫩草影院久久| 久久99精品久久久久久水蜜桃| 精品久久久久久久久久中文字幕| 久久天天躁狠狠躁夜夜2020老熟妇 | 亚洲国产精品人久久| 久久精品国产秦先生| 久久久久99精品成人片| 综合久久一区二区三区 | 91精品国产高清久久久久久国产嫩草 | 久久综合亚洲色HEZYO国产| 亚洲精品视频久久久| 久久久久久久久久久精品尤物 | 久久久久久久精品妇女99| 久久精品国产亚洲av影院| AA级片免费看视频久久| 久久精品国产99久久久古代| 99久久精品国内| 久久伊人色| 久久国产亚洲精品麻豆| 亚洲国产日韩欧美久久| 99热成人精品热久久669| 欧美性猛交xxxx免费看久久久| 香蕉久久av一区二区三区| 久久久精品日本一区二区三区| 亚洲精品白浆高清久久久久久| 久久精品不卡| 欧美综合天天夜夜久久| 欧美日韩精品久久免费| 国产高潮国产高潮久久久91 |