DEVLOG: Grace Self-Learns Computer Graphics.

As an artist and software person, I've always been drawn to computer graphics on a high-level. To me, it is about time to dive deeper into it!

Work in Progress
Preview of Grace's computer graphics projects including ray tracing and rasterization

Tech Stack

Jump to Entry:

Graphics Rasterizer Series
Ray Tracer Series
πŸ“… August 8, 2025

Reverse Engineering OpenGL by Building my Own Graphics Renderer from Scratch

I wanted to learn more deeply how OpenGL works by writing a simplified clone and suffering through the learning process. With no third-party libraries, I am trying to get an image like this one (insert image after i figure out how to render stuff):

πŸ“… July 29, 2025

Migrating My Implementation to CUDA

Smart engineers have already done the hard work of speeding up the ray tracing process lmao. Even with my unoptimized C++ raytracer right now, I can just use CUDA and it'll be over 10x faster. I will be referencing Accelerated Ray Tracing Using CUDA today. This man absolutely glazes the Ray Tracing in One Weekend fundamentals and rightfully so. I am glad I started with that first so I can jump right in.

πŸ“… July 28, 2025

Attempt at Optimizing the Ray Tracer (BVH and Multithreading)

If I don't my raytracer to immediately fry my laptop when rendering objects with more vertices, I need to make some optimizations! I focused on implementing the Bounding Volume Hierarchy (BVH) algorithm from Ray Tracing the Next Week and multithreading and first. I also do want my program to be faster on average, I will use CUDA after this! But for now:

Bounding Volume Hierarchy wikipedia article on this neat thing: In short, this algorithm is a glorified binary tree. In long, it is a binary tree acceleration structure that dramatically speeds up ray-object intersection tests. Instead of testing every object in the scene, BVH organizes objects in a tree where each node has an axis-aligned bounding box (a simple rectangular box aligned with the coordinate axes that completely encloses an object, if a ray misses a bounding box, it misses everything inside), and the leaf nodes will contain 1-2 objects of actual geometry. TL;DR, objects close in space are grouped together, if a ray misses a box the whole subtree is skipped, and we always choose the longest axis to split on.

This BVH optimization reduces ray-intersection tests from O(n) to O(logn) This is my basic algorithm:

    bvh_node(std::vector> &objects, size_t start, size_t end)
    {
    // 1. calculate bounding box for all objects in range using AABB
    bbox = aabb();
    for (size_t i = start; i < end; i++) {
        bbox = aabb::surrounding_box(bbox, get_bounding_box_static(objects[i]));
    }
    
    // 2. shoose split axis (longest dimension)
    int axis = bbox.longest_axis();
    
    // 3. Handle the base cases for if we have a single object or two objects
    if (object_span == 1) {
        left = right = objects[start];  
    }
    else if (object_span == 2) {
        left = objects[start];          
        right = objects[start + 1];
    }
    else {
        // 4. If more than 2 objects, we sort objects along chosen axis
        std::sort(objects.begin() + start, objects.begin() + end,
                  [axis](const shared_ptr &a, const shared_ptr &b) {
                      return get_bounding_box_static(a).axis_interval(axis).min 
                             get_bounding_box_static(b).axis_interval(axis).min;
                  });
        
        // 5. we split in middle and recurse amongst the tree
        auto mid = start + object_span / 2;
        left = make_shared(objects, start, mid);
        right = make_shared(objects, mid, end);
    }
}
        

MultiThreading: (I will give this one my best shot. I take OS and Systems Programming in the fall, this is what I only know right now.) Anyways, unoptimized ray tracing is considered "embarrassingly parallel" - each pixel can be computed independently, so we can optimize via a multithreading approach. I divide the image we are going to render into horizontal strips and assign each thread to a different CPU thread. Each thread will render its assigned row by doing the same old ray tracer behavior as always--shoot rays through pixels and calculate colors--and we write the results to SEPARATE parts of a SHARED image buffer. I use an atomic counter to track thread progress, and just mutex for ensuring on thread writes progress at a time to the console. Once all threads finishes their strips, the main thread finally combines all the results and outputs the final image.

I first import this to my camera.h class:

#include         // for std::thread
#include         // for std::vector
#include          // for std::mutex, std::lock_guard
#include         // for std::atomic
        

We query the hardware for vailable CPU cores and create a static thread pool.

unsigned int num_threads = std::thread::hardware_concurrency();

We divide the image into horizontal strips where each thread is responsible for a contingous block.

//something like this!
int rows_per_thread = image_height / num_threads;
for (unsigned int t = 0; t < num_threads; t++) {
    int start_row = t * rows_per_thread;
    int end_row = (t == num_threads - 1) ? image_height : (t + 1) * rows_per_thread;
    threads.emplace_back(render_chunk, start_row, end_row);
}

I also wrote each thread to distinct memory locations in the image buffer. The main threaad will block until all worker threads complete.

πŸ“… July 27, 2025

Coding My First Ray Tracer - Technicals

TL;DR: I love how some 2d hand-drawn anime music videos mix in rendered 3D backgrounds/objects, so I’m making my own ray tracer to learn more about graphics and create cool renders for my projects. Just for fun, you know? The end goal is to have a decent, slightly optimized ray tracer with a GUI and camera system so I can load in 3d models and render them. You can read about my (highkey funny) full motivation here

Here's what it looks at as of this entry:

 the ray tracer render as of 7/28

Coding it Up: Anyways, technical part. One of the best resources out there is Ray Tracing in One Weekend, which I am just wrapping up learning. I closely followed the book initially, and took notes of the important concepts. Which is like, everything because it's quite the dense book lol. Case in point:

 First ray tracer render
schizo notes from learning
↑ Back to Top

I'll mention the notable parts here:

First Image: We need to write the renderer to image somehow, and the most straightfoward is to write it out as a PPM stored in RGB format. If your IDE cannot visualize it as an image, this is my favorite site to use: PPM image viewer. Note that the code is written to standard output stream, so we use the redirection > operator to write it to an image file. Personally I use ++ -o main main.cpp to build the program and .\main.exe > image.ppm to run the program.

#include 

int main() {

    // Image

    int image_width = 256;
    int image_height = 256;

    // Render

    std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

    for (int j = 0; j < image_height; j++) {
        std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
        for (int i = 0; i < image_width; i++) {
            auto r = double(i) / (image_width-1);
            auto g = double(j) / (image_height-1);
            auto b = 0.0;

            int ir = int(255.999 * r);
            int ig = int(255.999 * g);
            int ib = int(255.999 * b);

            std::cout << ir << ' ' << ig << ' ' << ib << '\n';
        }
    }
    std::clog << "\rDone.                 \n";
}

It'll output an image here.

first ppm image render!
first ppm image render of 256px x 256px!

more writeup to come...let my wrist rest...

πŸ“… July 27, 2025

Coding My First Ray Tracer - Motivations and Inspiration (Spoiler: It's Because I'm A Weeb)

TL;DR: I love how some 2d hand-drawn anime music videos mix in rendered 3D backgrounds/objects, so I’m making my own ray tracer to learn more about graphics and create cool renders for my projects. Just for fun, you know? The end goal is to have a decent, (at least) slightly optimized ray tracer with a GUI and camera system so I can load in 3d models and render them.

Long Story for the Cool People: Recently I've been into computer graphics, right? So, I've been looking into other cool projects to do so I can learn more. Then, Twisted Wonderland's Diasomnia Dorm's Music Video dropped and bam, inspiration! (girl bye imagine you're a victorian child starving to death and the last thing you read is this string of words.) In general, I have always liked how anime/vocaloid/jpop MV's frequently just have 3D rendered backgrounds/objects overlaid/underlaid over the hand-drawn 2d art.

Basically, I like how they illuminated these columns LOL and I was wondering how I'd recreate this effect with a ray tracer

music video inspiration
music video inspiration

My schizo instagram story might also sum up my thought process:

 First ray tracer render

I think the use case will turn out pretty funny, I want to render objects and make my own version of like, shitty MS paint remakes of anime openings, in the most convoluted way. It's like me growing the grain and making the yeast so I can make a loaf of bread

πŸ“… July 15, 2025

Chappell Roan Good Luck Babe Ahh Globe Drawn With Maths

This is the project in question

High Level: This shader draws a textured sphere plus another slightly larger and goofier textured sphere. Everything drawn here comes from maths. I was learning from this video and translated his basic instructions to shader code. For my level of expertise, it is still a bit of a challenge.

Also, this is the joke:

starting off strong
guys i swear it was funny in my head

STEP 1: Draw a circle, normalize the coordinates to [-1,1]. We then calculate distance from the circle and with the cool step function, we create a hard edge where points outside the radius is colored black.

starting off strong

STEP 2: Convert the pixel locations to 3d locations on the sphere using the general distance formula, and start rotating with a rotation matrix about y

starting off strong

STEP 3: Toss in some Fractal Brownian Motion which is just summing up waves to simulate a terrain. Map some colors to the various heights it simulates:

starting off strong
I should get a VSCode Extension for shader languages...
πŸ“… July 9, 2025

And so it begins...

The story behind all this is that I have been wondering how I could combine my art skills with programming. One of the engineers at my current internship at Cepton suggested I learn computer graphics/graphics programming, especially on a lower level of abstraction. It still requires an artistic eye, after all. And, I was already using Rust and WGSL (web gpu shader langauge or something) for my job and I liked it a lot. I also took an introductory computer graphics class in my first semester at college and loved it. I already really like Three.JS projects for the web. Maybe now is my calling to dive in deep.

Understanding graphics needs math and low-level knowledge to truly understand. And so out of fear ngl, I said, "I'm not good at low-level!" But the aforementioned engineer said, "i think you're more than capable enough to be suitable for whatever you enjoy doing" and "also bro you’ll be good at low level don’t sweat it" (thanks Jacob Bokor!) He also suggested I check out Acerola, a graphics programmer who is insane in his field. He does seem very knowledgeble and introduced me to a subset of software engineering that I never considered as a skill I could hone (like, I never thought about being capable of it) or profession.

starting off strong
From Acerola's "What is a Graphics Programmer?" video. He mad funny and explained the field very well. I do maxx out on math and comp sci! I thought I could give this a shot!

As this is the case, I will try it out. This is day 1, maybe on day anyone who is reading this (hi me!) in the future will think "wow, this is inspiring, this is thoughtful." I barely know C, C++ right now. I've only taken an intro to computer graphics class--more like the math behind it and how color is optimized to display on a screen-- and touched on Computer Organization and OS relatively lightly. Uh to defend myself I am just a sophomore right now. As this is the case, I have a long way to self-learn, to dive deeper, to take Systems Engineering, Comp Arch and OS this fall and spring. But, most of the learning must be driven by myself, I am the only one responsible for how deep I dive.

I hope that people, myself included, can see that consistent effort within a short amount of time can lead to great learning and great results. Or, if I eventually threw in the rug (god forbid) and gave up, I don't think anything is for naught. I will have gotten a lot better at low-level and writing to GPU and stuff. But I hope I like this.

The plan is to start by speedrunning most of OpenGL's tutorials, learnopengl.com. Though it is outdated and overshadowed by the much better WebGL, this is still a solid starting point because graphics pipeline stages are identical, shader programming should be similar, and the matrix math specifically will be identical no matter the language. I will laern Vulkan after! I just don't want to spend a thousand years drawing a triangle to the screen just yet. Give me a week.

starting off strong
most readable notes #1 in the world tbh. based off learnopengl.com, it is a really good resource!
awesome textbook
Great textbook! I love free and open source stuffs!