UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

167 lines (119 loc) 4.31 kB
import { v3_dot } from "../../vec3/v3_dot.js"; /** * * @param {number[]} result result is written as a 2d vector, since barycentrics add up to 1, we omit the last value * @param {number} result_offset * @param {number} px reference point * @param {number} py reference point * @param {number} pz reference point * @param {number} ax Triangle apex A * @param {number} ay Triangle apex A * @param {number} az Triangle apex A * @param {number} bx Triangle apex B * @param {number} by Triangle apex B * @param {number} bz Triangle apex B * @param {number} cx Triangle apex C * @param {number} cy Triangle apex C * @param {number} cz Triangle apex C * @returns {void} */ export function computeTriangleClosestPointToPointBarycentric( result, result_offset, px, py, pz, ax, ay, az, bx, by, bz, cx, cy, cz ) { // adapted from https://github.com/mrdoob/three.js/blob/676e85dc7cd5971a6565c4152e9e6d8bdd20a2b7/src/math/Triangle.js#L222 let v, w; // algorithm thanks to Real-Time Collision Detection by Christer Ericson, // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., // under the accompanying license; see chapter 5.1.5 for detailed explanation. // basically, we're distinguishing which of the voronoi regions of the triangle // the point lies in with the minimum amount of redundant computation. // localize coordinates with respect to A const _vab_x = bx - ax; const _vab_y = by - ay; const _vab_z = bz - az; const _vac_x = cx - ax; const _vac_y = cy - ay; const _vac_z = cz - az; const _vap_x = px - ax; const _vap_y = py - ay; const _vap_z = pz - az; const d1 = v3_dot(_vab_x, _vab_y, _vab_z, _vap_x, _vap_y, _vap_z); const d2 = v3_dot(_vac_x, _vac_y, _vac_z, _vap_x, _vap_y, _vap_z); if (d1 <= 0 && d2 <= 0) { // vertex region of A; barycentric coords (1, 0, 0) result[result_offset] = 1; result[result_offset + 1] = 0; return; } const _vbp_x = px - bx; const _vbp_y = py - by; const _vbp_z = pz - bz; const d3 = v3_dot(_vab_x, _vab_y, _vab_z, _vbp_x, _vbp_y, _vbp_z); const d4 = v3_dot(_vac_x, _vac_y, _vac_z, _vbp_x, _vbp_y, _vbp_z); if (d3 >= 0 && d4 <= d3) { // vertex region of B; barycentric coords (0, 1, 0) result[result_offset] = 0; result[result_offset + 1] = 1; return; } const vc = d1 * d4 - d3 * d2; if (vc <= 0 && d1 >= 0 && d3 <= 0) { const s = d1 - d3; if (s !== 0) { v = d1 / s; } else { v = 0; } // edge region of AB; barycentric coords (1-v, v, 0) result[result_offset] = 1 - v; result[result_offset + 1] = v; return; } const _vcp_x = px - cx; const _vcp_y = py - cy; const _vcp_z = pz - cz; const d5 = v3_dot(_vab_x, _vab_y, _vab_z, _vcp_x, _vcp_y, _vcp_z); const d6 = v3_dot(_vac_x, _vac_y, _vac_z, _vcp_x, _vcp_y, _vcp_z); if (d6 >= 0 && d5 <= d6) { // vertex region of C; barycentric coords (0, 0, 1) result[result_offset] = 0; result[result_offset + 1] = 0; return; } const vb = d5 * d2 - d1 * d6; if (vb <= 0 && d2 >= 0 && d6 <= 0) { const s = d2 - d6; if (s !== 0) { w = d2 / s; } else { w = 0; } // edge region of AC; barycentric coords (1-w, 0, w) result[result_offset] = 1 - w; result[result_offset + 1] = 0; return; } const va = d3 * d6 - d5 * d4; if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { const s = (d4 - d3) + (d5 - d6); if(s !== 0) { w = (d4 - d3) / s; }else{ w = 1; } // edge region of BC; barycentric coords (0, 1-w, w) result[result_offset] = 0; result[result_offset + 1] = 1 - w; return; } // face region const denom = 1 / (va + vb + vc); const u = va * denom v = vb * denom; result[result_offset] = u; result[result_offset + 1] = v; }