Skip to main content

pbrt/
lib.rs

1// Copyright 2018 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![warn(missing_docs)]
16
17//! pbrt is a rust implementation of http://www.pbr-book.org/3ed-2018/contents.html
18
19pub mod core;
20pub mod filters;
21pub mod textures;
22
23#[cfg(feature = "float-as-double")]
24/// submodule to defined types, constants and methods when `Float` is defined as a `f64` using the
25/// "float-as-double" cargo feature.
26pub mod float {
27    pub use std::f64::*;
28    /// Alias of the `f64` type, to be used through out the codebase anywhere a default sized
29    /// `Float` is necessary.
30    pub type Float = f64;
31}
32
33#[cfg(not(feature = "float-as-double"))]
34/// submodule to defined types, constants and methods when `Float` is defined as a `f32` when not using the
35/// "float-as-double" cargo feature.
36pub mod float {
37    pub use std::f32::*;
38    /// Alias of the `f32` type, to be used through out the codebase anywhere a default sized
39    /// `Float` is necessary.
40    pub type Float = f32;
41}
42
43pub use float::Float;
44
45/// Wrapper type for `Float` to ensure degree vs radian is clear.
46#[derive(Copy, Clone)]
47pub struct Degree(pub(crate) Float);
48
49impl From<Float> for Degree {
50    fn from(f: Float) -> Degree {
51        Degree(f)
52    }
53}
54
55/// Options for the renderer.  These are mostly passed through from commandline flags or from the
56/// configuration file parsed.
57#[derive(Clone, Debug)]
58pub struct Options {
59    /// number of threads to use when rendering.
60    pub num_threads: u32,
61    /// Not implemented: enable some options for quick draft quality rendering.
62    pub quick_render: bool,
63    /// Squelch all non-error output.
64    pub quiet: bool,
65    /// Enable extra logging output.
66    pub verbose: bool,
67    /// Path to stored rendered output.
68    pub image_file: String,
69}
70
71impl Default for Options {
72    fn default() -> Options {
73        Options {
74            num_threads: 1,
75            quick_render: false,
76            quiet: false,
77            verbose: true,
78            image_file: "".to_owned(),
79        }
80    }
81}
82
83//const PI: Float = 3.14159265358979323846;
84//const INV_PI: Float = 0.31830988618379067154;
85//const INV2_PI: Float = 0.15915494309189533577;
86//const INV4_PI: Float = 0.07957747154594766788;
87//const PI_OVER2: Float = 1.57079632679489661923;
88//const PI_OVER4: Float = 0.78539816339744830961;
89//const SQRT2: Float = 1.41421356237309504880;
90
91/// Convert `value` into sRGB gamma-corrected value.
92pub fn gamma_correct(value: Float) -> Float {
93    if value <= 0.0031308 {
94        12.92 * value
95    } else {
96        1.055 * value.powf(1. / 2.4) - 0.055
97    }
98}
99
100/// Clamp `val` between `low` and `high`.
101///
102/// # Examples
103/// ```
104/// use pbrt::clamp;
105///
106/// assert_eq!(clamp(-1., 0., 1.), 0.);
107/// assert_eq!(clamp(0.5, 0., 1.), 0.5);
108/// assert_eq!(clamp(2., 0., 1.), 1.0);
109///
110/// assert_eq!(clamp(-1, 0, 2), 0);
111/// assert_eq!(clamp(1, 0, 2), 1);
112/// assert_eq!(clamp(3, 0, 2), 2);
113/// ```
114pub fn clamp<T>(val: T, low: T, high: T) -> T
115where
116    T: PartialOrd,
117{
118    if val < low {
119        low
120    } else if val > high {
121        high
122    } else {
123        val
124    }
125}
126
127/// Linear interpolate `t` between `v1` and `v2`.
128///
129/// # Examples
130/// ```
131/// use pbrt::lerp;
132///
133/// assert_eq!(lerp(0., 0., 1.), 0.);
134/// assert_eq!(lerp(0.5, 0., 1.), 0.5);
135/// assert_eq!(lerp(1., 0., 1.), 1.);
136/// assert_eq!(lerp(0.75, 0., 2.), 1.5);
137/// ```
138pub fn lerp(t: Float, v1: Float, v2: Float) -> Float {
139    (1. - t) * v1 + t * v2
140}
141
142/// Note: assert_almost_equal_options exists only for doc tests, it is not part of the pbrt API.
143pub fn assert_almost_equal_options(l: Option<(Float, Float)>, r: Option<(Float, Float)>) {
144    if l.is_none() && r.is_none() {
145        return;
146    }
147    assert!(l.is_some());
148    assert!(r.is_some());
149    let l = l.unwrap();
150    let r = r.unwrap();
151    assert_almost_equal(l.0, r.0);
152    assert_almost_equal(l.1, r.1);
153}
154
155fn assert_almost_equal(f1: Float, f2: Float) {
156    let diff = (f1 - f2).abs();
157    assert!(diff < float::EPSILON, "{} != {}, diff of {}", f1, f2, diff);
158}
159
160/// Find roots of quadratic equation, if they exist.
161///
162/// # Examples
163/// From
164/// https://www.cliffsnotes.com/study-guides/algebra/algebra-i/quadratic-equations/solving-quadratic-equations
165/// ```
166/// use pbrt::Float;
167/// use pbrt::quadratic;
168/// use pbrt::assert_almost_equal_options;
169///
170/// assert_eq!(quadratic(1., 1., 1.), None);
171/// assert_eq!(quadratic(1., -6., -16.), Some((-2., 8.)));
172/// assert_eq!(quadratic(1., 6., 5.), Some((-5., -1.)));
173/// assert_eq!(quadratic(1., 0., -16.), Some((-4. ,4.)));
174/// assert_eq!(quadratic(1., 6., 0.), Some((-6. ,0.)));
175/// // This quadratic returns irrational numbers, so some care is taken to ensure the equality
176/// // tests work out.
177/// let three: Float = 3.;
178/// assert_almost_equal_options(quadratic(1., 2., -2.),
179///     Some(((-1.-three.sqrt()), (-1.+three.sqrt()))));
180pub fn quadratic(a: Float, b: Float, c: Float) -> Option<(Float, Float)> {
181    let a = a as f64;
182    let b = b as f64;
183    let c = c as f64;
184    // Find quadratic discriminant
185    let discrim = b * b - 4. * a * c;
186    if discrim < 0. {
187        return None;
188    }
189    let root_discrim = discrim.sqrt();
190    let q = if b < 0. {
191        -0.5 * (b - root_discrim)
192    } else {
193        -0.5 * (b + root_discrim)
194    };
195    let t0 = (q / a) as Float;
196    let t1 = (c / q) as Float;
197    if t0 > t1 {
198        Some((t1, t0))
199    } else {
200        Some((t0, t1))
201    }
202}