Sunday, May 1, 2011

How the rasterization process works, the RasterizerState object

You probably noticed that when we draw something we use polygons (triangles) but on screen we have pixels. The process of converting from triangles to pixels on the screen. We can play with this process by using a few settings exposed to us by the RasterizerObject.

In the above image you can see the rasterization process in action, it looks to determine what pixel is part of what polygon and the fills that pixel in that polygons color or texture. As you can see the edges aren't very pretty, those jaggies are caused by the fact that the screen resolution isn't high enough to properly display the art we want. The effect is called aliasing and the process of removing it is known as anti-aliasing, on modern GPU we use multi-sampling anti-aliasing, what this does it actually does the rasterization process at a higher resolution and the samples the pixels at the normal resolution. To turn in on I recommend using the graphics.PreferMultiSampling boolean value. To set it from the RasterizerState object use the property MultiSampleAntiAlias which is also a boolean.
     The above polygon completely colors all the pixels within it, but what if I just want to render only the edges? this is known as wireframe rendering, to enable it we have to change the FillMode property of the RasterizerState to another value. The FillMode propertie is an item from the FillMode enumeration, the 2 options are FillMode.Solid (render full geometry) and FillMode.WireFrame (render edges only). You can see part of the terrain I've been using rendered in wire frame here:

     Another important thing to note is that rendering triangles that are oriented away from the camera isn't always needed. For example, when rendering a cube you can't see triangles (faces) that are oriented away from the camera because they are occluded by the triangles facing the camera, this type of occlusion is called self-occlusion. Because these triangles will never make any difference to the final image we can just skip rendering them altogether. This process is known as back-face culling (or culling). When we render triangles we send only 3 primitives to the rasterizer unit, the order they are sent determine if they are going to get drawn or not. The order (clockwise or counterclockwise) that they are sent in is called winding order. When we want to cull geometry we set the CullMode parameter of the RasterizerState to an item of the CullMode enumeration. We can have CullMode.CounterClockwise to cull triangles with counter clockwise winding order (default), CullMode.Clockwise to cull clockwise triangles and CullMode.None for no geometry culling. This can come in handy for non-opaque geometry or single sided geometry (like a fence).

    This is not the only optimization what we can make, for example we can specify that we are going to render to the whole screen and we would like to render only part of the screen (useful in games whit a fixed HUD like an RTS). This called a scissor test, where geometry is 'clipped' at the sides of a rectangle and only the geometry inside the rectangle is drawn. This property is enabled by setting the boolean ScissorTestEnable to true. By default it is enabled and the rectangles used to perform the scissor test is the whole screen, you can change it by modifying the ScissorRectangle property of the GraphicsDevice.

    When the rasterisation process occurs sometimes 2 primitives may have the same depth but the GPU will sometime render one object and sometimes the other. This happens because we have limited  numerical precision of our depth buffer. For example we may want to render both the geometry and it's wireframe (in different passes) and the wireframe may appear to flicker, this is because of the numerical clamping,.To avoid it we must make sure that the wireframe is a little closer. To do this we can set the DepthBias and SlopeScaleDepthBias float values (these two are 0 by default). The first one is a direct bias while the second one takes into account the slope of the primitives.

    1 comment: