js跟随鼠标移动旋转心形特效代码

版权:原创 更新时间:1年以上
[该文章底部包含文件资源,可根据自己情况,决定是否下载资源使用,时间>金钱,如有需要,立即查看资源]

以下是 js跟随鼠标移动旋转心形特效代码 的示例演示效果:

当前平台(PC电脑)
  • 平台:

部分效果截图:

js跟随鼠标移动旋转心形特效代码

HTML代码(index.html):

<!DOCTYPE html>
<html lang="en">
<head>
<title>js跟随鼠标移动旋转心形特效</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
	body {
		font-family: Monospace;
		background-color: #f0f0f0;
		margin: 0px;
		overflow: hidden;
	}
</style>
</head>
<body>

<script src="js/nb.js"></script>

<script src="js/Projector.js"></script>
<script src="js/CanvasRenderer.js"></script>

<script src="js/tween.min.js"></script>
<script src="js/Sparks.js"></script>

<!-- load the font file from canvas-text -->

<script src="js/helvetiker_regular.typeface.js"></script>

<script>

	var container;

	var camera, scene, renderer;

	var group, text, plane;

	var targetRotation = 0;
	var targetRotationOnMouseDown = 0;

	var mouseX = 0;
	var mouseXOnMouseDown = 0;

	var windowHalfX = window.innerWidth / 2;
	var windowHalfY = window.innerHeight / 2;

	var heartShape, particleCloud, sparksEmitter, emitterPos;
	var _rotation = 0;
	var timeOnShapePath = 0;

	init();
	animate();

	function init() {

		container = document.createElement( 'div' );
		document.body.appendChild( container );


		//相机
		camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000);
		camera.position.set( 0, 150, 800 );

		//场景
		scene = new THREE.Scene();

		group = new THREE.Group();
		scene.add( group );

		// Get text from hash

		var string = "LOVE U";
		var hash = document.location.hash.substr( 1 );

		if ( hash.length !== 0 ) {

			string = hash;

		}

		var text3d = new THREE.TextGeometry( string, {

			size: 80,
			height: 20,
			curveSegments: 2,
			font: "helvetiker"

		});

		text3d.computeBoundingBox();
		var centerOffset = -0.5 * ( text3d.boundingBox.max.x - text3d.boundingBox.min.x );

		var textMaterial = new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, overdraw: 0.5 } );

		text = new THREE.Mesh( text3d, textMaterial );

		// Potentially, we can extract the vertices or faces of the text to generate particles too.
		// Geo > Vertices > Position

		text.position.x = centerOffset;
		text.position.y = 100;
		text.position.z = 0;

		text.rotation.x = 0;
		text.rotation.y = Math.PI * 2;

		group.add( text );


		particleCloud = new THREE.Object3D(); // Just a group
		particleCloud.y = 800;
		group.add( particleCloud );

		// Create Particle Systems

		// Heart

		var x = 0, y = 0;

		heartShape = new THREE.Shape();

		heartShape.moveTo( x + 25, y + 25 );
		heartShape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y );
		heartShape.bezierCurveTo( x - 30, y, x - 30, y + 35,x - 30,y + 35 );
		heartShape.bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 );
		heartShape.bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 );
		heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y );
		heartShape.bezierCurveTo( x + 35, y, x + 25, y + 25, x + 25, y + 25 );

		var hue = 0;

		var hearts = function ( context ) {

			context.globalAlpha = 0.5;
			var x = 0, y = 0;
			context.scale(0.05, -0.05); // Scale so canvas render can redraw within bounds
			context.beginPath();
			 // From http://blog.burlock.org/html5/130-paths
			context.bezierCurveTo( x + 2.5, y + 2.5, x + 2.0, y, x, y );
			context.bezierCurveTo( x - 3.0, y, x - 3.0, y + 3.5,x - 3.0,y + 3.5 );
			context.bezierCurveTo( x - 3.0, y + 5.5, x - 1.0, y + 7.7, x + 2.5, y + 9.5 );
			context.bezierCurveTo( x + 6.0, y + 7.7, x + 8.0, y + 5.5, x + 8.0, y + 3.5 );
			context.bezierCurveTo( x + 8.0, y + 3.5, x + 8.0, y, x + 5.0, y );
			context.bezierCurveTo( x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5 );
			context.fill();
			context.lineWidth = 0.5; //0.05
			context.stroke();

		}

		var setTargetParticle = function() {

			var material = new THREE.SpriteCanvasMaterial( {
				program: hearts
			} );

			material.color.setHSL(hue, 1, 0.75);
			hue += 0.001;
			if (hue>1) hue-=1;

			particle = new THREE.Sprite( material );

			particle.scale.x = particle.scale.y = Math.random() * 40 + 40;
			particleCloud.add( particle );

			return particle;

		};

		var onParticleCreated = function( p ) {

			p.target.position.copy( p.position );

		};

		var onParticleDead = function( particle ) {

			particle.target.visible = false;
			particleCloud.remove( particle.target );

		};

		sparksEmitter = new SPARKS.Emitter(new SPARKS.SteadyCounter(160));

		emitterpos = new THREE.Vector3();

		sparksEmitter.addInitializer(new SPARKS.Position( new SPARKS.PointZone( emitterpos ) ) );
		sparksEmitter.addInitializer(new SPARKS.Lifetime(0,2));
		sparksEmitter.addInitializer(new SPARKS.Target(null, setTargetParticle));

		sparksEmitter.addInitializer(new SPARKS.Velocity(new SPARKS.PointZone(new THREE.Vector3(0,-50,10))));

		// TOTRY Set velocity to move away from centroid

		sparksEmitter.addAction(new SPARKS.Age());
		//sparksEmitter.addAction(new SPARKS.Accelerate(0.2));
		sparksEmitter.addAction(new SPARKS.Move());
		sparksEmitter.addAction(new SPARKS.RandomDrift(50,50,2000));

		sparksEmitter.addCallback("created", onParticleCreated);
		sparksEmitter.addCallback("dead", onParticleDead);
		sparksEmitter.addCallback("updated", function( particle ) {

			particle.target.position.copy( particle.position );

		});

		sparksEmitter.start();

		// End Particles


		renderer = new THREE.CanvasRenderer();
		renderer.setClearColor( 0xf0f0f0 );
		renderer.setPixelRatio( window.devicePixelRatio );
		renderer.setSize( window.innerWidth, window.innerHeight );
		container.appendChild( renderer.domElement );

		document.addEventListener( 'mousedown', onDocumentMouseDown, false );
		document.addEventListener( 'touchstart', onDocumentTouchStart, false );
		document.addEventListener( 'touchmove', onDocumentTouchMove, false );

		//

		window.addEventListener( 'resize', onWindowResize, false );

	}

	function onWindowResize() {

		windowHalfX = window.innerWidth / 2;
		windowHalfY = window.innerHeight / 2;

		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();

		renderer.setSize( window.innerWidth, window.innerHeight );

	}

	//

	document.addEventListener( 'mousemove', onDocumentMouseMove, false );

	function onDocumentMouseDown( event ) {

		event.preventDefault();

		mouseXOnMouseDown = event.clientX - windowHalfX;
		targetRotationOnMouseDown = targetRotation;

		if ( sparksEmitter.isRunning() ) {

			sparksEmitter.stop();

		} else {

			sparksEmitter.start();

		}

	}

	function onDocumentMouseMove( event ) {

		mouseX = event.clientX - windowHalfX;

		targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;

	}

	function onDocumentTouchStart( event ) {

		if ( event.touches.length == 1 ) {

			event.preventDefault();

			mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
			targetRotationOnMouseDown = targetRotation;

		}

	}

	function onDocumentTouchMove( event ) {

		if ( event.touches.length == 1 ) {

			event.preventDefault();

			mouseX = event.touches[ 0 ].pageX - windowHalfX;
			targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;

		}

	}

	//

	function animate() {//更新场景

		requestAnimationFrame( animate );

		render();

	}

	function render() {

		timeOnShapePath += 0.0337;

		if (timeOnShapePath > 1) timeOnShapePath -= 1;

		// TODO Create a PointOnShape Action/Zone in the particle engine
		var pointOnShape = heartShape.getPointAt( timeOnShapePath );

		emitterpos.x = pointOnShape.x * 5 - 100;
		emitterpos.y = -pointOnShape.y * 5 + 400;

		// Pretty cool effect if you enable this
		// particleCloud.rotation.y += 0.05;

		group.rotation.y += ( targetRotation - group.rotation.y ) * 0.05;
		renderer.render( scene, camera );
	}

</script>
</body>
</html>

JS代码(CanvasRenderer.js):

THREE.SpriteCanvasMaterial = function ( parameters ){
	THREE.Material.call( this );
	this.type = 'SpriteCanvasMaterial';
	this.color = new THREE.Color( 0xffffff );
	this.program = function ( context,color ){
}
;
	this.setValues( parameters );
}
;
	THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
	THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;
	THREE.SpriteCanvasMaterial.prototype.clone = function (){
	var material = new THREE.SpriteCanvasMaterial();
	THREE.Material.prototype.clone.call( this,material );
	material.color.copy( this.color );
	material.program = this.program;
	return material;
}
;
	//THREE.CanvasRenderer = function ( parameters ){
	console.log( 'THREE.CanvasRenderer',THREE.REVISION );
	var smoothstep = THREE.Math.smoothstep;
	parameters = parameters ||{
}
;
	var _this = this,_renderData,_elements,_lights,_projector = new THREE.Projector(),_canvas = parameters.canvas !== undefined ? parameters.canvas:document.createElement( 'canvas' ),_canvasWidth = _canvas.width,_canvasHeight = _canvas.height,_canvasWidthHalf = Math.floor( _canvasWidth / 2 ),_canvasHeightHalf = Math.floor( _canvasHeight / 2 ),_viewportX = 0,_viewportY = 0,_viewportWidth = _canvasWidth,_viewportHeight = _canvasHeight,pixelRatio = 1,_context = _canvas.getContext( '2d',{
	alpha:parameters.alpha === true}
),_clearColor = new THREE.Color( 0x000000 ),_clearAlpha = parameters.alpha === true ? 0:1,_contextGlobalAlpha = 1,_contextGlobalCompositeOperation = 0,_contextStrokeStyle = null,_contextFillStyle = null,_contextLineWidth = null,_contextLineCap = null,_contextLineJoin = null,_contextLineDash = [],_camera,_v1,_v2,_v3,_v4,_v5 = new THREE.RenderableVertex(),_v6 = new THREE.RenderableVertex(),_v1x,_v1y,_v2x,_v2y,_v3x,_v3y,_v4x,_v4y,_v5x,_v5y,_v6x,_v6y,_color = new THREE.Color(),_color1 = new THREE.Color(),_color2 = new THREE.Color(),_color3 = new THREE.Color(),_color4 = new THREE.Color(),_diffuseColor = new THREE.Color(),_emissiveColor = new THREE.Color(),_lightColor = new THREE.Color(),_patterns ={
}
,_image,_uvs,_uv1x,_uv1y,_uv2x,_uv2y,_uv3x,_uv3y,_clipBox = new THREE.Box2(),_clearBox = new THREE.Box2(),_elemBox = new THREE.Box2(),_ambientLight = new THREE.Color(),_directionalLights = new THREE.Color(),_pointLights = new THREE.Color(),_vector3 = new THREE.Vector3(),// Needed for PointLight_centroid = new THREE.Vector3(),_normal = new THREE.Vector3(),_normalViewMatrix = new THREE.Matrix3();
	// dash+gap fallbacks for Firefox and everything elseif ( _context.setLineDash === undefined ){
	_context.setLineDash = function (){
}
}
this.domElement = _canvas;
	this.autoClear = true;
	this.sortObjects = true;
	this.sortElements = true;
	this.info ={
	render:{
	vertices:0,faces:0}
}
// WebGLRenderer compatibilitythis.supportsVertexTextures = function (){
}
;
	this.setFaceCulling = function (){
}
;
	//this.getPixelRatio = function (){
	return pixelRatio;
}
;
	this.setPixelRatio = function ( value ){
	pixelRatio = value;
}
;
	this.setSize = function ( width,height,updateStyle ){
	_canvasWidth = width * pixelRatio;
	_canvasHeight = height * pixelRatio;
	_canvas.width = _canvasWidth;
	_canvas.height = _canvasHeight;
	_canvasWidthHalf = Math.floor( _canvasWidth / 2 );
	_canvasHeightHalf = Math.floor( _canvasHeight / 2 );
	if ( updateStyle !== false ){
	_canvas.style.width = width + 'px';
	_canvas.style.height = height + 'px';
}
_clipBox.min.set( -_canvasWidthHalf,-_canvasHeightHalf ),_clipBox.max.set( _canvasWidthHalf,_canvasHeightHalf );
	_clearBox.min.set( - _canvasWidthHalf,- _canvasHeightHalf );
	_clearBox.max.set( _canvasWidthHalf,_canvasHeightHalf );
	_contextGlobalAlpha = 1;
	_contextGlobalCompositeOperation = 0;
	_contextStrokeStyle = null;
	_contextFillStyle = null;
	_contextLineWidth = null;
	_contextLineCap = null;
	_contextLineJoin = null;
	this.setViewport( 0,0,width,height );
}
;
	this.setViewport = function ( x,y,width,height ){
	_viewportX = x * pixelRatio;
	_viewportY = y * pixelRatio;
	_viewportWidth = width * pixelRatio;
	_viewportHeight = height * pixelRatio;
}
;
	this.setScissor = function (){
}
;
	this.enableScissorTest = function (){
}
;
	this.setClearColor = function ( color,alpha ){
	_clearColor.set( color );
	_clearAlpha = alpha !== undefined ? alpha:1;
	_clearBox.min.set( - _canvasWidthHalf,- _canvasHeightHalf );
	_clearBox.max.set( _canvasWidthHalf,_canvasHeightHalf );
}
;
	this.setClearColorHex = function ( hex,alpha ){
	console.warn( 'THREE.CanvasRenderer:.setClearColorHex() is being removed. Use .setClearColor() instead.' );
	this.setClearColor( hex,alpha );
}
;
	this.getClearColor = function (){
	return _clearColor;
}
;
	this.getClearAlpha = function (){
	return _clearAlpha;
}
;
	this.getMaxAnisotropy = function (){
	return 0;
}
;
	this.clear = function (){
	if ( _clearBox.empty() === false ){
	_clearBox.intersect( _clipBox );
	_clearBox.expandByScalar( 2 );
	_clearBox.min.x = _clearBox.min.x + _canvasWidthHalf;
	_clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf;
	// higher y value !_clearBox.max.x = _clearBox.max.x + _canvasWidthHalf;
	_clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf;
	// lower y value !if ( _clearAlpha < 1 ){
	_context.clearRect(_clearBox.min.x | 0,_clearBox.max.y | 0,( _clearBox.max.x - _clearBox.min.x ) | 0,( _clearBox.min.y - _clearBox.max.y ) | 0);
}
if ( _clearAlpha > 0 ){
	setBlending( THREE.NormalBlending );
	setOpacity( 1 );
	setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' );
	_context.fillRect(_clearBox.min.x | 0,_clearBox.max.y | 0,( _clearBox.max.x - _clearBox.min.x ) | 0,( _clearBox.min.y - _clearBox.max.y ) | 0);
}
_clearBox.makeEmpty();
}
}
;
	// compatibilitythis.clearColor = function (){
}
;
	this.clearDepth = function (){
}
;
	this.clearStencil = function (){
}
;
	this.render = function ( scene,camera ){
	if ( camera instanceof THREE.Camera === false ){
	console.error( 'THREE.CanvasRenderer.render:camera is not an instance of THREE.Camera.' );
	return;
}
if ( this.autoClear === true ) this.clear();
	_this.info.render.vertices = 0;
	_this.info.render.faces = 0;
	_context.setTransform( _viewportWidth / _canvasWidth,0,0,- _viewportHeight / _canvasHeight,_viewportX,_canvasHeight - _viewportY );
	_context.translate( _canvasWidthHalf,_canvasHeightHalf );
	_renderData = _projector.projectScene( scene,camera,this.sortObjects,this.sortElements );
	_elements = _renderData.elements;
	_lights = _renderData.lights;
	_camera = camera;
	_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
	/* DEBUGsetFillStyle( 'rgba( 0,255,255,0.5 )' );
	_context.fillRect( _clipBox.min.x,_clipBox.min.y,_clipBox.max.x - _clipBox.min.x,_clipBox.max.y - _clipBox.min.y );
	*/
calculateLights();
	for ( var e = 0,el = _elements.length;
	e < el;
	e ++ ){
	var element = _elements[ e ];
	var material = element.material;
	if ( material === undefined || material.opacity === 0 ) continue;
	_elemBox.makeEmpty();
	if ( element instanceof THREE.RenderableSprite ){
	_v1 = element;
	_v1.x *= _canvasWidthHalf;
	_v1.y *= _canvasHeightHalf;
	renderSprite( _v1,element,material );
}
else if ( element instanceof THREE.RenderableLine ){
	_v1 = element.v1;
	_v2 = element.v2;
	_v1.positionScreen.x *= _canvasWidthHalf;
	_v1.positionScreen.y *= _canvasHeightHalf;
	_v2.positionScreen.x *= _canvasWidthHalf;
	_v2.positionScreen.y *= _canvasHeightHalf;
	_elemBox.setFromPoints( [_v1.positionScreen,_v2.positionScreen] );
	if ( _clipBox.isIntersectionBox( _elemBox ) === true ){
	renderLine( _v1,_v2,element,material );
}
}
else if ( element instanceof THREE.RenderableFace ){
	_v1 = element.v1;
	_v2 = element.v2;
	_v3 = element.v3;
	if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue;
	if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue;
	if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue;
	_v1.positionScreen.x *= _canvasWidthHalf;
	_v1.positionScreen.y *= _canvasHeightHalf;
	_v2.positionScreen.x *= _canvasWidthHalf;
	_v2.positionScreen.y *= _canvasHeightHalf;
	_v3.positionScreen.x *= _canvasWidthHalf;
	_v3.positionScreen.y *= _canvasHeightHalf;
	if ( material.overdraw > 0 ){
	expand( _v1.positionScreen,_v2.positionScreen,material.overdraw );
	expand( _v2.positionScreen,_v3.positionScreen,material.overdraw );
	expand( _v3.positionScreen,_v1.positionScreen,material.overdraw );
}
_elemBox.setFromPoints( [_v1.positionScreen,_v2.positionScreen,_v3.positionScreen] );
	if ( _clipBox.isIntersectionBox( _elemBox ) === true ){
	renderFace3( _v1,_v2,_v3,0,1,2,element,material );
}
}
/* DEBUGsetLineWidth( 1 );
	setStrokeStyle( 'rgba( 0,255,0,0.5 )' );
	_context.strokeRect( _elemBox.min.x,_elemBox.min.y,_elemBox.max.x - _elemBox.min.x,_elemBox.max.y - _elemBox.min.y );
	*/
_clearBox.union( _elemBox );
}
/* DEBUGsetLineWidth( 1 );
	setStrokeStyle( 'rgba( 255,0,0,0.5 )' );
	_context.strokeRect( _clearBox.min.x,_clearBox.min.y,_clearBox.max.x - _clearBox.min.x,_clearBox.max.y - _clearBox.min.y );
	*/
_context.setTransform( 1,0,0,1,0,0 );
}
;
	//function calculateLights(){
	_ambientLight.setRGB( 0,0,0 );
	_directionalLights.setRGB( 0,0,0 );
	_pointLights.setRGB( 0,0,0 );
	for ( var l = 0,ll = _lights.length;
	l < ll;
	l ++ ){
	var light = _lights[ l ];
	var lightColor = light.color;
	if ( light instanceof THREE.AmbientLight ){
	_ambientLight.add( lightColor );
}
else if ( light instanceof THREE.DirectionalLight ){
	// for sprites_directionalLights.add( lightColor );
}
else if ( light instanceof THREE.PointLight ){
	// for sprites_pointLights.add( lightColor );
}
}
}
function calculateLight( position,normal,color ){
	for ( var l = 0,ll = _lights.length;
	l < ll;
	l ++ ){
	var light = _lights[ l ];
	_lightColor.copy( light.color );
	if ( light instanceof THREE.DirectionalLight ){
	var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
	var amount = normal.dot( lightPosition );
	if ( amount <= 0 ) continue;
	amount *= light.intensity;
	color.add( _lightColor.multiplyScalar( amount ) );
}
else if ( light instanceof THREE.PointLight ){
	var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
	var amount = normal.dot( _vector3.subVectors( lightPosition,position ).normalize() );
	if ( amount <= 0 ) continue;
	amount *= light.distance == 0 ? 1:1 - Math.min( position.distanceTo( lightPosition ) / light.distance,1 );
	if ( amount == 0 ) continue;
	amount *= light.intensity;
	color.add( _lightColor.multiplyScalar( amount ) );
}
}
}
function renderSprite( v1,element,material ){
	setOpacity( material.opacity );
	setBlending( material.blending );
	var scaleX = element.scale.x * _canvasWidthHalf;
	var scaleY = element.scale.y * _canvasHeightHalf;
	var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY );
	// allow for rotated sprite_elemBox.min.set( v1.x - dist,v1.y - dist );
	_elemBox.max.set( v1.x + dist,v1.y + dist );
	if ( material instanceof THREE.SpriteMaterial ){
	var texture = material.map;
	if ( texture !== null && texture.image !== undefined ){
	if ( texture.hasEventListener( 'update',onTextureUpdate ) === false ){
	if ( texture.image.width > 0 ){
	textureToPattern( texture );
}
texture.addEventListener( 'update',onTextureUpdate );
}
var pattern = _patterns[ texture.id ];
	if ( pattern !== undefined ){
	setFillStyle( pattern );
}
else{
	setFillStyle( 'rgba( 0,0,0,1 )' );
}
//var bitmap = texture.image;
	var ox = bitmap.width * texture.offset.x;
	var oy = bitmap.height * texture.offset.y;
	var sx = bitmap.width * texture.repeat.x;
	var sy = bitmap.height * texture.repeat.y;
	var cx = scaleX / sx;
	var cy = scaleY / sy;
	_context.save();
	_context.translate( v1.x,v1.y );
	if ( material.rotation !== 0 ) _context.rotate( material.rotation );
	_context.translate( - scaleX / 2,- scaleY / 2 );
	_context.scale( cx,cy );
	_context.translate( - ox,- oy );
	_context.fillRect( ox,oy,sx,sy );
	_context.restore();
}
else{
	// no texturesetFillStyle( material.color.getStyle() );
	_context.save();
	_context.translate( v1.x,v1.y );
	if ( material.rotation !== 0 ) _context.rotate( material.rotation );
	_context.scale( scaleX,- scaleY );
	_context.fillRect( - 0.5,- 0.5,1,1 );
	_context.restore();
}
}
else if ( material instanceof THREE.SpriteCanvasMaterial ){
	setStrokeStyle( material.color.getStyle() );
	setFillStyle( material.color.getStyle() );
	_context.save();
	_context.translate( v1.x,v1.y );
	if ( material.rotation !== 0 ) _context.rotate( material.rotation );
	_context.scale( scaleX,scaleY );
	material.program( _context );
	_context.restore();
}
/* DEBUGsetStrokeStyle( 'rgb(255,255,0)' );
	_context.beginPath();
	_context.moveTo( v1.x - 10,v1.y );
	_context.lineTo( v1.x + 10,v1.y );
	_context.moveTo( v1.x,v1.y - 10 );
	_context.lineTo( v1.x,v1.y + 10 );
	_context.stroke();
	*/
}
function renderLine( v1,v2,element,material ){
	setOpacity( material.opacity );
	setBlending( material.blending );
	_context.beginPath();
	_context.moveTo( v1.positionScreen.x,v1.positionScreen.y );
	_context.lineTo( v2.positionScreen.x,v2.positionScreen.y );
	if ( material instanceof THREE.LineBasicMaterial ){
	setLineWidth( material.linewidth );
	setLineCap( material.linecap );
	setLineJoin( material.linejoin );
	if ( material.vertexColors !== THREE.VertexColors ){
	setStrokeStyle( material.color.getStyle() );
}
else{
	var colorStyle1 = element.vertexColors[ 0 ].getStyle();
	var colorStyle2 = element.vertexColors[ 1 ].getStyle();
	if ( colorStyle1 === colorStyle2 ){
	setStrokeStyle( colorStyle1 );
}
else{
	try{
	var grad = _context.createLinearGradient(v1.positionScreen.x,v1.positionScreen.y,v2.positionScreen.x,v2.positionScreen.y);
	grad.addColorStop( 0,colorStyle1 );
	grad.addColorStop( 1,colorStyle2 );
}
catch ( exception ){
	grad = colorStyle1;
}
setStrokeStyle( grad );
}
}
_context.stroke();
	_elemBox.expandByScalar( material.linewidth * 2 );
}
else if ( material instanceof THREE.LineDashedMaterial ){
	setLineWidth( material.linewidth );
	setLineCap( material.linecap );
	setLineJoin( material.linejoin );
	setStrokeStyle( material.color.getStyle() );
	setLineDash( [ material.dashSize,material.gapSize ] );
	_context.stroke();
	_elemBox.expandByScalar( material.linewidth * 2 );
	setLineDash( [] );
}
}
function renderFace3( v1,v2,v3,uv1,uv2,uv3,element,material ){
	_this.info.render.vertices += 3;
	_this.info.render.faces ++;
	setOpacity( material.opacity );
	setBlending( material.blending );
	_v1x = v1.positionScreen.x;
	_v1y = v1.positionScreen.y;
	_v2x = v2.positionScreen.x;
	_v2y = v2.positionScreen.y;
	_v3x = v3.positionScreen.x;
	_v3y = v3.positionScreen.y;
	drawTriangle( _v1x,_v1y,_v2x,_v2y,_v3x,_v3y );
	if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ){
	_diffuseColor.copy( material.color );
	_emissiveColor.copy( material.emissive );
	if ( material.vertexColors === THREE.FaceColors ){
	_diffuseColor.multiply( element.color );
}
_color.copy( _ambientLight );
	_centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );
	calculateLight( _centroid,element.normalModel,_color );
	_color.multiply( _diffuseColor ).add( _emissiveColor );
	material.wireframe === true ? strokePath( _color,material.wireframeLinewidth,material.wireframeLinecap,material.wireframeLinejoin ):fillPath( _color );
}
else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ){
	if ( material.map !== null ){
	var mapping = material.map.mapping;
	if ( mapping === THREE.UVMapping ){
	_uvs = element.uvs;
	patternPath( _v1x,_v1y,_v2x,_v2y,_v3x,_v3y,_uvs[ uv1 ].x,_uvs[ uv1 ].y,_uvs[ uv2 ].x,_uvs[ uv2 ].y,_uvs[ uv3 ].x,_uvs[ uv3 ].y,material.map );
}
}
else if ( material.envMap !== null ){
	if ( material.envMap.mapping === THREE.SphericalReflectionMapping ){
	_normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix );
	_uv1x = 0.5 * _normal.x + 0.5;
	_uv1y = 0.5 * _normal.y + 0.5;
	_normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix );
	_uv2x = 0.5 * _normal.x + 0.5;
	_uv2y = 0.5 * _normal.y + 0.5;
	_normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix );
	_uv3x = 0.5 * _normal.x + 0.5;
	_uv3y = 0.5 * _normal.y + 0.5;
	patternPath( _v1x,_v1y,_v2x,_v2y,_v3x,_v3y,_uv1x,_uv1y,_uv2x,_uv2y,_uv3x,_uv3y,material.envMap );
}
}
else{
	_color.copy( material.color );
	if ( material.vertexColors === THREE.FaceColors ){
	_color.multiply( element.color );
}
material.wireframe === true ? strokePath( _color,material.wireframeLinewidth,material.wireframeLinecap,material.wireframeLinejoin ):fillPath( _color );
}
}
else if ( material instanceof THREE.MeshDepthMaterial ){
	_color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w,_camera.near,_camera.far );
	material.wireframe === true ? strokePath( _color,material.wireframeLinewidth,material.wireframeLinecap,material.wireframeLinejoin ):fillPath( _color );
}
else if ( material instanceof THREE.MeshNormalMaterial ){
	_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
	_color.setRGB( _normal.x,_normal.y,_normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
	material.wireframe === true ? strokePath( _color,material.wireframeLinewidth,material.wireframeLinecap,material.wireframeLinejoin ):fillPath( _color );
}
else{
	_color.setRGB( 1,1,1 );
	material.wireframe === true ? strokePath( _color,material.wireframeLinewidth,material.wireframeLinecap,material.wireframeLinejoin ):fillPath( _color );
}
}
//function drawTriangle( x0,y0,x1,y1,x2,y2 ){
	_context.beginPath();
	_context.moveTo( x0,y0 );
	_context.lineTo( x1,y1 );
	_context.lineTo( x2,y2 );
	_context.closePath();
}
function strokePath( color,linewidth,linecap,linejoin ){
	setLineWidth( linewidth );
	setLineCap( linecap );
	setLineJoin( linejoin );
	setStrokeStyle( color.getStyle() );
	_context.stroke();
	_elemBox.expandByScalar( linewidth * 2 );
}
function fillPath( color ){
	setFillStyle( color.getStyle() );
	_context.fill();
}
function onTextureUpdate ( event ){
	textureToPattern( event.target );
}
function textureToPattern( texture ){
	if ( texture instanceof THREE.CompressedTexture ) return;
	var repeatX = texture.wrapS === THREE.RepeatWrapping;
	var repeatY = texture.wrapT === THREE.RepeatWrapping;
	var image = texture.image;
	var canvas = document.createElement( 'canvas' );
	canvas.width = image.width;
	canvas.height = image.height;
	var context = canvas.getContext( '2d' );
	context.setTransform( 1,0,0,- 1,0,image.height );
	context.drawImage( image,0,0 );
	_patterns[ texture.id ] = _context.createPattern(canvas,repeatX === true && repeatY === true ? 'repeat':repeatX === true && repeatY === false ? 'repeat-x':repeatX === false && repeatY === true ? 'repeat-y':'no-repeat');
}
function patternPath( x0,y0,x1,y1,x2,y2,u0,v0,u1,v1,u2,v2,texture ){
	if ( texture instanceof THREE.DataTexture ) return;
	if ( texture.hasEventListener( 'update',onTextureUpdate ) === false ){
	if ( texture.image !== undefined && texture.image.width > 0 ){
	textureToPattern( texture );
}
texture.addEventListener( 'update',onTextureUpdate );
}
var pattern = _patterns[ texture.id ];
	if ( pattern !== undefined ){
	setFillStyle( pattern );
}
else{
	setFillStyle( 'rgba(0,0,0,1)' );
	_context.fill();
	return;
}
// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120var a,b,c,d,e,f,det,idet,offsetX = texture.offset.x / texture.repeat.x,offsetY = texture.offset.y / texture.repeat.y,width = texture.image.width * texture.repeat.x,height = texture.image.height * texture.repeat.y;
	u0 = ( u0 + offsetX ) * width;
	v0 = ( v0 + offsetY ) * height;
	u1 = ( u1 + offsetX ) * width;
	v1 = ( v1 + offsetY ) * height;
	u2 = ( u2 + offsetX ) * width;
	v2 = ( v2 + offsetY ) * height;
	x1 -= x0;
	y1 -= y0;
	x2 -= x0;
	y2 -= y0;
	u1 -= u0;
	v1 -= v0;
	u2 -= u0;
	v2 -= v0;
	det = u1 * v2 - u2 * v1;
	if ( det === 0 ) return;
	idet = 1 / det;
	a = ( v2 * x1 - v1 * x2 ) * idet;
	b = ( v2 * y1 - v1 * y2 ) * idet;
	c = ( u1 * x2 - u2 * x1 ) * idet;
	d = ( u1 * y2 - u2 * y1 ) * idet;
	e = x0 - a * u0 - c * v0;
	f = y0 - b * u0 - d * v0;
	_context.save();
	_context.transform( a,b,c,d,e,f );
	_context.fill();
	_context.restore();
}
function clipImage( x0,y0,x1,y1,x2,y2,u0,v0,u1,v1,u2,v2,image ){
	// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120var a,b,c,d,e,f,det,idet,width = image.width - 1,height = image.height - 1;
	u0 *= width;
	v0 *= height;
	u1 *= width;
	v1 *= height;
	u2 *= width;
	v2 *= height;
	x1 -= x0;
	y1 -= y0;
	x2 -= x0;
	y2 -= y0;
	u1 -= u0;
	v1 -= v0;
	u2 -= u0;
	v2 -= v0;
	det = u1 * v2 - u2 * v1;
	idet = 1 / det;
	a = ( v2 * x1 - v1 * x2 ) * idet;
	b = ( v2 * y1 - v1 * y2 ) * idet;
	c = ( u1 * x2 - u2 * x1 ) * idet;
	d = ( u1 * y2 - u2 * y1 ) * idet;
	e = x0 - a * u0 - c * v0;
	f = y0 - b * u0 - d * v0;
	_context.save();
	_context.transform( a,b,c,d,e,f );
	_context.clip();
	_context.drawImage( image,0,0 );
	_context.restore();
}
// Hide anti-alias gapsfunction expand( v1,v2,pixels ){
	var x = v2.x - v1.x,y = v2.y - v1.y,det = x * x + y * y,idet;
	if ( det === 0 ) return;
	idet = pixels / Math.sqrt( det );
	x *= idet;
	y *= idet;
	v2.x += x;
	v2.y += y;
	v1.x -= x;
	v1.y -= y;
}
// Context cached methods.function setOpacity( value ){
	if ( _contextGlobalAlpha !== value ){
	_context.globalAlpha = value;
	_contextGlobalAlpha = value;
}
}
function setBlending( value ){
	if ( _contextGlobalCompositeOperation !== value ){
	if ( value === THREE.NormalBlending ){
	_context.globalCompositeOperation = 'source-over';
}
else if ( value === THREE.AdditiveBlending ){
	_context.globalCompositeOperation = 'lighter';
}
else if ( value === THREE.SubtractiveBlending ){
	_context.globalCompositeOperation = 'darker';
}
_contextGlobalCompositeOperation = value;
}
}
function setLineWidth( value ){
	if ( _contextLineWidth !== value ){
	_context.lineWidth = value;
	_contextLineWidth = value;
}
}
function setLineCap( value ){
	// "butt","round","square"if ( _contextLineCap !== value ){
	_context.lineCap = value;
	_contextLineCap = value;
}
}
function setLineJoin( value ){
	// "round","bevel","miter"if ( _contextLineJoin !== value ){
	_context.lineJoin = value;
	_contextLineJoin = value;
}
}
function setStrokeStyle( value ){
	if ( _contextStrokeStyle !== value ){
	_context.strokeStyle = value;
	_contextStrokeStyle = value;
}
}
function setFillStyle( value ){
	if ( _contextFillStyle !== value ){
	_context.fillStyle = value;
	_contextFillStyle = value;
}
}
function setLineDash( value ){
	if ( _contextLineDash.length !== value.length ){
	_context.setLineDash( value );
	_contextLineDash = value;
}
}
}
;
	

JS代码(Sparks.js):

/* * @author zz85 (http://github.com/zz85 http://www.lab4games.net/zz85/blog) * * a simple to use javascript 3d particles system inspired by FliNT and Stardust * created with TWEEN.js and THREE.js * * for feature requests or bugs,please visit https://github.com/zz85/sparks.js * * licensed under the MIT license */
var SPARKS ={
}
;
	/********************************* Emitter Class** Creates and Manages Particles*********************************/
SPARKS.Emitter = function (counter){
	this._counter = counter ? counter:new SPARKS.SteadyCounter(10);
	// provides number of particles to producethis._particles = [];
	this._initializers = [];
	// use for creation of particlesthis._actions = [];
	// uses action to update particlesthis._activities = [];
	// not supported yetthis._handlers = [];
	this.callbacks ={
}
;
}
;
	SPARKS.Emitter.prototype ={
	_TIMESTEP:15,_timer:null,_lastTime:null,_timerStep:10,_velocityVerlet:true,// run its built in timer / steppingstart:function(){
	this._lastTime = Date.now();
	this._timer = setTimeout(this.step,this._timerStep,this);
	this._isRunning = true;
}
,stop:function(){
	this._isRunning = false;
	clearTimeout(this._timer);
}
,isRunning:function(){
	return this._isRunning & true;
}
,// Step gets called upon by the engine// but attempts to call update() on a regular basics// This method is also described in http://gameclosure.com/2011/04/11/deterministic-delta-tee-in-js-games/step:function(emitter){
	var time = Date.now();
	var elapsed = time - emitter._lastTime;
	if (!this._velocityVerlet){
	// if elapsed is way higher than time step,(usually after switching tabs,or excution cached in ff)// we will drop cycles. perhaps set to a limit of 10 or something?var maxBlock = emitter._TIMESTEP * 20;
	if (elapsed >= maxBlock){
	//console.log('warning:sparks.js is fast fowarding engine,skipping steps',elapsed / emitter._TIMESTEP);
	//emitter.update( (elapsed - maxBlock) / 1000);
	elapsed = maxBlock;
}
while (elapsed >= emitter._TIMESTEP){
	emitter.update(emitter._TIMESTEP / 1000);
	elapsed -= emitter._TIMESTEP;
}
emitter._lastTime = time - elapsed;
}
else{
	emitter.update(elapsed / 1000);
	emitter._lastTime = time;
}
if (emitter._isRunning)setTimeout(emitter.step,emitter._timerStep,emitter);
}
,// Update particle engine in seconds,not milliseconds update:function(time){
	var i,j;
	var len = this._counter.updateEmitter( this,time );
	// Create particlesfor ( i = 0;
	i < len;
	i ++ ){
	this.createParticle();
}
// Update activitieslen = this._activities.length;
	for ( i = 0;
	i < len;
	i ++ ){
	this._activities[i].update( this,time );
}
len = this._actions.length;
	var particle;
	var action;
	var len2 = this._particles.length;
	for ( j = 0;
	j < len;
	j ++ ){
	action = this._actions[j];
	for ( i = 0;
	i < len2;
	++ i ){
	particle = this._particles[i];
	action.update( this,particle,time );
}
}
// remove dead particlesfor ( i = len2;
	i --;
	){
	particle = this._particles[i];
	if ( particle.isDead ){
	//particle =this._particles.splice( i,1 );
	this.dispatchEvent("dead",particle);
	SPARKS.VectorPool.release(particle.position);
	//SPARKS.VectorPool.release(particle.velocity);
}
else{
	this.dispatchEvent("updated",particle);
}
}
this.dispatchEvent("loopUpdated");
}
,createParticle:function(){
	var particle = new SPARKS.Particle();
	// In future,use a Particle Factoryvar len = this._initializers.length,i;
	for ( i = 0;
	i < len;
	i ++ ){
	this._initializers[i].initialize( this,particle );
}
this._particles.push( particle );
	this.dispatchEvent("created",particle);
	// ParticleCreatedreturn particle;
}
,addInitializer:function (initializer){
	this._initializers.push(initializer);
}
,addAction:function (action){
	this._actions.push(action);
}
,removeInitializer:function (initializer){
	var index = this._initializers.indexOf(initializer);
	if (index > -1){
	this._initializers.splice( index,1 );
}
}
,removeAction:function (action){
	var index = this._actions.indexOf(action);
	if (index > -1){
	this._actions.splice( index,1 );
}
//console.log('removeAction',index,this._actions);
}
,addCallback:function(name,callback){
	this.callbacks[name] = callback;
}
,dispatchEvent:function(name,args){
	var callback = this.callbacks[name];
	if (callback){
	callback(args);
}
}
}
;
	/* * Constant Names for * Events called by emitter.dispatchEvent() * */
SPARKS.EVENT_PARTICLE_CREATED = "created"SPARKS.EVENT_PARTICLE_UPDATED = "updated"SPARKS.EVENT_PARTICLE_DEAD = "dead";
	SPARKS.EVENT_LOOP_UPDATED = "loopUpdated";
	/* * Steady Counter attempts to produces a particle rate steadily * */
// Number of particles per secondsSPARKS.SteadyCounter = function(rate){
	this.rate = rate;
	// we use a shortfall counter to make up for slow emittersthis.leftover = 0;
}
;
	SPARKS.SteadyCounter.prototype.updateEmitter = function(emitter,time){
	var targetRelease = time * this.rate + this.leftover;
	var actualRelease = Math.floor(targetRelease);
	this.leftover = targetRelease - actualRelease;
	return actualRelease;
}
;
	/* * Shot Counter produces specified particles * on a single impluse or burst */
SPARKS.ShotCounter = function(particles){
	this.particles = particles;
	this.used = false;
}
;
	SPARKS.ShotCounter.prototype.updateEmitter = function(emitter,time){
	if (this.used){
	return 0;
}
else{
	this.used = true;
}
return this.particles;
}
;
	/********************************* Particle Class** Represents a single particle*********************************/
SPARKS.Particle = function(){
	/** * The lifetime of the particle,in seconds. */
this.lifetime = 0;
	/** * The age of the particle,in seconds. */
this.age = 0;
	/** * The energy of the particle. */
this.energy = 1;
	/** * Whether the particle is dead and should be removed from the stage. */
this.isDead = false;
	this.target = null;
	// tag /** * For 3D */
this.position = SPARKS.VectorPool.get().set(0,0,0);
	//new THREE.Vector3( 0,0,0 );
	this.velocity = SPARKS.VectorPool.get().set(0,0,0);
	//new THREE.Vector3( 0,0,0 );
	this._oldvelocity = SPARKS.VectorPool.get().set(0,0,0);
	// rotation vec3 // angVelocity vec3 // faceAxis vec3}
;
	/********************************* Action Classes** An abstract class which have* update function*********************************/
SPARKS.Action = function(){
	this._priority = 0;
}
;
	SPARKS.Age = function(easing){
	this._easing = (easing == null) ? TWEEN.Easing.Linear.None:easing;
}
;
	SPARKS.Age.prototype.update = function (emitter,particle,time){
	particle.age += time;
	if ( particle.age >= particle.lifetime ){
	particle.energy = 0;
	particle.isDead = true;
}
else{
	var t = this._easing(particle.age / particle.lifetime);
	particle.energy = -1 * t + 1;
}
}
;
	/*/
/ Mark particle as dead when particle's < 0SPARKS.Death = function(easing){
	this._easing = (easing == null) ? TWEEN.Linear.None:easing;
}
;
	SPARKS.Death.prototype.update = function (emitter,particle,time){
	if (particle.life <= 0){
	particle.isDead = true;
}
}
;
	*/
SPARKS.Move = function(){
}
;
	SPARKS.Move.prototype.update = function(emitter,particle,time){
	// attempt verlet velocity updating.var p = particle.position;
	var v = particle.velocity;
	var old = particle._oldvelocity;
	if (this._velocityVerlet){
	p.x += (v.x + old.x) * 0.5 * time;
	p.y += (v.y + old.y) * 0.5 * time;
	p.z += (v.z + old.z) * 0.5 * time;
}
else{
	p.x += v.x * time;
	p.y += v.y * time;
	p.z += v.z * time;
}
// OldVel = Vel;
	// Vel = Vel + Accel * dt;
	// Pos = Pos + (vel + Vel + Accel * dt) * 0.5 * dt;
}
;
	/* Marks particles found in specified zone dead */
SPARKS.DeathZone = function(zone){
	this.zone = zone;
}
;
	SPARKS.DeathZone.prototype.update = function(emitter,particle,time){
	if (this.zone.contains(particle.position)){
	particle.isDead = true;
}
}
;
	/* * SPARKS.ActionZone applies an action when particle is found in zone */
SPARKS.ActionZone = function(action,zone){
	this.action = action;
	this.zone = zone;
}
;
	SPARKS.ActionZone.prototype.update = function(emitter,particle,time){
	if (this.zone.contains(particle.position)){
	this.action.update( emitter,particle,time );
}
}
;
	/* * Accelerate action affects velocity in specified 3d direction */
SPARKS.Accelerate = function(x,y,z){
	if (x instanceof THREE.Vector3){
	this.acceleration = x;
	return;
}
this.acceleration = new THREE.Vector3(x,y,z);
}
;
	SPARKS.Accelerate.prototype.update = function(emitter,particle,time){
	var acc = this.acceleration;
	var v = particle.velocity;
	particle._oldvelocity.set(v.x,v.y,v.z);
	v.x += acc.x * time;
	v.y += acc.y * time;
	v.z += acc.z * time;
}
;
	/* * Accelerate Factor accelerate based on a factor of particle's velocity. */
SPARKS.AccelerateFactor = function(factor){
	this.factor = factor;
}
;
	SPARKS.AccelerateFactor.prototype.update = function(emitter,particle,time){
	var factor = this.factor;
	var v = particle.velocity;
	var len = v.length();
	var adjFactor;
	if (len > 0){
	adjFactor = factor * time / len;
	adjFactor += 1;
	v.multiplyScalar(adjFactor);
	// v.x *= adjFactor;
	// v.y *= adjFactor;
	// v.z *= adjFactor;
}
}
;
	/*AccelerateNormal * AccelerateVelocity affects velocity based on its velocity direction */
SPARKS.AccelerateVelocity = function(factor){
	this.factor = factor;
}
;
	SPARKS.AccelerateVelocity.prototype.update = function(emitter,particle,time){
	var factor = this.factor;
	var v = particle.velocity;
	v.z += - v.x * factor;
	v.y += v.z * factor;
	v.x += v.y * factor;
}
;
	/* Set the max ammount of x,y,z drift movements in a second */
SPARKS.RandomDrift = function(x,y,z){
	if (x instanceof THREE.Vector3){
	this.drift = x;
	return;
}
this.drift = new THREE.Vector3(x,y,z);
}
SPARKS.RandomDrift.prototype.update = function(emitter,particle,time){
	var drift = this.drift;
	var v = particle.velocity;
	v.x += ( Math.random() - 0.5 ) * drift.x * time;
	v.y += ( Math.random() - 0.5 ) * drift.y * time;
	v.z += ( Math.random() - 0.5 ) * drift.z * time;
}
;
	/********************************* Zone Classes** An abstract classes which have* getLocation() function*********************************/
SPARKS.Zone = function(){
}
;
	// TODO,contains() for ZoneSPARKS.PointZone = function(pos){
	this.pos = pos;
}
;
	SPARKS.PointZone.prototype.getLocation = function(){
	return this.pos;
}
;
	SPARKS.PointZone = function(pos){
	this.pos = pos;
}
;
	SPARKS.PointZone.prototype.getLocation = function(){
	return this.pos;
}
;
	SPARKS.LineZone = function(start,end){
	this.start = start;
	this.end = end;
	this._length = end.clone().sub( start );
}
;
	SPARKS.LineZone.prototype.getLocation = function(){
	var len = this._length.clone();
	len.multiplyScalar( Math.random() );
	return len.add( this.start );
}
;
	// Basically a RectangleZoneSPARKS.ParallelogramZone = function(corner,side1,side2){
	this.corner = corner;
	this.side1 = side1;
	this.side2 = side2;
}
;
	SPARKS.ParallelogramZone.prototype.getLocation = function(){
	var d1 = this.side1.clone().multiplyScalar( Math.random() );
	var d2 = this.side2.clone().multiplyScalar( Math.random() );
	d1.add(d2);
	return d1.add( this.corner );
}
;
	SPARKS.CubeZone = function(position,x,y,z){
	this.position = position;
	this.x = x;
	this.y = y;
	this.z = z;
}
;
	SPARKS.CubeZone.prototype.getLocation = function(){
	//TODO use pool?var location = this.position.clone();
	location.x += Math.random() * this.x;
	location.y += Math.random() * this.y;
	location.z += Math.random() * this.z;
	return location;
}
;
	SPARKS.CubeZone.prototype.contains = function(position){
	var startX = this.position.x;
	var startY = this.position.y;
	var startZ = this.position.z;
	var x = this.x;
	// widthvar y = this.y;
	// depthvar z = this.z;
	// heightif (x < 0){
	startX += x;
	x = Math.abs(x);
}
if (y < 0){
	startY += y;
	y = Math.abs(y);
}
if (z < 0){
	startZ += z;
	z = Math.abs(z);
}
var diffX = position.x - startX;
	var diffY = position.y - startY;
	var diffZ = position.z - startZ;
	if ( (diffX > 0) && (diffX < x) &&(diffY > 0) && (diffY < y) &&(diffZ > 0) && (diffZ < z) ){
	return true;
}
return false;
}
;
	/** * The constructor creates a DiscZone 3D zone. * * @param centre The point at the center of the disc. * @param normal A vector normal to the disc. * @param outerRadius The outer radius of the disc. * @param innerRadius The inner radius of the disc. This defines the hole * in the center of the disc. If set to zero,there is no hole. */
/*/
/ BUGGY!!SPARKS.DiscZone = function(center,radiusNormal,outerRadius,innerRadius){
	this.center = center;
	this.radiusNormal = radiusNormal;
	this.outerRadius = (outerRadius==undefined) ? 0:outerRadius;
	this.innerRadius = (innerRadius==undefined) ? 0:innerRadius;
}
;
	SPARKS.DiscZone.prototype.getLocation = function(){
	var rand = Math.random();
	var _innerRadius = this.innerRadius;
	var _outerRadius = this.outerRadius;
	var center = this.center;
	var _normal = this.radiusNormal;
	_distToOrigin = _normal.dot( center );
	var radius = _innerRadius + (1 - rand * rand ) * ( _outerRadius - _innerRadius );
	var angle = Math.random() * SPARKS.Utils.TWOPI;
	var _distToOrigin = _normal.dot( center );
	var axes = SPARKS.Utils.getPerpendiculars( _normal.clone() );
	var _planeAxis1 = axes[0];
	var _planeAxis2 = axes[1];
	var p = _planeAxis1.clone();
	p.multiplyScalar( radius * Math.cos( angle ) );
	var p2 = _planeAxis2.clone();
	p2.multiplyScalar( radius * Math.sin( angle ) );
	p.add( p2 );
	return _center.add( p );
}
;
	*/
SPARKS.SphereCapZone = function(x,y,z,minr,maxr,angle){
	this.x = x;
	this.y = y;
	this.z = z;
	this.minr = minr;
	this.maxr = maxr;
	this.angle = angle;
}
;
	SPARKS.SphereCapZone.prototype.getLocation = function(){
	var theta = Math.PI * 2 * SPARKS.Utils.random();
	var r = SPARKS.Utils.random();
	//new THREE.Vector3var v = SPARKS.VectorPool.get().set(r * Math.cos(theta),-1 / Math.tan(this.angle * SPARKS.Utils.DEGREE_TO_RADIAN),r * Math.sin(theta));
	//v.length = StardustMath.interpolate(0,_minRadius,1,_maxRadius,Math.random());
	var i = this.minr - ((this.minr - this.maxr) * Math.random() );
	v.multiplyScalar(i);
	v.__markedForReleased = true;
	return v;
}
;
	/********************************* Initializer Classes** Classes which initializes* particles. Implements initialize( emitter:Emitter,particle:Particle )*********************************/
// Specifies random life between max and minSPARKS.Lifetime = function(min,max){
	this._min = min;
	this._max = max ? max:min;
}
;
	SPARKS.Lifetime.prototype.initialize = function( emitter/*Emitter*/
,particle/*Particle*/
 ){
	particle.lifetime = this._min + SPARKS.Utils.random() * ( this._max - this._min );
}
;
	SPARKS.Position = function(zone){
	this.zone = zone;
}
;
	SPARKS.Position.prototype.initialize = function( emitter/*Emitter*/
,particle/*Particle*/
 ){
	var pos = this.zone.getLocation();
	particle.position.set(pos.x,pos.y,pos.z);
}
;
	SPARKS.Velocity = function(zone){
	this.zone = zone;
}
;
	SPARKS.Velocity.prototype.initialize = function( emitter/*Emitter*/
,particle/*Particle*/
 ){
	var pos = this.zone.getLocation();
	particle.velocity.set(pos.x,pos.y,pos.z);
	if (pos.__markedForReleased){
	//console.log("release");
	SPARKS.VectorPool.release(pos);
	pos.__markedForReleased = false;
}
}
;
	SPARKS.Target = function(target,callback){
	this.target = target;
	this.callback = callback;
}
;
	SPARKS.Target.prototype.initialize = function( emitter,particle ){
	if (this.callback){
	particle.target = this.callback();
}
else{
	particle.target = this.target;
}
}
;
	/********************************* VectorPool** Reuse much of Vectors if possible*********************************/
SPARKS.VectorPool ={
	__pools:[],// Get a new Vectorget:function(){
	if (this.__pools.length > 0){
	return this.__pools.pop();
}
return this._addToPool();
}
,// Release a vector back into the poolrelease:function(v){
	this.__pools.push(v);
}
,// Create a bunch of vectors and add to the pool_addToPool:function(){
	//console.log("creating some pools");
	for (var i = 0,size = 100;
	i < size;
	i ++){
	this.__pools.push(new THREE.Vector3());
}
return new THREE.Vector3();
}
}
;
	/********************************* Util Classes** Classes which initializes* particles. Implements initialize( emitter:Emitter,particle:Particle )*********************************/
SPARKS.Utils ={
	random:function(){
	return Math.random();
}
,DEGREE_TO_RADIAN:Math.PI / 180,TWOPI:Math.PI * 2,getPerpendiculars:function(normal){
	var p1 = this.getPerpendicular( normal );
	var p2 = normal.cross( p1 );
	p2.normalize();
	return [ p1,p2 ];
}
,getPerpendicular:function( v ){
	if ( v.x == 0 ){
	return new THREE.Vector3D( 1,0,0 );
}
else{
	var temp = new THREE.Vector3( v.y,-v.x,0 );
	return temp.normalize();
}
}
}
;
	
附件:下载该文件资源,减少时间成本(增值服务)
留言
该资源可下载
File Source
.rar
129.85 KB
Html JS 其它特效2
最新结算
jquery虚拟键盘中文打字效果js代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
jquery虚拟键盘中文打字效果js代码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
HTML5实现CSS滤镜图片切换特效代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
jQuery头像裁剪插件cropbox js代码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
jQuery头像裁剪插件cropbox js代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
CSS3制作3D图片立方体旋转特效
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
CSS3制作3D图片立方体旋转特效
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
CSS3制作3D图片立方体旋转特效
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
CSS3制作3D图片立方体旋转特效
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
jQuery+css3实现信封效果
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
我们力求给您提供有用的文章,再此基础上,会附加营收资源,不做任何广告,让平台可以更好发展 若您发现您的权利被侵害,或使用了您的版权,请发邮件联系 sunlifel@foxmail.com ggbig觉得 : 不提供源码的文章不是好文章
合作伙伴
联系我们
  • QQ:21499807
  • 邮箱:sunlifel@foxmail.com
  • QQ扫一扫加QQ
    QQ扫一扫
Copyright 2023-2024 ggbig.com·皖ICP备2023004211号-1
打赏文章