import { Vector3 } from '../math/Vector3.js'; import { Vector2 } from '../math/Vector2.js'; import { Sphere } from '../math/Sphere.js'; import { Ray } from '../math/Ray.js'; import { Matrix4 } from '../math/Matrix4.js'; import { Object3D } from '../core/Object3D.js'; import { Triangle } from '../math/Triangle.js'; import { DoubleSide, BackSide } from '../constants.js'; import { MeshBasicMaterial } from '../materials/MeshBasicMaterial.js'; import { BufferGeometry } from '../core/BufferGeometry.js'; const _inverseMatrix = /*@__PURE__*/ new Matrix4(); const _ray = /*@__PURE__*/ new Ray(); const _sphere = /*@__PURE__*/ new Sphere(); const _vA = /*@__PURE__*/ new Vector3(); const _vB = /*@__PURE__*/ new Vector3(); const _vC = /*@__PURE__*/ new Vector3(); const _tempA = /*@__PURE__*/ new Vector3(); const _tempB = /*@__PURE__*/ new Vector3(); const _tempC = /*@__PURE__*/ new Vector3(); const _morphA = /*@__PURE__*/ new Vector3(); const _morphB = /*@__PURE__*/ new Vector3(); const _morphC = /*@__PURE__*/ new Vector3(); const _uvA = /*@__PURE__*/ new Vector2(); const _uvB = /*@__PURE__*/ new Vector2(); const _uvC = /*@__PURE__*/ new Vector2(); const _intersectionPoint = /*@__PURE__*/ new Vector3(); const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); class Mesh extends Object3D { constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { super(); this.isMesh = true; this.type = 'Mesh'; this.geometry = geometry; this.material = material; 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 = source.material; this.geometry = source.geometry; return this; } 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; } } } } raycast( raycaster, intersects ) { const geometry = this.geometry; const material = this.material; const matrixWorld = this.matrixWorld; if ( material === undefined ) return; // Checking boundingSphere distance to ray if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); _sphere.copy( geometry.boundingSphere ); _sphere.applyMatrix4( matrixWorld ); if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; // _inverseMatrix.copy( matrixWorld ).invert(); _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); // Check boundingBox before continuing if ( geometry.boundingBox !== null ) { if ( _ray.intersectsBox( geometry.boundingBox ) === false ) return; } let intersection; const index = geometry.index; const position = geometry.attributes.position; const morphPosition = geometry.morphAttributes.position; const morphTargetsRelative = geometry.morphTargetsRelative; const uv = geometry.attributes.uv; const uv2 = geometry.attributes.uv2; 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 = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, 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 = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, 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 = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, 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 = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); if ( intersection ) { intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics intersects.push( intersection ); } } } } } } function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { let intersect; if ( material.side === BackSide ) { intersect = ray.intersectTriangle( pC, pB, pA, true, point ); } else { intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, 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 checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) { _vA.fromBufferAttribute( position, a ); _vB.fromBufferAttribute( position, b ); _vC.fromBufferAttribute( position, c ); const morphInfluences = object.morphTargetInfluences; if ( morphPosition && morphInfluences ) { _morphA.set( 0, 0, 0 ); _morphB.set( 0, 0, 0 ); _morphC.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, a ); _tempB.fromBufferAttribute( morphAttribute, b ); _tempC.fromBufferAttribute( morphAttribute, c ); if ( morphTargetsRelative ) { _morphA.addScaledVector( _tempA, influence ); _morphB.addScaledVector( _tempB, influence ); _morphC.addScaledVector( _tempC, influence ); } else { _morphA.addScaledVector( _tempA.sub( _vA ), influence ); _morphB.addScaledVector( _tempB.sub( _vB ), influence ); _morphC.addScaledVector( _tempC.sub( _vC ), influence ); } } _vA.add( _morphA ); _vB.add( _morphB ); _vC.add( _morphC ); } if ( object.isSkinnedMesh ) { object.boneTransform( a, _vA ); object.boneTransform( b, _vB ); object.boneTransform( c, _vC ); } const intersection = checkIntersection( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint ); if ( intersection ) { if ( uv ) { _uvA.fromBufferAttribute( uv, a ); _uvB.fromBufferAttribute( uv, b ); _uvC.fromBufferAttribute( uv, c ); intersection.uv = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ); } if ( uv2 ) { _uvA.fromBufferAttribute( uv2, a ); _uvB.fromBufferAttribute( uv2, b ); _uvC.fromBufferAttribute( uv2, c ); intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ); } const face = { a: a, b: b, c: c, normal: new Vector3(), materialIndex: 0 }; Triangle.getNormal( _vA, _vB, _vC, face.normal ); intersection.face = face; } return intersection; } export { Mesh };