像素着色器入门(2)

像素着色器入门(2)

新建网页 1

18.4 HLSL采样器对象

在像素着色器中使用HLSL的内建函数tex*XXXX给纹理采样。注意:采样时引用纹理上图素的坐标索引和采样器状态来生成像素。

通常这些函数需要我们做2件事:

使用纹理中的索引建立(u, v)纹理坐标。

给特定的纹理中编入索引。

将纹理坐标(u, v)输入到像素着色器,在一个指定的HLSL对象中的像素着色器中,我们想编入索引的纹理是在像素着色器中被定义过的,在HLSL中叫作采样器。(The particular texture that we want to index into is identified in the pixel shader by a special HLSL object called a sampler.),我们可以把采样器对象想象成定义纹理和采样器阶段的对象。例如:假如我们使用3张纹理,这意味着我们需要在像素着色器里能够引用3个阶段中的每个一个。在像素着色器中我们这样写:

                
        

        sampler FirstTex;

        

        sampler SecondTex;

        

        sampler ThirdTex;

Direct3D将给每个采样器对象连接一个唯一的纹理级别(stage),在应用程序中我们找出与采样器对象相关联的阶段,并设置相应的纹理和采样器状态给该阶段。下列代码将举例说明如何在应用程序中设置纹理并把采样器状态设置为FirstTex


            

        //         创建

        IDirect3DTexture9* Tex;

        D3DXCreateTextureFromFile(Device, "tex.bmp", &Tex);

        

        … …

        

        //         取得常量FirstTex的句柄

        FirstTexHandle = MultiTexCT->GetConstantByName(0, "FirstTex");

                

        //         取得常量的描述

        D3DXCONSTANT_DESC FirstTexDesc;

        

        UINT         count;

        MultiTexCT->GetConstantDesc(FirstTexHandle, &FirstTexDesc, &count);

        

         … …

        

        //         FirstTex设置纹理和采样器状态.        

        

        // We identify the stage FirstTex is associated with from the           D3DXCONSTANT_DESC::RegisterIndex member:

        

        Device->SetTexture(FirstTexDesc.RegisterIndex, Tex);

        

        Device->SetSamplerState(FirstTexDesc.RegisterIndex,  D3DSAMP_MAGFILTER,      D3DTEXF_LINEAR);

        

        Device->SetSamplerState(FirstTexDesc.RegisterIndex,  D3DSAMP_MINFILTER,       D3DTEXF_LINEAR);

        

        Device->SetSamplerState(FirstTexDesc.RegisterIndex,  D3DSAMP_MIPFILTER,       D3DTEXF_LINEAR);

注意:作为选择,替换使用采样器类型,你可以使用更多特殊的、强大的类型,如:sampler1Dsampler2Dsampler3D,和samplerCube类型,这些类型更安全并且它们只使用tex*函数。例如:一个sampler2D对象只使用tex2D*函数,同样一个sampler3D对象只使用tex3D*函数。

 

 

18.5例子程序:Multitexturing in a Pixel Shader

这章中的例子演示了在像素着色器中使用多纹理,这个例子渲染的目标是一个木箱纹理,一个聚光灯纹理,和一个包含字符串的纹理。这就是例子程序:Pixel Shader

 

像素着色器入门(2)_第1张图片

这个例子可以不使用像素着色器来实现,但实现这个程序是简单直接,它允许我们示范如何编写,创建,而且使用像素着色器实现一些特效不必使用那些复杂的算法。

虽然在这个例子中一次只使用3张纹理,检查采样器对象的成员以确定每个像素着色器能够使用的版本,这是值得的。换句话说,我们一次能使用多少纹理,这依赖于使用的像素着色器的版本:

像素着色器的版本ps_1_1 ps_1_3支持4个纹理采样器。

像素着色器的版本ps_1_4支持6个纹理采样器。

像素着色器的版本ps_2_0 ps_3_0支持16个纹理采样器。

 

     /******************************************************************************
      Pixel shader that does multi texturing.
     ******************************************************************************/

    
    sampler g_base_texture;
    sampler g_spotlight_texture;
    sampler g_string_texture;
    
    
struct  sPixelInput
    {
        float2 
base          : TEXCOORD0;
        float2 spotlight : TEXCOORD1;
        float2 text         : TEXCOORD2;
    };
    
    
struct  sPixelOutput
    {
        vector diffuse : COLOR0;
    };
    
    
    /////////////////////////////////////////////////////////////////////////////////
    

    sPixelOutput main(sPixelInput input)
    {
        sPixelOutput output = (sPixelOutput) 0;
    
        
// sample appropriate textures
    
        vector base_color       = tex2D(g_base_texture,        input. base );
        vector spotlight_color = tex2D(g_spotlight_texture, input.spotlight);
        vector text_color       = tex2D(g_string_texture,    input.text);
    
        
// combine texel colors
    
        vector color = base_color * spotlight_color + text_color;
    
        
// increase the intensity of the pixel slightly
    
    color += 0.1f;
    
        
// save the resulting pixel color
    
    output.diffuse = color;
    
        
return  output;
    }

tex2D的函数使用说明如下:

There are two overloaded tex2D texture lookup functions:

  • 2D texture lookup
  •     
  • 2D texture lookup with partial derivatives     

2D texture lookup

This function performs a 2D texture lookup.

Syntax

                  
ret tex2D(s, t)

Where:

                                                                                                                                                                                                                           
NameIn/OutTemplate TypeComponent TypeSize
sinobjectsampler2D1
tinvectorfloat2
retoutvectorfloat4

2D texture lookup with partial derivatives

This function performs a 2D texture lookup also, but also uses the partial derivatives to help pick the LOD.

Syntax

                  
ret tex2D(s, t, ddx, ddy)

Where:

                                                                                                                                                                                                                                                                                                                                         
NameIn/OutTemplate TypeComponent TypeSize
sinobjectsampler2D1
tinvectorfloat2
ddxinvectorfloat2
ddyinvectorfloat2
retoutvectorfloat4

 

首先像素着色器定义了3sampler对象,要渲染的每个纹理,接下来定义是inputoutput结构。注意:我们没有将任何的颜色值输入到像素着色器中,这是因为我们使用纹理自己的颜色和光照;即BaseTex保存表面的颜色,SpotLightTex是光照图。像素着色器输出只一个简颜色值,指定了我们计算过的这个特定像素的颜色。

Main函数使用tex2D函数采样3个纹理,即它取得每个纹理的图素,计算映射到的像素,这通常依赖于指定的纹理坐标和采样器对象。然后我们混合图素的颜色用公式:c = b * s + t。接下来我们让全部的像素变亮一个bit,给每个部分增加0.1f。最后我们保存结果像素颜色并返回它。

执行程序:

     /**************************************************************************************************
      Deomstrates multi-texturing using a pixel shader.  You will have to switch to the REF 
      device to run this sample if your hardware doesn't support pixel shaders.
     **************************************************************************************************/

    
    #include "d3dUtility.h"
    
    #pragma warning(disable : 4100)
    
    
struct  sMultiTextureVertex
    {
        sMultiTextureVertex(
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;
        
float  _u1, _v1;
        
float  _u2, _v2;
    };
    
    
const  DWORD MULTI_TEXTURE_VERTEX_FVF = D3DFVF_XYZ | D3DFVF_TEX3; 
    
    
    /////////////////////////////////////////////////////////////////////////////////////////////
    

    
const   int  WIDTH  = 640;
    
const   int  HEIGHT = 480;
    
    IDirect3DDevice9*        g_device;
    IDirect3DPixelShader9*    g_pixel_shader;
    ID3DXConstantTable*        g_constant_table;
    IDirect3DVertexBuffer9*    g_vertex_buffer;
    
    IDirect3DTexture9*        g_base_texture;
    IDirect3DTexture9*        g_spotlight_texture;
    IDirect3DTexture9*        g_string_texture;
    
    D3DXHANDLE                g_base_texture_handle;
    D3DXHANDLE                g_spotlight_texture_handle;
    D3DXHANDLE                g_string_texture_handle;
    
    D3DXCONSTANT_DESC        g_base_texture_desc;
    D3DXCONSTANT_DESC        g_spotlight_texture_desc;
    D3DXCONSTANT_DESC        g_string_texture_desc;
    
    
    /////////////////////////////////////////////////////////////////////////////////////////////////// /
    

    
bool  setup()
    {    
        
// create geometry
    

        g_device->CreateVertexBuffer(6 * 
sizeof (sMultiTextureVertex), D3DUSAGE_WRITEONLY,
            MULTI_TEXTURE_VERTEX_FVF, D3DPOOL_MANAGED, &g_vertex_buffer, NULL);
    
        sMultiTextureVertex* v;
    
        g_vertex_buffer->Lock(0, 0, (
void **)&v, 0);
    
        v[0] = sMultiTextureVertex(-10.0f, -10.0f, 5.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
        v[1] = sMultiTextureVertex(-10.0f,  10.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
        v[2] = sMultiTextureVertex( 10.0f,  10.0f, 5.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
    
        v[3] = sMultiTextureVertex(-10.0f, -10.0f, 5.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
        v[4] = sMultiTextureVertex( 10.0f,  10.0f, 5.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
        v[5] = sMultiTextureVertex( 10.0f, -10.0f, 5.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
    
        g_vertex_buffer->Unlock();
    
        
// compile shader
    

        ID3DXBuffer*    shader_buffer;
        ID3DXBuffer*    error_buffer;
    
        HRESULT hr = D3DXCompileShaderFromFile("MultiTextureShader.cxx", NULL, NULL, "main", "ps_2_0", D3DXSHADER_DEBUG,
                                               &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, "D3DXCompileShaderFromFile() - FAILED", "ERROR", MB_OK);
            
return   false ;
        }
    
        hr = g_device->CreatePixelShader((DWORD*) shader_buffer->GetBufferPointer(), &g_pixel_shader);
    
        
if (FAILED(hr))
        {
            MessageBox(NULL, "CreatePixelShader - FAILED", "ERROR", MB_OK);
            
return   false ;
        }
    
        safe_release<ID3DXBuffer*>(shader_buffer);
    
        
// load textures
    
        D3DXCreateTextureFromFile(g_device, "crate.bmp",     &g_base_texture);
        D3DXCreateTextureFromFile(g_device, "spotlight.bmp", &g_spotlight_texture);
        D3DXCreateTextureFromFile(g_device, "text.bmp",         &g_string_texture);
    
        
// get handles
    
        g_base_texture_handle        = g_constant_table->GetConstantByName(NULL, "g_base_texture");
        g_spotlight_texture_handle    = g_constant_table->GetConstantByName(NULL, "g_spotlight_texture");
        g_string_texture_handle        = g_constant_table->GetConstantByName(NULL, "g_string_texture");
    
        
// set constant descriptions
    

        UINT count;
    
        g_constant_table->GetConstantDesc(g_base_texture_handle,      &g_base_texture_desc,         &count);
        g_constant_table->GetConstantDesc(g_spotlight_texture_handle, &g_spotlight_texture_desc, &count);
        g_constant_table->GetConstantDesc(g_string_texture_handle,      &g_string_texture_desc,     &count);    
    
        g_constant_table->SetDefaults(g_device);
    
        
// set the projection matrix
    
    D3DXMATRIX proj;
        D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI/4.0f, (
float )WIDTH/HEIGHT, 1.0f, 1000.0f);
        g_device->SetTransform(D3DTS_PROJECTION, &proj);
        
        
//g_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
    
    
        
return   true ;
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////// /
    

    
void  cleanup()
    {    
        safe_release<IDirect3DVertexBuffer9*>(g_vertex_buffer);
    
        safe_release<IDirect3DTexture9*>(g_base_texture);
        safe_release<IDirect3DTexture9*>(g_spotlight_texture);
        safe_release<IDirect3DTexture9*>(g_string_texture);
        
        safe_release<IDirect3DPixelShader9*>(g_pixel_shader);
        safe_release<ID3DXConstantTable*>(g_constant_table);
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////// /
    

    
bool  display( float  time_delta)
    {    
        
// update the scene: allow user to rotate around scene.
    

        
static   float  angle  = (3.0f * D3DX_PI) / 2.0f;
        
static   float  radius = 20.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)
            radius -= 2.0f * time_delta;
    
        
if (GetAsyncKeyState(VK_DOWN) & 0x8000f)
            radius += 2.0f * time_delta;
    
        D3DXVECTOR3 position(cosf(angle) * radius, 0.0f, sinf(angle) * radius);
        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);
        g_device->SetTransform(D3DTS_VIEW, &view_matrix);
            
        
// render now
    

        g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xFFFFFFFF, 1.0f, 0);
    
        g_device->BeginScene();
    
        g_device->SetPixelShader(g_pixel_shader);
    
        g_device->SetFVF(MULTI_TEXTURE_VERTEX_FVF);
        g_device->SetStreamSource(0, g_vertex_buffer, 0, 
sizeof (sMultiTextureVertex));
    
        
// base texture
    
        g_device->SetTexture(g_base_texture_desc.RegisterIndex, g_base_texture);
        g_device->SetSamplerState(g_base_texture_desc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
        g_device->SetSamplerState(g_base_texture_desc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        g_device->SetSamplerState(g_base_texture_desc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
    
        
// spotlight texture
    
        g_device->SetTexture(g_spotlight_texture_desc.RegisterIndex, g_spotlight_texture);
        g_device->SetSamplerState(g_spotlight_texture_desc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
        g_device->SetSamplerState(g_spotlight_texture_desc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        g_device->SetSamplerState(g_spotlight_texture_desc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
    
        
// string texture
    
        g_device->SetTexture(g_string_texture_desc.RegisterIndex, g_string_texture);
        g_device->SetSamplerState(g_string_texture_desc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
        g_device->SetSamplerState(g_string_texture_desc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        g_device->SetSamplerState(g_string_texture_desc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
    
        g_device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
        
        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函数执行下列功能:

填充方形的顶点缓存

编译着像素色器

创建像素色器

读取纹理

设置投影矩阵,不使用光照

取得采样器(sampler)对象的句柄

取得采样器对象的描述


display函数设置像素着色器,使用2个纹理,并且在渲染方格前设置他们对应的采样器状态。


运行截图:

像素着色器入门(2)_第2张图片

 

下载源程序


你可能感兴趣的:(像素着色器入门(2))