DirectX:Direct3D:Tutorials:Vertex Shaders Introduction
Contents |
Versions
Vertex- and pixel shaders come in various versions. A lower version supports less programming commands than newer versions. You can find exact tables of which version supports what easily on Google, or books. If someone is interested in writing a nice table for it, please do so and put it below here :-).
Loading a shader
You first have to load a shader, before you can use them. In DirectX8 the only thing you will receive is a DWORD (in C++). This DWORD is likea pointer to the shader which is internally stored in the DirectX device. Don't forget to delete this object as well.
Loading a shader is quite simple:
Vertex shader:
// Assemble the vertex shader from the file
D3DXAssembleShaderFromFile("normalmodelshader.vsh", 0 , NULL, &pCode, NULL );
// Create the vertex shader
DWORD dwVertexDecl[] =
{
D3DVSD_STREAM( 0 ),
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2),
D3DVSD_END()
};
//Create shader, store id in dwNormalShader
D3DDevice->CreateVertexShader( dwVertexDecl, (DWORD*)pCode->GetBufferPointer(),
&dwNormalShader, 0 );
//Release code again.
pCode->Release();
The vertex shader needs a vertex declaration. This is basically the same like the Flexible Vertex Format. The videocard only receives data, and without a "map" of the data, it is unable to tell which byte means what.
Pixelshader:
// Assemble the pixel shader from the file D3DXAssembleShaderFromFile( "pixelshader.psh", 0, NULL, &pCode, NULL ); // Create the pixel shader D3DDevice->CreatePixelShader( (DWORD*)pCode->GetBufferPointer(), &dwShaderHandle); pCode->Release();
Note: A Pixelshader does not need a special FVF declaration.
The last argument of D3DXAssembleShaderFromFile can be used to receive a list of error and warning messages. These messages are the same messages as one would receive using the debug DirectX runtimes. If the assemble fails, so wil the CreatePixelShader/CreateVertexShader.
Both functions return a DWORD (dwShaderHandle in these code snippets).
Using the shaders
Using the shaders is quite straightforward:
//Enabling your vertex shader: D3DDevice.SetVertexShader(Vertexshaderhandle)
//Enabling your pixel shader: D3DDevice.SetPixelShader(Pixelshaderhandle)
Now, anything that is rendered will go through the vertex and/or pixelshader files. Even if you do not want any special effects, you will still need to transform the vertex into world coordinates and set texture coordinates in the vertex shader.
If you want to disable the rendering using vertex shaders, simply call the functions again, specifying NULL:
//Disabling your vertex shader: D3DDevice.SetVertexShader(NULL)
//Disabling your pixel shader: D3DDevice.SetPixelShader(NULL)
Note: To use the shaders again, you will have to redeclare the FVF format again.
Deleting shaders
You have to clean up the shaders, or you might create memory leaks.
//Delete your vertex shader: D3DDevice.DeleteVertexShader(Vertexshaderhandle)
//Delete your pixel shader: D3DDevice.DeletePixelShader(Pixelshaderhandle)
Vertex transformations
When using a vertex shader, DirectX will not do the world and view transformations. In order to transform the vector, we need to set a transformation matrix as a shader constant, and use that to transform the coordinates.
//Only transform the vertices: m4x4 oPos, v0, c0
oPos is an output register, which is required for a vertex shader to return. Omitting the output register will result in a compilation error. Alternatively, we could simply multiply our incoming vertexes with the transformation matrix before we pass it to the vertex shader.