Render states can be used to change many features of the rasterization module used by the Direct3D device.
There are many render states that can be set (over 200) you can see them listed at the bottom of this page along with their default values. Described below are the ones you will use most often. I have grouped them roughly according to what they do:
Setting a render state
The device method:
HRESULT SetRenderState(D3DRENDERSTATETYPE State, DWORD Value );
- State - this is a flag representing one of the many states that you want to change.
- Value - each state can have a value, sometimes this is true or false at other times it is an enumerated value. What goes here depends totally on the State value.
Z Buffer States
When we render 3D geometry to the screen it is projected onto the 2D screen space and hence we lose the z (depth) value. It is useful however when rendering to store a depth value for each pixel on the screen to avoid drawing pixels when something is behind something else.
- D3DRS_ZENABLE - used to set the buffering method. Choices are D3DZB_TRUE to enable Z buffering, D3DZB_USEW to enable W buffering (rarely used) or D3DZB_FALSE to disable Z buffering. To enable a Z buffer also see the Z buffer page.
- D3DRS_ZWRITEENABLE - you can turn on or off the writing of data to the Z buffer (TRUE or FALSE). Normally you want it enabled so that geometry is only rendered if it is in front of previous rendered geometry (relative to the camera). You can however turn this off at particular times so you do not write to the Z buffer but can still read from it. This can be useful for advanced rendering techniques. E.g. if you are trying to save fill rate you may want to render something late but you do not want to write into the z buffer but simply read from it.
- D3DRS_ZFUNC - allows control of the way the depth buffer value is used in determining if a pixel should be rendered. Normally this is D3DCMP_LESSEQUAL which means that a pixel is rendered if it's distance (depth) is less or equal to what was rendered at that pixel previously. There are many other advanced options like: D3DCMP_NEVER, D3DCMP_LESS, D3DCMP_EQUAL etc. look in the help file for full details
To enable the z buffer for tests and writes we could do this:
Textures can contain alpha information, this represents how transparent a texel in the texture is. This is normally held in a separate channel. So you may have an RGBA (Red, Green, Blue, Alpha) texture format.
- D3DRS_ALPHABLENDENABLE - to enable alpha blending you have to set this state to TRUE. To disable it you set it to FALSE. The way in which the alpha is blended depends on the D3DRS_SRCBLEND and D3DRS_DESTBLEND states (see blending states below).
- D3DRS_ALPHATESTENABLE - you can apply a test each time a pixel with alpha is written. This way you can prevent pixels being written if the test fails. If you set this to TRUE then the test is carried out using the alpha function and reference values defined by the next two states:
- D3DRS_ALPHAREF - an alpha value you can specify that will be compared in an alpha test. You fill the low 8 bits of a DWORD to pass the value.
- D3DRS_ALPHAFUNC - here you can define the function that determines the alpha test. This defaults to D3DCMP_ALWAYS which means the test always passes but you can use any of the other options like D3DCMP_LESS, D3DCMP_EQUAL, D3DPCMPCAPS_GREATEREQUAL etc.
If you wish to render transparent pixels you must enable alpha blending. The other states can be used to reduce rendering time. E.g. You could say that if a pixel is nearly transparent then do not bother rendering it. This can speed up rendering.
Note: in order to get correct blending you often have to sort your transparent objects before rendering.
To turn on alpha blending and to not bother rendering pixels whose alpha is less than 8 we could do this:
We can control the way pixels from a texture are blended as they are drawn. We control the way the source and destination is blended. This is particularly useful when doing multi pass texturing (as opposed to single pass).
- D3DRS_SRCBLEND - the default value is D3DBLEND_ONE which means the blending factor is 1 for each colour component. So the source (the texture pixel) is blended fully.
- D3DRS_DESTBLEND - the default value is D3DBLEND_ZERO which means the destination has no effect on the final pixel colour. There are many other possibilities, look at the D3DBLEND enumerated types in the DirectX help for a full list.
- D3DRS_SEPARATEALPHABLENDENABLE - if required you can set a different blending mode for the alpha channel to the other channels. To do this set this state to TRUE. The type of blending is set by D3DRS_SRCBLENDALPHA and D3DRS_DESTBLENDALPHA.
The first two are the ones you will use most often.
No blend - the default values give a final pixel colour of source colour * 1 + destination colour * 0:
Multiply - for source colour * 0 + destination colour * source colour you could code:
When you are doing more than one pass (rendering the scene more than once each frame) these blend modes are often used for effects like mapping and shadows etc. E.g. you could render the scene once with normal blending states set and then render again with another texture over the top which blends with the first texture rendered.
Stencil Buffer States
The stencil buffer is very useful for doing special effects. It is similar to a z buffer in that it has a value for each pixel on the screen. In fact the z buffer and stencil buffer normally reside together in memory. You can set render states so that values are written in to the stencil buffer while rasterizing and then use comparison checks to render or not depending on the existing value. Note: you cannot actually read and write pure values but instead use the render state comparisons.
A common example of a use for the stencil buffer is stencil shadows using shadow volumes. To create shadows with this method you firstly find the edges of the geometry (from the lights point of view) creating a shadow volume. You cast a shape from that onto other geometry (e.g. the ground). But instead of drawing this shape you turn off drawing and simply write into the stencil buffer. You then render the rest of your scene as normal. Next you apply a large grey quad over the scene and use the stencil comparison states to only render the shadow where a value is set. That was a rather brief explanation of stencil shadows but if you are interested do a search on the Internet for a fuller explanation.
Other uses for the stencil buffer are for mirrors, decaling, dissolves etc. look in the DirectX help for some further details.
- D3DRS_STENCILENABLE - set this to TRUE to enable stenciling. Note that you must have created a stencil buffer when you created your device.
- D3DRS_STENCILFUNC - here you can define what comparison function to perform on the stencil value and the reference value (below).
- D3DRS_STENCILREF - a reference value you want to use in the comparison
- D3DRS_STENCILFAIL - if a stencil test fails this defines what operation to perform. There are many possible values.
- D3DRS_STENCILZFAIL - if the stencil test passes but the depth test fails this defines what operation will be performed.
- D3DRS_STENCILPASS - if both the stencil and depth test pass this defines what operation to perform.
- D3DRS_STENCILMASK - you can mask out bits when comparing the reference and stencil buffer values.
- D3DRS_STENCILWRITEMASK - you can also mask out bits when writing to the stencil buffer.
I plan to add some more notes in the future on how to use the stencil buffer.
Direct3D provides two types of fog, pixel and vertex. You basically set up a fog colour and Direct3D blends the colour of objects with the fog colour based on the distance the object is from the camera. A common use of fogging is to reduce the amount of polygons you need to render in an outdoor scene. You make the scene disappear into fog over a certain distance and then not bother rendering anything beyond that distance.
- D3DRS_FOGENABLE - set this to TRUE to enable fog
- D3DRS_FOGCOLOR - here you can define the colour of your fog, it is a D3DCOLOR type so you can use the macro D3DCOLOR_RGB
- D3DRS_FOGTABLEMODE - if you want pixel fog you need to define what formula to use, choices include D3DFOG_NONE and D3DFOG_LINEAR for the intensity to simply increase linearly between the fog start and end values (below). There are other options like exponential intensity increases but these are not yet supported.
- D3DRS_FOGSTART - the depth at which the fog effect should start.
- D3DRS_FOGEND - the depth at which the fog effect should end.
- D3DRS_RANGEFOGENABLE - only for vertex fog. Rather than use the depth value the calculations use the distance an object is from the camera. This can slow down calculations somewhat but improve the effect.
Note: vertex fog is performed by the Direct3D pipeline but pixel fog is performed by the graphic card driver so you may need to check a cards capabilities before using pixel fog.
Other common render states that are not so easy to categorise are shown below:
- D3DRS_FILLMODE - this is a useful render state as it allows you to turn wireframe on and off - useful for debugging. It has three possible values: D3DFILL_POINT (just renders a point at each vertex), D3DFILL_WIREFRAME (renders lines for triangle edges) and the default D3DFILL_SOLID.
- D3DRS_SHADEMODE - this render states allows you to specify how you want your triangles shaded. The default is D3DSHADE_GOURAUD which applies Gouraud shading but you can also specify D3DSHADE_FLAT which means the triangle is shaded without any interpolation.
- D3DRS_CULLMODE - when rendering back facing triangles (those facing away from the camera) they need not be rendered saving processing time. With this render state you tell the device how to detect back facing triangles. The default is D3DCULL_CCW which means cull those triangles whose vertices are counter clockwise. Since you normally use the left handed co-ordinate system with Direct3D this culls back facing triangles. Other choices are D3DCULL_NONE for no culling and D3DCULL_CW for clockwise culling.
- D3DRS_DITHERENABLE - you can enable dithering by setting this to TRUE, the default is FALSE. This is a bit of a legacy as it only works when rendering to a 16 bit surface.
- D3DRS_SPECULARENABLE - if you want specular highlights on objects you need to define specular values in the lighting and in the material and set this render state to TRUE. The default is FALSE.
- D3DRS_LIGHTING - many people who have problems with getting Direct3D lights to work have often simply forgotten to turn the lights on! You need to set this render state to TRUE to enable lighting. Also see the lighting notes.
- D3DRS_AMBIENT - this render state allows you to set an ambient light colour. Ambient light is used to model the low background light that is created by the scattering of light from directional sources. It is a very cheap light in terms of frame rate. This render state requires a D3DCOLOR type. I normally use the conversion macros so to set an ambient light of green I would do this: device->SetRenderState(D3DRS_AMBIENT,D3DCOLOR_RGB(0,255,0);
- D3DRS_DEPTHBIAS- this render state allows you to add a bias to the depth value used in comparisons, normally this is 0. The reason for using this is to help solve depth fighting or flickering effects. These occur when two triangles are close enough together in z value that which is in front changes with the slight inaccuracies. The problem is really due to a lack of resolution in the z buffer.
- D3DRS_NORMALIZENORMALS - the normals defined per vertex are used for lighting calculations and should be normalised (have a length of 1) for correct lighting (sometimes you may get away without it or indeed like the effect). In most cases your vertex normals will be normalised but there are instances where they may not be and you could enable this render state so that Direct3D normalises the normals for you. This can hit your frame rate though! One common reason why your normals may not be normalised is if you have scaled your geometry using the world matrix as this also scales the normals.
There are many render states that can be set. They control how rasterization is performed. I have looked at the main ones above but there are over 200 of these so check the DirectX help for the remaining ones.
Default Render States
The default values for the render states are shown below: