Graduation

Black and white photo of a man's shadow wearing graduation attire

Hi all, sorry for the huge delay in updates, hopefully you can cut me a just little slack… as I finally graduated! I took an admittedly long break after classes ended in June and I am so happy to be able to say that I have officially completed my bachelor’s degree in Computer Science. I was just going over some of my projects this afternoon as I continue to refine my CV and it’s really incredible how far I’ve come. Like many of life’s great moments I couldn’t have done any of this without support, and I want to thank my partner Valerie. From the bottom of my heart, I appreciate all that you’ve done to help me on this journey.

My final projects for Computer Graphics Shaders as well as Intro to Databases went exceptionally well. For my shaders class I chose to create a realistic motion blur based on documentation in Nvidia’s GPU Gems 3. I was rather excited about this project and I’d like to go through a few details for anyone who might be interested, otherwise feel free to skip ahead.

I used a two pass process with OpenGL and GLSL in which I first simply rendered an object to a texture. Then to create a per-fragment blur effect I sample the depth buffer in the fragment shader to find each pixel’s current position and world position.

// Sample depth buffer
float dbAtPixel = texture(uDepthBuf, vec3(st, 1.));

// Find view position
vec4 viewAtPixel = vec4(s * 2 - 1, (1 - t) * 2 - 1, dbAtPixel, 1);

// Convert to world coords, -1 to 1
vec4 worldPos = viewAtPixel / viewAtPixel.w;

Next, I multiply the world position by a “blur position” (a stand-in for the direction of movement) to find a previous position. This allows me to calculate a velocity.

// No previous view in a static image, so we make one up with uBlurPos
vec4 prevPos = worldPos * uBlurPos;

// Put in range -1 to 1
prevPos = prevPos / prevPos.w;

// Find pixel velocity and scale it if desired
vec2 velocity = uVelScale *  vec2((currPos - prevPos)/2.);

In the third and final stage I sample the color buffer in a loop, using the velocity to cacluate each fragments color. The number of times the color buffer is sampled directly impacts the quality of the effect, with higher sample rates resulting in a smoother and more realistic blur.

// Sample color buffer
vec4 color = texture(uColorBuf, st);

// Add velocity to st coords
st += velocity;

// Continue sampling color buffer until preferred number of samples is reached
for (int i = 1; i < uNumSamples; ++i, st += velocity) {
  vec4 rgba = texture(uColorBuf, st);
  color += rgba;
}

// Average samples to get blur color
color = color / uNumSamples;

Of course, all of that was very boring if you don’t know what it means. Let’s see what it actually looks like!

2D bunny with orange and red stripes 2D bunny with orange and red stripes and a low quality blur 2D bunny with orange and red stripes and a high quality blur

With those two classes completed I began the spring term and my final Capstone Project, a three month long grind to produce a complete piece of professional quality software. I was grouped with two other students and selected for the “3D Escape Room Game” - a video game intended to mimic the experience of a real life escape room. This was the first full video game we had ever created so naturally I was incredibly excited, but quite nervous too! I’ll have a lot more to say about this project in the near future, I was required to write a few blog-style assignments so I intend on posting those as a series too. Unfortunately I don’t think I’m allowed to make our code public, but on the bright side you will be able to download and actually play the game!