UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

88 lines (68 loc) 2.92 kB
import { array_copy } from "../../../../collection/array/array_copy.js"; import { min2 } from "../../../../math/min2.js"; import { ConicRay } from "../../../ConicRay.js"; import { Miniball } from "../../../packing/miniball/Miniball.js"; import { PointSet } from "../../../packing/miniball/PointSet.js"; import { v3_angle_between } from "../../../vec3/v3_angle_between.js"; /** * Using Shirman and Abi-Ezzi method, compute bounding sphere of points, then build a cone from that * @see L.A. Shirman and S.S. Abi-Ezzi, The cone of normals technique for fast processing of curved patches, Computer Graphics Forum, 12 (1993), 261-272. * @param {ConicRay} result * @param {Iterable<TopoTriangle>} faces */ export function computeTriangleClusterNormalBoundingCone(result, faces) { const normal_data = []; let normal_count = 0; // extract face normals for (let face of faces) { const face_normal = face.normal; if (face_normal[0] === 0 && face_normal[1] === 0 && face_normal[1] === 0) { // skip continue; } const address = normal_count * 3; array_copy(face_normal, 0, normal_data, address, 3); normal_count++; } const result_direction = result.direction; if (normal_count === 0) { // no valid normals, produce an arbitrary result result_direction.set(1, 0, 0); result.angle = 0; return; } const point_set = new PointSet(normal_count, 3, normal_data); const miniball = new Miniball(point_set); const miniball_center = miniball.center(); if (Number.isNaN(miniball_center[0]) || Number.isNaN(miniball_center[1]) || Number.isNaN(miniball_center[2])) { // something went wrong, center is undefined, fall-back to an open cone result_direction.set(1, 0, 0); result.angle = Math.PI; return; } result_direction.fromArray(miniball_center, 0); const center_vector_magnitude = result_direction.length(); if (center_vector_magnitude === 0) { // degenerate, pointing in all directions result_direction.set(1, 0, 0); result.angle = Math.PI; return; } result_direction.multiplyScalar(1 / center_vector_magnitude); // normalize direction vector // include normals into the cone let max_angle = 0; for (let i = 0; i < normal_count; i++) { const i3 = i * 3; const normal_x = normal_data[i3]; const normal_y = normal_data[i3]; const normal_z = normal_data[i3]; const angle = v3_angle_between( normal_x, normal_y, normal_z, result_direction.x, result_direction.y, result_direction.z ); if (angle > max_angle) { max_angle = angle; } } result.angle = min2(max_angle, Math.PI); }