meshlet/
meshlet.rs

1//! Meshlet rendering for dense high-poly scenes (experimental).
2
3// Note: This example showcases the meshlet API, but is not the type of scene that would benefit from using meshlets.
4
5#[path = "../helpers/camera_controller.rs"]
6mod camera_controller;
7
8use bevy::{
9    pbr::{
10        experimental::meshlet::{MeshletMesh3d, MeshletPlugin},
11        CascadeShadowConfigBuilder, DirectionalLightShadowMap,
12    },
13    prelude::*,
14    render::render_resource::AsBindGroup,
15};
16use camera_controller::{CameraController, CameraControllerPlugin};
17use std::{f32::consts::PI, path::Path, process::ExitCode};
18
19const ASSET_URL: &str =
20    "https://raw.githubusercontent.com/JMS55/bevy_meshlet_asset/7a7c14138021f63904b584d5f7b73b695c7f4bbf/bunny.meshlet_mesh";
21
22fn main() -> ExitCode {
23    if !Path::new("./assets/external/models/bunny.meshlet_mesh").exists() {
24        eprintln!("ERROR: Asset at path <bevy>/assets/external/models/bunny.meshlet_mesh is missing. Please download it from {ASSET_URL}");
25        return ExitCode::FAILURE;
26    }
27
28    App::new()
29        .insert_resource(DirectionalLightShadowMap { size: 4096 })
30        .add_plugins((
31            DefaultPlugins,
32            MeshletPlugin {
33                cluster_buffer_slots: 8192,
34            },
35            MaterialPlugin::<MeshletDebugMaterial>::default(),
36            CameraControllerPlugin,
37        ))
38        .add_systems(Startup, setup)
39        .run();
40
41    ExitCode::SUCCESS
42}
43
44fn setup(
45    mut commands: Commands,
46    asset_server: Res<AssetServer>,
47    mut standard_materials: ResMut<Assets<StandardMaterial>>,
48    mut debug_materials: ResMut<Assets<MeshletDebugMaterial>>,
49    mut meshes: ResMut<Assets<Mesh>>,
50) {
51    commands.spawn((
52        Camera3d::default(),
53        Transform::from_translation(Vec3::new(1.8, 0.4, -0.1)).looking_at(Vec3::ZERO, Vec3::Y),
54        Msaa::Off,
55        EnvironmentMapLight {
56            diffuse_map: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"),
57            specular_map: asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
58            intensity: 150.0,
59            ..default()
60        },
61        CameraController::default(),
62    ));
63
64    commands.spawn((
65        DirectionalLight {
66            illuminance: light_consts::lux::FULL_DAYLIGHT,
67            shadows_enabled: true,
68            ..default()
69        },
70        CascadeShadowConfigBuilder {
71            num_cascades: 1,
72            maximum_distance: 15.0,
73            ..default()
74        }
75        .build(),
76        Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, PI * -0.15, PI * -0.15)),
77    ));
78
79    // A custom file format storing a [`bevy_render::mesh::Mesh`]
80    // that has been converted to a [`bevy_pbr::meshlet::MeshletMesh`]
81    // using [`bevy_pbr::meshlet::MeshletMesh::from_mesh`], which is
82    // a function only available when the `meshlet_processor` cargo feature is enabled.
83    let meshlet_mesh_handle = asset_server.load("external/models/bunny.meshlet_mesh");
84    let debug_material = debug_materials.add(MeshletDebugMaterial::default());
85
86    for x in -2..=2 {
87        commands.spawn((
88            MeshletMesh3d(meshlet_mesh_handle.clone()),
89            MeshMaterial3d(standard_materials.add(StandardMaterial {
90                base_color: match x {
91                    -2 => Srgba::hex("#dc2626").unwrap().into(),
92                    -1 => Srgba::hex("#ea580c").unwrap().into(),
93                    0 => Srgba::hex("#facc15").unwrap().into(),
94                    1 => Srgba::hex("#16a34a").unwrap().into(),
95                    2 => Srgba::hex("#0284c7").unwrap().into(),
96                    _ => unreachable!(),
97                },
98                perceptual_roughness: (x + 2) as f32 / 4.0,
99                ..default()
100            })),
101            Transform::default()
102                .with_scale(Vec3::splat(0.2))
103                .with_translation(Vec3::new(x as f32 / 2.0, 0.0, -0.3)),
104        ));
105    }
106    for x in -2..=2 {
107        commands.spawn((
108            MeshletMesh3d(meshlet_mesh_handle.clone()),
109            MeshMaterial3d(debug_material.clone()),
110            Transform::default()
111                .with_scale(Vec3::splat(0.2))
112                .with_rotation(Quat::from_rotation_y(PI))
113                .with_translation(Vec3::new(x as f32 / 2.0, 0.0, 0.3)),
114        ));
115    }
116
117    commands.spawn((
118        Mesh3d(meshes.add(Plane3d::default().mesh().size(5.0, 5.0))),
119        MeshMaterial3d(standard_materials.add(StandardMaterial {
120            base_color: Color::WHITE,
121            perceptual_roughness: 1.0,
122            ..default()
123        })),
124    ));
125}
126
127#[derive(Asset, TypePath, AsBindGroup, Clone, Default)]
128struct MeshletDebugMaterial {
129    _dummy: (),
130}
131impl Material for MeshletDebugMaterial {}