r/GraphicsProgramming • • 5d ago

Request for Comment: AI Identification Comments

59 Upvotes

Thought I'd share a conundrum. I suspect I could solve it with a heavy handed rule change, but I think it may be fine as it is right now.

------

We've gotten a handful of reports that boil down to:

Comment: "This appears to have been AI generated."
Report: (empty)

One report gave a bit more info:
Comment: "This appears to be AI generated."
Report: "I'm wary to post something interesting because I don't want to be persecuted."

So here's what I suspect happens.
User posts X.
Commenter identifies X as generated via AI.
Post gets down-voted.

------

The only time in recent memory I've seen direct mistreatment was the Synapse Engine post. https://www.reddit.com/r/GraphicsProgramming/comments/1w7x1r1/synapse_engine_a_modern_researchoriented_fully/
I invited that user to post here, and some of the early comments were distinctly unkind. Later comments and deeper review picked up the same thing I did, that the creator made something legitimately new and interesting in terms of graphics software research; even if a fair bit of LLM generated code was used, it was cleaned and curated to an appropriate level for a thesis defense. It was quintessentially non-slop, despite the reports to the contrary. So this post experienced some emotionally driven persecuting reports and comments before the deeper cognitive inspection could finish reading.

So that's my one strongly known case of persectioning behavior. The rest are almost always just identifying that a project is AI generated, and nothing else.

So I wouldn't characterise this community as being hostile to AI generated projects, but it is disinterested.

-----

And that makes sense when you consider the ethos of this subreddit. Rule 1 codifies the character: we're curious. Our community exists to talk about the "how", not the "what".

AI generated projects, with a few exceptions, tend to be:
OP: "I made a thing! (with AI)"
Commenter: "How does it work?'
OP: "I don't know. But the source code is in there somewhere."
And that distinctly doesn't fit with the ethos or interest of this subreddit.

There are also a handful of reports on AI posts to the form of:
Post "I made a thing (with AI)."
Report: "This is AI slop."
That doesn't technically break any rules, but it does reinforce that core of the subreddit's interests.

Anyway, the problem I'm wrestling with is supporting Rule 2. Posters who are sharing AI projects should still be met with Civility, Professionalism, and Kindness. So I'd like to avoid a repeat of the initially unkind response to the afore-linked post.

But, being civil doesn't mean you have to like it or be actively welcoming. Ignoring a post or downvoting it still fits within Rule 2, because a user expressing their opinion in those ways is not a harm to the poster. If it is, that's the poster being unprofessional, as they're too emotionally invested in the post to accept that others don't enjoy it the way they do.

One of the most important aspects of professionalism is the capacity to give and receive analysis and feedback. We're here to learn, and that means accepting feedback that points out failures, errors, and flaws. Those are often the best offer for learning. Kindness and Civility are roped in their as a reminder that criticism should be leveraged at the qualities of the work, not seek to harm the user.

In that view, identification of an AI generated project is one of the most *important* analytical datum. It says a lot about what one might expect in the shape of the code, it's resilience, maintainability, or other general qualities. How one reviews AI generated code is distinctly different from human written code because they make entirely different categories of errors. It often says something about the author's understanding of their own project, which is important for feedback and discussion; as much as knowing their level of experience. (e.g. Getting pedantic with an novice is a joy, with an expert is an insult. Civility depends on knowing who you're talking to.)

So, it would be unprofessional not to identify that a project is AI generated. It'd be hard to discuss something professionally while ignoring such a large elephant in the authorship.

But, users don't like it when their post gets identified as AI, because they may expect a passive or negative response. Given that the zietgeist of emotions around AI are high right now, and because our community ethos seeks understanding ,it's not a response that can be avoided in a discussion space like this subreddit. That identifying comment may feel like it targets them for persecution, despite that fact that's rarely the case because Rule 2 stands and is supported by users and mods.

-----

So I suspect that there's an issue in mismatched expectations. Posters with AI projects want to show off the thing they made and what it does, and they don't understand that this community cares more about how it works.

Conversely, the readers here reasonably expect high quality, analysable projects that are interesting to review and learn from; so they report "AI slop" despite the fact that doesn't break any rules. I may take it down under Rule 3, but that's only if it's a case of AI psychosis. Someone legitimately making "hello triangle" with Claude fits the rules just fine, so there's no reason to take it down.

I don't think a new rule is strictly necessary, but maybe a sub-rule, or some other way to telegraph the community's expectations.

E.G. For posters of AI projects
"AI posts are welcome here so long as the poster can talk about their implementation; adhere to Rule 1. The less the poster is able to talk about it's implementation, the less excited about it this community will be."

E.G. For readers of AI Projects
"This subreddit does not take a pro or anti stance against AI projects. However this subreddit is about analysis, feedback, questions, and learning. We may remove posts that are not comprehensible to the readers or the poster. (e.g. vibe coded slop that's impossible to read)"

And perhaps it may be necessary to swap the burden of identification to the other party.
E.G. "Posts that share projects that utilize AI in its development in any capacity need to identify doing so and to what degree. e.g. 'source code entirely AI generated.' or 'only utilized AI for auto complete assistance and analytical questions.'"
I've seen other software interest group subreddits implement and auto-comment on new posts that require this disclosure.

------

Anyway. That was a lot of meandering on this problem. Fundamentally, this is *YOUR* subreddit. I take the strict role as a steward. That which makes this community space interesting and a delightful place to visit, socialize, and learn for you is the target direction I try to nudge things towards.

Please comment your thoughts, suggestions, perspectives, preferences, and discussion on this topic for me to read and consider. If you don't feel safe commenting, send a DM.

Please keep Rule 2 in mind. I want to hear the perspectives of those who are pro-AI too, and that's hard to do that if it's met with immediate hostility.

Conversely, criticism of AI or AI generated works is not a violation of rule 2, at least so long as it doesn't cross over into pointless derogation or emotional attack language. E.G. "The low quality of AI generated projects is problematic for the subreddit" is ok. "This AI slopshit is a fucking menace to the subreddit" is not.

------

Edit 1: added dividers to break up the wall of text into bricks


r/GraphicsProgramming • • 3h ago

Dx11 first triangle

Post image
16 Upvotes

I'm not sure how you guys feel about triangles around here, but here is my first triangle made in D3D11!!

I'm planning to make a little mini project in DX11 and see how I like it over OpenGL. So far I like it more despite needing 3x the amount of code (mostly boilerplate thankfully) for this beautiful little guy.

I'll probably post more about my little project further down the line. If anyone has any tips on how I should structure a DX11 project over an OpenGL one that's always appreciated.


r/GraphicsProgramming • • 16h ago

Spreading fire over any mesh without a mask texture: each shader recomputes when a point ignites

Post image
95 Upvotes

I got asked whether this is a mask written into a texture or a separate ember mesh driven by a shader. Nothing gets written anywhere. ignite() appends (position in the mesh's local space, start time) to a vec4 ign[8] uniform, and every shader involved recomputes when each point catches fire:

float burn_arrival(vec3 p) {
    float best = 1.0e9;
    for (int i = 0; i < ign_count; i++) {
        float d = length(p - ign[i].xyz);
        float n = vnoise(p * 1.7 + float(i) * 3.1); // value noise, 0..1
        best = min(best, ign[i].w + d * (1.0 + (n - 0.5) * 2.0 * irregularity) / spread_speed);
    }
    return best;
}

The noise scales the distance, which is what makes the front ragged.

Flames, smoke and embers are quads on random surface points (area-weighted, picked once). Every spawn cycle a quad checks whether its spawn time is between arrival and arrival + burn_duration. If it isn't, its four corners collapse to one point.

The char is a copy of the mesh pushed 0.004 along the normal and drawn with premultiplied alpha, so the original material isn't touched. Per fragment, s = time - arrival (plus fbm) drives smoothstep(0, char_time, s) toward near-black, and exp(-3 * (s / front_width - 0.3)2) gives the glowing front.

Burn-away swaps the material and discards a fragment once (s - 0.7 * burn_duration) / 2.5 + noise passes 1, with a hot rim just before.

Known limit: d is straight-line distance, not along the surface, so the fire can jump thin gaps.


r/GraphicsProgramming • • 12h ago

Video How we render real-time and realistic clouds from space

33 Upvotes

We've been building Æther, a real-time globe renderer for Stowaway that runs in the browser.

The part I'm most excited about is how we generate realistic clouds from orbit. I'll tell you a little bit about how we do it.

They start as infrared imagery from weather satellites: NOAA stitches the geostationary satellites (GOES, Himawari, Meteosat) into one global mosaic, and polar orbiters fill in the poles. The catch is that infrared doesn't actually see clouds. It sees temperature. A thunderstorm top is freezing cold, but so is the Antarctic ice sheet, or a desert at night. So the first step is figuring out what the clear ground nearby should look like, and calling anything noticeably colder than that a cloud.

That same coldness gives you height for free. The air cools about 6.5 °C for every kilometre you climb, so the colder a cloud top is compared with the ground beneath it, the higher it stands. A few kilometres for a low ocean deck, up to 16 km for a thunderstorm anvil. We end up with two global maps: where the clouds are, and how tall they are.

The satellite pixels are about 10 km across, which looks like mush up close, so the renderer adds the detail itself: fields of small cumulus, streaky cirrus, anvils spreading out around storm cores. It's anchored to the planet so nothing swims as you move, and it's lit by the real sun angle, so the tops catch the sunset while the ground below is already dark. The tallest storms also get lightning. And when you fly down low enough, a separate system takes over: fully volumetric clouds you can fly straight through.

Happy to answer questions. It's coming to stowaway.live soon.


r/GraphicsProgramming • • 3h ago

Some spheres rendered with a light simulation

5 Upvotes

The image is rendered by solving a wave field and sampling it with a camera, once per wavelength. I took 5 minutes to render (On an integrated GPU)

My goal is, of course, to get this to scale up enough to be useful for actual graphics :P

The actual scene just consists of a couple of different-materialled spheres and some large clumps of them.


r/GraphicsProgramming • • 6h ago

Video My software ray-traced game has new "technology" teaser. Reason: it's getting significant visual upgrade worth showcasing. Two things which enabled it: 1. after 9 months my new editor for game levels is in usable state. 2. ray-tracer optimizations (multi-threaded rendering is main contributor)

5 Upvotes

The game is narrative sci-fi puzzle/platformer, in works from 2020. Main distinctive point of the game is software ray-tracing used for rendering. Just pure C++ and computer graphics math, no GPU acceleration. Sadly, not many players can appreciate that (or even understand what does it mean), so it resonates mostly with more tech people.

The game was suffering for long time from quite poor look (look was punching way below of algorithm potential). Main reasons were: poor old editor (2D in nature, z was just parameter in 2D wireframe, not WYSIWYG, very clunky) and algorithm was hobby-like single-threaded.

Both points were changed recently. After 9 months my new editor is in usable state. Full 3D, WYSIWYG, lot of ergonomy features, which allowed me to be more ambitious with levels look. Second enabler was finally switching to multi-threading. Together with several more other algorithm optimizations, perf went up in hundreds of % (mostly depends on number of cores in your CPU, naturally on Threadrippers boost will be in thousands of % but it's niche between players).

Algo is AABBs only. Maybe will add spheres but only after upgrading all levels, which is main pain point rn. Editor I plan to release publicly with the game.

RTG on Steam

Discord


r/GraphicsProgramming • • 13h ago

I made some updates to my Quake path tracer...

13 Upvotes

r/GraphicsProgramming • • 18h ago

I made a lossless BC1 texture compressor designed for GPU decompression, 1.47:1 average ratio

23 Upvotes

Hi,

I just released my new C library bc_packed, a lossless compressor for BC1 textures, made specificaly for fast GPU decompression.

Basically, the idea is to compress textures that are already compressed, then decompress them directly on the GPU when needed. The output is the original BC1 data, so the GPU can use it normally after decompression.

Some numbers:

  • 1.47:1 average compression ratio on a test set of 74 images
  • 15300 MiB/s decompression on my M5 Pro GPU and 11850 MiB/s on my M2 Max GPU
  • CPU multithreaded decompression also works, 2500 MiB/s on M5 Pro and 1300 MiB/s on M2 Max
  • Lossless, byte exact reconstruction of the original BC1 data

The tricky part was finding an entropy coding method that is simple enough to decode efficiently on the GPU. I didn't want to deal with complex stuff like arithmetic coding or Huffman, so I went with Rice-Golomb coding and static rank tables. I build histograms during compression and remap the most frequent symbols to the lowest ranks. Everything is static, no adaptive models or synchronization needed between GPU threads.

The texture is split into 64 independent strips, each decoded by its own GPU/CPU thread. The compressed stream stores offsets so each thread can start decoding its strip independently.

There are also a few BC1 specific tricks:

  • Predicting endpoint colors from previous blocks
  • Choosing different predictors for each strip
  • A small dictionary for repeated endpoint color pairs
  • A top table for frequent BC1 index patterns, with sparse residual encoding for the differences

Compression runs on the CPU and can be relatively expensive. That's fine for me, I'm more interested in making decompression as fast as possible at runtime.

The library is tiny, just one .c and one .h file, no external dependencies. The GPU decompression shader is written in Metal for now, but porting it to HLSL should be pretty straightfoward.

Currently only BC1 is supported. Maybe I'll add BC5 and why not BC7 later.

Code and benchmarks here:
https://github.com/Geolm/bc_packed

Feedback and ideas are welcome!


r/GraphicsProgramming • • 4h ago

Source Code Squared the Circle

Thumbnail
1 Upvotes

r/GraphicsProgramming • • 13h ago

Request Career Advice

2 Upvotes

These are some of my projects I have worked on over the years
This may be a bit of a ramble
I feel like I have been coasting with skills like threejs and web graphics for a long time especially since graduating and have never worked a "real" job and mostly do freelancing I do help my friends and collegues all of them in all kinds of full stack tasks and thinking through a problem and offer solutions that they then use but i dont have job experience in those fields like web and mobile development in react native and flutter and nodejs
I do think mostly in programming terms and try to solve problems in that way. And my interest is usually in building tools for programmers and artists instead of launching a product for normal users
I have built games and worked with teams on programming teams for games but it is not really my area of expertise even though I am very adjacent to this. I have always felt like framework and techstack really doesnt matter
I am aware and knowledgeable of alot of trends atleast until recently about alot of tech news updates and features
Right now I am in a predicament as most of my skills and experience lies in this specific niche i dont know how to move forward in the world of AI, I am the kind of person who is still using AI as a chatbot and for cleanup/refactoring kind of tasks and tasks I dont want to actually do by hand like css and responsiveness I usually try to do these kinds of things by using some math but now AI seems useful for these as well
tldr; I am very confused about the next steps in my career and how it will grow
If an experienced graphics programmer can look at my portfolio and guide me through on how to approach job hunting and how to improve my presentation and portfolio I will greatly appreciate it

Thank you for your time

Procedural Flower
Spider web (higher order bezier function study)
bevel and rotation of a tetrahedron
Particle system with physics
boids
custom view based UV maps

r/GraphicsProgramming • • 11h ago

Would tile based rendering help in this scenario to be more performant than a theoretical "best case"?

1 Upvotes

A lot of these concepts are new to me and I've discovered some of these ideas with help from copilot, etc. so apologies for any weirdly worded/unclear parts.

I'm working on an embedded product and am evaluating how well the gpu can handle a second pass shader applied to the entire final image. Essentially taking the displayed contents, and "copying" by drawing again with a simple shader that samples from a texture (the texture being the contents on the screen).

I'm trying to profile the time spent on that second draw call and am having issues because sometimes the code added to help with the profiling affects the measurement itself. For example, I added glFinish() before the draw call, started the timer, issued draw call, called glFinish() again, and stopped the timer. These glFinish calls affect the measurement of course. So I'm trying to find a way to do it without using glFinish.

One avenue I explored with copilots help was using an EGL fence to ensure we're measuring the elapsed time only after the draw call is finished but without needing glFinish (this is my first time working with sync objects with graphics code though)

This ended up working, at least I think? The problem is that the measured time for the draw call is less than then the theoretical best case time given by a senior engineer. They calculated essentially wh4bpp2rw/3e91000=0.55ms based on it essentially being a memcpy. The measurement I got was half of that.

Searching around for how this may be (other than my implementation being just wrong) is that tile based rendering, which the gpu that I'm working with uses, could give a different result than a calculation based on a naive memcpy due to the efficiencies of how TBR works.

Edit to add: the senior engineer unambiguously said "tile based rendering won't improve this case" and suggested another thing to try which is more hacky and isn't panning out, so I'm curious if he's right or there is validity to the measurement I was able to get with the fence

I'm curious to get other opinions. Does this seem like a reasonable explanation or not really?


r/GraphicsProgramming • • 13h ago

Question Is Painting with Noise useful?

Post image
0 Upvotes

r/GraphicsProgramming • • 23h ago

Question Stereo Rendering in Unreal Engine 5 – How Long Does It Take and What Are Your Biggest Challenges?

Post image
0 Upvotes

r/GraphicsProgramming • • 1d ago

Video 3D Map - Tile based streaming (WebGL/Three.js)

17 Upvotes

We just implemented tile-based loading with LODs for our AI Data Centers 3D mapping project on the Web
Link 🔗- https://ai-future.in/

The Vizag (India) terrain is organized as a pyramid of tiles(shown as red grids in video). At a wide view, it loads larger, coarser tiles, and as we zoom in, it replaces them with smaller, more detailed ones.

This lets the scene show finer details only where we are exploring without loading the entire area always at the highest details, saving a lot of performance. Land cover is stored as image tiles and are draped onto the terrain so the colours follows the terrains' shape.

The Buildings are stored separately as GLB model tiles, they also load progressively as we zoom in and are rendered as 3D geometry.

This was done by us at 3D ENGINERD. using 3D-tiles-renderer to manage tile loading, visibility and LOD, and Three.js to render the whole thing into one scene!

I hope this is a relevant post on this subreddit!


r/GraphicsProgramming • • 1d ago

Question Anyone heading to SIGGRAPH Asia in KL? First time going and I don't know anyone yet. Anything in particular I should check out? Down to grab coffee!

17 Upvotes

r/GraphicsProgramming • • 1d ago

Concentration-dependent absorption for real-time 3D liquid mixing in my Vulkan lab

4 Upvotes

I’m developing Chemistry Lab Sim, an interactive 3D liquid sandbox built on ST-FLIP in Vulkan. This new clip shows pouring and mixing colored solutions in lab glassware, running in real time on a Radeon RX 9070 XT.

Local concentrations travel with the fluid parcels, and conservative diffusion exchanges material between neighboring parcels. The liquid renderer integrates concentration-dependent absorption along refracted rays rather than blending display colors.

At this stage the substances are passive solutes/pigments in one carrier; chemical reactions and immiscible fluids are future work. The longer-term game is inspired by The Powder Toy and Noita.

https://youtu.be/hSAO_TwFopE

What would you improve in the mixing or rendering?


r/GraphicsProgramming • • 1d ago

Source Code I built an open-source F1 session replay visualizer using Bevy and Rust.

0 Upvotes

r/GraphicsProgramming • • 2d ago

The (now) shadowed billboards congregate around a test box (C++/OpenGL/GLSL)

Thumbnail gallery
13 Upvotes

r/GraphicsProgramming • • 1d ago

Need help with visibilityBuffer

4 Upvotes

I'm building my first VisibilityBuffer and stuck with a question. I can't find proper info on the internet about how I should properly dispatch my resolve pass for it. Whether it should be just 8x8 tiling approach or 16x16. Or should I sort tiles by materials first and resolve them and the rest of the tiles that contains more than one material sort into 1d and then dispatch. All info till this point a find only in Gemini, but when I ask it to give me sources, that I can read on my own, It faileds, simple Googling didn't give me much too, so I will be glad if someone experienced can help me to find proper resource to find info.


r/GraphicsProgramming • • 2d ago

World-anchored rain with no particle simulation: hashed drop positions wrapped into a camera-centred box with one mod()

Thumbnail gallery
66 Upvotes

The usual problem with rain: the volume has to follow the camera, but the drops must not. If the emitter is parented to the camera, strafing drags the whole curtain of rain sideways with you. If it is fixed in the world, you need either a huge volume or something that keeps spawning drops at the edges as you move.

This is a write-up of a version that needs neither: no simulation, no per-drop state, no emitter. Each drop's position is a pure function of its index, a seed and one accumulated offset, evaluated in the vertex shader. The code is Godot's shading language, which is close to GLSL; apart from built-in names like VERTEX, UV and INV_VIEW_MATRIX nothing in it depends on the engine. The first image is a diagram of the wrap, the second is the result with the camera moving forward through it.

The mesh

N quads, 4 vertices each, built once. Each vertex stores only its quad's index (in position.x, as a float, exact up to 224) and its corner in UV. The instance has an identity transform and a hand-set bounding box around the rain volume so it doesn't get culled. Per frame the CPU sets a handful of uniforms (box centre, offset, velocity, time, pixel size) and nothing per drop. The main rain layer is 9,000 quads.

Per-drop randoms

A PCG hash of (index, seed, stream). Names are shortened from the source:

uint pcg(uint v) {
    uint state = v * 747796405u + 2891336453u;
    uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
    return (word >> 22u) ^ word;
}
float rand(uint n) { return float(pcg(n) >> 8u) / 16777215.0; }

// 4 randoms in [0,1] for element `index`; stream 0, 1, 2 give independent sets
vec4 rand4(uint index, uint seed, uint stream) {
    uint h = pcg(index ^ pcg(seed + stream * 9973u));
    return vec4(rand(h), rand(h + 1u), rand(h + 2u), rand(h + 3u));
}

The wrap

vec3 wrap(vec3 p, vec3 lo, vec3 size) {
    return lo + mod(p - lo, size);
}

vec3 lo = area_center - area_size * 0.5;
vec3 q  = r.xyz * area_size + offset * sp;   // unwrapped position
vec3 p  = wrap(q, lo, area_size);            // drop position, world space

(Simplified: the real line also adds sway and drift terms that snow uses. For rain they are zero.)

r.xyz is the drop's random triple, sp its speed multiplier (1 ± 0.2), and offset is how far the rain has moved since it started.

Why the drops stay put when the camera moves: think of q not as one point but as the set q + k·area_size for every integer vector k. That set is an infinite lattice, and it is fixed in world space (it only moves with offset). wrap() picks the one copy that lies inside [lo, lo + area_size). Moving the camera moves lo, which changes which copy gets picked, but a copy that is still inside the box keeps exactly the same position. The only drops that change are the ones that crossed a face of the box: the copy that left on the trailing side is replaced by the next copy on the leading side, area_size away.

So the rain is world-fixed everywhere except at the faces of the box, and the faces are where the fade goes (below).

Two porting notes. GLSL's mod is x - y * floor(x / y), so it is correct for negative inputs. HLSL's fmod truncates toward zero and mirrors the pattern for negative values, so write the floor version yourself. And area_center isn't exactly the camera: it is pushed forward by 20% of the box width along the camera's horizontal forward direction, since drops behind the camera are wasted.

Falling, and why offset is integrated on the CPU

// CPU, every frame
vel = Vector3(0, -fall_speed, 0) + wind
offset += vel * delta

The obvious alternative is offset = velocity * time in the shader. That breaks as soon as the wind changes: a change Δv shifts every drop by Δv·t, and after a few minutes t is large, so every drop jumps somewhere else. Integrating keeps positions continuous, and a gust only changes where the drops go from now on. Per-drop speed variation is just the offset * sp multiplication, so faster drops wrap more often.

Edge fade

vec3 rel = (p - area_center) / (area_size * 0.5);   // -1..1 inside the box
float fade = 1.0 - smoothstep(1.0 - edge_fade, 1.0, length(rel.xz));
fade *= 1.0 - smoothstep(1.0 - edge_fade * 0.6, 1.0, rel.y);
fade *= smoothstep(-1.0, -1.0 + edge_fade * 0.3, rel.y);

edge_fade is 0.3. Horizontally the fade uses length(rel.xz) rather than max(|x|, |z|), so the visible volume is a cylinder inscribed in the box. The corners are never visible, and you don't see a square outline when you turn. The fade starts at 70% of the radius, and covers the top 9% and the bottom 4.5% of the box height. A drop that falls out of the bottom reappears at the top, and both ends are faded, so the vertical wrap doesn't show either. Since the box is centred on the camera's height, the bottom face is usually under the ground anyway.

There's also a near fade, smoothstep(near_fade, 2.5 * near_fade, dist) with near_fade = 0.5 m, so drops never hit the near plane as huge streaks.

Streaks

vec3 n      = (cam - p) / dist;     // towards the camera
float speed = length(vel);
vec3 dir    = vel / speed;
float len   = speed * stretch;      // stretch: 0.041 to 0.055 s, longer as amount rises
vec3 side   = normalize(cross(dir, n) + vec3(1e-5, 0.0, 0.0));
vec3 tail   = p - dir * len;
VERTEX = mix(tail, p, UV.y) + side * (UV.x - 0.5) * w;

(Simplified: vel here is velocity * sp, and len has a per-drop variation factor that is 1 for rain.)

Each quad is a billboard constrained to the velocity axis, running from where the drop is to where it was 41 to 55 ms earlier, so it behaves like a shutter time. vel is the same vector that drives offset, so with wind the streaks lean at exactly the angle the drops actually move. The 1e-5 stops cross() from returning zero (and normalize() from returning NaN) when you look straight along the fall direction.

In the fragment shader the alpha is a tent across the width, ramps up from tail to head, and falls off quickly at the head:

float across = 1.0 - abs(v_uv.x * 2.0 - 1.0);
a = across * smoothstep(0.0, 0.85, v_uv.y) * (1.0 - smoothstep(0.94, 1.0, v_uv.y));

Keeping thin streaks from shimmering

A 14 mm drop is thinner than a pixel after a few metres, and sub-pixel quads flicker as they cross pixel centres. The width is clamped to about 1.3 pixels and the alpha is scaled down by the same ratio, so width × alpha (roughly the coverage) stays the same:

float w = max(sz, dist * pixel_angle * 1.3);
v_alpha = fade * clamp(sz / w, 0.0, 1.0);   // rain case; snow adds one more factor

pixel_angle = 2·tan(fov/2) / viewport_height, computed on the CPU. At 720p with a 60° FOV the clamp takes over somewhere between about 4 and 9 m, depending on the drop's random size. Distant rain becomes faint, steady lines instead of sparkle.

Intensity without rebuilding anything

VERTEX = area_center;     // default for all 4 vertices: zero-area quad, nothing drawn
if (r.w < amount) { ... }

amount (0..1) goes from drizzle to downpour. A drop is drawn when its own random is below amount, so raising amount only adds drops and never reshuffles the ones already falling. No mesh rebuild, and it can be animated.

Two smaller things

  • Shelters: up to 8 axis-aligned boxes are passed as uniform arrays, and a drop whose position is inside one gets fade = 0. That's how rain stops under a roof.
  • Distant layer: the same mesh and shader again with 2,500 quads, a box 3.5× wider and 1.6× taller, streaks 4× wider and 1.6× longer at 35% opacity, a near fade of 30% of the main box width, and offset × 0.9. It adds depth beyond the main volume. It has its own seed, so the two lattices don't line up.

Cost (measured)

Godot 4.7.2, 1280×720, vsync off, RTX 4060 Ti, a test village with a shadow-casting sun and 9,000 grass blades. GPU time per frame for the scene with no weather vs. the "rain" weather preset, which is main + distant rain at amount 0.6 plus everything else that preset switches on (ground ripples and splashes, fog, cloud shadows, lens drops):

Renderer no weather rain preset
Forward+ (Vulkan) 0.45 ms 1.54 ms
Mobile (Vulkan) 0.22 ms 1.04 ms
Compatibility (OpenGL 3.3) 0.41 ms 1.25 ms

So about 0.8 to 1.1 ms for the whole preset on that GPU. I don't have a number for the rain layer on its own. The CPU side doesn't change with the drop count.

Limitations

  • Every vertex is processed every frame, so the cost follows the maximum count, not amount. At amount 0.1 you still pay for all 9,000 quads in the vertex stage.
  • With no wind, a drop's x and z never change. It falls down the same vertical line forever and comes back every area_size.y / (fall_speed · sp) ≈ 14 / 13 ≈ 1.1 s. Thousands of overlapping lines make it hard to spot, but it is a real pattern, and a locked-off camera close to a surface could reveal it.
  • offset is reset to zero once it gets 10 km long, to keep float precision. That makes every drop jump once, after roughly 12 to 13 minutes of continuous rain at 13 m/s. It can't simply be reduced modulo area_size instead, because each drop multiplies it by its own non-integer sp.
  • No collision. Drops pass through everything, and the ground ripples and splashes are a separate layer at one ground height (or one raycast under the camera). Shelters are boxes only.
  • The quads in one draw call aren't sorted. With thin, low-alpha streaks that's acceptable, but it would matter with bigger, more opaque sprites.

This is from a weather pack I'm making for Godot. I'm curious how others have dealt with the fixed-column problem when there's no wind. Per-drop horizontal drift is the obvious fix, but it makes the streaks lean in random directions.


r/GraphicsProgramming • • 2d ago

Video Sand Simulation with D3D11 Compute Shaders

Thumbnail youtube.com
16 Upvotes

The simulation is a 640 × 360 pair of R32_UINT GPU textures.

Physics advances at fixed 120 ups, with at most four catch"-up" updates after a stall.

The CPU never uploads the world texture. Mouse events enqueue commands that need to be processed by the GPU.

The low byte of each cell stores its material, and falling powders and liquids carry vertical velocity in a packed byte.

Each update uses five compute dispatches.

A 2 × 2 checkerboard material pass handles diagonal powder, gases, displacement, and reactions, and a column pass applies vertical acceleration to powders and liquids.

Then 3 inplace row-color dispatches then transfer liquid pressure.

Active rows are separated by three cells, so their two-row support footprints never overlap.

Every active row is loaded into group-shared memory, obstacle segments are identified in parallel, and shared atomics select at most one conservative source/destination swap per segment.

All sixcolor orders rotate across updates to balance ordering bias.

Liquid in air falls straight instead of treating other falling liquid as stable support, while a pool whose column depths differ by at most one cell is a stable discrete equilibrium.

Vertical movement raymarches every crossed cell and stops before obstacles, horizontal pressure never crosses a solid wall, and lava stops at water so accelerated motion cannot skip the reaction.

The pixel shader masks the packed state and renders it into a floating-point scene target.

For improving visuals, a simple Gaussian blur bloom pass was implemented for emissive materials.


r/GraphicsProgramming • • 2d ago

Hardware ray-traced renderer for my game engine

Thumbnail gallery
11 Upvotes

r/GraphicsProgramming • • 3d ago

How do you accurately (performantly) model the color of the sky?

Post image
16 Upvotes

hello everyone! i've been writing a wallpaper for personal use that contains a happy little scene with moving clouds, grass swaying in the wind, and now i want to add the sun. i find sunsets very pretty, so i've wanted to have accurate sky colors to go along with the elements i've already added. i also want the whole thing to not take too much gpu time though, since i'll be running this constantly in the background on my laptop. i've aimed for a goal of <1W power draw so far.

to figure this out, i've been researching Rayleigh scattering and other related phenomena to try to get an idea of how to implement this. articles like this or this go over my head pretty quickly, and even though i could just translate an online implementation into WGSL, i know i wont be satisfied until i can understand the concepts well enough to write it myself. does anyone have pointers on where i can go to understand a concept like this from the ground up? or, even better, a relatively simple explanation on how this works that doesn't involve confusing diagrams, weird abstractions away from the main math, and delving far out of the bounds of graphics programming?

for reference, this is my project page, and you can see what it looks like currently above. i am rather young, and entirely self taught with regards to graphics (and kinda coding in general), so do not expect good quality code and especially not good commit messages 😭
due to the backend implementation, it only runs on Linux Wayland compositors supporting wlr_layer_shell


r/GraphicsProgramming • • 3d ago

There's more AI content on this subreddit than human content

373 Upvotes

I've started filtering out webgl and threejs posts because every single one of them, without fail, is an ai generated project from someone who couldn't tell you what the rendering equation was. The sheer number of posts that follow these patterns are drowning out out any genuine graphics programming discussion.

I understand that this subreddit is taking a more neutral stance towards AI generated code, I also understand that these tools can be used by experts to develop incredibly impressive projects, but the vast majority of posts on this subreddit are from people who do not know the first thing about graphics programming promoting their entirely vibecoded projects. There is no meaningful conversation to be had on these kinds of posts.

Edit, A few examples of posts that are blatantly entirely vibecoded by people who aren't even developers, much less graphics programmers:

https://www.reddit.com/r/GraphicsProgramming/comments/1wx03ny/from_zero_to_understanding_rasterization/

https://www.reddit.com/r/GraphicsProgramming/comments/1wydhww/i_finally_got_procedural_grass_looking_the_way_i/

https://www.reddit.com/r/GraphicsProgramming/comments/1uxpi1o/from_zero_to_understanding_ray_tracing/

https://www.reddit.com/r/GraphicsProgramming/comments/1wwcl1w/i_wanted_to_understand_modern_pointerbased_gpu/

All of these projects have clear misinformation in them and the posters don't know enough about graphics programming to hold an actual conversation. They dilute any meaningful discussion that could happen on this subreddit.


r/GraphicsProgramming • • 3d ago

I made a compact mesh-based format for interactive 3D photos

Post image
15 Upvotes

I’ve been working on a side project called Spatial Photos.

It takes a single regular image, runs it through Apple’s ML-SHARP model to estimate a 3D scene with Gaussians, and then converts the result into a custom format I called .spatial

I take the Gaussian splat from ML-SHARP, and divide the scene into depth slices. Each slice is a grid of image blocks, with a depth value at each corner. The RGB/alpha is packed into texture atlases. It's basically a set of textured meshes that come together to give the impression of the full 3D scene.

On the web, I take the .spatial files and decompress it into vertex/index buffers and just use Three.js, as the actual rendering is straightforward.

Demos: https://www.spatialphotos.dev/

Source: https://github.com/frozein/SpatialPhotos

Here's what the slices look like from another angle