mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
9cc7e7c080
* Save 16 bytes per vertex by calculating tangents in the shader at runtime, rather than storing them in the vertex data. * Based on https://jcgt.org/published/0009/03/04, https://www.jeremyong.com/graphics/2023/12/16/surface-gradient-bump-mapping. * Fixed visbuffer resolve to use the updated algorithm that flips ddy correctly * Added some more docs about meshlet material limitations, and some TODOs about transforming UV coordinates for the future. ![image](https://github.com/user-attachments/assets/222d8192-8c82-4d77-945d-53670a503761) For testing add a normal map to the bunnies with StandardMaterial like below, and then test that on both main and this PR (make sure to download the correct bunny for each). Results should be mostly identical. ```rust normal_map_texture: Some(asset_server.load_with_settings( "textures/BlueNoise-Normal.png", |settings: &mut ImageLoaderSettings| settings.is_srgb = false, )), ```
143 lines
5 KiB
Rust
143 lines
5 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://raw.githubusercontent.com/JMS55/bevy_meshlet_asset/854eb98353ad94aea1104f355fc24dbe4fda679d/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 {
|
|
cluster_buffer_slots: 8192,
|
|
},
|
|
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),
|
|
msaa: Msaa::Off,
|
|
..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,
|
|
..default()
|
|
},
|
|
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 {}
|