天行健 君子当自强而不息

顶点着色器入门(2)

新建网页 1

17.3使用顶点着色器的步骤

下面的列表概括了创建和使用顶点着色器的必须步骤:

1.      编写并编译顶点着色器

2.      创建一个IDirect3DVertexShader9接口以引用已编译的着色器代码上的顶点着色器。

3.      IDirect3DDevice9:: SetVertexShader方法使用这个顶点着色器。

当然,在我们做完这些之后,我们还得销毁这个顶点着色器。

17.3.1 编写并编译顶点着色器

首先,我们必须编写一个顶点着色器程序。一旦着色器代码写好之后,我们就使用D3DXCompileShaderFromFile函数编译这个着色器。回忆一下,这个函数返回一个ID3DXBuffer指针,它包含已编译的着色器代码。

17.3.2 创建顶点着色器

一旦我们拥有了编译好的着色器代码,我们就能够获得一个IDirect3DVertexShader9接口的指针,它代表一个顶点着色器——通过使用下面的方法:

               
       

        HRESULT IDirect3DDevice9::CreateVertexShader(

       

             const DWORD *pFunction,

       

             IDirect3DVertexShader9** ppShader

       

);

pFunction——已编译着色器代码的指针

ppShader——返回一个IDirect3DVertexShader9接口的指针

例如,假设变量shader是一个包含已编译的,着色器代码的ID3DXBuffer指针。然后要获得一个IDirect3DVertexShader9接口,我们可以写:

               
       

        IDirect3DVertexShader9* ToonShader = 0;

       

hr =         Device->CreateVertexShader(

       

                   (DWORD*)shader->GetBufferPointer(),

       

                   &ToonShader);

注意:重申一遍,D3DXCompileShaderFromFile是一个函数,它将返回已编译着色器的代码(shader)。

17.3.3 建立顶点着色器

在我们获得了一个代表我们的顶点着色器的IDirect3DVertexShader9接口的指针之后,我们就能够使用下面的方法使用它:

               
       

        HRESULT IDirect3DDevice9::SetVertexShader(

       

             IDirect3DVertexShader9* pShader

       

);

这个方法仅接受一个参数,我们在其中传递一个想要使用的顶点着色器的指针。要使用这个着色器,我们可以写:Device->SetVertexShader(ToonShader);

 

17.3.4 销毁顶点着色器

和所有的Direc3D接口一样,要清除他们,我们就必须在用完它们之后调用其的Release方法。

17.4应用程序:散射光照

作为创建并使用顶点着色器的热身,我们写一个顶点着色器,它用一个方向(平行)光对每个顶点进行标准的散射光照。简而言之,散射光照根据顶点法线和光线向量(它朝向光源方向)的角度计算顶点接收到的光线的数量。角度越小,则顶点接收到的光线就越多;而角度越大,则顶点接收到的光线就越少。如果角度大于等于90度,顶点就接收不到光线了。

我们以检阅着色器代码作为开始:

     /**********************************************************************************
      Vertex shader that does diffuse lighting.         
     **********************************************************************************/

   
    matrix g_view_matrix;
    matrix g_view_proj_matrix;
   
    vector g_ambient_material;
    vector g_diffuse_material;
   
    vector g_dir_to_light;    
// the direction to the light source
   
    // Global variables used to hold the ambient light intensity (ambient light the light 
    // source emits) and the diffuse light intensity (diffuse light the light source emits).  
    // These variables are initialized here in the shader.
   

   
const vector DIFFUSE_LIGHT_INTENSITY = {0.5f, 0.5f, 0.5f, 1.0f};
   
const vector AMBIENT_LIGHT_INTENSITY = {2.0f, 2.0f, 1.0f, 1.0f};
   
   
   
struct sVertexInput
    {
        vector position : POSITION;
        vector normal    : NORMAL;
    };
   
   
struct sVertexOutput
    {
        vector position : POSITION;
        vector diffuse  : COLOR;
    };
   
   
   
    ///////////////////////////////////////////////////////////////////////////////////////////////
   

    sVertexOutput main(sVertexInput vertex_input)
    {
        sVertexOutput vertex_output = (sVertexOutput) 0;
   
        
// transform position to homogeneous clip space
   
        vertex_output.position = mul(vertex_input.position, g_view_proj_matrix);
   
        
// Transform lights and normals to view space.
        // Set w components to zero since we're transforming vectors here and not points.
   

        g_dir_to_light.w      = 0.0f;
        vertex_input.normal.w = 0.0f;
   
        g_dir_to_light        = mul(g_dir_to_light,       g_view_matrix);
        vertex_input.normal = mul(vertex_input.normal, g_view_matrix);
   
        
// compute cosine of the angle between light and normal
   
    float scalar = dot(g_dir_to_light, vertex_input.normal);
   
        
// Recall that if the angle between the surface and light is greater than 90 degrees 
        // the surface recieves no light. Thus, if the angle is greater than 90 degrees we set
        // scalar to zero so that the surface will not be lit.
   
    if(scalar < 0.0f)
            scalar = 0.0f;
   
        
// Ambient light reflected is computed by performing a component wise multiplication with 
        // the ambient material vector and the ambient light intensity vector.
        //
        // Diffuse light reflected is computed by performing a component wise multiplication with 
        // the diffuse material vector and the diffuse light intensity vector.  
        // Further we scale each component by the shading scalar s, which shades the color based on 
        // how much light the vertex received from the light source.
        //
        // The sum of both the ambient and diffuse components gives us our final vertex color.
   
        vertex_output.diffuse = (g_ambient_material * AMBIENT_LIGHT_INTENSITY) +
                                (scalar * (g_diffuse_material * DIFFUSE_LIGHT_INTENSITY));
   
        
return vertex_output;
    }

执行程序:
     /**************************************************************************************************
      Demonstrates diffuse lighting using a vertex shader.  You will have to switch to 
      the REF device to run this sample if your hardware does not support shaders.  
      Or you can use software vertex processing: D3DCREATE_SOFTWARE_VERTEXPROCESSING. 
     **************************************************************************************************/

   
    #include "d3dUtility.h"
   
    #pragma warning(disable : 4100)
   
   
const int WIDTH  = 640;
   
const int HEIGHT = 480;
   
    IDirect3DDevice9*        g_device;
    ID3DXMesh*                g_teapot_mesh;
    IDirect3DVertexShader9* g_vertex_shader;
    ID3DXConstantTable*        g_constant_table;
   
    D3DXHANDLE                g_view_matrix_handle;
    D3DXHANDLE                g_view_proj_matrix_handle;
    D3DXHANDLE                g_ambient_material_handle;
    D3DXHANDLE                g_diffuse_material_handle;
    D3DXHANDLE                g_dir_to_light_handle;
   
    D3DXMATRIX                g_proj_matrix;
   
   
    ////////////////////////////////////////////////////////////////////////////////////////////////////
   

   
bool setup()
    {    
        D3DXCreateTeapot(g_device, &g_teapot_mesh, NULL);
   
        
// compile shader
   

        ID3DXBuffer*    shader_buffer;
        ID3DXBuffer*    error_buffer;
   
        HRESULT hr = D3DXCompileShaderFromFile("DiffuseShader.cxx", NULL, NULL, "main", "vs_1_1",
                                               D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
                                               &shader_buffer, &error_buffer, &g_constant_table);
   
        
// output any error messages
   
    if(error_buffer)
        {
            MessageBox(NULL, (
char*)error_buffer->GetBufferPointer(), "ERROR", MB_OK);
            safe_release<ID3DXBuffer*>(error_buffer);
        }
   
        
if(FAILED(hr))
        {
            MessageBox(NULL, "D3DXCreateEffectFromFile() - FAILED", "ERROR", MB_OK);
            
return false;
        }
   
        hr = g_device->CreateVertexShader((DWORD*) shader_buffer->GetBufferPointer(), &g_vertex_shader);
   
        
if(FAILED(hr))
        {
            MessageBox(NULL, "CreateVertexShader - FAILED", "ERROR", MB_OK);
            
return false;
        }
   
        safe_release<ID3DXBuffer*>(shader_buffer);
   
        
// get handles
   
        g_view_matrix_handle        = g_constant_table->GetConstantByName(NULL, "g_view_matrix");
        g_view_proj_matrix_handle    = g_constant_table->GetConstantByName(NULL, "g_view_proj_matrix");
        g_ambient_material_handle   = g_constant_table->GetConstantByName(NULL, "g_ambient_material");
        g_diffuse_material_handle   = g_constant_table->GetConstantByName(NULL, "g_diffuse_material");
        g_dir_to_light_handle        = g_constant_table->GetConstantByName(NULL, "g_light_direction");
   
        
//
        // set shader constants
        //
   
        // light direction
   
        D3DXVECTOR4 dir_to_light(-0.57f, 0.57f, -0.57f, 0.0f);
        g_constant_table->SetVector(g_device, g_dir_to_light_handle, &dir_to_light);
   
        
// materials
   
        D3DXVECTOR4 ambient_material(1.0f, 1.0f, 0.5f, 1.0f);
        D3DXVECTOR4 diffuse_material(1.0f, 1.0f, 0.5f, 1.0f);
   
        g_constant_table->SetVector(g_device, g_ambient_material_handle, &ambient_material);
        g_constant_table->SetVector(g_device, g_diffuse_material_handle, &diffuse_material);
   
        g_constant_table->SetDefaults(g_device);
   
        
// set the projection matrix
   
        D3DXMatrixPerspectiveFovLH(&g_proj_matrix, D3DX_PI/4.0f, (float)WIDTH/HEIGHT, 1.0f, 1000.0f);
        
        
//g_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
   
    
        
return true;
    }
   
   
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
   

   
void cleanup()
    {    
        safe_release<ID3DXMesh*>(g_teapot_mesh);
        safe_release<IDirect3DVertexShader9*>(g_vertex_shader);
        safe_release<ID3DXConstantTable*>(g_constant_table);
    }
   
   
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
   

   
bool display(float time_delta)
    {    
        
static float angle  = (3.0f * D3DX_PI) / 2.0f;
        
static float height = 3.0f;
   
        
if(GetAsyncKeyState(VK_LEFT) & 0x8000f)
            angle -= 0.5f * time_delta;
   
        
if(GetAsyncKeyState(VK_RIGHT) & 0x8000f)
            angle += 0.5f * time_delta;
   
        
if(GetAsyncKeyState(VK_UP) & 0x8000f)
            height += 5.0f * time_delta;
   
        
if(GetAsyncKeyState(VK_DOWN) & 0x8000f)
            height -= 5.0f * time_delta;
   
        D3DXVECTOR3 position(cosf(angle) * 7.0f, height, sinf(angle) * 7.0f);
        D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
        D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
   
        D3DXMATRIX view_matrix;
        D3DXMatrixLookAtLH(&view_matrix, &position, &target, &up);
        
        D3DXMATRIX view_proj_matrix = view_matrix * g_proj_matrix;
        g_constant_table->SetMatrix(g_device, g_view_proj_matrix_handle, &view_proj_matrix);
        
        
// render now
   

        g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
   
        g_device->BeginScene();
   
        g_device->SetVertexShader(g_vertex_shader);
        g_teapot_mesh->DrawSubset(0);
        
        g_device->EndScene();
   
        g_device->Present(NULL, NULL, NULL, NULL);
   
        
return true;
    }
   
   
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
   

    LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param)
    {
        
switch(msg)
        {
        
case WM_DESTROY:
            PostQuitMessage(0);
            
break;
   
        
case WM_KEYDOWN:
            
if(word_param == VK_ESCAPE)
                DestroyWindow(hwnd);
   
            
break;
        }
   
        
return DefWindowProc(hwnd, msg, word_param, long_param);
    }
   
   
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
   

   
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
    {
        
if(! init_d3d(inst, WIDTH, HEIGHT, true, D3DDEVTYPE_HAL, &g_device))
        {
            MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK);
            
return 0;
        }
   
        
if(! setup())
        {
            MessageBox(NULL, "Steup() - failed.", 0, MB_OK);
            
return 0;
        }
   
        enter_msg_loop(display);
   
        cleanup();
        g_device->Release();
   
        
return 0;
    }

运行截图:

setup函数执行下列任务:

创建茶壶网格

编译顶点着色器

根据已编译代码创建顶点着色器

通过常量表获取着色器程序中的几个变量的句柄

通过常量表初始化着色器的这几个变量

注意:对于本应用程序,我们的顶点结构不需要任何自由顶点格式没有的额外的分量。

display函数非常简单。它检测用户输入(这里指的是用户输入的传入着色器程序的变量),并相应的更新视图矩阵。但是,因为我们在着色器中执行这个视图矩阵变换,所以我们还必须更新着色器中的视图矩阵变量。我们用常量表完成这件事情。


下载源程序


posted on 2008-04-06 14:23 lovedday 阅读(1380) 评论(2)  编辑 收藏 引用

评论

# re: 顶点着色器入门(2) 2008-04-13 09:17 zjh

发现楼主渲染的地方少了一行

g_constant_table->SetMatrix(g_device, g_view_matrix_handle, &view_matrix);

运行的截图似乎不对啊  回复  更多评论   

# re: 顶点着色器入门(2) 2008-04-13 10:51 lovedday

确实是少了那么一行,不过我测试的时候有没有那一行都没什么影响。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论