mirror of
https://github.com/bevyengine/bevy
synced 2024-11-13 00:17:27 +00:00
e1a0da0fa6
Keeping track of explicit visibility per cluster between frames does not work with LODs, and leads to worse culling (using the final depth buffer from the previous frame is more accurate). Instead, we need to generate a second depth pyramid after the second raster pass, and then use that in the first culling pass in the next frame to test if a cluster would have been visible last frame or not. As part of these changes, the write_index_buffer pass has been folded into the culling pass for a large performance gain, and to avoid tracking a lot of extra state that would be needed between passes. Prepass previous model/view stuff was adapted to work with meshlets as well. Also fixed a bug with materials, and other misc improvements. --------- Co-authored-by: François <mockersf@gmail.com> Co-authored-by: atlas dostal <rodol@rivalrebels.com> Co-authored-by: vero <email@atlasdostal.com> Co-authored-by: Patrick Walton <pcwalton@mimiga.net> Co-authored-by: Robert Swain <robert.swain@gmail.com>
138 lines
4.8 KiB
Rust
138 lines
4.8 KiB
Rust
//! Meshlet rendering for dense high-poly scenes (experimental).
|
|
|
|
// Note: This example showcases the meshlet API, but is not the type of scene that would benefit from using meshlets.
|
|
|
|
#[path = "../helpers/camera_controller.rs"]
|
|
mod camera_controller;
|
|
|
|
use bevy::{
|
|
pbr::{
|
|
experimental::meshlet::{MaterialMeshletMeshBundle, MeshletPlugin},
|
|
CascadeShadowConfigBuilder, DirectionalLightShadowMap,
|
|
},
|
|
prelude::*,
|
|
render::render_resource::AsBindGroup,
|
|
};
|
|
use camera_controller::{CameraController, CameraControllerPlugin};
|
|
use std::{f32::consts::PI, path::Path, process::ExitCode};
|
|
|
|
const ASSET_URL: &str = "https://github.com/JMS55/bevy_meshlet_asset/blob/bd869887bc5c9c6e74e353f657d342bef84bacd8/bunny.meshlet_mesh";
|
|
|
|
fn main() -> ExitCode {
|
|
if !Path::new("./assets/models/bunny.meshlet_mesh").exists() {
|
|
eprintln!("ERROR: Asset at path <bevy>/assets/models/bunny.meshlet_mesh is missing. Please download it from {ASSET_URL}");
|
|
return ExitCode::FAILURE;
|
|
}
|
|
|
|
App::new()
|
|
.insert_resource(DirectionalLightShadowMap { size: 4096 })
|
|
.add_plugins((
|
|
DefaultPlugins,
|
|
MeshletPlugin,
|
|
MaterialPlugin::<MeshletDebugMaterial>::default(),
|
|
CameraControllerPlugin,
|
|
))
|
|
.add_systems(Startup, setup)
|
|
.run();
|
|
|
|
ExitCode::SUCCESS
|
|
}
|
|
|
|
fn setup(
|
|
mut commands: Commands,
|
|
asset_server: Res<AssetServer>,
|
|
mut standard_materials: ResMut<Assets<StandardMaterial>>,
|
|
mut debug_materials: ResMut<Assets<MeshletDebugMaterial>>,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
) {
|
|
commands.spawn((
|
|
Camera3dBundle {
|
|
transform: Transform::from_translation(Vec3::new(1.8, 0.4, -0.1))
|
|
.looking_at(Vec3::ZERO, Vec3::Y),
|
|
..default()
|
|
},
|
|
EnvironmentMapLight {
|
|
diffuse_map: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"),
|
|
specular_map: asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
|
|
intensity: 150.0,
|
|
},
|
|
CameraController::default(),
|
|
));
|
|
|
|
commands.spawn(DirectionalLightBundle {
|
|
directional_light: DirectionalLight {
|
|
illuminance: light_consts::lux::FULL_DAYLIGHT,
|
|
shadows_enabled: true,
|
|
..default()
|
|
},
|
|
cascade_shadow_config: CascadeShadowConfigBuilder {
|
|
num_cascades: 1,
|
|
maximum_distance: 15.0,
|
|
..default()
|
|
}
|
|
.build(),
|
|
transform: Transform::from_rotation(Quat::from_euler(
|
|
EulerRot::ZYX,
|
|
0.0,
|
|
PI * -0.15,
|
|
PI * -0.15,
|
|
)),
|
|
..default()
|
|
});
|
|
|
|
// A custom file format storing a [`bevy_render::mesh::Mesh`]
|
|
// that has been converted to a [`bevy_pbr::meshlet::MeshletMesh`]
|
|
// using [`bevy_pbr::meshlet::MeshletMesh::from_mesh`], which is
|
|
// a function only available when the `meshlet_processor` cargo feature is enabled.
|
|
let meshlet_mesh_handle = asset_server.load("models/bunny.meshlet_mesh");
|
|
let debug_material = debug_materials.add(MeshletDebugMaterial::default());
|
|
|
|
for x in -2..=2 {
|
|
commands.spawn(MaterialMeshletMeshBundle {
|
|
meshlet_mesh: meshlet_mesh_handle.clone(),
|
|
material: standard_materials.add(StandardMaterial {
|
|
base_color: match x {
|
|
-2 => Srgba::hex("#dc2626").unwrap().into(),
|
|
-1 => Srgba::hex("#ea580c").unwrap().into(),
|
|
0 => Srgba::hex("#facc15").unwrap().into(),
|
|
1 => Srgba::hex("#16a34a").unwrap().into(),
|
|
2 => Srgba::hex("#0284c7").unwrap().into(),
|
|
_ => unreachable!(),
|
|
},
|
|
perceptual_roughness: (x + 2) as f32 / 4.0,
|
|
..default()
|
|
}),
|
|
transform: Transform::default()
|
|
.with_scale(Vec3::splat(0.2))
|
|
.with_translation(Vec3::new(x as f32 / 2.0, 0.0, -0.3)),
|
|
..default()
|
|
});
|
|
}
|
|
for x in -2..=2 {
|
|
commands.spawn(MaterialMeshletMeshBundle {
|
|
meshlet_mesh: meshlet_mesh_handle.clone(),
|
|
material: debug_material.clone(),
|
|
transform: Transform::default()
|
|
.with_scale(Vec3::splat(0.2))
|
|
.with_rotation(Quat::from_rotation_y(PI))
|
|
.with_translation(Vec3::new(x as f32 / 2.0, 0.0, 0.3)),
|
|
..default()
|
|
});
|
|
}
|
|
|
|
commands.spawn(PbrBundle {
|
|
mesh: meshes.add(Plane3d::default().mesh().size(5.0, 5.0)),
|
|
material: standard_materials.add(StandardMaterial {
|
|
base_color: Color::WHITE,
|
|
perceptual_roughness: 1.0,
|
|
..default()
|
|
}),
|
|
..default()
|
|
});
|
|
}
|
|
|
|
#[derive(Asset, TypePath, AsBindGroup, Clone, Default)]
|
|
struct MeshletDebugMaterial {
|
|
_dummy: (),
|
|
}
|
|
impl Material for MeshletDebugMaterial {}
|