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

            永遠也不完美的程序

            不斷學習,不斷實踐,不斷的重構(gòu)……

            常用鏈接

            統(tǒng)計

            積分與排名

            好友鏈接

            最新評論

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

             

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

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

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

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

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

            以下是運行圖例:


             

             

             

             

             

             


            首先看看我們程序的結(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

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

            我們先來看看Vertex Shader

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

            float4x4 worldViewProj;

             

            struct VS_INPUT

            {

                 float3 position : POSITION; //位置

                 float4 color0    : COLOR0;    //顏色

                 float2 texcoord0 : TEXCOORD0; //紋理坐標

            };

             

            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; //復制紋理坐標

             

                return OUT;

            }

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

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

                float3 position : POSITION; //位置

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

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

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

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

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

            接下來我們建立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的代碼簡單很多,程序聲明了一個樣本對象,然后在PS的入口程序中用到了tex2D函數(shù),這個函數(shù)可以用制定的紋理坐標集存取不同類型的樣本并返回一個向量結(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();

            }

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

            typedef struct _D3DVERTEXELEMENT9 {

                WORD Stream; //Stream number

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

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

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

                BYTE Usage;   //用途

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

            } D3DVERTEXELEMENT9

             

            接下來,我們就要建立一個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 );

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

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

             

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

            By sssa2000

            5/15/2005

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

            久久ZYZ资源站无码中文动漫| 久久人人爽爽爽人久久久| 国产精品美女久久久久网| 粉嫩小泬无遮挡久久久久久| 日本一区精品久久久久影院| 91超碰碰碰碰久久久久久综合| 久久久久亚洲精品中文字幕| 国内精品人妻无码久久久影院导航| 亚洲AV日韩精品久久久久久久| 久久婷婷国产麻豆91天堂| 综合久久久久久中文字幕亚洲国产国产综合一区首| 亚洲国产高清精品线久久| 国产人久久人人人人爽| 亚洲欧美日韩久久精品| 国产精品9999久久久久| 伊人伊成久久人综合网777| 久久免费线看线看| 久久精品国产精品亚洲毛片| 中文成人无码精品久久久不卡 | 久久亚洲私人国产精品vA| 91精品国产91久久久久久青草| 伊人久久大香线焦AV综合影院| 国产国产成人久久精品| 国产精品美女久久久m| 国产精品久久新婚兰兰| 国产亚洲精午夜久久久久久 | 青青草原精品99久久精品66| 久久人人爽人人澡人人高潮AV| 99久久er这里只有精品18| 久久久高清免费视频| 久久亚洲电影| 国内精品久久久久久久影视麻豆| 人妻精品久久无码区| 久久精品无码专区免费青青| 久久精品无码一区二区WWW| 亚洲精品NV久久久久久久久久| 久久精品视频91| 久久久精品久久久久久| 久久久久国产精品三级网| 久久亚洲电影| 久久精品国产亚洲αv忘忧草|