@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
167 lines (119 loc) • 4.31 kB
JavaScript
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;
}