UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

148 lines (113 loc) 3.8 kB
import { mat4 } from "gl-matrix"; import { array_copy } from "../../../../core/collection/array/array_copy.js"; import { AABB3 } from "../../../../core/geom/3d/aabb/AABB3.js"; import { aabb3_from_v3_array_transformed } from "../../../../core/geom/3d/aabb/aabb3_from_v3_array_transformed.js"; import { allocate_m4 } from "../../../../core/geom/3d/mat4/allocate_m4.js"; import { decompose_matrix_4_array } from "../../../../core/geom/3d/mat4/decompose_matrix_4_array.js"; import { Ray3 } from "../../../../core/geom/3d/ray/Ray3.js"; import Quaternion from "../../../../core/geom/Quaternion.js"; import { v3_distance } from "../../../../core/geom/vec3/v3_distance.js"; import Vector3 from "../../../../core/geom/Vector3.js"; import { ray_hit_apply_transform } from "./ray_hit_apply_transform.js"; const local_ray = new Ray3(); let mesh_id_counter = 0; export class PathTracedMesh { /** * * @type {number} */ id = mesh_id_counter++; /** * * @type {AABB3} */ aabb = new AABB3(); /** * * @type {BufferedGeometryBVH|null} */ bvh = null; /** * * @type {THREE.BufferGeometry|null} */ geometry = null; /** * * @type {StandardMaterial|null} */ material = null; #transform = allocate_m4(); #transform_inverse = allocate_m4(); get transform_inverse() { return this.#transform_inverse; } build_tight_bounds() { const position = new Vector3(); const rotation = new Quaternion(); const scale = new Vector3(); decompose_matrix_4_array(this.#transform, position, rotation, scale); if (rotation.roughlyEquals(Quaternion.identity)) { // no rotation component, can safely scale/translate geometry bounds to get tight fit this.update_bounds(); } else { const position_attribute = this.geometry.getAttribute('position'); const position_array = position_attribute.array; aabb3_from_v3_array_transformed( this.aabb, position_array, position_array.length, this.#transform ); } } update_bounds() { this.bvh.getBounds(this.aabb); this.aabb.applyMatrix4(this.#transform); } set transform(m) { array_copy(m, 0, this.#transform, 0, 16); mat4.invert(this.#transform_inverse, m); if (this.bvh !== null) { this.update_bounds(); } } get transform() { return this.#transform; } /** * * @param {Ray3} ray * @returns {boolean} */ occluded(ray) { const m4 = this.#transform_inverse; local_ray.copy(ray); local_ray.applyMatrix4(m4); return this.bvh.occluded(local_ray); } /** * * @param {number[]} out * @param {number[]|Ray3} ray * @param {number} ray_limit overrides Ray.tMax * @returns {number} distance along the ray to contact */ hit(out, ray, ray_limit) { //transform ray const m4 = this.#transform_inverse; local_ray.copy(ray); local_ray.tMax = ray_limit; local_ray.applyMatrix4(m4); let distance_to_hit = this.bvh.raycast2(out, local_ray); if (distance_to_hit >= 0) { // transform output ray_hit_apply_transform(out, out, this.#transform); out[10] = this.id; distance_to_hit = v3_distance( ray[0], ray[1], ray[2], out[0], out[1], out[2] ); } return distance_to_hit; } }