Skip to content

Instantly share code, notes, and snippets.

@Naxela
Created December 11, 2024 22:01
Show Gist options
  • Save Naxela/a0ce261405df3ecffbeead4681466741 to your computer and use it in GitHub Desktop.
Save Naxela/a0ce261405df3ecffbeead4681466741 to your computer and use it in GitHub Desktop.
Lightmap loading example code for Bevy 0.14 - Can't promise it works!
use std::fs;
use bevy::render::camera::TemporalJitter;
use bevy::{
core_pipeline::*,
pbr::*,
gltf::*,
prelude::*,
};
use bevy_panorbit_camera::*;
use bloom::BloomSettings;
use experimental::taa::{TemporalAntiAliasBundle, TemporalAntiAliasPlugin, TemporalAntiAliasSettings};
use fxaa::Fxaa;
use tonemapping::Tonemapping;
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Resource)]
struct SsaoState {
enabled: bool,
}
impl Default for SsaoState {
fn default() -> Self {
SsaoState { enabled: true } // Start with SSAO enabled
}
}
#[derive(Resource)]
pub struct SceneReady(pub bool);
#[derive(Resource, Debug)]
struct LightmapRegistry {
set: bool,
loaded: bool,
map: HashMap<String, String>,
}
use bevy_mod_mipmap_generator::{MipmapGeneratorPlugin, generate_mipmaps};
//Read project manifest + lightmap manifest (merge into one function)
// Main entry call
fn main() {
App::new()
.insert_resource(Msaa::Off) // Keep MSAA off for TAA to work better
.insert_resource(SceneReady(false))
// .insert_resource(AmbientLight {
// brightness: 100.,
// ..default()
// })
.insert_resource(LightmapRegistry {
set: false,
loaded: false,
map: HashMap::new(),
})
.add_plugins(DefaultPlugins
.set(ImagePlugin::default_linear())
.set(WindowPlugin {
primary_window: Some(Window {
..default()
}),
..default()
}))
.add_plugins(TemporalAntiAliasPlugin)
.add_plugins(MipmapGeneratorPlugin)
.add_plugins(PanOrbitCameraPlugin)
.add_systems(Startup, initialize_project)
.add_systems(Startup, setup)
.add_systems(Startup, spawn_scene.after(setup))
.add_systems(Update, generate_mipmaps::<StandardMaterial>)
.add_systems(Update, create_lightmap_registry.after(spawn_scene))
.add_systems(Update, load_lightmaps.after(create_lightmap_registry))
.add_systems(Update, start_runtime.after(load_lightmaps))
.add_systems(Update, toggle_ssao)
.run();
}
/* ASSET LOADING */
#[derive(Resource)]
pub struct SceneHandle(pub Handle<Gltf>); // Make the field public
#[derive(Deserialize, Debug, Clone)]
pub struct ProjectData {
pub name: String,
pub options: HashMap<String, String>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct LightmapManifestData {
pub ext: String,
pub lightmaps: HashMap<String, String>,
}
#[derive(Resource, Debug)]
pub struct ProjectDataResource(pub ProjectData);
#[derive(Resource, Debug)]
pub struct LightmapManifestDataResource(pub LightmapManifestData);
fn initialize_project(
mut commands: Commands
){
println!("Reading project file");
let project_file: String = fs::read_to_string("package.json").expect("Failed to read file");
let project_data: ProjectData = serde_json::from_str(&project_file).expect("Failed to parse JSON");
println!("Reading lightmap manifest file");
let lightmap_manifest_file: String = fs::read_to_string("assets/lightmaps/manifest.json").expect("Failed to read file");
let lightmap_manifest_data: LightmapManifestData = serde_json::from_str(&lightmap_manifest_file).expect("Failed to parse JSON");
println!("{:?}", lightmap_manifest_data);
commands.insert_resource(ProjectDataResource(project_data));
commands.insert_resource(LightmapManifestDataResource(lightmap_manifest_data));
println!("Done initializing");
}
fn spawn_scene(
mut commands: Commands,
asset_server: Res<AssetServer>,
){
commands.spawn(SceneBundle {
scene: asset_server.load("models/model.glb#Scene0"),
..default()
});
}
fn start_runtime(
mut scene_ready : ResMut<SceneReady>,
registry: ResMut<LightmapRegistry>
){
if registry.loaded {
if !scene_ready.0 {
println!("Everything ready");
*scene_ready = SceneReady(true);
}
}
}
// Setup function (spawns the camera and scene)
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>
) {
commands.insert_resource(SsaoState::default());
let scene_handle: Handle<Gltf>= asset_server.load("models/model.glb");
commands
.spawn((
Camera3dBundle {
transform: Transform::from_translation(Vec3::new(-5.0, 1.0, -5.0)),
camera: Camera {
hdr: true,
..default()
},
tonemapping: Tonemapping::BlenderFilmic,
..default()
},
// ScreenSpaceAmbientOcclusionSettings {
// quality_level: ScreenSpaceAmbientOcclusionQualityLevel::Ultra,
// ..default()
// },
// ScreenSpaceAmbientOcclusionBundle {
// settings: ScreenSpaceAmbientOcclusionSettings {
// quality_level:ScreenSpaceAmbientOcclusionQualityLevel::Ultra
// },
// ..default()
// },
//TemporalAntiAliasBundle::default(),
//TemporalAntiAliasSettings::default(),
//BloomSettings::NATURAL,
PanOrbitCamera::default(),
//Fxaa::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: 100.0,
},
))
.insert(ScreenSpaceAmbientOcclusionBundle::default())
.insert(TemporalAntiAliasBundle::default());
commands.insert_resource(SceneHandle(scene_handle));
}
fn toggle_ssao(
mut commands: Commands,
mut query: Query<Entity, With<Camera3d>>,
mut ssao_state: ResMut<SsaoState>,
input: Res<ButtonInput<KeyCode>>,
) {
if input.just_pressed(KeyCode::KeyF) {
for entity in query.iter_mut() {
if ssao_state.enabled {
// Disable SSAO by removing the SSAO settings component
commands.entity(entity).remove::<ScreenSpaceAmbientOcclusionSettings>();
println!("SSAO disabled");
} else {
// Enable SSAO by adding the SSAO settings component back
commands.entity(entity).insert(ScreenSpaceAmbientOcclusionSettings {
..default()
});
println!("SSAO enabled");
}
}
// Toggle the state
ssao_state.enabled = !ssao_state.enabled;
}
}
#[derive(Deserialize, Debug)]
pub struct GltfExtrasValue {
#[serde(rename = "TLM_Lightmap")]
pub tlm_lightmap: Option<String>,
}
fn load_lightmaps(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<StandardMaterial>>,
meshes: Query<(Entity, &Name, &Handle<StandardMaterial>), With<Handle<Mesh>>>,
mut registry: ResMut<LightmapRegistry>
){
let exposure = 1000.0;
if(registry.loaded == false){
if meshes.iter().count() > 0 {
println!("Applying lightmaps after scene is fully spawned!");
for (entity, name, material) in meshes.iter() {
// Look up the mesh name in the lightmap manifest
if let Some(lightmap_name) = registry.map.get(name.as_str()) {
println!("Found lightmap for {}: {}", name, lightmap_name);
materials.get_mut(material).unwrap().lightmap_exposure = exposure;
commands.entity(entity).insert(Lightmap {
image: asset_server.load("lightmaps/".to_owned() + lightmap_name + ".ktx2"),
..default()
});
} else {
println!("No lightmap found for mesh: {}", name);
}
}
registry.loaded = true;
}
}
}
fn create_lightmap_registry(
q: Query<(Entity, &Name, Option<&GltfExtras>)>,
children_query: Query<&Children>,
name_query: Query<&Name>,
mut registry: ResMut<LightmapRegistry>
){
if registry.set == false {
//println!("Setting registry now");
if q.iter().count() > 0 {
for (entity, name, extras) in q.iter() {
//println!("Checking registry for: {}", name);
let mut lightmap_found = false;
let mut object_name = ""; // Initialize with a default value
let mut lightmap_name = String::new(); // Initialize as an empty String
if let Some(extras) = extras {
//println!("Found extras for: {}", name);
// Deserialize the JSON value to extract TLM-Lightmap
match serde_json::from_str::<GltfExtrasValue>(&extras.value) {
Ok(parsed) => {
//println!("V: {:?}", parsed);
if let Some(lightmap) = parsed.tlm_lightmap {
object_name = name.as_str();
lightmap_name = lightmap.to_string();
lightmap_found = true;
//println!("A: {}, B: {}, C:{}",object_name, name, lightmap_name)
}
}
Err(err) => {
println!("Failed to parse extras for {}: {}", name.as_str(), err);
}
}
}
if lightmap_found {
if let Ok(children) = children_query.get(entity) {
for child in children.iter() {
// Access child entity names or data if necessary.
if let Ok(child_name) = name_query.get(*child) {
//println!("X: {}, Y: {}", child_name, lightmap_name);
registry.map.insert(child_name.to_string().clone(), lightmap_name.clone());
}
}
}
}
}
registry.set = true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment