Shader2 - Apply vertex colors

DirectX8

Microsoft DirectX 8.1 (shader versions 1.0, 1.1)

Shader2 - Apply vertex colors

This example applies the vertex color from the vertex data to the object. The vertex data contains position data as well as diffuse color data. This is reflected in the vertex declaration and the fixed vertex function macro. These are shown below.

struct CUSTOMVERTEX_POS_COLOR
{
    float       x, y, z;
    DWORD       diffuseColor;
};
#define D3DFVF_CUSTOMVERTEX_POS_COLOR (D3DFVF_XYZ|D3DFVF_DIFFUSE)

// Create vertex data with position and texture coordinates.
CUSTOMVERTEX_POS_COLOR g_Vertices[]=
{
    //  x      y     z     diffuse   
    { -1.0f, 0.25f, 0.0f, 0xffff0000,  },	//  - bottom right - red
    {  0.0f, 0.25f, 0.0f, 0xff00ff00,  },	//  - bottom left - green
    {  0.0f, 1.25f, 0.0f, 0xff0000ff,  },	//  - top left - blue
    { -1.0f, 1.25f, 0.0f, 0xffffffff,  },	//  - top right - white
};

The vertex shader declaration needs to reflect the position and color data also.

DWORD dwDecl2[] =
{
    D3DVSD_STREAM(0),
    D3DVSD_REG(0, D3DVSDT_FLOAT3),      // Register 0 will contain the position data.
    D3DVSD_REG(1, D3DVSDT_D3DCOLOR ),   // Register 1 will contain the color data.
    D3DVSD_END()
};

One way for the shader to get the transformation matrix is from a constant register. This is done by calling SetVertexShaderConstant.

    D3DXMATRIX mat;
	D3DXMatrixMultiply( &mat;, &m;_matView, &m;_matProj );
    D3DXMatrixTranspose( &mat;, &mat; );
    hr = m_pd3dDevice->SetVertexShaderConstant( 1, &mat;, 4 );
	if(FAILED(hr)) return hr;

This declaration declares one stream of data, which contains the position and the color data. The color data is assigned to vertex register 7.

Lastly, here is the shader file.

vs.1.0              ; version instruction
m4x4 oPos, v0, c0   ; transform vertices by view/projection matrix
mov oD0, v1         ; load color from register 7 to diffuse color

It contains three instructions. The first is always the version instruction. The second instruction transforms the vertices. The third instruction moves the color in the vertex register to the output diffuse color register. The result is output vertices using the vertex color data.

The resulting output looks like the following:

// Here is an example of the class used to produce this vertex shader.
// This example is for illustration only. It has not been optimized for performance.

// CVShader.h

// Use vertex color to color the object.

CUSTOMVERTEX_POS_COLOR g_VerticesVS[]=
{
    //  x      y     z     diffuse   
    { -1.0f, 0.25f, 0.0f, 0xffff0000,  },	//  - bottom right - red
    {  0.0f, 0.25f, 0.0f, 0xff00ff00,  },	//  - bottom left - green
    {  0.0f, 1.25f, 0.0f, 0xff0000ff,  },	//  - top left - blue
    { -1.0f, 1.25f, 0.0f, 0xffffffff,  },	//  - top right - red
};


class CVShader
{
public:
    CVShader();

    HRESULT ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior, D3DFORMAT Format );
    HRESULT DeleteDeviceObjects();
    HRESULT Render();
    HRESULT RestoreDeviceObjects(LPDIRECT3DDEVICE8 l_pd3dDevice);
    HRESULT InitMatrices();
    HRESULT UpdateVertexShaderConstants();

private:

    LPDIRECT3DVERTEXBUFFER8	m_pQuadVB;
    LPDIRECT3DDEVICE8		m_pd3dDevice;
    DWORD					m_hVertexShader;
    D3DXMATRIX				m_matView;
    D3DXMATRIX				m_matProj;
};

CVShader::CVShader()
{
    m_pQuadVB			= NULL;
    m_pd3dDevice		= NULL;
    m_hVertexShader		= 0;
}


HRESULT CVShader::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior,
                                          D3DFORMAT Format )
{
    if( D3DSHADER_VERSION_MAJOR( pCaps->VertexShaderVersion ) < 1 )
        return E_FAIL;

    return S_OK;
}


HRESULT CVShader::DeleteDeviceObjects()
{
    SAFE_RELEASE(m_pQuadVB);

    HRESULT hr;
    if(m_hVertexShader > 0)
    {
        hr = m_pd3dDevice->DeleteVertexShader(m_hVertexShader);
        if(FAILED(hr))
        {
            ::MessageBox(NULL,"","DeleteVertexShader failed",MB_OK);
            return E_FAIL;
        }

        m_hVertexShader = 0;
    }

    // local to this class
    m_pd3dDevice = NULL;

    return S_OK;
}

HRESULT CVShader::InitMatrices()
{
    HRESULT hr;

    D3DXVECTOR3 from( 0.0f, 0.0f, 3.0f );
    D3DXVECTOR3 at( 0.0f, 0.0f, 0.0f );
    D3DXVECTOR3 up( 0.0f, 1.0f, 0.0f );

    D3DXMATRIX matWorld;
    D3DXMatrixIdentity( &matWorld; );
    hr = m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld; );

    D3DXMatrixIdentity( &m;_matView );
    D3DXMatrixLookAtLH( &m;_matView, &from;, &at;, &up; );
    m_pd3dDevice->SetTransform( D3DTS_VIEW, &m;_matView );

    D3DXMatrixIdentity( &m;_matProj );
    D3DXMatrixPerspectiveFovLH( &m;_matProj, D3DX_PI/4, 1.0f, 0.5f, 1000.0f );
    m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &m;_matProj );

    return S_OK;
}


HRESULT CVShader::Render()
{
    if(m_pQuadVB)
    {
        HRESULT hr;
        hr = m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

        UpdateVertexShaderConstants();

        hr = m_pd3dDevice->SetStreamSource( 0, m_pQuadVB,
		    sizeof(CUSTOMVERTEX_POS_COLOR) );
        hr = m_pd3dDevice->SetVertexShader( m_hVertexShader );
        hr = m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 );
	}

    return S_OK;
}


HRESULT CVShader::RestoreDeviceObjects(LPDIRECT3DDEVICE8 l_pd3dDevice)
{
    HRESULT hr;

    if(l_pd3dDevice == NULL)
    {
        ::MessageBox(NULL,"","Invalid D3D8 Device ptr",MB_OK);
        return E_FAIL;
    }
    else
        m_pd3dDevice = l_pd3dDevice;

    InitMatrices();

    // Create quad Vertex Buffer.
    hr = m_pd3dDevice->CreateVertexBuffer( 4*sizeof(CUSTOMVERTEX_POS_COLOR),
					D3DUSAGE_WRITEONLY, 
					D3DFVF_CUSTOMVERTEX_POS_COLOR,
					D3DPOOL_DEFAULT, 
					&m;_pQuadVB );
    if( FAILED(hr) ) return hr;

    // Fill the quad VB.
    CUSTOMVERTEX_POS_COLOR1* pVertices = NULL;
    hr = m_pQuadVB->Lock( 0, 4*sizeof(CUSTOMVERTEX_POS_COLOR), (BYTE**)&pVertices;, 0 );
    if(FAILED(hr)) return hr;

    for( DWORD i=0; i<4; i++ )
        pVertices[i] = g_VerticesVS2[i];

    m_pQuadVB->Unlock();


    // Create the vertex shader.
    TCHAR        strVertexShaderPath[512];
    LPD3DXBUFFER pCode;

    DWORD dwDecl2[] =
    {
        D3DVSD_STREAM(0),
        D3DVSD_REG(0, D3DVSDT_FLOAT3),
	    D3DVSD_REG(1, D3DVSDT_D3DCOLOR ),
        D3DVSD_END()
    };

    // Find the vertex shader file.
    DXUtil_FindMediaFile( strVertexShaderPath, _T("VShader.vsh") );

    // Assemble the vertex shader from the file.
    if( FAILED( hr = D3DXAssembleShaderFromFile( strVertexShaderPath, 
                                                 0, NULL, &pCode;, NULL ) ) )
        return hr;

    // Create the vertex shader.
    if(SUCCEEDED(hr = m_pd3dDevice->CreateVertexShader( dwDecl2, 
					(DWORD*)pCode->GetBufferPointer(), &m;_hVertexShader, 0 )))
        pCode->Release();

    return hr;
}

HRESULT CVShader::UpdateVertexShaderConstants()
{
    HRESULT hr;
    D3DXMATRIX mat;
    D3DXMatrixMultiply( &mat;, &m;_matView, &m;_matProj );
    D3DXMatrixTranspose( &mat;, &mat; );
    hr = m_pd3dDevice->SetVertexShaderConstant( 1, &mat;, 4 );
    return hr;
}