initial commit
This commit is contained in:
26
lib/objects/Bone.js
Normal file
26
lib/objects/Bone.js
Normal file
@ -0,0 +1,26 @@
|
||||
import { Object3D } from '../core/Object3D.js';
|
||||
|
||||
/**
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author ikerr / http://verold.com
|
||||
*/
|
||||
|
||||
function Bone() {
|
||||
|
||||
Object3D.call( this );
|
||||
|
||||
this.type = 'Bone';
|
||||
|
||||
}
|
||||
|
||||
Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
||||
|
||||
constructor: Bone,
|
||||
|
||||
isBone: true
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Bone };
|
24
lib/objects/Group.js
Normal file
24
lib/objects/Group.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { Object3D } from '../core/Object3D.js';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
function Group() {
|
||||
|
||||
Object3D.call( this );
|
||||
|
||||
this.type = 'Group';
|
||||
|
||||
}
|
||||
|
||||
Group.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
||||
|
||||
constructor: Group,
|
||||
|
||||
isGroup: true
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Group };
|
176
lib/objects/LOD.js
Normal file
176
lib/objects/LOD.js
Normal file
@ -0,0 +1,176 @@
|
||||
import { Vector3 } from '../math/Vector3.js';
|
||||
import { Object3D } from '../core/Object3D.js';
|
||||
|
||||
/**
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
function LOD() {
|
||||
|
||||
Object3D.call( this );
|
||||
|
||||
this.type = 'LOD';
|
||||
|
||||
Object.defineProperties( this, {
|
||||
levels: {
|
||||
enumerable: true,
|
||||
value: []
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
||||
|
||||
constructor: LOD,
|
||||
|
||||
copy: function ( source ) {
|
||||
|
||||
Object3D.prototype.copy.call( this, source, false );
|
||||
|
||||
var levels = source.levels;
|
||||
|
||||
for ( var i = 0, l = levels.length; i < l; i ++ ) {
|
||||
|
||||
var level = levels[ i ];
|
||||
|
||||
this.addLevel( level.object.clone(), level.distance );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addLevel: function ( object, distance ) {
|
||||
|
||||
if ( distance === undefined ) distance = 0;
|
||||
|
||||
distance = Math.abs( distance );
|
||||
|
||||
var levels = this.levels;
|
||||
|
||||
for ( var l = 0; l < levels.length; l ++ ) {
|
||||
|
||||
if ( distance < levels[ l ].distance ) {
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
levels.splice( l, 0, { distance: distance, object: object } );
|
||||
|
||||
this.add( object );
|
||||
|
||||
},
|
||||
|
||||
getObjectForDistance: function ( distance ) {
|
||||
|
||||
var levels = this.levels;
|
||||
|
||||
for ( var i = 1, l = levels.length; i < l; i ++ ) {
|
||||
|
||||
if ( distance < levels[ i ].distance ) {
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return levels[ i - 1 ].object;
|
||||
|
||||
},
|
||||
|
||||
raycast: ( function () {
|
||||
|
||||
var matrixPosition = new Vector3();
|
||||
|
||||
return function raycast( raycaster, intersects ) {
|
||||
|
||||
matrixPosition.setFromMatrixPosition( this.matrixWorld );
|
||||
|
||||
var distance = raycaster.ray.origin.distanceTo( matrixPosition );
|
||||
|
||||
this.getObjectForDistance( distance ).raycast( raycaster, intersects );
|
||||
|
||||
};
|
||||
|
||||
}() ),
|
||||
|
||||
update: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
var v2 = new Vector3();
|
||||
|
||||
return function update( camera ) {
|
||||
|
||||
var levels = this.levels;
|
||||
|
||||
if ( levels.length > 1 ) {
|
||||
|
||||
v1.setFromMatrixPosition( camera.matrixWorld );
|
||||
v2.setFromMatrixPosition( this.matrixWorld );
|
||||
|
||||
var distance = v1.distanceTo( v2 );
|
||||
|
||||
levels[ 0 ].object.visible = true;
|
||||
|
||||
for ( var i = 1, l = levels.length; i < l; i ++ ) {
|
||||
|
||||
if ( distance >= levels[ i ].distance ) {
|
||||
|
||||
levels[ i - 1 ].object.visible = false;
|
||||
levels[ i ].object.visible = true;
|
||||
|
||||
} else {
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ( ; i < l; i ++ ) {
|
||||
|
||||
levels[ i ].object.visible = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
toJSON: function ( meta ) {
|
||||
|
||||
var data = Object3D.prototype.toJSON.call( this, meta );
|
||||
|
||||
data.object.levels = [];
|
||||
|
||||
var levels = this.levels;
|
||||
|
||||
for ( var i = 0, l = levels.length; i < l; i ++ ) {
|
||||
|
||||
var level = levels[ i ];
|
||||
|
||||
data.object.levels.push( {
|
||||
object: level.object.uuid,
|
||||
distance: level.distance
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { LOD };
|
267
lib/objects/Line.js
Normal file
267
lib/objects/Line.js
Normal file
@ -0,0 +1,267 @@
|
||||
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 { Vector3 } from '../math/Vector3.js';
|
||||
import { LineBasicMaterial } from '../materials/LineBasicMaterial.js';
|
||||
import { BufferGeometry } from '../core/BufferGeometry.js';
|
||||
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
function Line( geometry, material, mode ) {
|
||||
|
||||
if ( mode === 1 ) {
|
||||
|
||||
console.error( 'THREE.Line: parameter THREE.LinePieces no longer supported. Use THREE.LineSegments instead.' );
|
||||
|
||||
}
|
||||
|
||||
Object3D.call( this );
|
||||
|
||||
this.type = 'Line';
|
||||
|
||||
this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
|
||||
this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } );
|
||||
|
||||
}
|
||||
|
||||
Line.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
||||
|
||||
constructor: Line,
|
||||
|
||||
isLine: true,
|
||||
|
||||
computeLineDistances: ( function () {
|
||||
|
||||
var start = new Vector3();
|
||||
var end = new Vector3();
|
||||
|
||||
return function computeLineDistances() {
|
||||
|
||||
var geometry = this.geometry;
|
||||
|
||||
if ( geometry.isBufferGeometry ) {
|
||||
|
||||
// we assume non-indexed geometry
|
||||
|
||||
if ( geometry.index === null ) {
|
||||
|
||||
var positionAttribute = geometry.attributes.position;
|
||||
var lineDistances = [ 0 ];
|
||||
|
||||
for ( var i = 1, l = positionAttribute.count; i < l; i ++ ) {
|
||||
|
||||
start.fromBufferAttribute( positionAttribute, i - 1 );
|
||||
end.fromBufferAttribute( positionAttribute, i );
|
||||
|
||||
lineDistances[ i ] = lineDistances[ i - 1 ];
|
||||
lineDistances[ i ] += start.distanceTo( end );
|
||||
|
||||
}
|
||||
|
||||
geometry.addAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
|
||||
|
||||
}
|
||||
|
||||
} else if ( geometry.isGeometry ) {
|
||||
|
||||
var vertices = geometry.vertices;
|
||||
var lineDistances = geometry.lineDistances;
|
||||
|
||||
lineDistances[ 0 ] = 0;
|
||||
|
||||
for ( var i = 1, l = vertices.length; i < l; i ++ ) {
|
||||
|
||||
lineDistances[ i ] = lineDistances[ i - 1 ];
|
||||
lineDistances[ i ] += vertices[ i - 1 ].distanceTo( vertices[ i ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}() ),
|
||||
|
||||
raycast: ( function () {
|
||||
|
||||
var inverseMatrix = new Matrix4();
|
||||
var ray = new Ray();
|
||||
var sphere = new Sphere();
|
||||
|
||||
return function raycast( raycaster, intersects ) {
|
||||
|
||||
var precision = raycaster.linePrecision;
|
||||
|
||||
var geometry = this.geometry;
|
||||
var matrixWorld = this.matrixWorld;
|
||||
|
||||
// Checking boundingSphere distance to ray
|
||||
|
||||
if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
|
||||
|
||||
sphere.copy( geometry.boundingSphere );
|
||||
sphere.applyMatrix4( matrixWorld );
|
||||
sphere.radius += precision;
|
||||
|
||||
if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
|
||||
|
||||
//
|
||||
|
||||
inverseMatrix.getInverse( matrixWorld );
|
||||
ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
|
||||
|
||||
var localPrecision = precision / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
|
||||
var localPrecisionSq = localPrecision * localPrecision;
|
||||
|
||||
var vStart = new Vector3();
|
||||
var vEnd = new Vector3();
|
||||
var interSegment = new Vector3();
|
||||
var interRay = new Vector3();
|
||||
var step = ( this && this.isLineSegments ) ? 2 : 1;
|
||||
|
||||
if ( geometry.isBufferGeometry ) {
|
||||
|
||||
var index = geometry.index;
|
||||
var attributes = geometry.attributes;
|
||||
var positions = attributes.position.array;
|
||||
|
||||
if ( index !== null ) {
|
||||
|
||||
var indices = index.array;
|
||||
|
||||
for ( var i = 0, l = indices.length - 1; i < l; i += step ) {
|
||||
|
||||
var a = indices[ i ];
|
||||
var b = indices[ i + 1 ];
|
||||
|
||||
vStart.fromArray( positions, a * 3 );
|
||||
vEnd.fromArray( positions, b * 3 );
|
||||
|
||||
var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
|
||||
|
||||
if ( distSq > localPrecisionSq ) continue;
|
||||
|
||||
interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
|
||||
|
||||
var distance = raycaster.ray.origin.distanceTo( interRay );
|
||||
|
||||
if ( distance < raycaster.near || distance > raycaster.far ) continue;
|
||||
|
||||
intersects.push( {
|
||||
|
||||
distance: distance,
|
||||
// What do we want? intersection point on the ray or on the segment??
|
||||
// point: raycaster.ray.at( distance ),
|
||||
point: interSegment.clone().applyMatrix4( this.matrixWorld ),
|
||||
index: i,
|
||||
face: null,
|
||||
faceIndex: null,
|
||||
object: this
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) {
|
||||
|
||||
vStart.fromArray( positions, 3 * i );
|
||||
vEnd.fromArray( positions, 3 * i + 3 );
|
||||
|
||||
var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
|
||||
|
||||
if ( distSq > localPrecisionSq ) continue;
|
||||
|
||||
interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
|
||||
|
||||
var distance = raycaster.ray.origin.distanceTo( interRay );
|
||||
|
||||
if ( distance < raycaster.near || distance > raycaster.far ) continue;
|
||||
|
||||
intersects.push( {
|
||||
|
||||
distance: distance,
|
||||
// What do we want? intersection point on the ray or on the segment??
|
||||
// point: raycaster.ray.at( distance ),
|
||||
point: interSegment.clone().applyMatrix4( this.matrixWorld ),
|
||||
index: i,
|
||||
face: null,
|
||||
faceIndex: null,
|
||||
object: this
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if ( geometry.isGeometry ) {
|
||||
|
||||
var vertices = geometry.vertices;
|
||||
var nbVertices = vertices.length;
|
||||
|
||||
for ( var i = 0; i < nbVertices - 1; i += step ) {
|
||||
|
||||
var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );
|
||||
|
||||
if ( distSq > localPrecisionSq ) continue;
|
||||
|
||||
interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
|
||||
|
||||
var distance = raycaster.ray.origin.distanceTo( interRay );
|
||||
|
||||
if ( distance < raycaster.near || distance > raycaster.far ) continue;
|
||||
|
||||
intersects.push( {
|
||||
|
||||
distance: distance,
|
||||
// What do we want? intersection point on the ray or on the segment??
|
||||
// point: raycaster.ray.at( distance ),
|
||||
point: interSegment.clone().applyMatrix4( this.matrixWorld ),
|
||||
index: i,
|
||||
face: null,
|
||||
faceIndex: null,
|
||||
object: this
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}() ),
|
||||
|
||||
copy: function ( source ) {
|
||||
|
||||
Object3D.prototype.copy.call( this, source );
|
||||
|
||||
this.geometry.copy( source.geometry );
|
||||
this.material.copy( source.material );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Line };
|
24
lib/objects/LineLoop.js
Normal file
24
lib/objects/LineLoop.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { Line } from './Line.js';
|
||||
|
||||
/**
|
||||
* @author mgreter / http://github.com/mgreter
|
||||
*/
|
||||
|
||||
function LineLoop( geometry, material ) {
|
||||
|
||||
Line.call( this, geometry, material );
|
||||
|
||||
this.type = 'LineLoop';
|
||||
|
||||
}
|
||||
|
||||
LineLoop.prototype = Object.assign( Object.create( Line.prototype ), {
|
||||
|
||||
constructor: LineLoop,
|
||||
|
||||
isLineLoop: true,
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { LineLoop };
|
85
lib/objects/LineSegments.js
Normal file
85
lib/objects/LineSegments.js
Normal file
@ -0,0 +1,85 @@
|
||||
import { Line } from './Line.js';
|
||||
import { Vector3 } from '../math/Vector3.js';
|
||||
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
function LineSegments( geometry, material ) {
|
||||
|
||||
Line.call( this, geometry, material );
|
||||
|
||||
this.type = 'LineSegments';
|
||||
|
||||
}
|
||||
|
||||
LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {
|
||||
|
||||
constructor: LineSegments,
|
||||
|
||||
isLineSegments: true,
|
||||
|
||||
computeLineDistances: ( function () {
|
||||
|
||||
var start = new Vector3();
|
||||
var end = new Vector3();
|
||||
|
||||
return function computeLineDistances() {
|
||||
|
||||
var geometry = this.geometry;
|
||||
|
||||
if ( geometry.isBufferGeometry ) {
|
||||
|
||||
// we assume non-indexed geometry
|
||||
|
||||
if ( geometry.index === null ) {
|
||||
|
||||
var positionAttribute = geometry.attributes.position;
|
||||
var lineDistances = [];
|
||||
|
||||
for ( var i = 0, l = positionAttribute.count; i < l; i += 2 ) {
|
||||
|
||||
start.fromBufferAttribute( positionAttribute, i );
|
||||
end.fromBufferAttribute( positionAttribute, i + 1 );
|
||||
|
||||
lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
|
||||
lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end );
|
||||
|
||||
}
|
||||
|
||||
geometry.addAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
|
||||
|
||||
}
|
||||
|
||||
} else if ( geometry.isGeometry ) {
|
||||
|
||||
var vertices = geometry.vertices;
|
||||
var lineDistances = geometry.lineDistances;
|
||||
|
||||
for ( var i = 0, l = vertices.length; i < l; i += 2 ) {
|
||||
|
||||
start.copy( vertices[ i ] );
|
||||
end.copy( vertices[ i + 1 ] );
|
||||
|
||||
lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
|
||||
lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}() )
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { LineSegments };
|
462
lib/objects/Mesh.js
Normal file
462
lib/objects/Mesh.js
Normal file
@ -0,0 +1,462 @@
|
||||
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 };
|
148
lib/objects/Points.js
Normal file
148
lib/objects/Points.js
Normal file
@ -0,0 +1,148 @@
|
||||
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 { Vector3 } from '../math/Vector3.js';
|
||||
import { PointsMaterial } from '../materials/PointsMaterial.js';
|
||||
import { BufferGeometry } from '../core/BufferGeometry.js';
|
||||
|
||||
/**
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
*/
|
||||
|
||||
function Points( geometry, material ) {
|
||||
|
||||
Object3D.call( this );
|
||||
|
||||
this.type = 'Points';
|
||||
|
||||
this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
|
||||
this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } );
|
||||
|
||||
}
|
||||
|
||||
Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
||||
|
||||
constructor: Points,
|
||||
|
||||
isPoints: true,
|
||||
|
||||
raycast: ( function () {
|
||||
|
||||
var inverseMatrix = new Matrix4();
|
||||
var ray = new Ray();
|
||||
var sphere = new Sphere();
|
||||
|
||||
return function raycast( raycaster, intersects ) {
|
||||
|
||||
var object = this;
|
||||
var geometry = this.geometry;
|
||||
var matrixWorld = this.matrixWorld;
|
||||
var threshold = raycaster.params.Points.threshold;
|
||||
|
||||
// Checking boundingSphere distance to ray
|
||||
|
||||
if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
|
||||
|
||||
sphere.copy( geometry.boundingSphere );
|
||||
sphere.applyMatrix4( matrixWorld );
|
||||
sphere.radius += threshold;
|
||||
|
||||
if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
|
||||
|
||||
//
|
||||
|
||||
inverseMatrix.getInverse( matrixWorld );
|
||||
ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
|
||||
|
||||
var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
|
||||
var localThresholdSq = localThreshold * localThreshold;
|
||||
var position = new Vector3();
|
||||
var intersectPoint = new Vector3();
|
||||
|
||||
function testPoint( point, index ) {
|
||||
|
||||
var rayPointDistanceSq = ray.distanceSqToPoint( point );
|
||||
|
||||
if ( rayPointDistanceSq < localThresholdSq ) {
|
||||
|
||||
ray.closestPointToPoint( point, intersectPoint );
|
||||
intersectPoint.applyMatrix4( 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.isBufferGeometry ) {
|
||||
|
||||
var index = geometry.index;
|
||||
var attributes = geometry.attributes;
|
||||
var positions = attributes.position.array;
|
||||
|
||||
if ( index !== null ) {
|
||||
|
||||
var indices = index.array;
|
||||
|
||||
for ( var i = 0, il = indices.length; i < il; i ++ ) {
|
||||
|
||||
var a = 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 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}() ),
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this.geometry, this.material ).copy( this );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Points };
|
178
lib/objects/Skeleton.js
Normal file
178
lib/objects/Skeleton.js
Normal file
@ -0,0 +1,178 @@
|
||||
import { Matrix4 } from '../math/Matrix4.js';
|
||||
|
||||
/**
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author michael guerrero / http://realitymeltdown.com
|
||||
* @author ikerr / http://verold.com
|
||||
*/
|
||||
|
||||
function Skeleton( bones, boneInverses ) {
|
||||
|
||||
// copy the bone array
|
||||
|
||||
bones = bones || [];
|
||||
|
||||
this.bones = bones.slice( 0 );
|
||||
this.boneMatrices = new Float32Array( this.bones.length * 16 );
|
||||
|
||||
// use the supplied bone inverses or calculate the inverses
|
||||
|
||||
if ( boneInverses === undefined ) {
|
||||
|
||||
this.calculateInverses();
|
||||
|
||||
} else {
|
||||
|
||||
if ( this.bones.length === boneInverses.length ) {
|
||||
|
||||
this.boneInverses = boneInverses.slice( 0 );
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.Skeleton boneInverses is the wrong length.' );
|
||||
|
||||
this.boneInverses = [];
|
||||
|
||||
for ( var i = 0, il = this.bones.length; i < il; i ++ ) {
|
||||
|
||||
this.boneInverses.push( new Matrix4() );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Skeleton.prototype, {
|
||||
|
||||
calculateInverses: function () {
|
||||
|
||||
this.boneInverses = [];
|
||||
|
||||
for ( var i = 0, il = this.bones.length; i < il; i ++ ) {
|
||||
|
||||
var inverse = new Matrix4();
|
||||
|
||||
if ( this.bones[ i ] ) {
|
||||
|
||||
inverse.getInverse( this.bones[ i ].matrixWorld );
|
||||
|
||||
}
|
||||
|
||||
this.boneInverses.push( inverse );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
pose: function () {
|
||||
|
||||
var bone, i, il;
|
||||
|
||||
// recover the bind-time world matrices
|
||||
|
||||
for ( i = 0, il = this.bones.length; i < il; i ++ ) {
|
||||
|
||||
bone = this.bones[ i ];
|
||||
|
||||
if ( bone ) {
|
||||
|
||||
bone.matrixWorld.getInverse( this.boneInverses[ i ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// compute the local matrices, positions, rotations and scales
|
||||
|
||||
for ( i = 0, il = this.bones.length; i < il; i ++ ) {
|
||||
|
||||
bone = this.bones[ i ];
|
||||
|
||||
if ( bone ) {
|
||||
|
||||
if ( bone.parent && bone.parent.isBone ) {
|
||||
|
||||
bone.matrix.getInverse( bone.parent.matrixWorld );
|
||||
bone.matrix.multiply( bone.matrixWorld );
|
||||
|
||||
} else {
|
||||
|
||||
bone.matrix.copy( bone.matrixWorld );
|
||||
|
||||
}
|
||||
|
||||
bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
update: ( function () {
|
||||
|
||||
var offsetMatrix = new Matrix4();
|
||||
var identityMatrix = new Matrix4();
|
||||
|
||||
return function update() {
|
||||
|
||||
var bones = this.bones;
|
||||
var boneInverses = this.boneInverses;
|
||||
var boneMatrices = this.boneMatrices;
|
||||
var boneTexture = this.boneTexture;
|
||||
|
||||
// flatten bone matrices to array
|
||||
|
||||
for ( var i = 0, il = bones.length; i < il; i ++ ) {
|
||||
|
||||
// compute the offset between the current and the original transform
|
||||
|
||||
var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix;
|
||||
|
||||
offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
|
||||
offsetMatrix.toArray( boneMatrices, i * 16 );
|
||||
|
||||
}
|
||||
|
||||
if ( boneTexture !== undefined ) {
|
||||
|
||||
boneTexture.needsUpdate = true;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new Skeleton( this.bones, this.boneInverses );
|
||||
|
||||
},
|
||||
|
||||
getBoneByName: function ( name ) {
|
||||
|
||||
for ( var i = 0, il = this.bones.length; i < il; i ++ ) {
|
||||
|
||||
var bone = this.bones[ i ];
|
||||
|
||||
if ( bone.name === name ) {
|
||||
|
||||
return bone;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Skeleton };
|
209
lib/objects/SkinnedMesh.js
Normal file
209
lib/objects/SkinnedMesh.js
Normal file
@ -0,0 +1,209 @@
|
||||
import { Mesh } from './Mesh.js';
|
||||
import { Vector4 } from '../math/Vector4.js';
|
||||
import { Skeleton } from './Skeleton.js';
|
||||
import { Bone } from './Bone.js';
|
||||
import { Matrix4 } from '../math/Matrix4.js';
|
||||
|
||||
/**
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author ikerr / http://verold.com
|
||||
*/
|
||||
|
||||
function SkinnedMesh( geometry, material ) {
|
||||
|
||||
Mesh.call( this, geometry, material );
|
||||
|
||||
this.type = 'SkinnedMesh';
|
||||
|
||||
this.bindMode = 'attached';
|
||||
this.bindMatrix = new Matrix4();
|
||||
this.bindMatrixInverse = new Matrix4();
|
||||
|
||||
var bones = this.initBones();
|
||||
var skeleton = new Skeleton( bones );
|
||||
|
||||
this.bind( skeleton, this.matrixWorld );
|
||||
|
||||
this.normalizeSkinWeights();
|
||||
|
||||
}
|
||||
|
||||
SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
|
||||
|
||||
constructor: SkinnedMesh,
|
||||
|
||||
isSkinnedMesh: true,
|
||||
|
||||
initBones: function () {
|
||||
|
||||
var bones = [], bone, gbone;
|
||||
var i, il;
|
||||
|
||||
if ( this.geometry && this.geometry.bones !== undefined ) {
|
||||
|
||||
// first, create array of 'Bone' objects from geometry data
|
||||
|
||||
for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
|
||||
|
||||
gbone = this.geometry.bones[ i ];
|
||||
|
||||
// create new 'Bone' object
|
||||
|
||||
bone = new Bone();
|
||||
bones.push( bone );
|
||||
|
||||
// apply values
|
||||
|
||||
bone.name = gbone.name;
|
||||
bone.position.fromArray( gbone.pos );
|
||||
bone.quaternion.fromArray( gbone.rotq );
|
||||
if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );
|
||||
|
||||
}
|
||||
|
||||
// second, create bone hierarchy
|
||||
|
||||
for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
|
||||
|
||||
gbone = this.geometry.bones[ i ];
|
||||
|
||||
if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {
|
||||
|
||||
// subsequent bones in the hierarchy
|
||||
|
||||
bones[ gbone.parent ].add( bones[ i ] );
|
||||
|
||||
} else {
|
||||
|
||||
// topmost bone, immediate child of the skinned mesh
|
||||
|
||||
this.add( bones[ i ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// now the bones are part of the scene graph and children of the skinned mesh.
|
||||
// let's update the corresponding matrices
|
||||
|
||||
this.updateMatrixWorld( true );
|
||||
|
||||
return bones;
|
||||
|
||||
},
|
||||
|
||||
bind: function ( skeleton, bindMatrix ) {
|
||||
|
||||
this.skeleton = skeleton;
|
||||
|
||||
if ( bindMatrix === undefined ) {
|
||||
|
||||
this.updateMatrixWorld( true );
|
||||
|
||||
this.skeleton.calculateInverses();
|
||||
|
||||
bindMatrix = this.matrixWorld;
|
||||
|
||||
}
|
||||
|
||||
this.bindMatrix.copy( bindMatrix );
|
||||
this.bindMatrixInverse.getInverse( bindMatrix );
|
||||
|
||||
},
|
||||
|
||||
pose: function () {
|
||||
|
||||
this.skeleton.pose();
|
||||
|
||||
},
|
||||
|
||||
normalizeSkinWeights: function () {
|
||||
|
||||
var scale, i;
|
||||
|
||||
if ( this.geometry && this.geometry.isGeometry ) {
|
||||
|
||||
for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) {
|
||||
|
||||
var sw = this.geometry.skinWeights[ i ];
|
||||
|
||||
scale = 1.0 / sw.manhattanLength();
|
||||
|
||||
if ( scale !== Infinity ) {
|
||||
|
||||
sw.multiplyScalar( scale );
|
||||
|
||||
} else {
|
||||
|
||||
sw.set( 1, 0, 0, 0 ); // do something reasonable
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if ( this.geometry && this.geometry.isBufferGeometry ) {
|
||||
|
||||
var vec = new Vector4();
|
||||
|
||||
var skinWeight = this.geometry.attributes.skinWeight;
|
||||
|
||||
for ( i = 0; i < skinWeight.count; i ++ ) {
|
||||
|
||||
vec.x = skinWeight.getX( i );
|
||||
vec.y = skinWeight.getY( i );
|
||||
vec.z = skinWeight.getZ( i );
|
||||
vec.w = skinWeight.getW( i );
|
||||
|
||||
scale = 1.0 / vec.manhattanLength();
|
||||
|
||||
if ( scale !== Infinity ) {
|
||||
|
||||
vec.multiplyScalar( scale );
|
||||
|
||||
} else {
|
||||
|
||||
vec.set( 1, 0, 0, 0 ); // do something reasonable
|
||||
|
||||
}
|
||||
|
||||
skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
updateMatrixWorld: function ( force ) {
|
||||
|
||||
Mesh.prototype.updateMatrixWorld.call( this, force );
|
||||
|
||||
if ( this.bindMode === 'attached' ) {
|
||||
|
||||
this.bindMatrixInverse.getInverse( this.matrixWorld );
|
||||
|
||||
} else if ( this.bindMode === 'detached' ) {
|
||||
|
||||
this.bindMatrixInverse.getInverse( this.bindMatrix );
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this.geometry, this.material ).copy( this );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { SkinnedMesh };
|
222
lib/objects/Sky.js
Normal file
222
lib/objects/Sky.js
Normal file
@ -0,0 +1,222 @@
|
||||
/**
|
||||
* @author zz85 / https://github.com/zz85
|
||||
*
|
||||
* Based on "A Practical Analytic Model for Daylight"
|
||||
* aka The Preetham Model, the de facto standard analytic skydome model
|
||||
* http://www.cs.utah.edu/~shirley/papers/sunsky/sunsky.pdf
|
||||
*
|
||||
* First implemented by Simon Wallner
|
||||
* http://www.simonwallner.at/projects/atmospheric-scattering
|
||||
*
|
||||
* Improved by Martin Upitis
|
||||
* http://blenderartists.org/forum/showthread.php?245954-preethams-sky-impementation-HDR
|
||||
*
|
||||
* Three.js integration by zz85 http://twitter.com/blurspline
|
||||
*/
|
||||
|
||||
THREE.Sky = function () {
|
||||
|
||||
var shader = THREE.Sky.SkyShader;
|
||||
|
||||
var material = new THREE.ShaderMaterial( {
|
||||
fragmentShader: shader.fragmentShader,
|
||||
vertexShader: shader.vertexShader,
|
||||
uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
|
||||
side: THREE.BackSide
|
||||
} );
|
||||
|
||||
THREE.Mesh.call( this, new THREE.BoxBufferGeometry( 1, 1, 1 ), material );
|
||||
|
||||
};
|
||||
|
||||
THREE.Sky.prototype = Object.create( THREE.Mesh.prototype );
|
||||
|
||||
THREE.Sky.SkyShader = {
|
||||
|
||||
uniforms: {
|
||||
luminance: { value: 1 },
|
||||
turbidity: { value: 2 },
|
||||
rayleigh: { value: 1 },
|
||||
mieCoefficient: { value: 0.005 },
|
||||
mieDirectionalG: { value: 0.8 },
|
||||
sunPosition: { value: new THREE.Vector3() }
|
||||
},
|
||||
|
||||
vertexShader: [
|
||||
'uniform vec3 sunPosition;',
|
||||
'uniform float rayleigh;',
|
||||
'uniform float turbidity;',
|
||||
'uniform float mieCoefficient;',
|
||||
|
||||
'varying vec3 vWorldPosition;',
|
||||
'varying vec3 vSunDirection;',
|
||||
'varying float vSunfade;',
|
||||
'varying vec3 vBetaR;',
|
||||
'varying vec3 vBetaM;',
|
||||
'varying float vSunE;',
|
||||
|
||||
'const vec3 up = vec3( 0.0, 1.0, 0.0 );',
|
||||
|
||||
// constants for atmospheric scattering
|
||||
'const float e = 2.71828182845904523536028747135266249775724709369995957;',
|
||||
'const float pi = 3.141592653589793238462643383279502884197169;',
|
||||
|
||||
// wavelength of used primaries, according to preetham
|
||||
'const vec3 lambda = vec3( 680E-9, 550E-9, 450E-9 );',
|
||||
// this pre-calcuation replaces older TotalRayleigh(vec3 lambda) function:
|
||||
// (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn))
|
||||
'const vec3 totalRayleigh = vec3( 5.804542996261093E-6, 1.3562911419845635E-5, 3.0265902468824876E-5 );',
|
||||
|
||||
// mie stuff
|
||||
// K coefficient for the primaries
|
||||
'const float v = 4.0;',
|
||||
'const vec3 K = vec3( 0.686, 0.678, 0.666 );',
|
||||
// MieConst = pi * pow( ( 2.0 * pi ) / lambda, vec3( v - 2.0 ) ) * K
|
||||
'const vec3 MieConst = vec3( 1.8399918514433978E14, 2.7798023919660528E14, 4.0790479543861094E14 );',
|
||||
|
||||
// earth shadow hack
|
||||
// cutoffAngle = pi / 1.95;
|
||||
'const float cutoffAngle = 1.6110731556870734;',
|
||||
'const float steepness = 1.5;',
|
||||
'const float EE = 1000.0;',
|
||||
|
||||
'float sunIntensity( float zenithAngleCos ) {',
|
||||
' zenithAngleCos = clamp( zenithAngleCos, -1.0, 1.0 );',
|
||||
' return EE * max( 0.0, 1.0 - pow( e, -( ( cutoffAngle - acos( zenithAngleCos ) ) / steepness ) ) );',
|
||||
'}',
|
||||
|
||||
'vec3 totalMie( float T ) {',
|
||||
' float c = ( 0.2 * T ) * 10E-18;',
|
||||
' return 0.434 * c * MieConst;',
|
||||
'}',
|
||||
|
||||
'void main() {',
|
||||
|
||||
' vec4 worldPosition = modelMatrix * vec4( position, 1.0 );',
|
||||
' vWorldPosition = worldPosition.xyz;',
|
||||
|
||||
' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
|
||||
' gl_Position.z = gl_Position.w;', // set z to camera.far
|
||||
|
||||
' vSunDirection = normalize( sunPosition );',
|
||||
|
||||
' vSunE = sunIntensity( dot( vSunDirection, up ) );',
|
||||
|
||||
' vSunfade = 1.0 - clamp( 1.0 - exp( ( sunPosition.y / 450000.0 ) ), 0.0, 1.0 );',
|
||||
|
||||
' float rayleighCoefficient = rayleigh - ( 1.0 * ( 1.0 - vSunfade ) );',
|
||||
|
||||
// extinction (absorbtion + out scattering)
|
||||
// rayleigh coefficients
|
||||
' vBetaR = totalRayleigh * rayleighCoefficient;',
|
||||
|
||||
// mie coefficients
|
||||
' vBetaM = totalMie( turbidity ) * mieCoefficient;',
|
||||
|
||||
'}'
|
||||
].join( '\n' ),
|
||||
|
||||
fragmentShader: [
|
||||
'varying vec3 vWorldPosition;',
|
||||
'varying vec3 vSunDirection;',
|
||||
'varying float vSunfade;',
|
||||
'varying vec3 vBetaR;',
|
||||
'varying vec3 vBetaM;',
|
||||
'varying float vSunE;',
|
||||
|
||||
'uniform float luminance;',
|
||||
'uniform float mieDirectionalG;',
|
||||
|
||||
'const vec3 cameraPos = vec3( 0.0, 0.0, 0.0 );',
|
||||
|
||||
// constants for atmospheric scattering
|
||||
'const float pi = 3.141592653589793238462643383279502884197169;',
|
||||
|
||||
'const float n = 1.0003;', // refractive index of air
|
||||
'const float N = 2.545E25;', // number of molecules per unit volume for air at
|
||||
// 288.15K and 1013mb (sea level -45 celsius)
|
||||
|
||||
// optical length at zenith for molecules
|
||||
'const float rayleighZenithLength = 8.4E3;',
|
||||
'const float mieZenithLength = 1.25E3;',
|
||||
'const vec3 up = vec3( 0.0, 1.0, 0.0 );',
|
||||
// 66 arc seconds -> degrees, and the cosine of that
|
||||
'const float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324;',
|
||||
|
||||
// 3.0 / ( 16.0 * pi )
|
||||
'const float THREE_OVER_SIXTEENPI = 0.05968310365946075;',
|
||||
// 1.0 / ( 4.0 * pi )
|
||||
'const float ONE_OVER_FOURPI = 0.07957747154594767;',
|
||||
|
||||
'float rayleighPhase( float cosTheta ) {',
|
||||
' return THREE_OVER_SIXTEENPI * ( 1.0 + pow( cosTheta, 2.0 ) );',
|
||||
'}',
|
||||
|
||||
'float hgPhase( float cosTheta, float g ) {',
|
||||
' float g2 = pow( g, 2.0 );',
|
||||
' float inverse = 1.0 / pow( 1.0 - 2.0 * g * cosTheta + g2, 1.5 );',
|
||||
' return ONE_OVER_FOURPI * ( ( 1.0 - g2 ) * inverse );',
|
||||
'}',
|
||||
|
||||
// Filmic ToneMapping http://filmicgames.com/archives/75
|
||||
'const float A = 0.15;',
|
||||
'const float B = 0.50;',
|
||||
'const float C = 0.10;',
|
||||
'const float D = 0.20;',
|
||||
'const float E = 0.02;',
|
||||
'const float F = 0.30;',
|
||||
|
||||
'const float whiteScale = 1.0748724675633854;', // 1.0 / Uncharted2Tonemap(1000.0)
|
||||
|
||||
'vec3 Uncharted2Tonemap( vec3 x ) {',
|
||||
' return ( ( x * ( A * x + C * B ) + D * E ) / ( x * ( A * x + B ) + D * F ) ) - E / F;',
|
||||
'}',
|
||||
|
||||
|
||||
'void main() {',
|
||||
// optical length
|
||||
// cutoff angle at 90 to avoid singularity in next formula.
|
||||
' float zenithAngle = acos( max( 0.0, dot( up, normalize( vWorldPosition - cameraPos ) ) ) );',
|
||||
' float inverse = 1.0 / ( cos( zenithAngle ) + 0.15 * pow( 93.885 - ( ( zenithAngle * 180.0 ) / pi ), -1.253 ) );',
|
||||
' float sR = rayleighZenithLength * inverse;',
|
||||
' float sM = mieZenithLength * inverse;',
|
||||
|
||||
// combined extinction factor
|
||||
' vec3 Fex = exp( -( vBetaR * sR + vBetaM * sM ) );',
|
||||
|
||||
// in scattering
|
||||
' float cosTheta = dot( normalize( vWorldPosition - cameraPos ), vSunDirection );',
|
||||
|
||||
' float rPhase = rayleighPhase( cosTheta * 0.5 + 0.5 );',
|
||||
' vec3 betaRTheta = vBetaR * rPhase;',
|
||||
|
||||
' float mPhase = hgPhase( cosTheta, mieDirectionalG );',
|
||||
' vec3 betaMTheta = vBetaM * mPhase;',
|
||||
|
||||
' vec3 Lin = pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * ( 1.0 - Fex ), vec3( 1.5 ) );',
|
||||
' Lin *= mix( vec3( 1.0 ), pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * Fex, vec3( 1.0 / 2.0 ) ), clamp( pow( 1.0 - dot( up, vSunDirection ), 5.0 ), 0.0, 1.0 ) );',
|
||||
|
||||
// nightsky
|
||||
' vec3 direction = normalize( vWorldPosition - cameraPos );',
|
||||
' float theta = acos( direction.y ); // elevation --> y-axis, [-pi/2, pi/2]',
|
||||
' float phi = atan( direction.z, direction.x ); // azimuth --> x-axis [-pi/2, pi/2]',
|
||||
' vec2 uv = vec2( phi, theta ) / vec2( 2.0 * pi, pi ) + vec2( 0.5, 0.0 );',
|
||||
' vec3 L0 = vec3( 0.1 ) * Fex;',
|
||||
|
||||
// composition + solar disc
|
||||
' float sundisk = smoothstep( sunAngularDiameterCos, sunAngularDiameterCos + 0.00002, cosTheta );',
|
||||
' L0 += ( vSunE * 19000.0 * Fex ) * sundisk;',
|
||||
|
||||
' vec3 texColor = ( Lin + L0 ) * 0.04 + vec3( 0.0, 0.0003, 0.00075 );',
|
||||
|
||||
' vec3 curr = Uncharted2Tonemap( ( log2( 2.0 / pow( luminance, 4.0 ) ) ) * texColor );',
|
||||
' vec3 color = curr * whiteScale;',
|
||||
|
||||
' vec3 retColor = pow( color, vec3( 1.0 / ( 1.2 + ( 1.2 * vSunfade ) ) ) );',
|
||||
|
||||
' gl_FragColor = vec4( retColor, 1.0 );',
|
||||
|
||||
'}'
|
||||
].join( '\n' )
|
||||
|
||||
};
|
181
lib/objects/Sprite.js
Normal file
181
lib/objects/Sprite.js
Normal file
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
*/
|
||||
|
||||
import { Vector2 } from '../math/Vector2.js';
|
||||
import { Vector3 } from '../math/Vector3.js';
|
||||
import { Matrix4 } from '../math/Matrix4.js';
|
||||
import { Triangle } from '../math/Triangle.js';
|
||||
import { Object3D } from '../core/Object3D.js';
|
||||
import { BufferGeometry } from '../core/BufferGeometry.js';
|
||||
import { InterleavedBuffer } from '../core/InterleavedBuffer.js';
|
||||
import { InterleavedBufferAttribute } from '../core/InterleavedBufferAttribute.js';
|
||||
import { SpriteMaterial } from '../materials/SpriteMaterial.js';
|
||||
|
||||
var geometry;
|
||||
|
||||
function Sprite( material ) {
|
||||
|
||||
Object3D.call( this );
|
||||
|
||||
this.type = 'Sprite';
|
||||
|
||||
if ( geometry === undefined ) {
|
||||
|
||||
geometry = new BufferGeometry();
|
||||
|
||||
var float32Array = new Float32Array( [
|
||||
- 0.5, - 0.5, 0, 0, 0,
|
||||
0.5, - 0.5, 0, 1, 0,
|
||||
0.5, 0.5, 0, 1, 1,
|
||||
- 0.5, 0.5, 0, 0, 1
|
||||
] );
|
||||
|
||||
var interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
|
||||
|
||||
geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] );
|
||||
geometry.addAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
|
||||
geometry.addAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
|
||||
|
||||
}
|
||||
|
||||
this.geometry = geometry;
|
||||
this.material = ( material !== undefined ) ? material : new SpriteMaterial();
|
||||
|
||||
this.center = new Vector2( 0.5, 0.5 );
|
||||
|
||||
}
|
||||
|
||||
Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
||||
|
||||
constructor: Sprite,
|
||||
|
||||
isSprite: true,
|
||||
|
||||
raycast: ( function () {
|
||||
|
||||
var intersectPoint = new Vector3();
|
||||
var worldScale = new Vector3();
|
||||
var mvPosition = new Vector3();
|
||||
|
||||
var alignedPosition = new Vector2();
|
||||
var rotatedPosition = new Vector2();
|
||||
var viewWorldMatrix = new Matrix4();
|
||||
|
||||
var vA = new Vector3();
|
||||
var vB = new Vector3();
|
||||
var vC = new Vector3();
|
||||
|
||||
var uvA = new Vector2();
|
||||
var uvB = new Vector2();
|
||||
var uvC = new Vector2();
|
||||
|
||||
function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
|
||||
|
||||
// compute position in camera space
|
||||
alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
|
||||
|
||||
// to check if rotation is not zero
|
||||
if ( sin !== undefined ) {
|
||||
|
||||
rotatedPosition.x = ( cos * alignedPosition.x ) - ( sin * alignedPosition.y );
|
||||
rotatedPosition.y = ( sin * alignedPosition.x ) + ( cos * alignedPosition.y );
|
||||
|
||||
} else {
|
||||
|
||||
rotatedPosition.copy( alignedPosition );
|
||||
|
||||
}
|
||||
|
||||
|
||||
vertexPosition.copy( mvPosition );
|
||||
vertexPosition.x += rotatedPosition.x;
|
||||
vertexPosition.y += rotatedPosition.y;
|
||||
|
||||
// transform to world space
|
||||
vertexPosition.applyMatrix4( viewWorldMatrix );
|
||||
|
||||
}
|
||||
|
||||
return function raycast( raycaster, intersects ) {
|
||||
|
||||
worldScale.setFromMatrixScale( this.matrixWorld );
|
||||
viewWorldMatrix.getInverse( this.modelViewMatrix ).premultiply( this.matrixWorld );
|
||||
mvPosition.setFromMatrixPosition( this.modelViewMatrix );
|
||||
|
||||
var rotation = this.material.rotation;
|
||||
var sin, cos;
|
||||
if ( rotation !== 0 ) {
|
||||
|
||||
cos = Math.cos( rotation );
|
||||
sin = Math.sin( rotation );
|
||||
|
||||
}
|
||||
|
||||
var center = this.center;
|
||||
|
||||
transformVertex( vA.set( - 0.5, - 0.5, 0 ), mvPosition, center, worldScale, sin, cos );
|
||||
transformVertex( vB.set( 0.5, - 0.5, 0 ), mvPosition, center, worldScale, sin, cos );
|
||||
transformVertex( vC.set( 0.5, 0.5, 0 ), mvPosition, center, worldScale, sin, cos );
|
||||
|
||||
uvA.set( 0, 0 );
|
||||
uvB.set( 1, 0 );
|
||||
uvC.set( 1, 1 );
|
||||
|
||||
// check first triangle
|
||||
var intersect = raycaster.ray.intersectTriangle( vA, vB, vC, false, intersectPoint );
|
||||
|
||||
if ( intersect === null ) {
|
||||
|
||||
// check second triangle
|
||||
transformVertex( vB.set( - 0.5, 0.5, 0 ), mvPosition, center, worldScale, sin, cos );
|
||||
uvB.set( 0, 1 );
|
||||
|
||||
intersect = raycaster.ray.intersectTriangle( vA, vC, vB, false, intersectPoint );
|
||||
if ( intersect === null ) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var distance = raycaster.ray.origin.distanceTo( intersectPoint );
|
||||
|
||||
if ( distance < raycaster.near || distance > raycaster.far ) return;
|
||||
|
||||
intersects.push( {
|
||||
|
||||
distance: distance,
|
||||
point: intersectPoint.clone(),
|
||||
uv: Triangle.getUV( intersectPoint, vA, vB, vC, uvA, uvB, uvC, new Vector2() ),
|
||||
face: null,
|
||||
object: this
|
||||
|
||||
} );
|
||||
|
||||
};
|
||||
|
||||
}() ),
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this.material ).copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( source ) {
|
||||
|
||||
Object3D.prototype.copy.call( this, source );
|
||||
|
||||
if ( source.center !== undefined ) this.center.copy( source.center );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
} );
|
||||
|
||||
export { Sprite };
|
Reference in New Issue
Block a user