bevy/crates/bevy_pbr/src/meshlet/visibility_buffer_raster.wgsl
JMS55 4f20faaa43
Meshlet rendering (initial feature) (#10164)
# Objective
- Implements a more efficient, GPU-driven
(https://github.com/bevyengine/bevy/issues/1342) rendering pipeline
based on meshlets.
- Meshes are split into small clusters of triangles called meshlets,
each of which acts as a mini index buffer into the larger mesh data.
Meshlets can be compressed, streamed, culled, and batched much more
efficiently than monolithic meshes.


![image](https://github.com/bevyengine/bevy/assets/47158642/cb2aaad0-7a9a-4e14-93b0-15d4e895b26a)

![image](https://github.com/bevyengine/bevy/assets/47158642/7534035b-1eb7-4278-9b99-5322e4401715)

# Misc
* Future work: https://github.com/bevyengine/bevy/issues/11518
* Nanite reference:
https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf
Two pass occlusion culling explained very well:
https://medium.com/@mil_kru/two-pass-occlusion-culling-4100edcad501

---------

Co-authored-by: Ricky Taylor <rickytaylor26@gmail.com>
Co-authored-by: vero <email@atlasdostal.com>
Co-authored-by: François <mockersf@gmail.com>
Co-authored-by: atlas dostal <rodol@rivalrebels.com>
2024-03-25 19:08:27 +00:00

88 lines
2.8 KiB
WebGPU Shading Language

#import bevy_pbr::{
meshlet_bindings::{
meshlet_thread_meshlet_ids,
meshlets,
meshlet_vertex_ids,
meshlet_vertex_data,
meshlet_thread_instance_ids,
meshlet_instance_uniforms,
meshlet_instance_material_ids,
draw_index_buffer,
view,
get_meshlet_index,
unpack_meshlet_vertex,
},
mesh_functions::mesh_position_local_to_world,
}
#import bevy_render::maths::affine3_to_square
/// Vertex/fragment shader for rasterizing meshlets into a visibility buffer.
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
@location(0) @interpolate(flat) visibility: u32,
@location(1) @interpolate(flat) material_depth: u32,
#endif
#ifdef DEPTH_CLAMP_ORTHO
@location(0) unclamped_clip_depth: f32,
#endif
}
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
struct FragmentOutput {
@location(0) visibility: vec4<u32>,
@location(1) material_depth: vec4<u32>,
}
#endif
@vertex
fn vertex(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
let packed_ids = draw_index_buffer[vertex_index / 3u];
let cluster_id = packed_ids >> 8u;
let triangle_id = extractBits(packed_ids, 0u, 8u);
let index_id = (triangle_id * 3u) + (vertex_index % 3u);
let meshlet_id = meshlet_thread_meshlet_ids[cluster_id];
let meshlet = meshlets[meshlet_id];
let index = get_meshlet_index(meshlet.start_index_id + index_id);
let vertex_id = meshlet_vertex_ids[meshlet.start_vertex_id + index];
let vertex = unpack_meshlet_vertex(meshlet_vertex_data[vertex_id]);
let instance_id = meshlet_thread_instance_ids[cluster_id];
let instance_uniform = meshlet_instance_uniforms[instance_id];
let model = affine3_to_square(instance_uniform.model);
let world_position = mesh_position_local_to_world(model, vec4(vertex.position, 1.0));
var clip_position = view.view_proj * vec4(world_position.xyz, 1.0);
#ifdef DEPTH_CLAMP_ORTHO
let unclamped_clip_depth = clip_position.z;
clip_position.z = min(clip_position.z, 1.0);
#endif
return VertexOutput(
clip_position,
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
packed_ids,
meshlet_instance_material_ids[instance_id],
#endif
#ifdef DEPTH_CLAMP_ORTHO
unclamped_clip_depth,
#endif
);
}
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
@fragment
fn fragment(vertex_output: VertexOutput) -> FragmentOutput {
return FragmentOutput(
vec4(vertex_output.visibility, 0u, 0u, 0u),
vec4(vertex_output.material_depth, 0u, 0u, 0u),
);
}
#endif
#ifdef DEPTH_CLAMP_ORTHO
@fragment
fn fragment(vertex_output: VertexOutput) -> @builtin(frag_depth) f32 {
return vertex_output.unclamped_clip_depth;
}
#endif