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>
This commit is contained in:
154
crates/libmarathon/src/render/pbr/light_probe/light_probe.wgsl
Normal file
154
crates/libmarathon/src/render/pbr/light_probe/light_probe.wgsl
Normal file
@@ -0,0 +1,154 @@
|
||||
#define_import_path bevy_pbr::light_probe
|
||||
|
||||
#import bevy_pbr::clustered_forward
|
||||
#import bevy_pbr::clustered_forward::ClusterableObjectIndexRanges
|
||||
#import bevy_pbr::mesh_view_bindings::light_probes
|
||||
#import bevy_pbr::mesh_view_types::LightProbe
|
||||
|
||||
// The result of searching for a light probe.
|
||||
struct LightProbeQueryResult {
|
||||
// The index of the light probe texture or textures in the binding array or
|
||||
// arrays.
|
||||
texture_index: i32,
|
||||
// A scale factor that's applied to the diffuse and specular light from the
|
||||
// light probe. This is in units of cd/m² (candela per square meter).
|
||||
intensity: f32,
|
||||
// Transform from world space to the light probe model space. In light probe
|
||||
// model space, the light probe is a 1×1×1 cube centered on the origin.
|
||||
light_from_world: mat4x4<f32>,
|
||||
// Whether this light probe contributes diffuse light to lightmapped meshes.
|
||||
affects_lightmapped_mesh_diffuse: bool,
|
||||
};
|
||||
|
||||
fn transpose_affine_matrix(matrix: mat3x4<f32>) -> mat4x4<f32> {
|
||||
let matrix4x4 = mat4x4<f32>(
|
||||
matrix[0],
|
||||
matrix[1],
|
||||
matrix[2],
|
||||
vec4<f32>(0.0, 0.0, 0.0, 1.0));
|
||||
return transpose(matrix4x4);
|
||||
}
|
||||
|
||||
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3
|
||||
|
||||
// Searches for a light probe that contains the fragment.
|
||||
//
|
||||
// This is the version that's used when storage buffers are available and
|
||||
// light probes are clustered.
|
||||
//
|
||||
// TODO: Interpolate between multiple light probes.
|
||||
fn query_light_probe(
|
||||
world_position: vec3<f32>,
|
||||
is_irradiance_volume: bool,
|
||||
clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>,
|
||||
) -> LightProbeQueryResult {
|
||||
var result: LightProbeQueryResult;
|
||||
result.texture_index = -1;
|
||||
|
||||
// Reflection probe indices are followed by irradiance volume indices in the
|
||||
// cluster index list. Use this fact to create our bracketing range of
|
||||
// indices.
|
||||
var start_offset: u32;
|
||||
var end_offset: u32;
|
||||
if is_irradiance_volume {
|
||||
start_offset = (*clusterable_object_index_ranges).first_irradiance_volume_index_offset;
|
||||
end_offset = (*clusterable_object_index_ranges).first_decal_offset;
|
||||
} else {
|
||||
start_offset = (*clusterable_object_index_ranges).first_reflection_probe_index_offset;
|
||||
end_offset = (*clusterable_object_index_ranges).first_irradiance_volume_index_offset;
|
||||
}
|
||||
|
||||
for (var light_probe_index_offset: u32 = start_offset;
|
||||
light_probe_index_offset < end_offset && result.texture_index < 0;
|
||||
light_probe_index_offset += 1u) {
|
||||
let light_probe_index = i32(clustered_forward::get_clusterable_object_id(
|
||||
light_probe_index_offset));
|
||||
|
||||
var light_probe: LightProbe;
|
||||
if is_irradiance_volume {
|
||||
light_probe = light_probes.irradiance_volumes[light_probe_index];
|
||||
} else {
|
||||
light_probe = light_probes.reflection_probes[light_probe_index];
|
||||
}
|
||||
|
||||
// Unpack the inverse transform.
|
||||
let light_from_world =
|
||||
transpose_affine_matrix(light_probe.light_from_world_transposed);
|
||||
|
||||
// Check to see if the transformed point is inside the unit cube
|
||||
// centered at the origin.
|
||||
let probe_space_pos = (light_from_world * vec4<f32>(world_position, 1.0f)).xyz;
|
||||
if (all(abs(probe_space_pos) <= vec3(0.5f))) {
|
||||
result.texture_index = light_probe.cubemap_index;
|
||||
result.intensity = light_probe.intensity;
|
||||
result.light_from_world = light_from_world;
|
||||
result.affects_lightmapped_mesh_diffuse =
|
||||
light_probe.affects_lightmapped_mesh_diffuse != 0u;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else // AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3
|
||||
|
||||
// Searches for a light probe that contains the fragment.
|
||||
//
|
||||
// This is the version that's used when storage buffers aren't available and
|
||||
// light probes aren't clustered. It simply does a brute force search of all
|
||||
// light probes. Because platforms without sufficient SSBO bindings typically
|
||||
// lack bindless shaders, there will usually only be one of each type of light
|
||||
// probe present anyway.
|
||||
fn query_light_probe(
|
||||
world_position: vec3<f32>,
|
||||
is_irradiance_volume: bool,
|
||||
clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>,
|
||||
) -> LightProbeQueryResult {
|
||||
var result: LightProbeQueryResult;
|
||||
result.texture_index = -1;
|
||||
|
||||
var light_probe_count: i32;
|
||||
if is_irradiance_volume {
|
||||
light_probe_count = light_probes.irradiance_volume_count;
|
||||
} else {
|
||||
light_probe_count = light_probes.reflection_probe_count;
|
||||
}
|
||||
|
||||
for (var light_probe_index: i32 = 0;
|
||||
light_probe_index < light_probe_count && result.texture_index < 0;
|
||||
light_probe_index += 1) {
|
||||
var light_probe: LightProbe;
|
||||
if is_irradiance_volume {
|
||||
light_probe = light_probes.irradiance_volumes[light_probe_index];
|
||||
} else {
|
||||
light_probe = light_probes.reflection_probes[light_probe_index];
|
||||
}
|
||||
|
||||
// Unpack the inverse transform.
|
||||
let light_from_world =
|
||||
transpose_affine_matrix(light_probe.light_from_world_transposed);
|
||||
|
||||
// Check to see if the transformed point is inside the unit cube
|
||||
// centered at the origin.
|
||||
let probe_space_pos = (light_from_world * vec4<f32>(world_position, 1.0f)).xyz;
|
||||
if (all(abs(probe_space_pos) <= vec3(0.5f))) {
|
||||
result.texture_index = light_probe.cubemap_index;
|
||||
result.intensity = light_probe.intensity;
|
||||
result.light_from_world = light_from_world;
|
||||
result.affects_lightmapped_mesh_diffuse =
|
||||
light_probe.affects_lightmapped_mesh_diffuse != 0u;
|
||||
|
||||
// TODO: Workaround for ICE in DXC https://github.com/microsoft/DirectXShaderCompiler/issues/6183
|
||||
// We can't use `break` here because of the ICE.
|
||||
// So instead we rely on the fact that we set `result.texture_index`
|
||||
// above and check its value in the `for` loop header before
|
||||
// looping.
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3
|
||||
Reference in New Issue
Block a user