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}