1#[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 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 {}