CPU Rendering library written in C++ 17 for C/C++ with a scene loader (using stb, TinyObjLoader, GLFW and ImGui) and a mathematics library.
/!\ CPU Software renderers are not performant nor efficient, it is not recommended to use them on a serious project. Use it at your own risk. /!\
Description: CPU Renderer using rasterization to display 3D models in a color buffer (Use GLFW and ImGui)
- Draw triangles on the input color buffer using input vertices
- Triangle wireframe
- Triangle rasterization
- Depth test using the input depth buffer
- Triangle homogeneous clipping
- Texture support (+ bilinear filtering)
- Material support (ambient, diffuse, specular and emission)
- Lighting support using Gouraud and Phong models (ambient, diffuse, specular and attenuation)
- Blending support (+ texture with transparence and cutout)
- Gamma correction
- Post-process effect (Box blur, Gaussian blur, Light bloom, MSAA)
rdrImpl* rdrInit(float* colorBuffer, float* depthBuffer, int width, int height)
void rdrSetUniformFloatV(rdrImpl* renderer, rdrUniformType type, float* value)
void rdrSetUniformBool(rdrImpl* renderer, rdrUniformType type, bool value)
void rdrSetModel(rdrImpl* renderer, float* modelMatrix)
void rdrSetView(rdrImpl* renderer, float* viewMatrix)
void rdrSetProjection(rdrImpl* renderer, float* projectionMatrix)
void rdrSetTexture(rdrImpl* renderer, float* colors32Bits, int width, int height)
void rdrSetUniformMaterial(rdrImpl* renderer, rdrMaterial* material)
void rdrSetUniformLight(rdrImpl* renderer, int index, rdrLight* light)
void rdrFinish(rdrImpl* renderer)
void rdrShutdown(rdrImpl* renderer)
- Vertex shader
- Clipping
- Normalized Device Coordinates
- Screen coordinates
- Rasterization
- Pixel shader
- Blending
- Post-process
First of all, the renderer takes the input vertices and applies the vertex shader to them. The vertex shader computes the clip coordinates (which are homogeneous) with the Model-View-Projection matrix (it also applies the Model matrix to the normals and the local coordinates). It saves the vertex informations (like colors and UVs) in a varying (for each vertex) for further operations and to calculate lighting.
After that the pipeline calls two functions to check if the current triangle needs to be clipped, and how to clip it. If it should be clipped, it adds new triangles to rasterize with new varyings (for each vertex).
Then the renderer divides the homogeneous coordinates by their w component to get NDC coordinates (which are between -1 and 1). With these coordinates the renderer can ignore some faces (like back faces) using the normal of the triangle's face.
NDC coordinates are then remapped with the viewport definition, and the varyings are interpolated with the weights of clipped coordinates. With these remapped coordinates and the interpolated varyings the main function can finally rasterize the clipped triangles (or draw them as lines with the Wireframe mode).
At the start of this step the bounding box of the current triangle is calculated. For each of its pixel, his weight is computed to check if it is in the triangle or not (If MSAA is enabled, this step uses the samples of the pixel instead of using the pixel centroid). After passing this test, the depth test should be passed, it checks if there is already a pixel drawn in the color buffer at his position and if his depth is greater than its own. Then the perspective correction is occurred to avoid PS1 graphics-like and get correct weights to interpolate varyings.
After getting the interpolated varying, the fragment shader is called. The fragment shader calculates the pixel color using the differents values of the inputs. The lighting can be calculated here (If the Phong model is enabled, else it is calculated during Vertex shader). If the current triangle is textured, the fragment shader gets the appropriate color using the UVs (It can also filter the texture using bilinear interpolation). The fragment shader can also discard pixels depending on its settings.
After getting the fragment color, the blending can be applied with the old color of the pixel to have a transparency effect. Then the alpha test should be passed to write in the depth buffer (to avoid non-transparent faces due to the rendering order of the vertices). These two steps are applied to each sample of the current pixel if the MSAA is enabled. After these steps the buffers (color buffer or MSAA color buffer) can be filled with the blended color.
The final step is to apply effects on the frame buffer after getting all pixels (or of the samples) color, by traversing all the pixels of the frame buffer. If the MSAA is enabled, no pixel has a color, this color is obtained by calculating the average color of all samples of the current pixel. Then other effects can be applied like Box blur, Gaussian blur or Bloom. These effects are applied by obtaining the average of pixels around the current one with some factors. At the very end, the frame buffer is traversed once more to apply the gamma correction.
Colored diffuse using Phong shading.
Lighting using Gouraud and Phong shading: diffuse, specular, emissive and attenuation.
Depth test and blending using a transparent texture (this scene uses Gouraud shading with a red light, a blue and another green and a gray ambient visible on the window).
Configurable face culling and perspective correction.
10x10 Texture with a bilinear filter - The same texture without any filter.
Post-processing effects: MSAA, Box blur and Gaussian blur.
- Gives the formula to convert normalized device coordinates to viewport coordinates (here the viewport is the screen): https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glViewport.xhtml
- Shows how the triangle rasterization works and how to use the top-left rule: https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/rasterization-stage
- Shows the technique to correct the perspective: https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes
- Shows the method to use the face culling: https://www.students.cs.ubc.ca/~cs-314/notes/cull.html
- Shows the differences between Gouraud shading and Phong shading: https://en.wikipedia.org/wiki/Gouraud_shading
- Shows the principle of Phong shading: https://en.wikipedia.org/wiki/Phong_shading
- Gives an alternative to the Phong model: https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_reflection_model
- Gives the formulas for the Phong shading: https://en.wikipedia.org/wiki/Phong_reflection_model
- Shows how OpenGL uses its light systeme and how materials and light are related: https://www.glprogramming.com/red/chapter05.html
- Shows how to use the blending and the issues with the blending (like sorting the render order): https://learnopengl.com/Advanced-OpenGL/Blending
- Gives the main structure of the algorithm: https://fabiensanglard.net/polygon_codec/
- Shows how to use outcodes: https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
- Shows the complexity of the algorithm: https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
- Shows how to use bilinear filtering using bilinear interpolation: https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/interpolation/bilinear-filtering
- Shows the principle of bilinear filtering: https://docs.microsoft.com/en-us/windows/win32/direct3d9/bilinear-texture-filtering
- Gives some exemples of post-process effects: https://en.wikipedia.org/wiki/Kernel_(image_processing)
- Shows the principle of anti-aliasing: https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-rasterizer-stage-rules
- Shows how to arrange samples: https://mynameismjp.wordpress.com/2012/10/24/msaa-overview/
- Sometimes lines may appear on some models, for example if the camera is in (0;0;0) and it does not move.
- On small resolutions the accuracy of the rasterization is not perfect.
- Models with incorrect information can cause crashes.
- MSAA can prevent cutout (alpha test) from working if blending is enabled.
- Phong shading can be more performant than Gouraud shading.
- Box blur, Gaussian blur and Light bloom may not work properly.
Description: Default scene program to load .obj, textures and materials editable via ImGui, and then display them using the rendering software. (Use stb, TinyObjLoader and ImGui)
- Load .obj (support textures and materials), quads and triangles with TinyObjLoader
- Load textures
- Load materials
- Sort models with their transform using
- Fully editable lights, materials and objects from ImGui window
- Manage the function calls to the renderer
- WASD/ZQSD/Array keys: Move foward, backward, left and right.
- Space: Move upward.
- Left Shit: Move downward.
- NUMPAD+/NUMPAD-: Change the velocity of the camera.
scnImpl* scnCreate()
void scnUpdate(scnImpl* scene, float deltaTime, rdrImpl* renderer)
(To sort models)
void scnSetCameraPosition(scnImpl* scene, float* cameraPos)
void scnDestroy(scnImpl* scene)
void loadTriangle(...)
void loadQuad(...)
bool loadObject(...)
int loadMaterial(...)
int loadTexture(...)
void loadTriangle(...)
vector of Triangles | List of triangles that all have the same texture and material
int textureIndex | Index of the current texture
int materialIndex | Index of the current material
bool enable | Current state
vector of Mesh | List of mesh that all have the same transform
3 floats -> x, y, z | Position
3 floats -> x, y, z | Rotation
3 floats -> x, y, z | Scale
https://github.com/nothings/stb
https://github.com/tinyobjloader/tinyobjloader
https://github.com/ocornut/imgui
https://github.com/notnullnotvoid/msf_gif
3 floats -> x, y, z | Position
3 floats -> nx, ny, nz | Normal
4 floats -> r, g, b, a | Color
2 floats -> u, v | Texture coordinates
bool enabled | Current state
4 floats position -> x, y, z, w | Position and light type (w)
4 floats ambient -> r, g, b, a | Ambient color
4 floats diffuse -> r, g, b, a | Diffuse color
4 floats specular -> r, g, b, a | Specular colors
3 floats attenuation -> c, l, q | Constant, linear and quadratic attenuations
4 floats ambientColor -> r, g, b, a | Ambient color
4 floats diffuseColor -> r, g, b, a | Diffuse color
4 floats specularColor -> r, g, b, a | Specular colors
4 floats emissionColor -> r, g, b, a | Emission colors
float shininess | Shininess exponent
2 ints -> w, h | Texture size
4 floats -> r, g, b, a | Texture datas
(Only for the scene)
string -> filepath | Texture file path