| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967 | import {	Box3,	Color,	DoubleSide,	Frustum,	Matrix3,	Matrix4,	Vector2,	Vector3,	Vector4} from '../../../build/three.module.js';class RenderableObject {	constructor() {		this.id = 0;		this.object = null;		this.z = 0;		this.renderOrder = 0;	}}//class RenderableFace {	constructor() {		this.id = 0;		this.v1 = new RenderableVertex();		this.v2 = new RenderableVertex();		this.v3 = new RenderableVertex();		this.normalModel = new Vector3();		this.vertexNormalsModel = [ new Vector3(), new Vector3(), new Vector3() ];		this.vertexNormalsLength = 0;		this.color = new Color();		this.material = null;		this.uvs = [ new Vector2(), new Vector2(), new Vector2() ];		this.z = 0;		this.renderOrder = 0;	}}//class RenderableVertex {	constructor() {		this.position = new Vector3();		this.positionWorld = new Vector3();		this.positionScreen = new Vector4();		this.visible = true;	}	copy( vertex ) {		this.positionWorld.copy( vertex.positionWorld );		this.positionScreen.copy( vertex.positionScreen );	}}//class RenderableLine {	constructor() {		this.id = 0;		this.v1 = new RenderableVertex();		this.v2 = new RenderableVertex();		this.vertexColors = [ new Color(), new Color() ];		this.material = null;		this.z = 0;		this.renderOrder = 0;	}}//class RenderableSprite {	constructor() {		this.id = 0;		this.object = null;		this.x = 0;		this.y = 0;		this.z = 0;		this.rotation = 0;		this.scale = new Vector2();		this.material = null;		this.renderOrder = 0;	}}//class Projector {	constructor() {		let _object, _objectCount, _objectPoolLength = 0,			_vertex, _vertexCount, _vertexPoolLength = 0,			_face, _faceCount, _facePoolLength = 0,			_line, _lineCount, _linePoolLength = 0,			_sprite, _spriteCount, _spritePoolLength = 0,			_modelMatrix;		const			_renderData = { objects: [], lights: [], elements: [] },			_vector3 = new Vector3(),			_vector4 = new Vector4(),			_clipBox = new Box3( new Vector3( - 1, - 1, - 1 ), new Vector3( 1, 1, 1 ) ),			_boundingBox = new Box3(),			_points3 = new Array( 3 ),			_viewMatrix = new Matrix4(),			_viewProjectionMatrix = new Matrix4(),			_modelViewProjectionMatrix = new Matrix4(),			_frustum = new Frustum(),			_objectPool = [], _vertexPool = [], _facePool = [], _linePool = [], _spritePool = [];		//		this.projectVector = function ( vector, camera ) {			console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );			vector.project( camera );		};		this.unprojectVector = function ( vector, camera ) {			console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );			vector.unproject( camera );		};		this.pickingRay = function () {			console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );		};		//		function RenderList() {			const normals = [];			const colors = [];			const uvs = [];			let object = null;			const normalMatrix = new Matrix3();			function setObject( value ) {				object = value;				normalMatrix.getNormalMatrix( object.matrixWorld );				normals.length = 0;				colors.length = 0;				uvs.length = 0;			}			function projectVertex( vertex ) {				const position = vertex.position;				const positionWorld = vertex.positionWorld;				const positionScreen = vertex.positionScreen;				positionWorld.copy( position ).applyMatrix4( _modelMatrix );				positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );				const invW = 1 / positionScreen.w;				positionScreen.x *= invW;				positionScreen.y *= invW;				positionScreen.z *= invW;				vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 &&						 positionScreen.y >= - 1 && positionScreen.y <= 1 &&						 positionScreen.z >= - 1 && positionScreen.z <= 1;			}			function pushVertex( x, y, z ) {				_vertex = getNextVertexInPool();				_vertex.position.set( x, y, z );				projectVertex( _vertex );			}			function pushNormal( x, y, z ) {				normals.push( x, y, z );			}			function pushColor( r, g, b ) {				colors.push( r, g, b );			}			function pushUv( x, y ) {				uvs.push( x, y );			}			function checkTriangleVisibility( v1, v2, v3 ) {				if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;				_points3[ 0 ] = v1.positionScreen;				_points3[ 1 ] = v2.positionScreen;				_points3[ 2 ] = v3.positionScreen;				return _clipBox.intersectsBox( _boundingBox.setFromPoints( _points3 ) );			}			function checkBackfaceCulling( v1, v2, v3 ) {				return ( ( v3.positionScreen.x - v1.positionScreen.x ) *					    ( v2.positionScreen.y - v1.positionScreen.y ) -					    ( v3.positionScreen.y - v1.positionScreen.y ) *					    ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;			}			function pushLine( a, b ) {				const v1 = _vertexPool[ a ];				const v2 = _vertexPool[ b ];				// Clip				v1.positionScreen.copy( v1.position ).applyMatrix4( _modelViewProjectionMatrix );				v2.positionScreen.copy( v2.position ).applyMatrix4( _modelViewProjectionMatrix );				if ( clipLine( v1.positionScreen, v2.positionScreen ) === true ) {					// Perform the perspective divide					v1.positionScreen.multiplyScalar( 1 / v1.positionScreen.w );					v2.positionScreen.multiplyScalar( 1 / v2.positionScreen.w );					_line = getNextLineInPool();					_line.id = object.id;					_line.v1.copy( v1 );					_line.v2.copy( v2 );					_line.z = Math.max( v1.positionScreen.z, v2.positionScreen.z );					_line.renderOrder = object.renderOrder;					_line.material = object.material;					if ( object.material.vertexColors ) {						_line.vertexColors[ 0 ].fromArray( colors, a * 3 );						_line.vertexColors[ 1 ].fromArray( colors, b * 3 );					}					_renderData.elements.push( _line );				}			}			function pushTriangle( a, b, c, material ) {				const v1 = _vertexPool[ a ];				const v2 = _vertexPool[ b ];				const v3 = _vertexPool[ c ];				if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;				if ( material.side === DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {					_face = getNextFaceInPool();					_face.id = object.id;					_face.v1.copy( v1 );					_face.v2.copy( v2 );					_face.v3.copy( v3 );					_face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;					_face.renderOrder = object.renderOrder;					// face normal					_vector3.subVectors( v3.position, v2.position );					_vector4.subVectors( v1.position, v2.position );					_vector3.cross( _vector4 );					_face.normalModel.copy( _vector3 );					_face.normalModel.applyMatrix3( normalMatrix ).normalize();					for ( let i = 0; i < 3; i ++ ) {						const normal = _face.vertexNormalsModel[ i ];						normal.fromArray( normals, arguments[ i ] * 3 );						normal.applyMatrix3( normalMatrix ).normalize();						const uv = _face.uvs[ i ];						uv.fromArray( uvs, arguments[ i ] * 2 );					}					_face.vertexNormalsLength = 3;					_face.material = material;					if ( material.vertexColors ) {						_face.color.fromArray( colors, a * 3 );					}					_renderData.elements.push( _face );				}			}			return {				setObject: setObject,				projectVertex: projectVertex,				checkTriangleVisibility: checkTriangleVisibility,				checkBackfaceCulling: checkBackfaceCulling,				pushVertex: pushVertex,				pushNormal: pushNormal,				pushColor: pushColor,				pushUv: pushUv,				pushLine: pushLine,				pushTriangle: pushTriangle			};		}		const renderList = new RenderList();		function projectObject( object ) {			if ( object.visible === false ) return;			if ( object.isLight ) {				_renderData.lights.push( object );			} else if ( object.isMesh || object.isLine || object.isPoints ) {				if ( object.material.visible === false ) return;				if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return;				addObject( object );			} else if ( object.isSprite ) {				if ( object.material.visible === false ) return;				if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return;				addObject( object );			}			const children = object.children;			for ( let i = 0, l = children.length; i < l; i ++ ) {				projectObject( children[ i ] );			}		}		function addObject( object ) {			_object = getNextObjectInPool();			_object.id = object.id;			_object.object = object;			_vector3.setFromMatrixPosition( object.matrixWorld );			_vector3.applyMatrix4( _viewProjectionMatrix );			_object.z = _vector3.z;			_object.renderOrder = object.renderOrder;			_renderData.objects.push( _object );		}		this.projectScene = function ( scene, camera, sortObjects, sortElements ) {			_faceCount = 0;			_lineCount = 0;			_spriteCount = 0;			_renderData.elements.length = 0;			if ( scene.autoUpdate === true ) scene.updateMatrixWorld();			if ( camera.parent === null ) camera.updateMatrixWorld();			_viewMatrix.copy( camera.matrixWorldInverse );			_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );			_frustum.setFromProjectionMatrix( _viewProjectionMatrix );			//			_objectCount = 0;			_renderData.objects.length = 0;			_renderData.lights.length = 0;			projectObject( scene );			if ( sortObjects === true ) {				_renderData.objects.sort( painterSort );			}			//			const objects = _renderData.objects;			for ( let o = 0, ol = objects.length; o < ol; o ++ ) {				const object = objects[ o ].object;				const geometry = object.geometry;				renderList.setObject( object );				_modelMatrix = object.matrixWorld;				_vertexCount = 0;				if ( object.isMesh ) {					if ( geometry.isBufferGeometry ) {						let material = object.material;						const isMultiMaterial = Array.isArray( material );						const attributes = geometry.attributes;						const groups = geometry.groups;						if ( attributes.position === undefined ) continue;						const positions = attributes.position.array;						for ( let i = 0, l = positions.length; i < l; i += 3 ) {							let x = positions[ i ];							let y = positions[ i + 1 ];							let z = positions[ i + 2 ];							const morphTargets = geometry.morphAttributes.position;							if ( morphTargets !== undefined ) {								const morphTargetsRelative = geometry.morphTargetsRelative;								const morphInfluences = object.morphTargetInfluences;								for ( let t = 0, tl = morphTargets.length; t < tl; t ++ ) {									const influence = morphInfluences[ t ];									if ( influence === 0 ) continue;									const target = morphTargets[ t ];									if ( morphTargetsRelative ) {										x += target.getX( i / 3 ) * influence;										y += target.getY( i / 3 ) * influence;										z += target.getZ( i / 3 ) * influence;									} else {										x += ( target.getX( i / 3 ) - positions[ i ] ) * influence;										y += ( target.getY( i / 3 ) - positions[ i + 1 ] ) * influence;										z += ( target.getZ( i / 3 ) - positions[ i + 2 ] ) * influence;									}								}							}							renderList.pushVertex( x, y, z );						}						if ( attributes.normal !== undefined ) {							const normals = attributes.normal.array;							for ( let i = 0, l = normals.length; i < l; i += 3 ) {								renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );							}						}						if ( attributes.color !== undefined ) {							const colors = attributes.color.array;							for ( let i = 0, l = colors.length; i < l; i += 3 ) {								renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] );							}						}						if ( attributes.uv !== undefined ) {							const uvs = attributes.uv.array;							for ( let i = 0, l = uvs.length; i < l; i += 2 ) {								renderList.pushUv( uvs[ i ], uvs[ i + 1 ] );							}						}						if ( geometry.index !== null ) {							const indices = geometry.index.array;							if ( groups.length > 0 ) {								for ( let g = 0; g < groups.length; g ++ ) {									const group = groups[ g ];									material = isMultiMaterial === true										 ? object.material[ group.materialIndex ]										 : object.material;									if ( material === undefined ) continue;									for ( let i = group.start, l = group.start + group.count; i < l; i += 3 ) {										renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ], material );									}								}							} else {								for ( let i = 0, l = indices.length; i < l; i += 3 ) {									renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ], material );								}							}						} else {							if ( groups.length > 0 ) {								for ( let g = 0; g < groups.length; g ++ ) {									const group = groups[ g ];									material = isMultiMaterial === true										 ? object.material[ group.materialIndex ]										 : object.material;									if ( material === undefined ) continue;									for ( let i = group.start, l = group.start + group.count; i < l; i += 3 ) {										renderList.pushTriangle( i, i + 1, i + 2, material );									}								}							} else {								for ( let i = 0, l = positions.length / 3; i < l; i += 3 ) {									renderList.pushTriangle( i, i + 1, i + 2, material );								}							}						}					} else if ( geometry.isGeometry ) {						console.error( 'THREE.Projector no longer supports Geometry. Use THREE.BufferGeometry instead.' );						return;					}				} else if ( object.isLine ) {					_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );					if ( geometry.isBufferGeometry ) {						const attributes = geometry.attributes;						if ( attributes.position !== undefined ) {							const positions = attributes.position.array;							for ( let i = 0, l = positions.length; i < l; i += 3 ) {								renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );							}							if ( attributes.color !== undefined ) {								const colors = attributes.color.array;								for ( let i = 0, l = colors.length; i < l; i += 3 ) {									renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] );								}							}							if ( geometry.index !== null ) {								const indices = geometry.index.array;								for ( let i = 0, l = indices.length; i < l; i += 2 ) {									renderList.pushLine( indices[ i ], indices[ i + 1 ] );								}							} else {								const step = object.isLineSegments ? 2 : 1;								for ( let i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {									renderList.pushLine( i, i + 1 );								}							}						}					} else if ( geometry.isGeometry ) {						console.error( 'THREE.Projector no longer supports Geometry. Use THREE.BufferGeometry instead.' );						return;					}				} else if ( object.isPoints ) {					_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );					if ( geometry.isGeometry ) {						console.error( 'THREE.Projector no longer supports Geometry. Use THREE.BufferGeometry instead.' );						return;					} else if ( geometry.isBufferGeometry ) {						const attributes = geometry.attributes;						if ( attributes.position !== undefined ) {							const positions = attributes.position.array;							for ( let i = 0, l = positions.length; i < l; i += 3 ) {								_vector4.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ], 1 );								_vector4.applyMatrix4( _modelViewProjectionMatrix );								pushPoint( _vector4, object, camera );							}						}					}				} else if ( object.isSprite ) {					object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );					_vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );					_vector4.applyMatrix4( _viewProjectionMatrix );					pushPoint( _vector4, object, camera );				}			}			if ( sortElements === true ) {				_renderData.elements.sort( painterSort );			}			return _renderData;		};		function pushPoint( _vector4, object, camera ) {			const invW = 1 / _vector4.w;			_vector4.z *= invW;			if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {				_sprite = getNextSpriteInPool();				_sprite.id = object.id;				_sprite.x = _vector4.x * invW;				_sprite.y = _vector4.y * invW;				_sprite.z = _vector4.z;				_sprite.renderOrder = object.renderOrder;				_sprite.object = object;				_sprite.rotation = object.rotation;				_sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );				_sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );				_sprite.material = object.material;				_renderData.elements.push( _sprite );			}		}		// Pools		function getNextObjectInPool() {			if ( _objectCount === _objectPoolLength ) {				const object = new RenderableObject();				_objectPool.push( object );				_objectPoolLength ++;				_objectCount ++;				return object;			}			return _objectPool[ _objectCount ++ ];		}		function getNextVertexInPool() {			if ( _vertexCount === _vertexPoolLength ) {				const vertex = new RenderableVertex();				_vertexPool.push( vertex );				_vertexPoolLength ++;				_vertexCount ++;				return vertex;			}			return _vertexPool[ _vertexCount ++ ];		}		function getNextFaceInPool() {			if ( _faceCount === _facePoolLength ) {				const face = new RenderableFace();				_facePool.push( face );				_facePoolLength ++;				_faceCount ++;				return face;			}			return _facePool[ _faceCount ++ ];		}		function getNextLineInPool() {			if ( _lineCount === _linePoolLength ) {				const line = new RenderableLine();				_linePool.push( line );				_linePoolLength ++;				_lineCount ++;				return line;			}			return _linePool[ _lineCount ++ ];		}		function getNextSpriteInPool() {			if ( _spriteCount === _spritePoolLength ) {				const sprite = new RenderableSprite();				_spritePool.push( sprite );				_spritePoolLength ++;				_spriteCount ++;				return sprite;			}			return _spritePool[ _spriteCount ++ ];		}		//		function painterSort( a, b ) {			if ( a.renderOrder !== b.renderOrder ) {				return a.renderOrder - b.renderOrder;			} else if ( a.z !== b.z ) {				return b.z - a.z;			} else if ( a.id !== b.id ) {				return a.id - b.id;			} else {				return 0;			}		}		function clipLine( s1, s2 ) {			let alpha1 = 0, alpha2 = 1;			// Calculate the boundary coordinate of each vertex for the near and far clip planes,			// Z = -1 and Z = +1, respectively.			const bc1near = s1.z + s1.w,				bc2near = s2.z + s2.w,				bc1far = - s1.z + s1.w,				bc2far = - s2.z + s2.w;			if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {				// Both vertices lie entirely within all clip planes.				return true;			} else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) {				// Both vertices lie entirely outside one of the clip planes.				return false;			} else {				// The line segment spans at least one clip plane.				if ( bc1near < 0 ) {					// v1 lies outside the near plane, v2 inside					alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );				} else if ( bc2near < 0 ) {					// v2 lies outside the near plane, v1 inside					alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );				}				if ( bc1far < 0 ) {					// v1 lies outside the far plane, v2 inside					alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );				} else if ( bc2far < 0 ) {					// v2 lies outside the far plane, v2 inside					alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );				}				if ( alpha2 < alpha1 ) {					// The line segment spans two boundaries, but is outside both of them.					// (This can't happen when we're only clipping against just near/far but good					//  to leave the check here for future usage if other clip planes are added.)					return false;				} else {					// Update the s1 and s2 vertices to match the clipped line segment.					s1.lerp( s2, alpha1 );					s2.lerp( s1, 1 - alpha2 );					return true;				}			}		}	}}export { RenderableObject, RenderableFace, RenderableVertex, RenderableLine, RenderableSprite, Projector };
 |