UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

161 lines (128 loc) 4.47 kB
import { v3_dot } from "../../vec3/v3_dot.js"; import { assert } from "../../../assert.js"; /** * NOTE: adapted from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h * @source https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm (Möller and Trumbore, « Fast, Minimum Storage Ray-Triangle Intersection », Journal of Graphics Tools, vol. 2,‎ 1997, p. 21–28) * @param {SurfacePoint3} result * @param {number} origin_x * @param {number} origin_y * @param {number} origin_z * @param {number} direction_x * @param {number} direction_y * @param {number} direction_z * @param {number} ax * @param {number} ay * @param {number} az * @param {number} bx * @param {number} by * @param {number} bz * @param {number} cx * @param {number} cy * @param {number} cz * @returns {boolean} */ export function computeTriangleRayIntersection( result, origin_x, origin_y, origin_z, direction_x, direction_y, direction_z, ax, ay, az, bx, by, bz, cx, cy, cz ) { assert.isNumber(ax, 'ax'); assert.isNumber(ay, 'ay'); assert.isNumber(az, 'az'); assert.isNumber(bx, 'bx'); assert.isNumber(by, 'by'); assert.isNumber(bz, 'bz'); assert.isNumber(cx, 'cx'); assert.isNumber(cy, 'cy'); assert.isNumber(cz, 'cz'); // nan checks assert.notNaN(ax, 'ax'); assert.notNaN(ay, 'ay'); assert.notNaN(az, 'az'); assert.notNaN(bx, 'bx'); assert.notNaN(by, 'by'); assert.notNaN(bz, 'bz'); assert.notNaN(cx, 'cx'); assert.notNaN(cy, 'cy'); assert.notNaN(cz, 'cz'); // finate number check assert.isFiniteNumber(ax, 'ax'); assert.isFiniteNumber(ay, 'ay'); assert.isFiniteNumber(az, 'az'); assert.isFiniteNumber(bx, 'bx'); assert.isFiniteNumber(by, 'by'); assert.isFiniteNumber(bz, 'bz'); assert.isFiniteNumber(cx, 'cx'); assert.isFiniteNumber(cy, 'cy'); assert.isFiniteNumber(cz, 'cz'); // edge1 = a - b const edge1_x = bx - ax; const edge1_y = by - ay; const edge1_z = bz - az; // edge2 = c - a const edge2_x = cx - ax; const edge2_y = cy - ay; const edge2_z = cz - az; // Compute triangle normal // normal = edge1 x edge2 const normal_x = edge1_y * edge2_z - edge1_z * edge2_y; const normal_y = edge1_z * edge2_x - edge1_x * edge2_z; const normal_z = edge1_x * edge2_y - edge1_y * edge2_x let DdN = v3_dot(direction_x, direction_y, direction_z, normal_x, normal_y, normal_z); let sign = 1; if (DdN === 0) { // ray and the triangle normal are orthogonal, means that the ray can not pass penetrate triangle return false; } else if (DdN < 0) { sign = -1; DdN = -DdN; } // diff = origin - a const diff_x = origin_x - ax; const diff_y = origin_y - ay; const diff_z = origin_z - az; // edge3 = diff x edge2 const edge3_x = diff_y * edge2_z - diff_z * edge2_y; const edge3_y = diff_z * edge2_x - diff_x * edge2_z; const edge3_z = diff_x * edge2_y - diff_y * edge2_x; // DdQxE2 = sign * ( direction . edge3) const DdQxE2 = sign * v3_dot(direction_x, direction_y, direction_z, edge3_x, edge3_y, edge3_z); if (DdQxE2 < 0) { // b1 < 0, no intersection return false; } const edge4_x = edge1_y * diff_z - edge1_z * diff_y; const edge4_y = edge1_z * diff_x - edge1_x * diff_z; const edge4_z = edge1_x * diff_y - edge1_y * diff_x; const DdE1xQ = sign * v3_dot(direction_x, direction_y, direction_z, edge4_x, edge4_y, edge4_z); if (DdE1xQ < 0) { // b2 < 0, no intersection return false; } if (DdQxE2 + DdE1xQ > DdN) { // b1+b2 > 1, no intersection return false; } // Line intersects triangle, check if ray does. const QdN = -sign * v3_dot(diff_x, diff_y, diff_z, normal_x, normal_y, normal_z); if (QdN < 0) { // t < 0, no intersection return false; } // Ray intersects triangle. const t = QdN / DdN; result.normal.set( normal_x, normal_y, normal_z ); result.position.set( direction_x * t + origin_x, direction_y * t + origin_y, direction_z * t + origin_z, ); return true; }