Context: I'm working on a retro-style arcade game using pixel-based collision, where any non-transparent pixel (with an alpha > 0.0) can be collided with.
I'm comfortable with how to do this on the CPU, directly manipulating image data. Now I'd like to do this with shaders and the rendering pipeline as much as possible, mostly for the learning experience. I think I'm getting a bit bogged down in some of the concepts though (giant surprise, I know!)
I can render to an image render target, which I suspect will be part of the solution. I know how to apply a mask to the underlying image at the location of the mouse cursor, in a fragment shader:
#import bevy_sprite::mesh2d_vertex_output::VertexOutput
@group(2) @binding(0) var<uniform> cursor_position: vec2<f32>;
@group(2) @binding(1) var terrain_texture: texture_2d<f32>;
@group(2) @binding(2) var terrain_texture_sampler: sampler;
@group(2) @binding(3) var mask_texture: texture_2d<f32>;
@group(2) @binding(4) var mask_texture_sampler: sampler;
@fragment
fn fragment(mesh: VertexOutput) -> @location(0) vec4<f32> {
var terrain_color = textureSample(terrain_texture, terrain_texture_sampler, mesh.uv);
let diff = mesh.position.xy - cursor_position;
if all(abs(diff) < vec2<f32>(36.0, 36.0)) {
let mask_uv = (diff + vec2<f32>(36.0)) / 72.0;
var mask_color = textureSample(mask_texture, mask_texture_sampler, mask_uv);
if terrain_color.a != 0. {
terrain_color.a = mask_color.a;
}
}
return terrain_color;
}
Where I'm getting a bit iffy is, how would one approach retaining the changes to the rendered image i.e. making the pixels set to alpha persist for the duration of the level. I'm reasonably sure there's a strategy here that doesn't involve copying the entire thing back out to the CPU. Does anyone perhaps have an example I could look at, or a high-level description of the approach?