Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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();

image of a marble bust lit by the helipad environment map

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();

image of a marble bust lit by the helipad environment map

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.