/** * @author alteredq / http://alteredqualia.com/ */ THREE.PointCloud = function ( geometry, material ) { THREE.Object3D.call( this ); this.type = 'PointCloud'; this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.PointCloudMaterial( { color: Math.random() * 0xffffff } ); }; THREE.PointCloud.prototype = Object.create( THREE.Object3D.prototype ); THREE.PointCloud.prototype.constructor = THREE.PointCloud; THREE.PointCloud.prototype.raycast = ( function () { var inverseMatrix = new THREE.Matrix4(); var ray = new THREE.Ray(); return function raycast( raycaster, intersects ) { var object = this; var geometry = object.geometry; var threshold = raycaster.params.PointCloud.threshold; inverseMatrix.getInverse( this.matrixWorld ); ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); if ( geometry.boundingBox !== null ) { if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { return; } } var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); var localThresholdSq = localThreshold * localThreshold; var position = new THREE.Vector3(); var testPoint = function ( point, index ) { var rayPointDistanceSq = ray.distanceSqToPoint( point ); if ( rayPointDistanceSq < localThresholdSq ) { var intersectPoint = ray.closestPointToPoint( point ); intersectPoint.applyMatrix4( object.matrixWorld ); var distance = raycaster.ray.origin.distanceTo( intersectPoint ); if ( distance < raycaster.near || distance > raycaster.far ) return; intersects.push( { distance: distance, distanceToRay: Math.sqrt( rayPointDistanceSq ), point: intersectPoint.clone(), index: index, face: null, object: object } ); } }; if ( geometry instanceof THREE.BufferGeometry ) { var attributes = geometry.attributes; var positions = attributes.position.array; if ( attributes.index !== undefined ) { var indices = attributes.index.array; var offsets = geometry.drawcalls; if ( offsets.length === 0 ) { offsets = [ { start: 0, count: indices.length, index: 0 } ]; } for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { var offset = offsets[ oi ]; var start = offset.start; var count = offset.count; var index = offset.index; for ( var i = start, il = start + count; i < il; i ++ ) { var a = index + indices[ i ]; position.fromArray( positions, a * 3 ); testPoint( position, a ); } } } else { for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { position.fromArray( positions, i * 3 ); testPoint( position, i ); } } } else { var vertices = geometry.vertices; for ( var i = 0, l = vertices.length; i < l; i ++ ) { testPoint( vertices[ i ], i ); } } }; }() ); THREE.PointCloud.prototype.clone = function () { var pointCloud = new THREE.PointCloud( this.geometry, this.material ); return pointCloud.copy( this ); }; THREE.PointCloud.prototype.copy = function ( source ) { THREE.Object3D.prototype.copy.call( this, source ); return this; }; THREE.PointCloud.prototype.toJSON = function ( meta ) { var data = THREE.Object3D.prototype.toJSON.call( this, meta ); // only serialize if not in meta geometries cache if ( meta.geometries[ this.geometry.uuid ] === undefined ) { meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON(); } // only serialize if not in meta materials cache if ( meta.materials[ this.material.uuid ] === undefined ) { meta.materials[ this.material.uuid ] = this.material.toJSON(); } data.object.geometry = this.geometry.uuid; data.object.material = this.material.uuid; return data; }; // Backwards compatibility THREE.ParticleSystem = function ( geometry, material ) { console.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); return new THREE.PointCloud( geometry, material ); };