DirectX:Direct3D:Tutorials:Vertex Shaders Introduction
From GPWiki
[edit] Vertex / pixel shaders (DirectX)Every game programmer should have probably heard the terms by now. Shaders. These shaders open a wonderful new dimension to many games that have been released recently. Realistic movements, lightning, reflections, real-time rendered hair on faces, etc. The list is quite long. I won't go into exact detail what shaders exactly are. The web is covered with detailed explanations. And, if you really want to get started on shaders, you might get yourself a book about it. Note that this article is meant for C++. In Visual Basic things are probably quite similar. I just want to give a short summary of the types of languages that are available. I'm not sure if these are all, though.
I just want to say something short about HLSL and the ASM variant. HLSL is a C++ like language for shaders. ASM is more low level (think of real assembler) than the HLSL. Basically, HLSL compiles to the ASM code, and ASM does not need compilation anymore. Unfortunately, HLSL is only supported in DirectX9. For DirectX8 you will have to use the ASM version. In DirectX, there are two kinds of shaders. Pixel shaders, and vertex shaders. The names are quite self explanatory.
[edit] VersionsVertex- 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 :-). [edit] Loading a shaderYou 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 just a 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. I believe you can use the last argument of D3DXAssembleShaderFromFile() to receive an error message. The DirectX8 debugger for C++ will also tell you of errors. You should do some decent error checking here, though. If the assemble fails, so wil the CreatePixelShader/CreateVertexShader. Both functions return a DWORD (dwShaderHandle in these code snippets). [edit] Using the shadersUsing the shaders is quite straightforward: //Enabling your vertex shader: D3DDevice.SetVertexShader(Vertexshaderhandle) //Enabling your pixel shader: D3DDevice.SetPixelShader(Pixelshaderhandle) Those handles are the DWORD which I explained before. Now, anything that is rendered will go through the vertex and/or pixelshader files. Notice, that even if you do not want any special effects or so, you will still need to do something in a vertex shader. The world transformation needs to be done by yourself now. Texture coordinates need to be explicitly set as well. I will explain more about that in a moment. 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: You have to specify the FVF you'd like to use for your vertex shaders again though. Or do this directly, instead of NULL. [edit] Deleting shadersYou have to clean up the shaders, or you might create memory leaks Doing this is also quite straight forward: //Delete your vertex shader: D3DDevice.DeleteVertexShader(Vertexshaderhandle) //Delete your pixel shader: D3DDevice.DeletePixelShader(Pixelshaderhandle) [edit] Vertex transformationsWhen you are using a vertex shaders, DirectX won't do the transformations anymore. You have to do that yourself now. This means that you have to set a world*view*projection matrix as a shader constant, and 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. Otherwise it won't compile. We simply multiply our v0 (the incoming vertices) with the world*view*projection matrix we set in our code. [edit] ConclusionThis article is ended for now. More might follow later. You can easily google some articles together which go more in depth in the shader language. I'm not sure when I have the time to add more to this article. Almar [edit] External Links |


