diff --git a/assets/shaders/pbr/convolute_diffuse_irradiance.frag.wgsl b/assets/shaders/pbr/convolute_diffuse_irradiance.frag.wgsl index 5ce7714d..426e438b 100644 --- a/assets/shaders/pbr/convolute_diffuse_irradiance.frag.wgsl +++ b/assets/shaders/pbr/convolute_diffuse_irradiance.frag.wgsl @@ -3,7 +3,8 @@ struct FragmentOutput { } struct Params { - time100: u32, // tick modulo 100 + time97: u32, // tick modulo 100 + sample_count: u32, } @group(0) @binding(0) var t_environment: texture_cube; @@ -11,8 +12,6 @@ struct Params { @group(1) @binding(0) var params: Params; -const SAMPLE_COUNT: u32 = 16u; - #include "sample.wgsl" @fragment @@ -24,14 +23,14 @@ fn frag(@location(0) wpos: vec3) -> FragmentOutput { var irradiance: vec3 = vec3(0.0); var totalWeight: f32 = 0.0; - for(var i: u32 = params.time100; i < SAMPLE_COUNT*97u; i += 97u) { - let Xi: vec2 = Hammersley(i, SAMPLE_COUNT*97u); + for(var i: u32 = params.time97; i < params.sample_count*97u; i += 97u) { + let Xi: vec2 = Hammersley(i, params.sample_count*97u); let ts: vec3 = HemisphereSampleuniform(Xi); // tangeant space let ws: vec3 = ts.x * right + ts.y * up + ts.z * normal; // world space irradiance += min(vec3(10.0), textureSampleLevel(t_environment, s_environment, ws, 0.0).rgb); } - irradiance = irradiance / f32(SAMPLE_COUNT); + irradiance = irradiance / f32(params.sample_count); return FragmentOutput(vec4(irradiance.r, irradiance.g, irradiance.b, 0.02)); } \ No newline at end of file diff --git a/assets/shaders/pbr/specular_prefilter.frag.wgsl b/assets/shaders/pbr/specular_prefilter.frag.wgsl index 36bca40d..af814660 100644 --- a/assets/shaders/pbr/specular_prefilter.frag.wgsl +++ b/assets/shaders/pbr/specular_prefilter.frag.wgsl @@ -4,7 +4,8 @@ struct FragmentOutput { struct Params { roughness: f32, - time100: u32, // tick modulo 100 + time97: u32, // tick modulo 97 + sample_count: u32, } @group(0) @binding(0) var t_environment: texture_cube; @@ -12,8 +13,6 @@ struct Params { @group(1) @binding(0) var params: Params; -const SAMPLE_COUNT: u32 = 30u; - #include "sample.wgsl" fn ImportanceSampleGGX(Xi: vec2, N: vec3, roughness: f32) -> vec3 { @@ -41,8 +40,8 @@ fn frag(@location(0) wpos: vec3) -> FragmentOutput { var totalWeight: f32 = 0.0; var color: vec3 = vec3(0.0); - for(var i: u32 = params.time100; i < SAMPLE_COUNT*97u; i += 97u) { - let Xi: vec2 = Hammersley(i, SAMPLE_COUNT*97u); + for(var i: u32 = params.time97; i < params.sample_count*97u; i += 97u) { + let Xi: vec2 = Hammersley(i, params.sample_count*97u); let H: vec3 = ImportanceSampleGGX(Xi, normal, params.roughness); let L: vec3 = normalize(2.0 * dot(V, H) * H - V); diff --git a/engine/src/drawables/lit_mesh.rs b/engine/src/drawables/lit_mesh.rs index 55bdafc7..bbd04a17 100644 --- a/engine/src/drawables/lit_mesh.rs +++ b/engine/src/drawables/lit_mesh.rs @@ -5,7 +5,7 @@ use wgpu::{ TextureViewDescriptor, TextureViewDimension, VertexBufferLayout, }; -use geom::{Camera, InfiniteFrustrum, LinearColor, Matrix4, Plane, Sphere, Vec2, Vec3}; +use geom::{Camera, InfiniteFrustrum, LinearColor, Matrix4, Sphere, Vec2, Vec3}; use crate::meshbuild::MeshLod; use crate::{ @@ -134,6 +134,8 @@ impl Mesh { dest: &Texture, dest_msaa: &Texture, ) { + const SHADOWMAP_RES: i32 = 1024; + let mut encoder = gfx .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { @@ -142,7 +144,8 @@ impl Mesh { let sun = Vec3::new(0.5, -1.3, 0.9).normalize(); - let smap_mat = cam.build_sun_shadowmap_matrix(sun, 1024.0, &InfiniteFrustrum::EMPTY); + let smap_mat = + cam.build_sun_shadowmap_matrix(sun, SHADOWMAP_RES as f32, &InfiniteFrustrum::EMPTY); let mut params = gfx.render_params.clone(&gfx.device); let value = params.value_mut(); @@ -161,7 +164,7 @@ impl Mesh { ]; value.time = 0.0; value.time_always = 0.0; - value.shadow_mapping_resolution = 1024; + value.shadow_mapping_resolution = SHADOWMAP_RES; params.upload_to_gpu(&gfx.queue); diff --git a/engine/src/passes/pbr.rs b/engine/src/passes/pbr.rs index c57f819c..00d5f798 100644 --- a/engine/src/passes/pbr.rs +++ b/engine/src/passes/pbr.rs @@ -36,13 +36,15 @@ enum PbrPipeline { #[derive(Default, Copy, Clone, Debug)] struct SpecularParams { roughness: f32, - time100: u32, + time97: u32, + sample_count: u32, } #[repr(C)] #[derive(Default, Copy, Clone, Debug)] struct DiffuseParams { - time100: u32, + time97: u32, + sample_count: u32, } u8slice_impl!(SpecularParams); @@ -180,7 +182,8 @@ impl Pbr { self.diffuse_uniform.write_direct( &gfx.queue, &DiffuseParams { - time100: ((gfx.tick * 7) % 97) as u32, + time97: ((gfx.tick * 7) % 97) as u32, + sample_count: if gfx.tick == 0 { 1024 } else { 32 }, }, ); for face in 0..6u32 { @@ -216,11 +219,11 @@ impl Pbr { &gfx.queue, &SpecularParams { roughness, - time100: ((gfx.tick * 7) % 97) as u32, + time97: ((gfx.tick * 7) % 97) as u32, + sample_count: if gfx.tick == 0 { 1024 } else { 60 }, }, ); - for face in 0..3 { - let face = face as u32 + ((gfx.tick % 2) * 3) as u32; + for face in 0..6 { let mut pass = enc.begin_render_pass(&RenderPassDescriptor { label: Some(format!("specular prefilter face {face} mip {mip}").as_str()), color_attachments: &[Some(RenderPassColorAttachment { diff --git a/engine/src/texture.rs b/engine/src/texture.rs index f31aceba..8c87f9f0 100644 --- a/engine/src/texture.rs +++ b/engine/src/texture.rs @@ -233,7 +233,13 @@ impl Texture { }) } - pub fn save_to_file(&self, device: &Device, queue: &wgpu::Queue, path: PathBuf) { + pub fn save_to_file( + &self, + device: &Device, + queue: &wgpu::Queue, + path: PathBuf, + mip_level: u32, + ) { match self.format { TextureFormat::Rgba8Unorm | TextureFormat::Rgba8UnormSrgb => {} _ => { @@ -242,13 +248,17 @@ impl Texture { } } + let w = self.extent.width >> mip_level; + let h = self.extent.height >> mip_level; + let size = w * h; + debug_assert!(self.extent.depth_or_array_layers == 1); let block_size = self.format.block_copy_size(None).unwrap(); let image_data_buf = Arc::new(device.create_buffer(&wgpu::BufferDescriptor { label: Some("save_to_file"), - size: (block_size * self.extent.width * self.extent.height) as u64, + size: (block_size * size) as u64, usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, mapped_at_creation: false, })); @@ -260,7 +270,7 @@ impl Texture { encoder.copy_texture_to_buffer( ImageCopyTexture { texture: &self.texture, - mip_level: 0, + mip_level, origin: wgpu::Origin3d::ZERO, aspect: wgpu::TextureAspect::All, }, @@ -268,7 +278,7 @@ impl Texture { buffer: &image_data_buf, layout: ImageDataLayout { offset: 0, - bytes_per_row: Some(block_size * self.extent.width), + bytes_per_row: Some(block_size * w), rows_per_image: None, }, }, @@ -278,7 +288,6 @@ impl Texture { queue.submit(std::iter::once(encoder.finish())); let image_data_buf_cpy = image_data_buf.clone(); - let extent_cpy = self.extent; image_data_buf.slice(..).map_async(MapMode::Read, move |v| { if v.is_err() { log::error!("Failed to map buffer for reading for save_to_file"); @@ -287,9 +296,7 @@ impl Texture { let v = image_data_buf_cpy.slice(..).get_mapped_range(); - let Some(rgba) = - image::RgbaImage::from_raw(extent_cpy.width, extent_cpy.height, v.to_vec()) - else { + let Some(rgba) = image::RgbaImage::from_raw(w, h, v.to_vec()) else { log::error!("Failed to create image from buffer for save_to_file"); return; }; diff --git a/native_app/src/gui/chat.rs b/native_app/src/gui/chat.rs index 2b1b561a..aa333ac3 100644 --- a/native_app/src/gui/chat.rs +++ b/native_app/src/gui/chat.rs @@ -57,7 +57,7 @@ pub fn chat(ui: &egui::Context, uiw: &UiWorld, sim: &Simulation) { ui.allocate_space(egui::Vec2::new(250.0, 0.0)); if msgs.len() < 12 { - ui.add_space((12 - msgs.len()) as f32 * tweak!(24.0)); + ui.add_space((12 - msgs.len()) as f32 * 24.0); } for message in msgs.iter().rev() { diff --git a/native_app/src/newgui/hud/mod.rs b/native_app/src/newgui/hud.rs similarity index 97% rename from native_app/src/newgui/hud/mod.rs rename to native_app/src/newgui/hud.rs index 748f19a6..314676bb 100644 --- a/native_app/src/newgui/hud/mod.rs +++ b/native_app/src/newgui/hud.rs @@ -45,8 +45,8 @@ pub fn render_newgui(uiworld: &UiWorld, sim: &Simulation) { minrow(5.0, || { let ids = &uiworld.read::().ids; - for id in ids { - image(*id, Vec2::splat(128.0)); + for id in ids.values() { + image(*id, Vec2::splat(96.0)); } }); }); diff --git a/native_app/src/newgui/hud/time_controls.rs b/native_app/src/newgui/hud/time_controls.rs index 38424f6b..16573772 100644 --- a/native_app/src/newgui/hud/time_controls.rs +++ b/native_app/src/newgui/hud/time_controls.rs @@ -99,7 +99,7 @@ pub fn time_controls(uiworld: &UiWorld, sim: &Simulation) { let mut l = List::column(); l.cross_axis_alignment = CrossAxisAlignment::Stretch; l.main_axis_size = MainAxisSize::Min; - l.item_spacing = tweak!(5.0); + l.item_spacing = 5.0; l.show(time_text); }); }); diff --git a/native_app/src/newgui/mod.rs b/native_app/src/newgui/mod.rs index 8fc8d30b..3cc7bddf 100644 --- a/native_app/src/newgui/mod.rs +++ b/native_app/src/newgui/mod.rs @@ -9,6 +9,7 @@ use simulation::map::BuildingID; use simulation::world_command::WorldCommand; use simulation::{AnyEntity, Simulation}; use std::borrow::Cow; +use std::path::PathBuf; use yakui::TextureId; mod hud; @@ -19,8 +20,7 @@ pub use tools::*; #[derive(Default)] pub struct IconTextures { - texs: FastMap, - ids: Vec, + ids: FastMap, } pub fn do_icons(gfx: &mut GfxContext, uiw: &mut UiWorld, yakui: &mut YakuiWrapper) { @@ -28,9 +28,9 @@ pub fn do_icons(gfx: &mut GfxContext, uiw: &mut UiWorld, yakui: &mut YakuiWrappe let mut cam = Camera::new(Vec3::new(0.0, 0.0, 0.0), 256.0, 256.0); - cam.fovy = tweak!(30.0); + cam.fovy = 30.0; cam.pitch = Degrees(35.0).into(); - cam.yaw = Degrees(tweak!(-130.0)).into(); + cam.yaw = Degrees(-130.0).into(); state.ids.clear(); @@ -38,9 +38,20 @@ pub fn do_icons(gfx: &mut GfxContext, uiw: &mut UiWorld, yakui: &mut YakuiWrappe let RenderAsset::Mesh { ref path } = building.asset else { continue; }; - //if state.texs.contains_key(&building.id) { + if state.ids.contains_key(&building.id) { + continue; + } + let cache_path = PathBuf::from(format!( + "assets/generated/building_icons/{}.png", + building.id.hash() + )); + //if std::fs::metadata(&cache_path).is_ok() { + // let t = TextureBuilder::from_path(&cache_path).build(&gfx.device, &gfx.queue); + // let tex_id = yakui.add_texture(&t); + // state.ids.insert(building.id, tex_id); // continue; //} + let Ok(mesh) = gfx.mesh(path.as_ref()) else { continue; }; @@ -49,6 +60,7 @@ pub fn do_icons(gfx: &mut GfxContext, uiw: &mut UiWorld, yakui: &mut YakuiWrappe .with_label("building icon") .with_usage( engine::wgpu::TextureUsages::COPY_DST + | engine::wgpu::TextureUsages::COPY_SRC | engine::wgpu::TextureUsages::RENDER_ATTACHMENT | engine::wgpu::TextureUsages::TEXTURE_BINDING, ) @@ -66,10 +78,12 @@ pub fn do_icons(gfx: &mut GfxContext, uiw: &mut UiWorld, yakui: &mut YakuiWrappe cam.update(); mesh.render_to_texture(&cam, gfx, &t, &t_msaa); + + t.save_to_file(&gfx.device, &gfx.queue, cache_path, 0); + let tex_id = yakui.add_texture(&t); - state.texs.insert(building.id, t); - state.ids.push(tex_id); + state.ids.insert(building.id, tex_id); } } diff --git a/native_app/src/newgui/tools/specialbuilding.rs b/native_app/src/newgui/tools/specialbuilding.rs index 470a20dd..159379bb 100644 --- a/native_app/src/newgui/tools/specialbuilding.rs +++ b/native_app/src/newgui/tools/specialbuilding.rs @@ -88,9 +88,7 @@ pub fn specialbuilding(sim: &Simulation, uiworld: &UiWorld) { let col = if red { simulation::colors().gui_danger.adjust_luminosity(1.3) } else { - simulation::colors() - .gui_primary - .adjust_luminosity(tweak!(1.5)) + simulation::colors().gui_primary.adjust_luminosity(1.5) }; if p.ends_with(".png") || p.ends_with(".jpg") { diff --git a/simulation/src/economy/market.rs b/simulation/src/economy/market.rs index 958a4b03..727b2e9b 100644 --- a/simulation/src/economy/market.rs +++ b/simulation/src/economy/market.rs @@ -496,7 +496,7 @@ mod tests { n_trucks = 1, n_workers = 2, size = 0.0, - asset_location = "", + asset = "no.jpg", price = 0, }, { @@ -518,7 +518,7 @@ mod tests { n_trucks = 1, n_workers = 5, size = 0.0, - asset_location = "", + asset = "no.jpg", price = 0, }} "#,