← All work

Personal/Course Project 2024

OpenGL renderer

My first graphics API project, based on an OpenGL course and extended for a university assignment with directional & omnidirectional shadow mapping.

  • C++
  • OpenGL 4.6
  • GLSL
  • ImGUI

This project started with the Udemy course Computer Graphics with Modern OpenGL and C++, where I came in touch with a graphics API for the first time. Through that I learned the basics of setting up a renderer, loading models, working with shaders and communicating with the GPU. I later extended the renderer for a university assignment, where I worked on omnidirectional shadow maps using geometry shaders.

Omnidirectional shadow maps

The shadowmap for a point light needs to cover all directions around it - for that you use a cubemap. The geometry shader projects each incoming triangle into all six views and uses the correct cubemap face to write to.

oShadowMapGeometry.glslGLSL
layout(triangles) in;
layout(triangle_strip, max_vertices = 18) out;

out vec4 FragPos;
uniform mat4 shadowMatrices[6];

void main()
{
    for (gl_Layer = 0; gl_Layer < 6; ++gl_Layer)
    {
        for (int i = 0; i < 3; ++i)
        {
            FragPos = gl_in[i].gl_Position;
            gl_Position = shadowMatrices[gl_Layer] * FragPos;
            EmitVertex();
        }
        EndPrimitive();
    }
}

The shadow-pass fragment shader stores the distance from the light. During the lighting pass you sample the cubemap using the direction from the light to the fragment and compare the stored distance with the current fragments distance to the light. If the fragment is farther away, it is in shadow.

fragment.glsl - Omnidirectional shadow comparisonGLSL
float CalcOmniDirectionalShadow(PointLight pLight, int index)
{
    vec3 fragToLight = FragPos - pLight.position;
    float closestDepth = texture(oShadowMaps[index].shadowMap, fragToLight).r;
    closestDepth *= oShadowMaps[index].farPlane;

    float currentDepth = length(fragToLight);
    float bias = 0.05;
    float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;

    return shadow;
}

More screenshots