Files
marathon/crates/libmarathon/src/render/oit/resolve/oit_resolve.wgsl
Sienna Meridian Satterwhite b03b71c1d9 feat(rendering): Vendor Bevy rendering crates (Phase 1 complete)
Closes #6, #7, #8, #9, #10
Refs #2, #122

Vendored bevy_render, bevy_core_pipeline, and bevy_pbr from Bevy v0.17.2
(commit 566358363126dd69f6e457e47f306c68f8041d2a) into libmarathon.

- ~51K LOC vendored to crates/libmarathon/src/render/
- Merged bevy_render_macros into crates/macros/
- Fixed 773→0 compilation errors
- Updated dependencies (encase 0.10→0.11, added 4 new deps)
- Removed bevy_render/pbr/core_pipeline from app Cargo features

All builds passing, macOS smoke test successful.

Signed-off-by: Sienna Meridian Satterwhite <sienna@r3t.io>
2026-02-07 18:22:13 +00:00

118 lines
3.9 KiB
WebGPU Shading Language

#import bevy_render::view::View
@group(0) @binding(0) var<uniform> view: View;
@group(0) @binding(1) var<storage, read_write> layers: array<vec2<u32>>;
@group(0) @binding(2) var<storage, read_write> layer_ids: array<atomic<i32>>;
@group(1) @binding(0) var depth: texture_depth_2d;
struct OitFragment {
color: vec3<f32>,
alpha: f32,
depth: f32,
}
// Contains all the colors and depth for this specific fragment
var<private> fragment_list: array<OitFragment, #{LAYER_COUNT}>;
struct FullscreenVertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) uv: vec2<f32>,
};
@fragment
fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
let buffer_size = i32(view.viewport.z * view.viewport.w);
let screen_index = i32(floor(in.position.x) + floor(in.position.y) * view.viewport.z);
let counter = atomicLoad(&layer_ids[screen_index]);
if counter == 0 {
reset_indices(screen_index);
// https://github.com/gfx-rs/wgpu/issues/4416
if true {
discard;
}
return vec4(0.0);
} else {
// Load depth for manual depth testing.
// This is necessary because early z doesn't seem to trigger in the transparent pass.
// This should be done during the draw pass so those fragments simply don't exist in the list,
// but this requires a bigger refactor
let d = textureLoad(depth, vec2<i32>(in.position.xy), 0);
let result = sort(screen_index, buffer_size, d);
reset_indices(screen_index);
return result.color;
}
}
// Resets all indices to 0.
// This means we don't have to clear the entire layers buffer
fn reset_indices(screen_index: i32) {
atomicStore(&layer_ids[screen_index], 0);
layers[screen_index] = vec2(0u);
}
struct SortResult {
color: vec4f,
depth: f32,
}
fn sort(screen_index: i32, buffer_size: i32, opaque_depth: f32) -> SortResult {
var counter = atomicLoad(&layer_ids[screen_index]);
// fill list
for (var i = 0; i < counter; i += 1) {
let fragment = layers[screen_index + buffer_size * i];
// unpack color/alpha/depth
let color = bevy_pbr::rgb9e5::rgb9e5_to_vec3_(fragment.x);
let depth_alpha = bevy_core_pipeline::oit::unpack_24bit_depth_8bit_alpha(fragment.y);
fragment_list[i].color = color;
fragment_list[i].alpha = depth_alpha.y;
fragment_list[i].depth = depth_alpha.x;
}
// bubble sort the list based on the depth
for (var i = counter; i >= 0; i -= 1) {
for (var j = 0; j < i; j += 1) {
if fragment_list[j].depth < fragment_list[j + 1].depth {
// swap
let temp = fragment_list[j + 1];
fragment_list[j + 1] = fragment_list[j];
fragment_list[j] = temp;
}
}
}
// resolve blend
var final_color = vec4(0.0);
for (var i = 0; i <= counter; i += 1) {
// depth testing
// This needs to happen here because we can only stop iterating if the fragment is
// occluded by something opaque and the fragments need to be sorted first
if fragment_list[i].depth < opaque_depth {
break;
}
let color = fragment_list[i].color;
let alpha = fragment_list[i].alpha;
var base_color = vec4(color.rgb * alpha, alpha);
final_color = blend(final_color, base_color);
if final_color.a == 1.0 {
break;
}
}
var result: SortResult;
result.color = final_color;
result.depth = fragment_list[0].depth;
return result;
}
// OVER operator using premultiplied alpha
// see: https://en.wikipedia.org/wiki/Alpha_compositing
fn blend(color_a: vec4<f32>, color_b: vec4<f32>) -> vec4<f32> {
let final_color = color_a.rgb + (1.0 - color_a.a) * color_b.rgb;
let alpha = color_a.a + (1.0 - color_a.a) * color_b.a;
return vec4(final_color.rgb, alpha);
}