Image based lighting 🌐
Image-based lighting (IBL) is a technique that uses environment maps to illuminate scenes. It captures real-world lighting conditions and applies them to 3D models, providing realistic reflections and ambient lighting. IBL is particularly effective for creating natural-looking scenes by simulating complex lighting scenarios that are difficult to achieve with traditional analytical lights alone.
Example setup
We'll start from where we left off with the skybox example (before adding analytical lights):
use renderling::{
camera::Camera,
context::Context,
glam::Vec4,
glam::{Mat4, Vec3},
gltf::GltfDocument,
stage::Stage,
types::GpuOnlyArray,
};
let ctx = Context::headless(512, 512).await;
let stage: Stage = ctx
.new_stage()
.with_background_color(Vec4::new(0.25, 0.25, 0.25, 1.0));
let _camera: Camera = {
let aspect = 1.0;
let fovy = core::f32::consts::PI / 4.0;
let znear = 0.1;
let zfar = 10.0;
let projection = Mat4::perspective_rh(fovy, aspect, znear, zfar);
let eye = Vec3::new(0.5, 0.5, 0.8);
let target = Vec3::new(0.0, 0.3, 0.0);
let up = Vec3::Y;
let view = Mat4::look_at_rh(eye, target, up);
stage
.new_camera()
.with_projection_and_view(projection, view)
};
let model: GltfDocument<GpuOnlyArray> = stage
.load_gltf_document_from_path(workspace_dir().join("gltf/marble_bust_1k.glb"))
.unwrap()
.into_gpu_only();
let skybox = stage
.new_skybox_from_path(workspace_dir().join("img/hdr/helipad.hdr"))
.unwrap();
stage.use_skybox(&skybox);
Now we'll add image based lighting.
The Ibl
type
Ibl
is the type responsible for image based lighting.
You can think of it as a type of "global" light.
More than one Ibl
may exist, but only one can be used
by the stage at render time.
Creating an Ibl
follows the same expected builder pattern,
and just like Skybox
we call a familiar use_*
function
on the Stage
to use it:
use renderling::pbr::ibl::Ibl;
let ibl: Ibl = stage.new_ibl(&skybox);
stage.use_ibl(&ibl);
let frame = ctx.get_next_frame().unwrap();
stage.render(&frame.view());
let img = frame.read_image().await.unwrap();
img.save("lighting/ibl.png").unwrap();
frame.present();
Mix it up! 🎨
You can mix global image based lighting with analytical lights, just as you might expect. Here we'll build on the previous example to add a point light:
use renderling::{color::css_srgb_color_to_linear, light::Candela};
let sunset_amber_sunlight_color = css_srgb_color_to_linear(250, 198, 104);
let _point = stage
.new_point_light()
.with_position({
let bust_aabb = model.bounding_volume().unwrap();
bust_aabb.max
})
.with_color(sunset_amber_sunlight_color)
.with_intensity(Candela(100.0));
let frame = ctx.get_next_frame().unwrap();
stage.render(&frame.view());
let img = frame.read_image().await.unwrap();
img.save("lighting/ibl-analytical-mixed.png").unwrap();
frame.present();
By combining IBL with analytical lights, you can achieve a rich and dynamic lighting environment that captures both the subtle nuances of ambient light and the dramatic effects of direct illumination. Experiment with different environment maps and light setups to find the perfect balance for your scene.