Implement HDRI skybox support
This commit is contained in:
parent
44489f9fe3
commit
1e9b997aeb
12 changed files with 282 additions and 17 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
|
@ -1 +1,2 @@
|
||||||
assets/models/* filter=lfs diff=lfs merge=lfs -text
|
assets/models/* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
assets/exr/* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
|
||||||
114
Cargo.lock
generated
114
Cargo.lock
generated
|
|
@ -130,6 +130,12 @@ version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit_field"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
|
@ -319,12 +325,37 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.21"
|
version = "0.8.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cursor-icon"
|
name = "cursor-icon"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
@ -384,6 +415,21 @@ dependencies = [
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "exr"
|
||||||
|
version = "1.73.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
|
"half",
|
||||||
|
"lebe",
|
||||||
|
"miniz_oxide",
|
||||||
|
"rayon-core",
|
||||||
|
"smallvec",
|
||||||
|
"zune-inflate",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
|
|
@ -603,6 +649,16 @@ dependencies = [
|
||||||
"gl_generator",
|
"gl_generator",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crunchy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.5"
|
version = "0.14.5"
|
||||||
|
|
@ -636,12 +692,14 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.6"
|
version = "0.25.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
|
checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder-lite",
|
"byteorder-lite",
|
||||||
|
"exr",
|
||||||
|
"moxcms",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png",
|
"png",
|
||||||
"zune-core",
|
"zune-core",
|
||||||
|
|
@ -769,6 +827,12 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lebe"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.174"
|
version = "0.2.174"
|
||||||
|
|
@ -864,6 +928,16 @@ version = "0.5.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
|
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "moxcms"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"pxfm",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|
@ -1267,11 +1341,11 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.16"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 2.9.1",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"fdeflate",
|
"fdeflate",
|
||||||
"flate2",
|
"flate2",
|
||||||
|
|
@ -1310,6 +1384,15 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pxfm"
|
||||||
|
version = "0.1.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83f9b339b02259ada5c0f4a389b7fb472f933aa17ce176fd2ad98f28bb401fde"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.37.5"
|
version = "0.37.5"
|
||||||
|
|
@ -1388,9 +1471,11 @@ name = "raidillon_glium"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"exr",
|
||||||
"glam",
|
"glam",
|
||||||
"glium",
|
"glium",
|
||||||
"gltf",
|
"gltf",
|
||||||
|
"image",
|
||||||
"imgui",
|
"imgui",
|
||||||
"imgui-glium-renderer",
|
"imgui-glium-renderer",
|
||||||
"imgui-winit-support",
|
"imgui-winit-support",
|
||||||
|
|
@ -1419,6 +1504,16 @@ version = "0.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
|
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
|
@ -2408,6 +2503,15 @@ version = "0.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zune-inflate"
|
||||||
|
version = "0.2.54"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
|
||||||
|
dependencies = [
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-jpeg"
|
name = "zune-jpeg"
|
||||||
version = "0.4.20"
|
version = "0.4.20"
|
||||||
|
|
|
||||||
BIN
assets/exr/citrus_orchard_road_puresky_4k.exr
(Stored with Git LFS)
Normal file
BIN
assets/exr/citrus_orchard_road_puresky_4k.exr
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/exr/qwantani_sunset_puresky_2k.exr
(Stored with Git LFS)
Normal file
BIN
assets/exr/qwantani_sunset_puresky_2k.exr
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -17,6 +17,7 @@ vec2 sample_spherical_map(vec3 v) {
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 uv = sample_spherical_map(normalize(direction));
|
vec2 uv = sample_spherical_map(normalize(direction));
|
||||||
|
uv.y = 1.0 - uv.y;
|
||||||
vec3 color = texture(equirect, uv).rgb;
|
vec3 color = texture(equirect, uv).rgb;
|
||||||
frag_color = vec4(color, 1.0);
|
frag_color = vec4(color, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,8 +101,8 @@ fn main() {
|
||||||
let platform = GliumPlatform::initialize(
|
let platform = GliumPlatform::initialize(
|
||||||
engine,
|
engine,
|
||||||
"Raidillon".to_string(),
|
"Raidillon".to_string(),
|
||||||
1920,
|
2560,
|
||||||
1080,
|
1440,
|
||||||
);
|
);
|
||||||
platform.run()
|
platform.run()
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,5 @@ indexmap = "2.10.0"
|
||||||
imgui = "0.12.0"
|
imgui = "0.12.0"
|
||||||
imgui-winit-support = "0.13.0"
|
imgui-winit-support = "0.13.0"
|
||||||
imgui-glium-renderer = "0.13.0"
|
imgui-glium-renderer = "0.13.0"
|
||||||
|
exr = "1.73.0"
|
||||||
|
image = { version = "0.25.8", default-features = false, features = ["exr"] }
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ use raidillon_core::engine::EngineTrait;
|
||||||
use raidillon_core::time;
|
use raidillon_core::time;
|
||||||
use raidillon_core::time::Time;
|
use raidillon_core::time::Time;
|
||||||
use crate::render::debug_ui::ImguiBridge;
|
use crate::render::debug_ui::ImguiBridge;
|
||||||
use crate::render::BasicMeshRenderingSystem;
|
use crate::render::{BasicMeshRenderingSystem, SkyboxRenderingSystem};
|
||||||
use crate::GliumAssetManager;
|
use crate::GliumAssetManager;
|
||||||
|
use glam::Vec3;
|
||||||
|
|
||||||
pub struct GliumPlatform<E: EngineTrait<PlatformCtx = PlatformContext>> {
|
pub struct GliumPlatform<E: EngineTrait<PlatformCtx = PlatformContext>> {
|
||||||
event_loop: EventLoop<()>,
|
event_loop: EventLoop<()>,
|
||||||
|
|
@ -44,7 +45,8 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
let time_cfg = time::Config::default();
|
let time_cfg = time::Config::default();
|
||||||
let time = time::Time::new(time_cfg);
|
let time = time::Time::new(time_cfg);
|
||||||
|
|
||||||
// Install rendering systems
|
// Install rendering systems in order
|
||||||
|
rendering_system_manager.add::<SkyboxRenderingSystem>(&display, &window);
|
||||||
rendering_system_manager.add::<BasicMeshRenderingSystem>(&display, &window);
|
rendering_system_manager.add::<BasicMeshRenderingSystem>(&display, &window);
|
||||||
rendering_system_manager.add::<ImguiBridge>(&display, &window);
|
rendering_system_manager.add::<ImguiBridge>(&display, &window);
|
||||||
|
|
||||||
|
|
@ -95,12 +97,14 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
asset_manager: self.asset_manager.clone(),
|
asset_manager: self.asset_manager.clone(),
|
||||||
window: &mut self.window,
|
window: &mut self.window,
|
||||||
debug_ui_buffer,
|
debug_ui_buffer,
|
||||||
|
env_light_dir: Vec3::new(0.0, -1.0, 0.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.rendering_system_manager
|
self.rendering_system_manager
|
||||||
.systems
|
.systems
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.for_each(|system| system.render(&mut context));
|
.for_each(|system| system.render(&mut context));
|
||||||
|
|
||||||
target.finish().unwrap();
|
target.finish().unwrap();
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,8 @@ impl RenderingSystem for BasicMeshRenderingSystem {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Direction from the light source (0,+Y) towards the scene.
|
// Use HDR-derived environment light direction if provided, otherwise default to downward
|
||||||
let light_dir: Vec3 = Vec3::new(0.0, -1.0, 0.0).normalize();
|
let light_dir: Vec3 = if ctx.env_light_dir.length_squared() > 0.0 { ctx.env_light_dir.normalize() } else { Vec3::new(0.0, -1.0, 0.0) };
|
||||||
|
|
||||||
// let asset_manager = ctx.asset_manager.borrow();
|
|
||||||
// let any_ref: &dyn Any = &**asset_manager;
|
|
||||||
// if let Some(glium_manager) = any_ref.downcast_ref::<GliumAssetManager>() {
|
|
||||||
// &glium_manager.models;
|
|
||||||
// }
|
|
||||||
|
|
||||||
let asset_manager = ctx.asset_manager.borrow();
|
let asset_manager = ctx.asset_manager.borrow();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
mod basic;
|
mod basic;
|
||||||
pub mod debug_ui;
|
pub mod debug_ui;
|
||||||
|
mod skybox;
|
||||||
|
|
||||||
pub use basic::BasicMeshRenderingSystem;
|
pub use basic::BasicMeshRenderingSystem;
|
||||||
|
pub use skybox::SkyboxRenderingSystem;
|
||||||
|
|
|
||||||
149
glium_platform/src/render/skybox.rs
Normal file
149
glium_platform/src/render/skybox.rs
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use glium::{Display, Program, Surface, VertexBuffer, IndexBuffer, implement_vertex};
|
||||||
|
use glium::glutin::surface::WindowSurface;
|
||||||
|
use glium::index::PrimitiveType;
|
||||||
|
use glium::texture::{RawImage2d, SrgbTexture2d, Texture2d};
|
||||||
|
use glium::uniform;
|
||||||
|
use glam::{Mat4, Vec2, Vec3};
|
||||||
|
use raidillon_assets::include_shader;
|
||||||
|
use crate::system::RenderingContext;
|
||||||
|
use crate::RenderingSystem;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct SkyboxVertex { position: [f32; 3] }
|
||||||
|
implement_vertex!(SkyboxVertex, position);
|
||||||
|
|
||||||
|
pub struct SkyboxRenderingSystem {
|
||||||
|
program: Program,
|
||||||
|
quad_vb: VertexBuffer<SkyboxVertex>,
|
||||||
|
quad_ib: IndexBuffer<u16>,
|
||||||
|
/// Equirectangular HDR image, tonemapped to sRGB for skybox view
|
||||||
|
equirect_srgb: SrgbTexture2d,
|
||||||
|
/// Dominant light direction estimated from HDRI
|
||||||
|
light_dir: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SkyboxRenderingSystem {
|
||||||
|
fn build_cube(display: &Display<WindowSurface>) -> (VertexBuffer<SkyboxVertex>, IndexBuffer<u16>) {
|
||||||
|
// Unit cube centered at origin
|
||||||
|
let p = &[
|
||||||
|
[-1.0, -1.0, -1.0], [ 1.0, -1.0, -1.0], [ 1.0, 1.0, -1.0], [-1.0, 1.0, -1.0], // back
|
||||||
|
[-1.0, -1.0, 1.0], [ 1.0, -1.0, 1.0], [ 1.0, 1.0, 1.0], [-1.0, 1.0, 1.0], // front
|
||||||
|
];
|
||||||
|
let verts = vec![
|
||||||
|
SkyboxVertex { position: p[0] }, SkyboxVertex { position: p[1] }, SkyboxVertex { position: p[2] }, SkyboxVertex { position: p[3] }, // back
|
||||||
|
SkyboxVertex { position: p[4] }, SkyboxVertex { position: p[5] }, SkyboxVertex { position: p[6] }, SkyboxVertex { position: p[7] }, // front
|
||||||
|
];
|
||||||
|
let idx: [u16; 36] = [
|
||||||
|
// back face
|
||||||
|
0,1,2, 2,3,0,
|
||||||
|
// front face
|
||||||
|
4,6,5, 6,4,7,
|
||||||
|
// left face
|
||||||
|
0,3,7, 7,4,0,
|
||||||
|
// right face
|
||||||
|
1,5,6, 6,2,1,
|
||||||
|
// bottom face
|
||||||
|
0,4,5, 5,1,0,
|
||||||
|
// top face
|
||||||
|
3,2,6, 6,7,3,
|
||||||
|
];
|
||||||
|
(
|
||||||
|
VertexBuffer::new(display, &verts).unwrap(),
|
||||||
|
IndexBuffer::new(display, PrimitiveType::TrianglesList, &idx).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_hdr_equirect_and_analyze(display: &Display<WindowSurface>, path: &std::path::Path) -> (SrgbTexture2d, Vec3) {
|
||||||
|
// Use image crate to decode EXR as f32 RGB
|
||||||
|
let dyn_img = image::ImageReader::open(path).expect("open exr").with_guessed_format().expect("guess format").decode().expect("decode exr");
|
||||||
|
let hdr = dyn_img.to_rgb32f();
|
||||||
|
let (width, height) = hdr.dimensions();
|
||||||
|
let width = width as usize; let height = height as usize;
|
||||||
|
let mut dir_accum = Vec3::ZERO;
|
||||||
|
let mut weight_sum = 0.0f32;
|
||||||
|
for y in 0..height {
|
||||||
|
let v = (y as f32 + 0.5) / height as f32;
|
||||||
|
let theta = (v - 0.5) * std::f32::consts::PI;
|
||||||
|
let lat_weight = theta.cos().max(0.0);
|
||||||
|
for x in 0..width {
|
||||||
|
let u = (x as f32 + 0.5) / width as f32;
|
||||||
|
let phi = (u - 0.5) * 2.0 * std::f32::consts::PI;
|
||||||
|
let px = hdr.get_pixel(x as u32, y as u32).0;
|
||||||
|
let rgb = Vec3::new(px[0], px[1], px[2]);
|
||||||
|
let lum = 0.2126*rgb.x + 0.7152*rgb.y + 0.0722*rgb.z;
|
||||||
|
if lum > 0.0 {
|
||||||
|
let dir = Vec3::new(phi.cos()*theta.cos(), theta.sin(), phi.sin()*theta.cos());
|
||||||
|
let w = lum * lat_weight;
|
||||||
|
dir_accum += dir * w;
|
||||||
|
weight_sum += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut light_dir = if weight_sum > 0.0 { dir_accum / weight_sum } else { Vec3::new(0.0, -1.0, 0.0) };
|
||||||
|
if light_dir.length_squared() < 1e-6 { light_dir = Vec3::new(0.0,-1.0,0.0); }
|
||||||
|
light_dir = light_dir.normalize();
|
||||||
|
|
||||||
|
// Tonemap to sRGB
|
||||||
|
let mut srgb_bytes = Vec::with_capacity(width*height*4);
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
let px = hdr.get_pixel(x as u32, y as u32).0;
|
||||||
|
let mapped = Vec3::new(px[0], px[1], px[2]) / (Vec3::new(px[0], px[1], px[2]) + Vec3::ONE);
|
||||||
|
let srgb = mapped.powf(1.0/2.2);
|
||||||
|
srgb_bytes.extend_from_slice(&[
|
||||||
|
(srgb.x.clamp(0.0,1.0)*255.0) as u8,
|
||||||
|
(srgb.y.clamp(0.0,1.0)*255.0) as u8,
|
||||||
|
(srgb.z.clamp(0.0,1.0)*255.0) as u8,
|
||||||
|
255u8,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let raw = RawImage2d::from_raw_rgba(srgb_bytes, (width as u32, height as u32));
|
||||||
|
let tex = SrgbTexture2d::new(display, raw).unwrap();
|
||||||
|
(tex, light_dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderingSystem for SkyboxRenderingSystem {
|
||||||
|
fn initialize(display: &Display<WindowSurface>, _window: &glium::winit::window::Window) -> Self {
|
||||||
|
const VERT_SRC: &str = include_shader!("skybox.vert");
|
||||||
|
const FRAG_SRC: &str = include_shader!("skybox.frag");
|
||||||
|
let program = Program::from_source(display, VERT_SRC, FRAG_SRC, None).unwrap();
|
||||||
|
let (quad_vb, quad_ib) = Self::build_cube(display);
|
||||||
|
|
||||||
|
// Load EXR from assets/exr
|
||||||
|
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||||
|
let path = std::path::Path::new(manifest_dir).join("../assets/exr/qwantani_sunset_puresky_2k.exr");
|
||||||
|
let (equirect_srgb, light_dir) = Self::load_hdr_equirect_and_analyze(display, &path);
|
||||||
|
Self { program, quad_vb, quad_ib, equirect_srgb, light_dir }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, ctx: &mut RenderingContext) {
|
||||||
|
// Provide view and projection without translation for skybox
|
||||||
|
let cam = match ctx.scene.world.query::<&raidillon_platform::Camera>().iter().next() {
|
||||||
|
Some((_, cam)) => *cam,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
let mut view = cam.view();
|
||||||
|
// remove translation from view matrix (only orientation)
|
||||||
|
view.col_mut(3).x = 0.0; view.col_mut(3).y = 0.0; view.col_mut(3).z = 0.0;
|
||||||
|
let uniforms = uniform! {
|
||||||
|
view: view.to_cols_array_2d(),
|
||||||
|
projection: cam.projection().to_cols_array_2d(),
|
||||||
|
equirect: &self.equirect_srgb,
|
||||||
|
};
|
||||||
|
let params = glium::DrawParameters { depth: glium::Depth { test: glium::draw_parameters::DepthTest::IfLessOrEqual, write: false, ..Default::default() }, ..Default::default() };
|
||||||
|
ctx.target.draw(&self.quad_vb, &self.quad_ib, &self.program, &uniforms, ¶ms).ok();
|
||||||
|
|
||||||
|
// Share light direction with following passes
|
||||||
|
ctx.env_light_dir = self.light_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide a getter for light direction for other systems
|
||||||
|
impl SkyboxRenderingSystem {
|
||||||
|
pub fn light_direction(&self) -> Vec3 { self.light_dir }
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ use glium::glutin::surface::WindowSurface;
|
||||||
use raidillon_assets::ModelManagerRef;
|
use raidillon_assets::ModelManagerRef;
|
||||||
use raidillon_core::DebugUIBuffer;
|
use raidillon_core::DebugUIBuffer;
|
||||||
use raidillon_core::scene::Scene;
|
use raidillon_core::scene::Scene;
|
||||||
|
use glam::Vec3;
|
||||||
|
|
||||||
pub struct RenderingContext<'a> {
|
pub struct RenderingContext<'a> {
|
||||||
pub scene: &'a Scene,
|
pub scene: &'a Scene,
|
||||||
|
|
@ -14,6 +15,7 @@ pub struct RenderingContext<'a> {
|
||||||
pub window: &'a mut glium::winit::window::Window,
|
pub window: &'a mut glium::winit::window::Window,
|
||||||
pub asset_manager: ModelManagerRef,
|
pub asset_manager: ModelManagerRef,
|
||||||
pub debug_ui_buffer: Rc<RefCell<DebugUIBuffer>>,
|
pub debug_ui_buffer: Rc<RefCell<DebugUIBuffer>>,
|
||||||
|
pub env_light_dir: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The internal "rendering system" trait of glium_platform.
|
/// The internal "rendering system" trait of glium_platform.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue