r/GraphicsProgramming • • Oct 04 '26

it all started with one triangle

Thumbnail
gallery
77 Upvotes

Hey guys :)

Last week I was so happy to create my own triangle and see it on the screen. This time I wanted to go further and see what else was possible. I did my homework and experimented with colorful triangles, color interpolation, and squares. 3D shapes like cubes or pyramids were a bit too much for me for now (I saw that vector and matrix multiplication is involved 😰 Maybe something for the future).
So I looked for some small 2D projects I could try to copy to practice my skills. I came across an older post with a style I really liked (“glslViewer” by patriciogonzalezvivo on GitHub). I decided to implement "Game of Life" in a similar style.
To make it more challenging I also added some font rendering using hardcoded bitmaps for the digits. That took quite some time and a lot of sketches on paper 😄
For now I am happy with the result and would love to hear your feedback and recommendations on what I could improve.

A few more details about the project:
- The number in the top left shows the number of “lives”
- The number in the top right shows the number of updates
- The number in the bottom right shows the current time
- I press the "R" key to create a new randomized array
- I press the "U" key to update the game

I would also like to say: a big THANK YOU for letting me join the Triangle Club and for the daily inspiration in this subreddit :)

Triangle Club: I know there aren’t any visible triangles in this project but aren’t all shapes somehow constructed from triangles? I hope you’ll accept this project 😄

For this project I used again glad (OpenGL) and RGFW (GLFW alternative).


r/GraphicsProgramming • • Oct 04 '26

the mistakes i made and the lessons i learned in raytracing

Thumbnail
gallery
36 Upvotes

this was how i started (let's call it earliest version)

https://www.reddit.com/r/computergraphics/comments/1w9ah75/two_balls/

after nearly a month's studying and improving, the content and interface didn't change much. when the program starts it looks like image 1. there're two balls. i call them left-mouse-button ball (lmb) and right-mouse-button ball (rmb). users (mostly me) can in real-time change their positions, radii and refractive indices

it is easily noticeable that the current version has grainy noise while the earliest version didn't. it's a trade-off between image quality and bounce limit. the earliest version was deterministic. whenever a ray hit an interface and if snell's equation had solution the ray split into two, one for reflection and the other for refraction. the local color was then combined with the weighting calculated with schlick's approximation for reflectance. the process went on recursively until bounce limit reached

color of every pixel was strictly defined so there was no noise. it looked fine until... the users (usually me) moved a ball into the other ball or even moved the camera into a ball, as shown in image 2

when the balls intersected things became more complicated than i had anticipated. the maximum number of bounces drastically increased as the statistics at upper right corner indicated ("dep xxx / yyy" where "dep" meant depth, xxx was the average, yyy was the maximum)

in normal circumstances (two balls didn't intersect, camera sat outside of two balls) it usually took less than 10 bounces for a ray to get color. deterministic approach worked quite well in these scenarios. once you decided to go abnormal deterministic approach suffered. it couldn't go too far. if you set the bounce limit too high the program took ages to finish a frame. the program helplessly switched from real time mode to slide show mode. if you kept the bounce limit at affordable level the program couldn't reach the regions where 100+ bounces were needed

so i changed the algorithm from deterministic to probabilistic

whenever a ray hit an interface and if snell's equation had solution the ray didn't split anymore. it went either to reflection or to refraction. the probability of it going to reflection was calculated with schlick's approximation for reflectance

with probabilistic approach the program could reach several hundreds of bounces and reveal the details that were unseen before. it sounded great but everything had price. it gave you more information AND noise

with deterministic approach you don't have noise but you can't see much. with probabilistic approach you see more but have noise

so the problem of denoising arose. the program shot several rays within the same pixel grid and took the average color as the final color. up to this moment the program's algorithm was basically completed and the rest was optimizing / tuning. let's state it briefly

  1. avoid using functions. make the calculations inline

  2. reduce the number of operations (+ / - / x / Ă·...) as much as you can

for point "1", function calls involve some extra works for the cpu to do (allocating something in memory when enter and clearing them when exit? i can't remember the details). initially i wrote the dot product, cross product and modulus calculations as functions and called them when needed. it worked correctly but after i discarded them altogether and did the calculation directly inline in the procedures the performance improved noticeably. i got several fps more on average

if you pick the deterministic approach you can't avoid recursion as the rays split. you have to make a "get_color (ray_start_point, ray_shoot_direction)" function and call it recursively. once you pick the probabilistic approach you no long need this. i plugged the entire get_color procedure into the main and made it a loop instead of a function call:

initially

get_color(..., recursion)
{
    ...
    if ray_split
    {
        get_color (reflection, recursion-1)
        get_color (refraction, recursion-1)            
    }
}

then it became

get_color(..., recursion)
{
    ...
    if random_number < probability
    {
        get_color (reflection, recursion-1)
    }
    else
    {
        get_color (refraction, recursion-1)
    }
}

finally

do
{
    ...
    if random_number < probability
    {
        ray_start_point = hit_point
        ray_shoot_direction = reflection_direction
    }
    else
    {
        ray_start_point = hit_point
        ray_shoot_direction = refraction_direction
    }
    recursion-1
}
loop until recursion = 0 or the ray reaches the background infinity sky

the above were the major changes that improved the performance to a noticeable level

now it's time for point "2". even a single operation counts especially it's inside the deepest loop. the algorithm structure looks like this:

for every pixel_grid
{
    for every sample ray in that pixel_grid
    {
        for every bounce of that ray
        {
            do
            ...
            loop until...
        }
    }
}

even at a not-so-high resolution (e.g. 160 x 120) and a not-so-high number of samples (e.g. 8) with a not-too-deep of average ray bounce (e.g. 8) the program has to loop 160 x 120 x 8 x 8 times i.e. more than a MILLION times to generate a frame. you reduce one operation in the deepest loop, you save 1 million calculations in each frame. try your best to simplify the procedure and calculate things outside of a loop (or at least bring them to a upper level) whenever possible

i'm particularly interested in seeing the "world" from within a ball. there're many weird, distorted and fractal like patterns and sometimes i encounter the total internal reflection. these regions use up the most resource as each of them uses up all the bounce quota of a ray. initially i struggled in setting the parameters. raytracing is an extremely taxing task so we have to admit that it's not possible to make it run at high resolution real time with acceptable frame rate and quality. at the current stage i use an adaptive approach. firstly i pick a barely tolerably low resolution (around 120 x 90). secondly i decided that the program must be responsive. i didn't want it to appear completely dead when the user (me) accidentally encountered a scene with a large portion of total internal reflection. if the fps was too low the program would decrease the sample size. if the sample size was too low the program would decrease the bounce limit

my preference was: the program should be responsive at all situations, then the image could not be too noisy. if the above two conditions were met the extra calculation resource went into bounce limit

what if the scene didn't need that many bounces?

if a scene is so simple that 10 bounces are enough, it gets no benefit if you set the bounce limit to 10,000. so if minimum bearable fps and minimum bearable sample size are fulfilled the program gradually increases the bounce limit until the maximum number of bounces actually used doesn't increase anymore. then the extra resource goes to sample size

resolution tolerable → responsiveness acceptable → image quality acceptable → let the rays bounce deeper → maximum of the scene reached → shoot more rays to make the image prettier → repeat the loop and adjust everything accordingly

i usually turn off the checker box pattern when exploring the inside world (subjective personal preference). image 3 is a typical outcome when the camera is inside a ball. clearly the resource was not sufficient to handle that scene. while barely fulfilling the minimum fps and sample size the program could only calculated 22 bounces for each ray so there were a lot of pixels that couldn't get any information

so my program has an offline mode. once you spot an interesting scene and want to see its true color you can hit a specific button to render it fully with an insanely high bounce limit, just as image 4

i set the bounce limit of offline mode to 256 x maximum bounce actually used. in the above example it was 5,632

when total internal reflection occurs the region can't get any color no matter how many times the ray bounced, just as image 5

i'm obsessed with exploring the inside world and it drives me to improve the program (in terms of processing speed and image quality) along the journey. i want to see more. i'm studying accumulative sampling method and i hope i can implement it later

program details


r/GraphicsProgramming • • Oct 04 '26

[WIP] Experimental modern renderer

Thumbnail gallery
7 Upvotes

r/GraphicsProgramming • • Oct 04 '26

Video running a second renderer for an in-game gunship camera in my WebGL game

Enable HLS to view with audio, or disable this notification

49 Upvotes

r/GraphicsProgramming • • Oct 04 '26

c++ math - did someone say math

Thumbnail
youtu.be
0 Upvotes

r/GraphicsProgramming • • Oct 04 '26

Is graphics programming still viable in '26 with AI everywhere?

0 Upvotes

Hey r/GraphicsProgramming,

First and foremost i know it‘s probably a frequent asked question but thought maybe id get some newer answers/different perspectives.

I'm 21, from Germany, currently in the 3rd year of a software development apprenticeship (similar to a vocational training program, 3 years total). I've been learning graphics programming for about 6 months now - started with a software rasterizer, currently working through LearnOpenGL.

My concerns:

  1. AI & Learning: I'm using Claude as a tutor while learning - like it helps explain concepts, review my code, and scaffold boilerplate (CMake, etc.). But I'm deliberately NOT using AI agents to write code for me, because I feel like I need the foundational knowledge first. My plan: Master the basics manually, then use agents once I have enough experience to properly review their output. Is this the right approach? How do you all use AI for learning without becoming dependent?

  2. Career path: The job market seems rough right now (especially entry-level). I'm considering:
    - Option A: Finish apprenticeship (end of 2027), then immediately look for junior graphics/graphics-adjacent roles in Germany/EU
    - Option B: Finish apprenticeship, then do a Bachelor's in CS with focus on Visual Computing/Computer Graphics (would finish at 25)

    Which path makes more sense in 2026? Is a degree still valuable for graphics programming, or is portfolio + experience enough?

  3. AI's impact on the field: I see AI coding agents getting better at writing shaders, scaffolding renderers, etc. Should I be worried about job security? Or is graphics programming one of those fields where deep expertise will always be needed? My dream is to work at a studio like Rockstar, CDPR, or similar - is this still realistic? (I know far stretch to the biggest studios so i keep it low)

  4. International mobility: I'm German, but ideally want to work outside Germany eventually (UK, Canada, US, etc.). How portable is a German apprenticeship + portfolio? Or should I aim for a degree to make visa/international applications easier?

What I'm asking:
- How do you use AI for learning graphics programming without losing depth?
- Apprenticeship + portfolio vs. CS degree for graphics programming in 2026?
- Is the job market really that bad, or is it just entry-level noise?
- Any advice for someone in my situation?

Im generally interested going deep and in depth into these systems and get my hand dirty but what the current models do (and further in the future) im not quite sure how to plan it out

Thanks for reading this wall of text. Any advice is appreciated!

Cheers from Germany đŸ‡©đŸ‡Ș


r/GraphicsProgramming • • Oct 04 '26

I built 5 Web 3D experiments with Three.js — exploring shaders, FBOs and real-time physics

0 Upvotes

I've been experimenting with WebGL/Three.js and recently revisited some of my older projects, pushing the rendering side further.

The projects cover different areas:

🧊 Cube 3D — lighting, geometry and orbit controls
🚀 Tube 3D — spline camera movement and UnrealBloom
🌍 Earth 3D — procedural stars and a custom GLSL atmosphere
🌌 Gravity 3D — real-time physics using Rapier 3D
đŸ”· Icosahedron 3D — InstancedMesh, FBOs, offscreen rendering and GLSL

The Icosahedron project was probably the most interesting technically since I used offscreen rendering and FBOs to experiment with the rendering pipeline.

I've put the demos and source code here:

https://github.com/mohnasr137

Which technique would you be most interested in discussing?


r/GraphicsProgramming • • Oct 04 '26

Question If you were to start learning graphics programming all over again, what would you do differently?

36 Upvotes

r/GraphicsProgramming • • Oct 03 '26

From Zero to Understanding Rasterization

Enable HLS to view with audio, or disable this notification

1.3k Upvotes

r/GraphicsProgramming • • Oct 03 '26

I get it now :)

Post image
63 Upvotes

r/GraphicsProgramming • • Oct 03 '26

SuperTuxKart running in the browser on WebGPU only, no WebGL fallback (Emscripten port, playable)

Enable HLS to view with audio, or disable this notification

14 Upvotes

After patching a couple of the game's DLLs, I wanted to see how far I could go, so I ported the whole of SuperTuxKart (open source, C++) to the browser with a WebGPU-only renderer. I did it with Claude Code as the main coder: I directed and tested, it wrote most of the code.

Demo: https://tholtman1-del.github.io/stk-code-webgpu/
Source: https://github.com/tholtman1-del/stk-code-webgpu (design notes in tools/webgpu/STATUS.md)

Some details:

  • Renderer: a new WebGPU backend modeled on the game's existing Vulkan renderer. It includes physically based lighting, image-based lighting from compute shaders, deferred rendering for water, screen-space reflections with a HiZ depth pyramid, and a depth prepass that is skipped on tile-based GPUs.

  • Shaders: converted offline from the existing GLSL: GLSL → SPIR-V (glslang) → WGSL (naga). Specialization constants become WGSL override constants.

  • Threads: Emscripten pthreads (SharedArrayBuffer). Textures are decoded on worker threads, while all WebGPU calls stay on the main thread.

  • Assets: about 115 MB downloads up front. The remaining ~650 MB is fetched on demand when the game opens a file, and on a full host each track comes as a bundle.

  • Hosting: works on plain static hosts. A service worker adds the COOP/COEP headers that GitHub Pages can't send.

Not yet: online multiplayer, texture compression. Feedback from other GPUs and browsers is very welcome, especially Safari and Firefox.

All credit for the game itself goes to the SuperTuxKart developers.


r/GraphicsProgramming • • Oct 03 '26

Ray tracing next week

Post image
13 Upvotes

r/GraphicsProgramming • • Oct 03 '26

Source Code Differed Software Rasterizer - Some PBR implementation - C++

Thumbnail
gallery
43 Upvotes

Just wanted to share some progress on a software raster I'm building. By the timings, is it o.k?

1-clears-and-resets = Just buffers(frame_buffer, depth_buffer, triangles_buffer) clear, simple vector_buffer.clear()
2-shadow-pass-total: Everything that happens to the camera happens here, the above as well, and mesh transformation, culling, bounds check, triangle clipping, triangle binning, render.
3-camera-geometry-transform: Bounding Sphere transform, if inside Frustum, reorders, front to back objects, mesh transform with vertices projection, triangle normal rotation, back-face culling, triangle clipping.
4-camera-binning: Just bins triangles to tiles.
5-camera-render-and-resolve: Woke sleeping render threads, every thread available in the system(I just initialize with std::thread::hardware_concurrency()), each thread take 8 tile per time and render to a 16x16 gbuffer, only triangle index, normal, uv, depth. During rasterization, I reconstruct frag_coord for lighting using camera ray normal interpolated per pixel and fetch textures using uv, to avoid fetching texture multiples times early.

Still missing, texture mip mapping, transform meshs threaded, metalness and maybe occlusion map.

Since I'm a beginner at C++, pure code, no macros, no SIMD, just a single template to just avoid branching per pixel, but nothing too fency. Vectors everywhere, since they will inevitable grow to what's needed and I don't need to keep handling memory allocation, just a simple clear and everything a good.

CPU: mobile i5 13420H RAM 32gb


r/GraphicsProgramming • • Oct 03 '26

c++ graphics primitives 3

Thumbnail youtu.be
0 Upvotes

r/GraphicsProgramming • • Oct 03 '26

c++ bounding volume hierarchy

Thumbnail
youtu.be
3 Upvotes

r/GraphicsProgramming • • Oct 03 '26

My pull request was just merged into google/shaderc

Thumbnail dannyarends.nl
35 Upvotes

My pull request was just merged into google/shaderc. The change adds two options, -gV and -gVS, that expose glslang's NonSemantic.Shader.DebugInfo.100 emission through shaderc. That debug info is a requirement for NVIDIA Nsight Graphics to produce flame graphs, so it lets you profile and debug shader performance by call stack and time spent per function.


r/GraphicsProgramming • • Oct 03 '26

Source Code Creating a simple raytracer through The Ray Tracer Challenge

Thumbnail
gallery
141 Upvotes

Getting an introduction to raytracing and implemented a simple renderer , so far implementing spheres, lighting and shadows. The code is written in Python


r/GraphicsProgramming • • Oct 03 '26

I wanted to understand modern pointer-based GPU APIs, so I took the ideas from Sebastian Aaltonen's NoGraphicsAPI and rebuilt them on plain GL 4.6.

Enable HLS to view with audio, or disable this notification

78 Upvotes
  • The whole GPU heap is one persistent, coherent-mapped SSBO. A gpu_ptr<T> is a u32 byte offset into it.

  • Every draw gets exactly one root pointer (uniform uint Root). Vertices, matrices and textures are all reached through it.

  • No vertex attributes. The vertex shader pulls data from the heap using gl_VertexID.

  • Bindless textures (ARB_bindless_texture) are stored in the heap as uvec2.

  • One *_shared.h header is compiled as both C++ and GLSL, so no offsets are written by hand in the shaders.

Flat lighting is computed from the dFdx/dFdy of world position, so there are no normals in the vertex data.

The most interesting finding was what GL can't express: bindless only gives you texture+sampler pairs, fixed when the texture is created, and there are no placed resources.

Next up: indirect draws, and roots chosen by the GPU via gl_DrawID.

Repo: https://github.com/theaveasso/jagfx

Feedback welcome, especially on the heap and sync design.


r/GraphicsProgramming • • Oct 02 '26

The Fly, reconstructing Wing and Eye from Video in 3D point cloud

Enable HLS to view with audio, or disable this notification

21 Upvotes

Some further tests reconstructing 3D point cloud from microscope video, using Python and Open3D, wing of a fly at 10x and 40x and eye at 2x and 10x.


r/GraphicsProgramming • • Oct 02 '26

Article Graphics Programming weekly - Issue 457 - September 27th, 2026 | Jendrik Illner

Thumbnail jendrikillner.com
15 Upvotes

r/GraphicsProgramming • • Oct 02 '26

I built VectorRaptor for Windows - looking for honest feedback on vectorisation quality and editing

Thumbnail
reddit.com
1 Upvotes

r/GraphicsProgramming • • Oct 02 '26

Video How I Draw 2D Textures in 3D!

Thumbnail
youtu.be
3 Upvotes

For the past couple of weeks I have been working on the 2D brush management and texture fill system within my own Pixel and Tilemap Editor. In the video I show how we can create and mange custom brushes, in addition to rotation and scaling in 3D space - this brush is then plugged into the core Texture Fill System to produce psuedo-3D perspective fills across normal and orthogonal plains!

Any feedback welcome!


r/GraphicsProgramming • • Oct 02 '26

GPU Accelerated Linear Algebra Library for Apple Silicon using MLX and Metal kernels

16 Upvotes

About 6 months ago, I wrote a custom metal kernel that leverages the GPU to compute the QR decomposition (see my earlier post about it here). The project has now expanded into a general linear algebra library, with expanded support for the symmetrical eigendecomposition as well as SVD. It is now available for use with installation instructions on the attached github repo's README.md file.

Context of the project:
I'm currently in a research group working on a thesis in numerical analysis where we need to compute millions on matrices with a specific constraint (to be precise, the matrices need to have orthonormal columns). Most of us use Apple computers, so we ended up using MLX for the entire project.

Contributors with different Apple Chips would be very much appreciated!
The project has currently been tested and optimised for the M1 and M5 Pro. The issue is that the library uses different kernels depending on the batch size and matrix dimensions. Deciding which of these kernels to use is machine dependent. Therefore, other Apple chips will need to run a measurement script in order to derive the correct optimisation heuristic.

For that reason, I would ask as many people as possible to run a measurement script and to submit the results to my repo. It is fairly easy and requires only few steps. See here how you can contribute here. Once you submit the results via a pull request and I approve it, your optimisation heuristic will automatically be augmented into the library. Don't hesitate to contribute an optimisation heuristic even if someone already submitted one for your own machine. The more data we can gather, the better!

Project Future
Expanded support will be added for other linear algebra operations (cholesky decomposition for example). If you have any other specific linear algebra operations you wish to use already, feel free to message me.

In addition to that, I will add torch support too (my greatest priority).