Thanks for the suggestion! I wasn’t aware that compute shaders existed, and after reading up on them for a bit, it does seem like it could be useful here. However, there are a few things I’m still uncertain on. Bare with me for a second here…
From my understanding so far, compute shaders are used to run arbitrary code (i.e., not necessarily related to graphics) in parallel on the GPU. They work best when given many small tasks that are independent from one another, especially if those tasks are not framerate dependent, so the GPU and CPU don’t have to be manually synced. However, this seems to present a problem with my project here because:
- The tasks I want to perform are dependent on one another. The output data that I want to obtain (image density and pre-multiplied alpha values) would have to be modified for every input texture.
- The tasks have to be completed before the render pipeline starts for every frame, requiring frequent synchronization between the CPU and GPU.
It doesn’t seem impossible by any means, but I’m not convinced it’s the best tool for the job. Of course, I could be misinterpreting the use case for these shaders.
I think it’s probably worth elaborating a bit on how I want things to work. Ideally, I would love a solution that was contained within a single shader script, with a variable tied to SCREEN_UV that could be modified by and persisted between all materials using the script. Something like this:
shader_type canvas_item;
// Magically persistent variables that are initialized each frame,
// are tied to SCREEN_UV, and can be modified between shaders
magic_var float density = 0.0;
magic_var vec4 colorSoFar = vec4(0,0,0,0);
void fragment() {
// Compute color so far based on density map and current color
colorSoFar.rgb = (colorSoFar.rgb * density + COLOR.rgb * COLOR.a) / (density + COLOR.a)
// Update density map
density += COLOR.a
// Update alpha
colorSoFar.a = 1.0 - (1.0-COLOR.a) * (1.0-colorSoFar.a)
// Update Color
COLOR = colorSoFar
}
Unfortunately, as far as I can tell, this “magic” variable type doesn’t exist for shaders. Fair enough. Surely there’s a way to emulate its behavior? Maybe compute shaders are the solution after all? I can envision a solution that looks something like this:
- initialize compute shader (similar to above) with buffers for the density map, and colorSoFar 2D array, as well as the input texture and its relative position in pixels.
- (Also the shader and buffers need to understand how many pixels the main viewport takes up since we can’t magically rely on SCREEN_UV anymore. This bit is still nebulous to me.)
- for each texture:
- pass the texture and its position to the compute shader
- sync the compute shader
- Use the colorSoFar buffer to write a texture which is displayed to the screen.
However, it still feels like a weird way to use the compute shader, since we have to sync the GPU and CPU for every single texture that’s part of the shader. Also, I’m not sure how to reliably obtain information about textures’ positions in pixels. (If my understanding is correct, the position variable on nodes cannot be used here, as it is somewhat independent from a viewport’s actual resolution.)
Oof. Sorry for rambling on about this. Hopefully that all makes sense. I’ve been fixating on this issue for a while now, and even though it’s little more than a theoretical exercise at this point, I’d still like to have it figured out. Basically, here are the questions I still have:
- Am I understanding the role of compute shaders correctly?
- Does the “magically persistent” variable that I’m dreaming of for basic shaders actually exist? If not, is there something close that I could use?
- If I do end up needing to use compute shaders, how do I solve the problem of getting/setting data relative to textures’ pixel position?
- Lastly, am I just way overthinking this? Maybe my original solution (encoding data in separate viewports to be sampled and passed to other shaders) is par for the course and not as hacky as it seems. I just don’t feel like I have a great frame of reference yet.
Any and all help is appreciated! I feel like I’m learning a lot here, and this community has been wonderful so far!