Buckets:
| 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 { BackSide, FrontSide } 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 _sphereHitAt = /*@__PURE__*/ new Vector3(); | |
| const _vA = /*@__PURE__*/ new Vector3(); | |
| const _vB = /*@__PURE__*/ new Vector3(); | |
| const _vC = /*@__PURE__*/ new Vector3(); | |
| const _tempA = /*@__PURE__*/ new Vector3(); | |
| const _morphA = /*@__PURE__*/ new Vector3(); | |
| const _intersectionPoint = /*@__PURE__*/ new Vector3(); | |
| const _intersectionPointWorld = /*@__PURE__*/ new 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 { | |
| /** | |
| * Constructs a new mesh. | |
| * | |
| * @param {BufferGeometry} [geometry] - The mesh geometry. | |
| * @param {Material|Array<Material>} [material] - The mesh material. | |
| */ | |
| constructor( geometry = new BufferGeometry(), material = new 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 ); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| 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 === 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 Vector3(); | |
| Triangle.getBarycoord( _intersectionPoint, _vA, _vB, _vC, barycoord ); | |
| if ( uv ) { | |
| intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() ); | |
| } | |
| if ( uv1 ) { | |
| intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() ); | |
| } | |
| if ( normal ) { | |
| intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() ); | |
| if ( intersection.normal.dot( ray.direction ) > 0 ) { | |
| intersection.normal.multiplyScalar( - 1 ); | |
| } | |
| } | |
| const face = { | |
| a: a, | |
| b: b, | |
| c: c, | |
| normal: new Vector3(), | |
| materialIndex: 0 | |
| }; | |
| Triangle.getNormal( _vA, _vB, _vC, face.normal ); | |
| intersection.face = face; | |
| intersection.barycoord = barycoord; | |
| } | |
| return intersection; | |
| } | |
| export { Mesh }; | |
Xet Storage Details
- Size:
- 12.2 kB
- Xet hash:
- 9770314791e2bb767f8b22e5127380a448a715ddf21cc31dbbe01b3f3480ea52
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.