UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

57 lines (46 loc) 1.72 kB
import { assert } from "../../assert.js"; import { v3_dot } from "./v3_dot.js"; import { v3_lerp } from "./v3_lerp.js"; /** * Spherical linear interpolation * NOTE: vectors are assumed to be normalized * @see https://en.wikipedia.org/wiki/Slerp * @param {Vector3|{set(x:number,y:number,z:number)}} result Rotated vector is written here * @param {number} a_x First vector * @param {number} a_y First vector * @param {number} a_z First vector * @param {number} b_x Second vector * @param {number} b_y Second vector * @param {number} b_z Second vector * @param {number} fraction Interpolation factor */ export function v3_slerp( result, a_x, a_y, a_z, b_x, b_y, b_z, fraction ) { assert.isNumber(fraction, 'fraction'); assert.notNaN(fraction, "fraction"); assert.greaterThanOrEqual(fraction, 0, "fraction"); const dot = v3_dot( a_x, a_y, a_z, b_x, b_y, b_z ); if (dot >= 1 || dot <= -1) { // avoid division by 0, both vectors are pointing in the same direction, use lerp instead v3_lerp(result, a_x, a_y, a_z, b_x, b_y, b_z, fraction); return; } // compute angle between two vectors const theta = Math.acos(dot); const sin_theta = Math.sin(theta); const inv_sin_theta = 1 / sin_theta; // TODO check for sin_theta == 0 to avoid division by 0 const scale_0 = Math.sin((1 - fraction) * theta) * inv_sin_theta; const scale_1 = Math.sin((fraction) * theta) * inv_sin_theta; const x = a_x * scale_0 + b_x * scale_1; const y = a_y * scale_0 + b_y * scale_1; const z = a_z * scale_0 + b_z * scale_1; result.set(x, y, z); }