Project Description

In this project my goal was to try and understand the mathematics and work behind 3D rendering. I used SDL2 for the visuals and load in a 3D model from an OBJ file, render and rotate the model to the viewport.

Short Video Preview

Overall, I was happy with my progress. There was a lot more that I could look into doing such as making it more efficient, occlusion culling, using different a different API to support materials, colours, lighting, etc.; however, overall, I feel like I achieved my goal of understanding some more of the mathematic concepts that go on behind the scenes.

Lighting and Shading

I added in some basic lighting and shading into the program. This was just very basic with simple calculations, enough to give the model some depth and shape.

In order to find the light strength, the dot product was found between the normal of the triangles surface and the light source, this then used to calculate the shade of white that should be rendered, creating trivial lighting and shading.

Overall I would like to do some further research in lighting, texturing and 3D graphics to better the performance of the rendering, as well as some improvements by fixing the black imperfections in the calculations shown in the picture below.

Performance Improvements

Due to using SDL, all the calculations were done on the CPU. This resulted in a few bottlenecks and challenges that needed to be optimised in order to render with consistent framerate.

Initially for shading, each pixels colour would be calculated to give shading/lighting. This soon made the rendering unstable and less than 1 frame per second, therefore in order to optimise this, instead of doing each pixel within the models outlines, horizontal line rendering was added to the triangles.

This has the positive of increasing performance significantly, however, leads to a negative of a triangle being one single colour (without adding the complexity of linear interpolation between vertices). Due to only wanting to shade the object, this method would suffice.

Additionally, in order to try and assist performance some very basic depth testing was used, discarding most (not all) faces that were behind other faces. This was done using normals to the triangles surface and the cameras direction (normals were already being used for lighting and shading, meaning this was essentially a "free test" in terms of the performance gained).

Lastly, I found a method which all the pixels in the screen could be converted into a buffer, and this buffer could be created into a SDL_Texture using a buffer upload. This significantly improved performance as I did not have to have 1000's of horizontal draw calls, but instead simply the trivial calculations (which were mostly completed at this point) and an upload.