Skip to content

nikolausrauch/software-rasterizer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CPU Software Rasterizer

A software-rasterizer in C++, that I wrote to get a basic understanding of the OpenGL graphics pipeline.

alt l.t.r. "Sad toaster" by tasha.lime, "Coatlicue" by aptass, "Gameboy Cartridge" by Karolina D, "Demon Skull" by Auxiar Molkhun

Features

  • C++ implementation
    • generic vertex and fragment attributes
    • programmable vertex and fragment shader (functors)
    • generic framebuffer targets (for "offscreen" rendering)
    • small math library (2D, 3D, 4D vectors and 2x2, 3x3, 4x4 matrices)
    • .obj and .mat loading
    • GLFW/OpenGL viewer (uploads framebuffer each frame)
  • Rasterizer
    • perspective-correct attribute interpolation
    • z-buffering
    • texture sampler filter (nearest, linear)
    • texture sampler wrapping (repeat, edge)
    • face culling
    • custom framebuffer
    • line rendering (wireframe rendering)
    • mip map generation
    • mip map level computation
    • anisotropic filtering
    • cubemap
  • Examples
    • minimal examples
      • colored triangle
      • index buffer
      • texture and sampler
      • custom framebuffer
      • glfw/gl viewer
      • model loading
    • Blinn-Phong illumination
    • Cel Shading with depth buffer edge detection
    • Normal Mapping
    • Shadow Mapping
    • Screen Space Ambient Occlusion
    • Physically-based rendering + offline pre-integration

Examples

Minimal setup (colored triangle)

Similar to traditional Graphic APIs we define the input and output of the shader stages, i.e. the data passing through the rasterization pipeline.

All members from Varying contained in the VARYING(...) macro are interpolated per fragment by the rasterizer. Note, that it is mandatory to have a Vec4 position interpolated attribute.

/* vertex data -> input to draw call (via Buffer) */
struct Vertex
{
    Vec3 pos;
    Vec3 color;
};

/*
 * Output of vertex stage, Input to fragment stage
 * -> position is mandatory
 * -> members to interpolate are declared by VARYING macro (member need scalar multiplication, and addition)
*/
struct Varying
{
    Vec4 position;
    Vec3 color;

    VARYING(position, color);
};

/* uniform struct accessable from both "shaders" */
struct Uniforms {};

Vertex and fragment shaders are written as function objects which need to be set accordingly with onVertex and onFragment (currently no default shader).

Program<Vertex, Varying, Uniforms> program;
program.onVertex([](const Uniforms& uniform, const Vertex& in, Varying& out)
{
    out.position = Vec4(in.pos, 1.0f);
    out.color = in.color;
});

program.onFragment([](const Uniforms& uniform, const Varying& in, Vec4& out)
{
    out = Vec4(in.color, 1.0f);
});

Mesh data is provided to the renderer with a Buffer object.

Buffer<Vertex> buffer;
buffer.primitive = ePrimitive::TRIANGLES;
buffer.vertices = { { {-0.5, -0.5, 0.5}, {1.0, 0.0, 0.0} },
                    { { 0.5, -0.5, 0.5}, {0.0, 1.0, 0.0} },
                    { { 0.0,  0.5, 0.5}, {0.0, 0.0, 1.0} } };

An instance of Renderer contains a default framebuffer with a color and depth target.

After clearing the framebuffer, a draw call can be submitted with the previously defined shader program and vertex buffer.

/* rasterizer with framebuffer size */
Renderer rasterizer(480, 480);

/* clear framebuffer */
rasterizer.framebuffer().clear(Vec4(0, 0, 0, 1));

/* submit draw call */
rasterizer.draw(program, buffer);

/* save framebuffer as .png */
rasterizer.framebuffer().color().save("00_triangle.png");

Results

Model Loading and Texture Mapping ("Sad toaster" Link by tasha.lime.) alt

Blinn-Phong Illumination with diffuse, normal and ambient occlusion map ("Demon Skull" Link by Auxiar Molkhun) alt

Physically-based rendering with pre-integrated irradiance and radiance maps ("Bilora Bella 46 Camera" Link by Martijn Vaes licensed under CC-BY-4.0) alt

Cel-Shading with post-process edge detection on the depth buffer ("Bird" Link by Václav Pleticha licensed under CC-BY-4.0) alt

Shadow Mapping (based on "low poly house" Link by cofitelle licensed under CC-BY-4.0 CC-BY-4.0) alt

Screen-space ambient occlussion ("Pokemon FireRed - Player's Room" Link by Wesai licensed under CC-BY-4.0) alt

📚 Useful Resources

Tiny Renderer
Scratchpixel Lesson Rasterator
SRPBR
Stack Overflow Perspective Interpolation
learnopengl Tutorials
IBL Blogpost by Bruno Opsenica