UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

68 lines (53 loc) 2.09 kB
import { v3_length } from "../../../../../core/geom/vec3/v3_length.js"; import { PI2 } from "../../../../../core/math/PI2.js"; /** * @see 2003 "Global Illumination Compendium" by Philip Dutré (equation 36) * @see http://blog.hvidtfeldts.net/index.php/2015/01/path-tracing-3d-fractals/ * @param {number[]} out * @param {number} out_offset * @param {number[]} normal * @param {number} normal_offset * @param {number} power * @param {function():number} random */ export function getBiasedNormalSample( out, out_offset, normal, normal_offset, power, random ) { const dir_x = normal[normal_offset]; const dir_y = normal[normal_offset + 1]; const dir_z = normal[normal_offset + 2]; // we build orthonormal vectors with respect to the direction vector let o1_x, o1_y, o1_z; if (Math.abs(dir_x) > Math.abs(dir_z)) { o1_x = -dir_y; o1_y = dir_x; o1_z = 0; } else { o1_x = 0; o1_y = -dir_z; o1_z = dir_y; } // normalize orthonormal vector const o1_norm = 1 / v3_length(o1_x, o1_y, o1_z); o1_x *= o1_norm; o1_y *= o1_norm; o1_z *= o1_norm; const o2_x = dir_y * o1_z - dir_z * o1_y; const o2_y = dir_z * o1_x - dir_x * o1_z; const o2_z = dir_x * o1_y - dir_y * o1_x; // we can skip normalizing second orthonormal vector, as it will be guaranteed to be unit length already // for explanation, see https://math.stackexchange.com/questions/23259/is-the-cross-product-of-two-unit-vectors-itself-a-unit-vector#:~:text=If%20you%20know%20that%20the,(a%20length%20of%20one). const r_x = random() * PI2; const r_y = Math.pow(random(), 1 / (power + 1)); const oneminus = Math.sqrt(1.0 - r_y * r_y); const k0 = Math.cos(r_x) * oneminus; const k1 = Math.sin(r_x) * oneminus; out[out_offset] = k0 * o1_x + k1 * o2_x + r_y * dir_x; out[out_offset + 1] = k0 * o1_y + k1 * o2_y + r_y * dir_y; out[out_offset + 2] = k0 * o1_z + k1 * o2_z + r_y * dir_z; }