Create a Pixel Shader

DirectX8

Microsoft DirectX 8.1 (C++)

Create a Pixel Shader

This example uses a pixel shader to apply a Gouraud interpolated diffuse color to a geometric plane. The example will show the contents of the shader file as well as the code required in the application to set up the Microsoft® Direct3D® pipeline for the shader data.

To create a pixel shader
  1. Check for pixel shader support.
  2. Declare the vertex data.
  3. Design the pixel shader.
  4. Create the pixel shader.
  5. Render the output pixels.

If you already know how to build and run Direct3D samples, you should be able to cut and paste code from this example into your existing application.

Step 1: Check for pixel shader support

To check for pixel shader support, use the following code. This example checks for pixel shader version 1.1.

D3DCAPS8 caps;
m_pd3dDevice->GetDeviceCaps(∩︀);        // init m_pd3dDevice before using
if( D3DPS_VERSION(1,1) != caps.PixelShaderVersion )
	return E_FAIL;

The caps structure returns the functional capabilities of the pipeline. Use the D3DPS_VERSION macro to test for the supported shader version number. If the version number is less than 1.1, this call will fail. If the hardware does not support the shader version that is tested, the application will have to fall back to another rendering approach (perhaps a lower shader version is available).

Step 2: Declare the vertex data

This example uses a plane, which is made up of two triangles. The data structure for each vertex will contain position and diffuse color data. The D3DFVF_CUSTOMVERTEX macro defines a data structure to match the vertex data. The actual vertex data is declared in a global array of vertices called g_Vertices[]. The four vertices are centered about the origin, and each vertex is given a different diffuse color.

// Declare vertex data structure. 
struct CUSTOMVERTEX
{
    FLOAT x, y, z;
    DWORD diffuseColor;
};
// Declare custom FVF macro.
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)

// Declare the vertex position and diffuse color data.
CUSTOMVERTEX g_Vertices[]=
{
//      x      y      z   diffuse color
    { -1.0f, -1.0f, 0.0f, 0xffff0000 },  // red   - bottom left
    { +1.0f, -1.0f, 0.0f, 0xff00ff00 },  // green - bottom right
    { +1.0f, +1.0f, 0.0f, 0xff0000ff },  // blue  - top right
    { -1.0f, +1.0f, 0.0f, 0xffffffff },  // white - top left
};

Step 3: Design the pixel shader

This shader moves the Gouraud interpolated diffuse color data to the output pixels. The shader file PixelShader.txt follows:

ps.1.0        // version instruction
mov r0,v0     // Move the diffuse vertex color to the output register.

The first instruction in a pixel shader file declares the pixel shader version, which is 1.0.

The second instruction moves the contents of the color register (v0) into the output register (r0). The color register contains the vertex diffuse color because the vertex data is declared to contain the interpolated diffuse color in step 1. The output register determines the pixel color used by the render target (because there is no additional processing, such as fog, in this case).

Step 4: Create the pixel shader

The pixel shader is created from the pixel shader instructions. In this example, the instructions are contained in a separate file. The instructions could also be used in a text string.

TCHAR        strPath[512];           // used to locate the shader file
LPD3DXBUFFER pCode;                  // points to the assembled shader code
DXUtil_FindMediaFile( strPath, _T("PixelShader.txt") );

This function is a helper function used by the Sample Framework. The sample framework is the foundation on which many of the samples are built.

D3DXAssembleShaderFromFile( strPath, 0, NULL, &pCode;, NULL );    // assemble shader code
m_pd3dDevice->CreatePixelShader( (DWORD*)pCode->GetBufferPointer(), &m;_hPixelShader );

Once the shader is created, the handle m_hPixelShader is used to refer to it.

Step 5: Render the output pixels

Rendering the output pixels is very similar to using the fixed function pipeline sequence of calls except that the pixel shader handle is now used to set the shader.

// Turn lighting off for this example. It will not contribute to the final pixel color.
// The pixel color will be determined solely by interpolating the vertex colors.
m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

m_pd3dDevice->SetStreamSource( 0, m_pQuadVB, sizeof(CUSTOMVERTEX) );
m_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
m_pd3dDevice->SetPixelShader( m_hPixelShader );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 );

The source of the vertex data is set with SetStreamSource. In this example, SetVertexShader uses the same Flexible Vertex Format (FVF) macro used during vertex data declaration to tell Direct3D to do fixed function vertex processing. Vertex shaders and pixel shaders may be used together or separately. The fixed function pipeline can also be used instead of either pixel or vertex shaders. SetPixelShader tells Direct3D which pixel shader to use, DrawPrimitive tells Direct3D how to draw the plane.

The gouraud shaded pixels are shown in the following image.

Pixel Shader Examples contains examples that show how to apply texture maps and blend between textures and vertex colors.