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>
118 lines
3.9 KiB
WebGPU Shading Language
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);
|
|
}
|