renderling/
pbr.rs

1//! "Physically based" types and functions.
2//!
3//! ## References
4//! * <https://learnopengl.com/PBR/Theory>
5//! * <https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/5b1b7f48a8cb2b7aaef00d08fdba18ccc8dd331b/source/Renderer/shaders/pbr.frag>
6//! * <https://github.khronos.org/glTF-Sample-Viewer-Release/>
7
8pub mod brdf;
9pub mod debug;
10pub mod ibl;
11
12pub mod shader;
13
14#[cfg(test)]
15mod test {
16    use crate::{
17        atlas::AtlasImage,
18        geometry::Vertex,
19        glam::{Vec3, Vec4},
20        test::BlockOnFuture,
21    };
22
23    #[test]
24    // TODO: Move this over to a manual example
25    // Tests the initial implementation of pbr metallic roughness on an array of
26    // spheres with different metallic roughnesses lit by an environment map.
27    //
28    // see https://learnopengl.com/PBR/Lighting
29    fn pbr_metallic_roughness_spheres() {
30        let ss = 600;
31        let ctx = crate::context::Context::headless(ss, ss).block();
32        let stage = ctx.new_stage();
33
34        let radius = 0.5;
35        let ss = ss as f32;
36        let projection = crate::camera::perspective(ss, ss);
37        let k = 7;
38        let diameter = 2.0 * radius;
39        let spacing = radius * 0.25;
40        let len = (k - 1) as f32 * (diameter + spacing);
41        let half = len / 2.0;
42        let view = crate::camera::look_at(
43            Vec3::new(half, half, 1.6 * len),
44            Vec3::new(half, half, 0.0),
45            Vec3::Y,
46        );
47        let _camera = stage
48            .new_camera()
49            .with_projection_and_view(projection, view);
50
51        let geometry = stage.new_vertices({
52            let mut icosphere = icosahedron::Polyhedron::new_isocahedron(radius, 5);
53            icosphere.compute_triangle_normals();
54            let icosahedron::Polyhedron {
55                positions,
56                normals,
57                cells,
58                ..
59            } = icosphere;
60            log::info!("icosphere created on CPU");
61
62            let to_vertex = |ndx: &usize| -> Vertex {
63                let p: [f32; 3] = positions[*ndx].0.into();
64                let n: [f32; 3] = normals[*ndx].0.into();
65                Vertex::default().with_position(p).with_normal(n)
66            };
67            cells
68                .iter()
69                .flat_map(|icosahedron::Triangle { a, b, c }| {
70                    let p0 = to_vertex(a);
71                    let p1 = to_vertex(b);
72                    let p2 = to_vertex(c);
73                    vec![p0, p1, p2]
74                })
75                .collect::<Vec<_>>()
76        });
77        let mut spheres = vec![];
78        for i in 0..k {
79            let roughness = i as f32 / (k - 1) as f32;
80            let x = (diameter + spacing) * i as f32;
81            for j in 0..k {
82                let metallic = j as f32 / (k - 1) as f32;
83                let y = (diameter + spacing) * j as f32;
84
85                let rez = stage
86                    .new_primitive()
87                    .with_material(
88                        stage
89                            .new_material()
90                            .with_albedo_factor(Vec4::new(1.0, 1.0, 1.0, 1.0))
91                            .with_metallic_factor(metallic)
92                            .with_roughness_factor(roughness),
93                    )
94                    .with_transform(stage.new_transform().with_translation(Vec3::new(x, y, 0.0)))
95                    .with_vertices(&geometry);
96                spheres.push(rez);
97            }
98        }
99
100        let hdr_image = AtlasImage::from_hdr_path("../../img/hdr/resting_place.hdr").unwrap();
101        let skybox = crate::skybox::Skybox::new(&ctx, hdr_image);
102        stage.use_skybox(&skybox);
103
104        let ibl = stage.new_ibl(&skybox);
105        stage.use_ibl(&ibl);
106
107        let frame = ctx.get_next_frame().unwrap();
108        stage.render(&frame.view());
109        let img = frame.read_image().block().unwrap();
110        img_diff::assert_img_eq("pbr/metallic_roughness_spheres.png", img);
111    }
112}