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 { Face3 } from '../core/Face3.js'; import { DoubleSide, BackSide, TrianglesDrawMode } from '../constants.js'; import { MeshBasicMaterial } from '../materials/MeshBasicMaterial.js'; import { BufferGeometry } from '../core/BufferGeometry.js'; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author jonobr1 / http://jonobr1.com/ */ function Mesh( geometry, material ) { Object3D.call( this ); this.type = 'Mesh'; this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } ); this.drawMode = TrianglesDrawMode; this.updateMorphTargets(); } Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), { constructor: Mesh, isMesh: true, setDrawMode: function ( value ) { this.drawMode = value; }, copy: function ( source ) { Object3D.prototype.copy.call( this, source ); this.drawMode = source.drawMode; if ( source.morphTargetInfluences !== undefined ) { this.morphTargetInfluences = source.morphTargetInfluences.slice(); } if ( source.morphTargetDictionary !== undefined ) { this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); } return this; }, updateMorphTargets: function () { var geometry = this.geometry; var m, ml, name; if ( geometry.isBufferGeometry ) { var morphAttributes = geometry.morphAttributes; var keys = Object.keys( morphAttributes ); if ( keys.length > 0 ) { var morphAttribute = morphAttributes[ keys[ 0 ] ]; if ( morphAttribute !== undefined ) { this.morphTargetInfluences = []; this.morphTargetDictionary = {}; for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) { name = morphAttribute[ m ].name || String( m ); this.morphTargetInfluences.push( 0 ); this.morphTargetDictionary[ name ] = m; } } } } else { var morphTargets = geometry.morphTargets; if ( morphTargets !== undefined && morphTargets.length > 0 ) { this.morphTargetInfluences = []; this.morphTargetDictionary = {}; for ( m = 0, ml = morphTargets.length; m < ml; m ++ ) { name = morphTargets[ m ].name || String( m ); this.morphTargetInfluences.push( 0 ); this.morphTargetDictionary[ name ] = m; } } } }, raycast: ( function () { var inverseMatrix = new Matrix4(); var ray = new Ray(); var sphere = new Sphere(); var vA = new Vector3(); var vB = new Vector3(); var vC = new Vector3(); var tempA = new Vector3(); var tempB = new Vector3(); var tempC = new Vector3(); var uvA = new Vector2(); var uvB = new Vector2(); var uvC = new Vector2(); var intersectionPoint = new Vector3(); var intersectionPointWorld = new Vector3(); function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { var 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 ); var 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, uv, a, b, c ) { vA.fromBufferAttribute( position, a ); vB.fromBufferAttribute( position, b ); vC.fromBufferAttribute( position, c ); var 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() ); } var face = new Face3( a, b, c ); Triangle.getNormal( vA, vB, vC, face.normal ); intersection.face = face; } return intersection; } return function raycast( raycaster, intersects ) { var geometry = this.geometry; var material = this.material; var 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.getInverse( matrixWorld ); ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); // Check boundingBox before continuing if ( geometry.boundingBox !== null ) { if ( ray.intersectsBox( geometry.boundingBox ) === false ) return; } var intersection; if ( geometry.isBufferGeometry ) { var a, b, c; var index = geometry.index; var position = geometry.attributes.position; var uv = geometry.attributes.uv; var groups = geometry.groups; var drawRange = geometry.drawRange; var i, j, il, jl; var group, groupMaterial; var start, end; if ( index !== null ) { // indexed buffer geometry if ( Array.isArray( material ) ) { for ( i = 0, il = groups.length; i < il; i ++ ) { group = groups[ i ]; groupMaterial = material[ group.materialIndex ]; start = Math.max( group.start, drawRange.start ); end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); for ( j = start, jl = end; j < jl; j += 3 ) { a = index.getX( j ); b = index.getX( j + 1 ); c = index.getX( j + 2 ); intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, ray, position, uv, a, b, c ); if ( intersection ) { intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics intersects.push( intersection ); } } } } else { start = Math.max( 0, drawRange.start ); end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); for ( i = start, il = end; i < il; i += 3 ) { a = index.getX( i ); b = index.getX( i + 1 ); c = index.getX( i + 2 ); intersection = checkBufferGeometryIntersection( this, material, raycaster, ray, position, uv, 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 ( i = 0, il = groups.length; i < il; i ++ ) { group = groups[ i ]; groupMaterial = material[ group.materialIndex ]; start = Math.max( group.start, drawRange.start ); end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); for ( j = start, jl = end; j < jl; j += 3 ) { a = j; b = j + 1; c = j + 2; intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, ray, position, uv, a, b, c ); if ( intersection ) { intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics intersects.push( intersection ); } } } } else { start = Math.max( 0, drawRange.start ); end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); for ( i = start, il = end; i < il; i += 3 ) { a = i; b = i + 1; c = i + 2; intersection = checkBufferGeometryIntersection( this, material, raycaster, ray, position, uv, a, b, c ); if ( intersection ) { intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics intersects.push( intersection ); } } } } } else if ( geometry.isGeometry ) { var fvA, fvB, fvC; var isMultiMaterial = Array.isArray( material ); var vertices = geometry.vertices; var faces = geometry.faces; var uvs; var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs; for ( var f = 0, fl = faces.length; f < fl; f ++ ) { var face = faces[ f ]; var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material; if ( faceMaterial === undefined ) continue; fvA = vertices[ face.a ]; fvB = vertices[ face.b ]; fvC = vertices[ face.c ]; if ( faceMaterial.morphTargets === true ) { var morphTargets = geometry.morphTargets; var morphInfluences = this.morphTargetInfluences; vA.set( 0, 0, 0 ); vB.set( 0, 0, 0 ); vC.set( 0, 0, 0 ); for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { var influence = morphInfluences[ t ]; if ( influence === 0 ) continue; var targets = morphTargets[ t ].vertices; vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence ); vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence ); vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence ); } vA.add( fvA ); vB.add( fvB ); vC.add( fvC ); fvA = vA; fvB = vB; fvC = vC; } intersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint ); if ( intersection ) { if ( uvs && uvs[ f ] ) { var uvs_f = uvs[ f ]; uvA.copy( uvs_f[ 0 ] ); uvB.copy( uvs_f[ 1 ] ); uvC.copy( uvs_f[ 2 ] ); intersection.uv = Triangle.getUV( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC, new Vector2() ); } intersection.face = face; intersection.faceIndex = f; intersects.push( intersection ); } } } }; }() ), clone: function () { return new this.constructor( this.geometry, this.material ).copy( this ); } } ); export { Mesh };