UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

341 lines (319 loc) 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Mesh = void 0; var _Vector = require("../math/Vector3.js"); var _Vector2 = require("../math/Vector2.js"); var _Sphere = require("../math/Sphere.js"); var _Ray = require("../math/Ray.js"); var _Matrix = require("../math/Matrix4.js"); var _Object3D = require("../core/Object3D.js"); var _Triangle = require("../math/Triangle.js"); var _constants = require("../constants.js"); var _MeshBasicMaterial = require("../materials/MeshBasicMaterial.js"); var _BufferGeometry = require("../core/BufferGeometry.js"); const _inverseMatrix = /*@__PURE__*/new _Matrix.Matrix4(); const _ray = /*@__PURE__*/new _Ray.Ray(); const _sphere = /*@__PURE__*/new _Sphere.Sphere(); const _sphereHitAt = /*@__PURE__*/new _Vector.Vector3(); const _vA = /*@__PURE__*/new _Vector.Vector3(); const _vB = /*@__PURE__*/new _Vector.Vector3(); const _vC = /*@__PURE__*/new _Vector.Vector3(); const _tempA = /*@__PURE__*/new _Vector.Vector3(); const _morphA = /*@__PURE__*/new _Vector.Vector3(); const _intersectionPoint = /*@__PURE__*/new _Vector.Vector3(); const _intersectionPointWorld = /*@__PURE__*/new _Vector.Vector3(); /** * Class representing triangular polygon mesh based objects. * * ```js * const geometry = new THREE.BoxGeometry( 1, 1, 1 ); * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); * const mesh = new THREE.Mesh( geometry, material ); * scene.add( mesh ); * ``` * * @augments Object3D */ class Mesh extends _Object3D.Object3D { /** * Constructs a new mesh. * * @param {BufferGeometry} [geometry] - The mesh geometry. * @param {Material|Array<Material>} [material] - The mesh material. */ constructor(geometry = new _BufferGeometry.BufferGeometry(), material = new _MeshBasicMaterial.MeshBasicMaterial()) { super(); /** * This flag can be used for type testing. * * @type {boolean} * @readonly * @default true */ this.isMesh = true; this.type = 'Mesh'; /** * The mesh geometry. * * @type {BufferGeometry} */ this.geometry = geometry; /** * The mesh material. * * @type {Material|Array<Material>} * @default MeshBasicMaterial */ this.material = material; /** * A dictionary representing the morph targets in the geometry. The key is the * morph targets name, the value its attribute index. This member is `undefined` * by default and only set when morph targets are detected in the geometry. * * @type {Object<String,number>|undefined} * @default undefined */ this.morphTargetDictionary = undefined; /** * An array of weights typically in the range `[0,1]` that specify how much of the morph * is applied. This member is `undefined` by default and only set when morph targets are * detected in the geometry. * * @type {Array<number>|undefined} * @default undefined */ this.morphTargetInfluences = undefined; this.updateMorphTargets(); } copy(source, recursive) { super.copy(source, recursive); if (source.morphTargetInfluences !== undefined) { this.morphTargetInfluences = source.morphTargetInfluences.slice(); } if (source.morphTargetDictionary !== undefined) { this.morphTargetDictionary = Object.assign({}, source.morphTargetDictionary); } this.material = Array.isArray(source.material) ? source.material.slice() : source.material; this.geometry = source.geometry; return this; } /** * Sets the values of {@link Mesh#morphTargetDictionary} and {@link Mesh#morphTargetInfluences} * to make sure existing morph targets can influence this 3D object. */ updateMorphTargets() { const geometry = this.geometry; const morphAttributes = geometry.morphAttributes; const keys = Object.keys(morphAttributes); if (keys.length > 0) { const morphAttribute = morphAttributes[keys[0]]; if (morphAttribute !== undefined) { this.morphTargetInfluences = []; this.morphTargetDictionary = {}; for (let m = 0, ml = morphAttribute.length; m < ml; m++) { const name = morphAttribute[m].name || String(m); this.morphTargetInfluences.push(0); this.morphTargetDictionary[name] = m; } } } } /** * Returns the local-space position of the vertex at the given index, taking into * account the current animation state of both morph targets and skinning. * * @param {number} index - The vertex index. * @param {Vector3} target - The target object that is used to store the method's result. * @return {Vector3} The vertex position in local space. */ getVertexPosition(index, target) { const geometry = this.geometry; const position = geometry.attributes.position; const morphPosition = geometry.morphAttributes.position; const morphTargetsRelative = geometry.morphTargetsRelative; target.fromBufferAttribute(position, index); const morphInfluences = this.morphTargetInfluences; if (morphPosition && morphInfluences) { _morphA.set(0, 0, 0); for (let i = 0, il = morphPosition.length; i < il; i++) { const influence = morphInfluences[i]; const morphAttribute = morphPosition[i]; if (influence === 0) continue; _tempA.fromBufferAttribute(morphAttribute, index); if (morphTargetsRelative) { _morphA.addScaledVector(_tempA, influence); } else { _morphA.addScaledVector(_tempA.sub(target), influence); } } target.add(_morphA); } return target; } /** * Computes intersection points between a casted ray and this line. * * @param {Raycaster} raycaster - The raycaster. * @param {Array<Object>} intersects - The target array that holds the intersection points. */ raycast(raycaster, intersects) { const geometry = this.geometry; const material = this.material; const matrixWorld = this.matrixWorld; if (material === undefined) return; // test with bounding sphere in world space if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); _sphere.copy(geometry.boundingSphere); _sphere.applyMatrix4(matrixWorld); // check distance from ray origin to bounding sphere _ray.copy(raycaster.ray).recast(raycaster.near); if (_sphere.containsPoint(_ray.origin) === false) { if (_ray.intersectSphere(_sphere, _sphereHitAt) === null) return; if (_ray.origin.distanceToSquared(_sphereHitAt) > (raycaster.far - raycaster.near) ** 2) return; } // convert ray to local space of mesh _inverseMatrix.copy(matrixWorld).invert(); _ray.copy(raycaster.ray).applyMatrix4(_inverseMatrix); // test with bounding box in local space if (geometry.boundingBox !== null) { if (_ray.intersectsBox(geometry.boundingBox) === false) return; } // test for intersections with geometry this._computeIntersections(raycaster, intersects, _ray); } _computeIntersections(raycaster, intersects, rayLocalSpace) { let intersection; const geometry = this.geometry; const material = this.material; const index = geometry.index; const position = geometry.attributes.position; const uv = geometry.attributes.uv; const uv1 = geometry.attributes.uv1; const normal = geometry.attributes.normal; const groups = geometry.groups; const drawRange = geometry.drawRange; if (index !== null) { // indexed buffer geometry if (Array.isArray(material)) { for (let i = 0, il = groups.length; i < il; i++) { const group = groups[i]; const groupMaterial = material[group.materialIndex]; const start = Math.max(group.start, drawRange.start); const end = Math.min(index.count, Math.min(group.start + group.count, drawRange.start + drawRange.count)); for (let j = start, jl = end; j < jl; j += 3) { const a = index.getX(j); const b = index.getX(j + 1); const c = index.getX(j + 2); intersection = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); if (intersection) { intersection.faceIndex = Math.floor(j / 3); // triangle number in indexed buffer semantics intersection.face.materialIndex = group.materialIndex; intersects.push(intersection); } } } } else { const start = Math.max(0, drawRange.start); const end = Math.min(index.count, drawRange.start + drawRange.count); for (let i = start, il = end; i < il; i += 3) { const a = index.getX(i); const b = index.getX(i + 1); const c = index.getX(i + 2); intersection = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); if (intersection) { intersection.faceIndex = Math.floor(i / 3); // triangle number in indexed buffer semantics intersects.push(intersection); } } } } else if (position !== undefined) { // non-indexed buffer geometry if (Array.isArray(material)) { for (let i = 0, il = groups.length; i < il; i++) { const group = groups[i]; const groupMaterial = material[group.materialIndex]; const start = Math.max(group.start, drawRange.start); const end = Math.min(position.count, Math.min(group.start + group.count, drawRange.start + drawRange.count)); for (let j = start, jl = end; j < jl; j += 3) { const a = j; const b = j + 1; const c = j + 2; intersection = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); if (intersection) { intersection.faceIndex = Math.floor(j / 3); // triangle number in non-indexed buffer semantics intersection.face.materialIndex = group.materialIndex; intersects.push(intersection); } } } } else { const start = Math.max(0, drawRange.start); const end = Math.min(position.count, drawRange.start + drawRange.count); for (let i = start, il = end; i < il; i += 3) { const a = i; const b = i + 1; const c = i + 2; intersection = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); if (intersection) { intersection.faceIndex = Math.floor(i / 3); // triangle number in non-indexed buffer semantics intersects.push(intersection); } } } } } } exports.Mesh = Mesh; function checkIntersection(object, material, raycaster, ray, pA, pB, pC, point) { let intersect; if (material.side === _constants.BackSide) { intersect = ray.intersectTriangle(pC, pB, pA, true, point); } else { intersect = ray.intersectTriangle(pA, pB, pC, material.side === _constants.FrontSide, point); } if (intersect === null) return null; _intersectionPointWorld.copy(point); _intersectionPointWorld.applyMatrix4(object.matrixWorld); const distance = raycaster.ray.origin.distanceTo(_intersectionPointWorld); if (distance < raycaster.near || distance > raycaster.far) return null; return { distance: distance, point: _intersectionPointWorld.clone(), object: object }; } function checkGeometryIntersection(object, material, raycaster, ray, uv, uv1, normal, a, b, c) { object.getVertexPosition(a, _vA); object.getVertexPosition(b, _vB); object.getVertexPosition(c, _vC); const intersection = checkIntersection(object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint); if (intersection) { const barycoord = new _Vector.Vector3(); _Triangle.Triangle.getBarycoord(_intersectionPoint, _vA, _vB, _vC, barycoord); if (uv) { intersection.uv = _Triangle.Triangle.getInterpolatedAttribute(uv, a, b, c, barycoord, new _Vector2.Vector2()); } if (uv1) { intersection.uv1 = _Triangle.Triangle.getInterpolatedAttribute(uv1, a, b, c, barycoord, new _Vector2.Vector2()); } if (normal) { intersection.normal = _Triangle.Triangle.getInterpolatedAttribute(normal, a, b, c, barycoord, new _Vector.Vector3()); if (intersection.normal.dot(ray.direction) > 0) { intersection.normal.multiplyScalar(-1); } } const face = { a: a, b: b, c: c, normal: new _Vector.Vector3(), materialIndex: 0 }; _Triangle.Triangle.getNormal(_vA, _vB, _vC, face.normal); intersection.face = face; intersection.barycoord = barycoord; } return intersection; }