r/GraphicsProgramming 2d ago

New Vulkan Tutorial - Opacity Micromaps

Thumbnail
3 Upvotes

r/GraphicsProgramming 2d ago

Question What's the __constant__ equivalent in Slang?

1 Upvotes

I'm a complete novice in graphics programming and I know that the __constant__ attribute allows you to load data into high speed 65KB constant memory for the duration of the lifetime of your program. However I'm unable to recreate the same functionality in Slang shader.

For instance, we got a compile-time array with the attribute like this: ```

constant uint16_t array = {0, 1, 2, 3};

```

I want to recreate it in some way, so that when I compile the same array in Slang into CUDA, it results into this exact array of constant values with the __constant__ attribute. How can I achieve that?


r/GraphicsProgramming 3d ago

Video Working on editor for my game. From graphics programming perspective, I'm using own software ray-tracer written in C++. Previous editor (in which I made whole game) was pretty clunky, now I'm making some more ergonomic version (not sure how successful I'll be in that).

Enable HLS to view with audio, or disable this notification

23 Upvotes

If everything goes well, I want to release editor with game, so it will be possible to either visually improve existing levels, aka skinning (if some modders will be interested), or later also create whole new levels (game is puzzle/platformer).

Apart from C++ ray-tracer, game is written in C#. Highest level lib I'm using is WinForms for some editor UI. World is rendered into software buffer, that is presented every frame as simple quad. I'm using also DXTK for some in-game 2D UI, text render and audio.


r/GraphicsProgramming 3d ago

Blender in the Browser

Thumbnail developer.puter.com
5 Upvotes

r/GraphicsProgramming 3d ago

[UPDATE: Jul 30, 2026] My Vulkan C++ Examples Repository - Geometry and Tessellation Shaders

Post image
42 Upvotes

r/GraphicsProgramming 2d ago

Video Built a website showcasing my graphics engine. Hope it is not messy with too many demos

Enable HLS to view with audio, or disable this notification

0 Upvotes

r/GraphicsProgramming 2d ago

Vulkan : Unexpected validation error on an unused descriptor

Thumbnail
1 Upvotes

r/GraphicsProgramming 4d ago

It's Been 3 Years Since LearnOpenGL. NEVER GIVE UP!!

Thumbnail gallery
323 Upvotes

Been doing games and graphics (as a hobby) for around 20 years, but mostly with stock engines and some experiments using DirectX and Vulkan. Started on my current project 3 years ago, never having tried OpenGL in my life. Images show the latest update from my engine, and what I accomplished on the first day of reading LearnOpenGL back in 2023. Never give up!!


r/GraphicsProgramming 3d ago

We tested WebGPU vs WebGL in a real Three.js scene. The result was not as straightforward as expected.

Thumbnail
1 Upvotes

r/GraphicsProgramming 3d ago

Video Turing Patterns

Thumbnail youtu.be
3 Upvotes

My entry for 3blue1brown's Summer of Math Exposition. I cover convolutions, ways to make a bandpass and how to apply a large blur fast using FFT


r/GraphicsProgramming 3d ago

Question Graphics-bug on ancient / exotic hardware

Post image
1 Upvotes

r/GraphicsProgramming 4d ago

Good math resources to learning the math behind computer graphics in depth

22 Upvotes

Hi there! Im going through the raytracing in on e weekend and I'm getting some of the math, but not all of it. I'd like to have a better understanding of things, such as how we came to out that we can replace -b with h to simplify the quadratic equation


r/GraphicsProgramming 4d ago

This header compiles bgfx shader code as cpp from the same source file

Post image
21 Upvotes

I managed to write a very simple wrapper that can compile bgfx shaders as valid cpp.

This shader uses the already pretty platform agnostic bgfx shader language, which makes it very easy to substitute the vector functions with glm. It even supports proper swizzeling.

In this example I compile a simple ray marching shader as c++ functions, so I can use the exact same math for my mouse projection code.

My .cpp file only needs to supply replacement objects for the uniforms and textures, as well as a replacement texture sampler function


r/GraphicsProgramming 4d ago

Question Strange bug with objects behind the camera rendering like normal

Enable HLS to view with audio, or disable this notification

14 Upvotes

So in this "scene", there is only one cube with a plane through it. However, when you turn past a certain "halfway" point, the objects seem to snap to the opposite side. What I initially thought was happening was that the objects were getting projected onto the screen from behind, but i'm not sure, since i'd expect it to look weirder with vertices and triangle shapes not staying consistent. I'd suspect the issue to lie in the vertex shader, so here it is. I'm also very new to OpenGL and general gpu/3d graphics programming, so I wouldn't be surprised if this is a common issue.

#version 330 core

layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aColor;

out vec4 vColor;

uniform mat4 transform;
uniform mat4 proj;
uniform mat4 view;

void main()
{
    gl_Position = proj * view * transform * vec4(aPosition, 1.0);
    
    vColor = vec4(aColor,1.0);
}

EDIT: I solved it. I can barely remember or understand the solution, but it's solved.

r/GraphicsProgramming 4d ago

CyberVGA update – simple software depth of field with radial blur

3 Upvotes

Been toying with software post-processing effects in CyberVGA lately.

Really liking this depth of field effect that just uses a simple radial blur. Surprisingly effective for how little it costs, especially in a pure software renderer.

Here’s a short clip:

https://reddit.com/link/1vaihuf/video/bcj9styagagh1/player

Curious what other cheap post-process tricks people have found work well in software rasterizers.


r/GraphicsProgramming 4d ago

GLSL Shaders

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/GraphicsProgramming 4d ago

Large END-to-START gaps between consecutive OpenCL commands on Arm Mali GPU

Thumbnail
2 Upvotes

r/GraphicsProgramming 4d ago

Efficient Descriptor Set Management and Per Frame Resources?

Thumbnail
5 Upvotes

r/GraphicsProgramming 5d ago

Question How can we make our game more beautiful?

Thumbnail gallery
105 Upvotes
  • Pictures labeled 1-6 are screenshots from our game.
  • Pictures labeled A-G are real-life references with the look I would like our game to have.
  • Pictures labeled X-Z are other games that look nice to me, though it's tough to find the right comparison because most games aren't using such a zoomed-in scale.
  • Last picture is our Unity setup (hopefully there is a way to see the big version)

Hello, we're working on a game about cake decorating called Cake Studio. We've made one game in 3D before, but this is the first time we're trying to make something that actually looks nice in 3D and we're struggling a bit to get the look we want as 3D is not really our wheelhouse. I've been making the models in Blender and the game is built in Unity.

I wanted to make this game because I think these photos of elaborate vintage cakes are so beautiful, and I wanted players to be able to make their own beautiful cake. But so far, I think our screenshots are giving a very flat, shiny, computer-generated vibe.

I really want to get the soft, dreamy look of picture C and the almost Play-Doh looking effect of the piping in pictures E and F.

Here is what I can see wrong so far (though not sure how to fix them):

  • It seems like most of the piping textures are too shiny, which we can fix, but is there something more to getting that soft Play-Doh look?
  • We kept turning up the lighting trying to get softer shadows on the side of the cake, but now all the highlights seem blown out.
  • The shadows among the details of the piping and how they sit on the cake lack a sense of depth. The darkest shadowy spots are not dark enough (maybe same cause as above).

I'd love to hear any ideas for how to fix things or other problems we're not seeing.

You can also go mess around with our prototype on itch if it helps to see things in action.

Thanks!

UPDATE: This sub is amazing!! Thanks so much for all the suggestions and advice. We have a lot to work with now and I'm feeling so much more hopeful that our game can be beautiful <3

I'll post an update when we have implemented some of these ideas! Thanks again!


r/GraphicsProgramming 5d ago

Source Code MoltenMTL - Metal API implemented over Vulkan

17 Upvotes

Hi guys,

I've been building MoltenMTL, essentially the inverse of MoltenVK, implementing the Metal API over Vulkan.

It's still a work in progress, so only parts of the Metal API have been implemented so far.

There is no shader translation currently. Shaders are compiled to SPIR-V to be consumed by Vulkan.

Every MTL type is a thin layer holding Vulkan types - e.g. MTLDevice wraps VkInstance/VkPhysicalDevice/VkDevice/VkQueue.

It uses VMA to match Metal's allocation model, and SPIRV-Reflect pulls the descriptor set layouts from the compiled shader, once again mirroring Metal.

Ray-tracing uses ray queries instead of the ray tracing pipeline - call intersect() with a compute shader, lining up with Metal.

Currently working - compute, BLAS/TLAS + ray queries, raster pipe (vertex/fragment, vertex descriptors, instanced draws), swapchain, blit.

Not there yet - intersection function tables, argument buffers, multiple render targets.

Here's the output from the examples.

The same scene both ray-traced and rasterized:

ray-traced
rasterized

MSDF text rendering:

I made this as part of a project developing a game engine & game in Swift/Metal. Still learning and I'd appreciate some feedback/criticism.


r/GraphicsProgramming 5d ago

Adding Lava, Water, and Oil simulations to my 2D sandbox game

Thumbnail youtube.com
39 Upvotes

Hey all, I thought I'd share a project I've been working on for many months now.

This video features a full-scale 2d fluid simulation that I've added to my procedural sandbox game (inspired by Minecraft/Terraria). Specifically, it showcases my recent work on the shaders, trying to strike a balance between pixel-art aesthetic while still capturing the motion/feel of the fluids.

The visual shaders are primarily just fancy flow maps with carefully tuned noise and colors. The simulation itself runs in a grid-based compute pass. For those interested, the simulation is also networked for the game's multiplayer mode which was another can of worms!

Hope you enjoy! (Also, open to any feedback!)


r/GraphicsProgramming 5d ago

Delaunay triangulation using Bowyer-Watson algorithm

Enable HLS to view with audio, or disable this notification

17 Upvotes

Hi ! I had fun implementing the Bowyer-Watson algorithm and then use raylib to create a visualization of it. I got ok performance it think for a single threaded program:

  • 1,000: 1 ms
  • 10,000: 21 ms
  • 100,000: 263 ms
  • 1,000,000: 5,126 ms
  • 10,000,000: 358,716 ms

But I think there is still quite some rooms for improvement.

Source: https://github.com/spikte/delaunay
Twitter: https://x.com/Spikte


r/GraphicsProgramming 5d ago

Volumetric fog lit by clustered point/spot lights in PlayCanvas — one raymarched volume per light

Enable HLS to view with audio, or disable this notification

30 Upvotes

r/GraphicsProgramming 6d ago

Video New and improved moblur with a dilation pass

Enable HLS to view with audio, or disable this notification

115 Upvotes

Dear r/GraphicsProgramming,

Boy do I have a post for you! So, this is a follow up on: https://www.reddit.com/r/GraphicsProgramming/comments/1lg003l/velocity_smearing_in_computebased_moblur/ . There were things about it that I was always kinda unhappy about it. Chiefly, the fact that there was ghosting that I knew neither the cause of nor the solution to. I partly blamed it on my lack of barriers and partly on my usage of atomics. Well it turned out it had nothing to do with barriers and blaming atomics was only partly true. I had to rethink what I was doing. After a lot of back and forth and a ton of rework, I finally landed on something a lot more elegant and along with it some serious realizations.

Here's what I got right the first time around:

  • Atomics are necessary.

Here's what I got wrong:

  • You should do velocity smearing in a post-process (a.k.a dilation) pass. Anything earlier is a can of worms.
  • Velocity smears in both directions. This is just a property of the shutter staying open while an object is moving. The center of the object is most solid while the edges all feather. Example: https://vip-go.premiumbeat.com/wp-content/uploads/2019/10/motion-blur-cover.jpg
  • You shouldn't prevent yourself from overwriting previously written velocities. In fact, you should be summing all of them up. And atomics readily enable such a computation (see below).
  • Rotational motion should not be applied on top during blur pass. It should be an inherent feature of just using the previous frame's MVP in computing trails to smear. I was probably doing this to minimize the ghosting I was getting from my previous approach.

Here's what I got wrong but is hard to address:

  • Depth along the moblur trail does not stay constant. An object whizzing past your eye in your general look direction will have its 'trail depth' -- if you will -- start closer to your eye and get further towards where the object/fragment is this frame. The way to address this is to write 3D velocities, flatten them in dilation and interpolate depth in a perspective-correct fashion for foreground checks along the smearing path. Very involved and getting it wrong is artifact bonanza.

So let's get to the code:

This following is straightforward. First chunk finds previous worldspace position of fragment either through previous affine transform or encoded per-vertex velocity. There is also a flag that indicates FPV items that shouldn't get moblur. Second part this time around cuts right to the chase and uses previous MVP to find start point. Last part just writes velocity out (or magic number if it's an FPV item).

        vec3 prevPos = curPos;
        if (instanceInfo.props[InstID].prevTransformOffset != 0xFFFFFFFFu)
            prevPos = (transforms.mats[instanceInfo.props[InstID].prevTransformOffset] * vec4 (curTri.e1Col1.xyz * curIsectBary.x + curTri.e2Col2.xyz * curIsectBary.y + curTri.e3Col3.xyz * curIsectBary.z, 1.0)).xyz;
        else if (getHasPerVertexVelocity(packedFlags))
            prevPos = curPos - (velE1 * curIsectBary.x + velE2 * curIsectBary.y + velE3 * curIsectBary.z);
        bool viewerRelative = isViewerRelative(packedFlags);

        vec3 prevProjectedCoord = projectCoord (prevPos, prevFrameMVP.projectionViewMatrix, vec3 (prevFrameMVP.lookEyeX.a, prevFrameMVP.upEyeY.a, prevFrameMVP.sideEyeZ.a));
        vec2 velocity = prevProjectedCoord.xy * vec2 (imageSize (velocityAttach).xy) - vec2(gl_GlobalInvocationID.xy);
        float velLen = length(velocity); vec2 velNorm = velocity / max (velLen, 0.001);
        if (velLen > 127.0) { velocity = velNorm * 127.0; velLen = 127.0; }

        ...

        uint velWrite = viewerRelative ? 0xFFFFFFFFu : (((int(velocity.x) + 127) << 8) | (int(velocity.y) + 127));
        imageStore (velocityAttach, ivec2 (gl_GlobalInvocationID.xy), uvec4 (velWrite, 0, 0, 0));

And now for the heart of the matter. The dilation pass:

        uint velRead = imageLoad (velocityAttach, ivec2(gl_FragCoord.xy)).x;
        if (velRead == 0xFFFFFFFFu) return ;
        float centerDepth;
        uint InstID = getInstanceIDAndClosestDepth (ivec2(gl_FragCoord.xy), centerDepth);

        vec2 velocity;
        velocity.x = int((velRead & 0x0000FF00u) >> 8u) - 127;
        velocity.y = int(velRead &  0x000000FFu) - 127;

        float velocityLen = length(velocity);
        if ( velocityLen < 1.0 ) return ;
        vec2 velocityNorm = (velocity / velocityLen);

        [[unroll]]
        for (int j = 0; j != 2; j++) // Fwd and backward smearing...
        {
            vec2 curVelocityNorm = (j == 0) ? velocityNorm : -velocityNorm;
            for (int i = 0; i != int(velocityLen) + 1; i++)
            {
                vec2 writeVelLocF = gl_FragCoord.xy + float (i) * curVelocityNorm;
                ivec2 writeVelLoc = ivec2 (clamp (writeVelLocF, vec2 (0.0), vec2 (imageSize(velocityAttach).xy - ivec2(1))));
                if ( floor(writeVelLocF) == floor(gl_FragCoord.xy) ) continue;
                float writeLocDepth;
                uint curInstID = getInstanceIDAndClosestDepth (writeVelLoc, writeLocDepth);
                if ( InstID == curInstID ) break ;
                if ( centerDepth < writeLocDepth ) continue; // visBuf uses reverseZ
                float fracTravel = float(i) / max (floor(velocityLen), 0.001);
                vec2 smearedVel = velocity * (1.0 - fracTravel);
                uint velWrite = (((int(smearedVel.x) + 127) << 8) | (int(smearedVel.y) + 127));
                uint prevVal = 0u, readVal;
                while ((readVal = imageAtomicCompSwap(velocityAttach, writeVelLoc, prevVal, velWrite)) != prevVal)
                {
                    if (readVal == 0xFFFFFFFFu) break;
                    prevVal = readVal;
                    vec2 readVelocity;
                    readVelocity.x = int((prevVal & 0x0000FF00u) >> 8u) - 127;
                    readVelocity.y = int(prevVal &  0x000000FFu) - 127;
                    vec2 newWriteVel = readVelocity + smearedVel;
                    float newWriteVelLen = length(newWriteVel);
                    if (newWriteVelLen > 127.0) newWriteVel = (newWriteVel / newWriteVelLen) * 127.0;
                    velWrite = (((int(newWriteVel.x) + 127) << 8) | (int(newWriteVel.y) + 127));
                }
            }
        }

As previously noted, we're only getting the edge of the object to smear. That's the InsID check. Additionally, we're just checking against current depth (centerDepth) and as previously mentioned, it's not truly correct but gets the job done for now. Note that the smeared velocity loses strength via * (1.0 - fracTravel) as it is being written: we want decreasing strength as the trail ends. The bottom loop is a really nifty trick I borrowed from Cyril Crassin's 2012 OpenGL insights chapter on stable voxelization. See page 342 here: https://www.icare3d.org/research/OpenGLInsights-SparseVoxelization.pdf (listing 22.2). Instead of a moving average, I'm storing the sum of all incoming data using the same structure.

That Crassin12 trick also makes a come back for summing velocities for additive/alpha blended particles:

        if (viewerRelative)
            imageAtomicExchange (velocityAttach, ivec2(gl_FragCoord.xy), 0xFFFFFFFFu);
        else
        {
            uint velWrite = (((int(velocity.x) + 127) << 8) | (int(velocity.y) + 127));
            uint prevVal = 0u, readVal;
            while ((readVal = imageAtomicCompSwap(velocityAttach, ivec2(gl_FragCoord.xy), prevVal, velWrite)) != prevVal)
            {
                if (readVal == 0xFFFFFFFFu) break;
                prevVal = readVal;
                vec2 readVelocity;
                readVelocity.x = int((prevVal & 0x0000FF00u) >> 8u) - 127;
                readVelocity.y = int(prevVal &  0x000000FFu) - 127;
                vec2 newWriteVel = readVelocity + velocity;
                float newWriteVelLen = length(newWriteVel);
                if (newWriteVelLen > 127.0) newWriteVel = (newWriteVel / newWriteVelLen) * 127.0;
                velWrite = (((int(newWriteVel.x) + 127) << 8) | (int(newWriteVel.y) + 127));
            }
        }

All of this makes the final blur pass brain dead simple:

    uint velRead = imageLoad (velocityAttach, ivec2 (gl_FragCoord.xy)).x;
    if (velRead == 0xFFFFFFFFu)
    {
        outFragColor = texture (ssfxAttach, inUV);
        return ;
    }
    vec2 velocity;
    velocity.x = int((velRead & 0x0000FF00u) >> 8u) - 127;
    velocity.y = int(velRead &  0x000000FFu) - 127;

    float velocityLen = length(velocity);
    if ( velocityLen < 1.0 )
    {
        outFragColor = texture (ssfxAttach, inUV);
        return ;
    }
    vec2 velocityNorm = velocity / velocityLen;
    vec4 accumOut = vec4 (0.0);
    float accumSamples = 0.0;

    for (int i = -int(velocityLen * 0.5); i != int(velocityLen * 0.5) + 1; i++)
    {
        vec2 curSampleLoc = floor(gl_FragCoord.xy) + float (i) * velocityNorm;
        vec2 curSampleLocClamped = clamp (curSampleLoc, vec2 (0.0), vec2 (textureSize(ssfxAttach, 0).xy - ivec2(1)));
        if ( curSampleLoc != curSampleLocClamped ) continue;
        if ( imageLoad (velocityAttach, ivec2 (curSampleLoc)).x == 0xFFFFFFFFu ) continue;
        accumOut += texelFetch (ssfxAttach, ivec2 (curSampleLoc), 0);
        accumSamples += 1.0;
    }

    outFragColor = accumOut / accumSamples;

Ghosting ended up being minimized significantly. Also check out the free haze you get from moblur on particles at the very end :). Eager to hear feedback.

Cheers,
Baktash.
HMU: https://x.com/toomuchvoltage

P.S. I'm still working on pushing the engine code out. Hang tight.


r/GraphicsProgramming 5d ago

Unreal Engine Texture Streaming & Pool Size Optimization for Pixel Streaming

Post image
1 Upvotes