ThreeJS学习笔记四:粒子系统

粒子和粒子系统

Threejs中制作粒子效果有两种方法:

  • THREE.Particle和THREE.ParticleSytem 
    如果项目使用的渲染器是CanvasRenderer,直接使用THREE.Particle创建完粒子即可直接添加到scene中,但是如果使用的是WebGlRenderer渲染器,那就要先创建THREE.ParticleSytem对象,然后通过这个对象来创建粒子。PatricleSystem具有形体和材质两个属性,因此使用PatitlceSystem可以借助几何体生成粒子,也可以先创建一个由多个点构成的形体后去创建粒子。

  • THREE.Sprite 
    使用Sprite来制作粒子可以实现以下两种需求: 
    1.使用useScreenCoordinates:true属性建立一个独立于camera摄像范围之外的元素,即它在屏幕上的位置不受camera的位置和焦点变化而变化,它的移动、定位、缩放是基于屏幕坐标的。 
    2.与在CanvasRenderer渲染器中使用THREE.Particle创建粒子一样,不需要使用THREE.ParticleSytem, 在WebGlRenderer渲染器中使用THREE.Sprite创建的粒子可以直接添加到scene中。三维场景中创建出来的精灵总是面向镜头的。即不会有倾斜变形之类透视变化,只有近大远小的变化

THREE.Sprite

  • Sprite默认大小是1*1,设置Sprite大小需要使用scale进行缩放

  • Sprite的样式通过参数meterial定义,参数meterial是使用THREE.SpriteMaterial类创建的材质对象

  • THREE.SpriteMaterial可以定义精灵的颜色和纹理,纹理对象可以调用new THREE.ImgesUtils.loadTexture(url)来引用一张图片作为纹理,也可以调用new THREE.CanvasTexture( canvas),使用动态绘制的canvas图作为纹理。

创建粒子

以下创建了300个粒子,并添加到场景中,

function createCanvas(width,height,colors){//创建画布并绘制精灵纹理
   var canvas = document.createElement( 'canvas' );
   canvas.width = width;
   canvas.height = height;
   var context = canvas.getContext( '2d' );
   var gradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2 );
   colors.forEach(function(color){
       gradient.addColorStop( color.start, color.rgba );
   })
   context.fillStyle = gradient;
   context.fillRect( 0, 0, canvas.width, canvas.height );
   return canvas;
}
function createMaterial(width,height,colors){//使用画布创建材质
   var sprite=createCanvas(width,height,colors);
   return new THREE.SpriteMaterial( {
       map: new THREE.CanvasTexture( sprite ),
       blending: THREE.AdditiveBlending,//使用饱和度叠加的混和模式渲染粒子
       overdraw:false,
       depthWrite:false
   } )
}
function initParticle( particle,coord,size) {//初始化粒子
   var particle = this instanceof THREE.Sprite ? this : particle;
   if(!size&&size!=0){
       size=Math.random() * 32 + 16;
   }
   particle.scale.x = particle.scale.y = size;
   particle.position.set( coord.x,coord.y,coord.z);    
}
function addParticles(){//在场景中创建300个粒子,粒子颜色在一个范围内随机取色
   for ( var i = 0; i < 300; i++ ) {
       var deepColor=Math.round(Math.random()*255);
       var lightColor=Math.round(deepColor*32/255);
       var material= createMaterial(32,32,[
           {start:0,rgba:'rgba(255,255,255,1)'},
           {start:0.2,rgba:'rgba(0,'+deepColor+','+Math.round(Math.random()*80+175)+',1)'},
           {start:0.4,rgba:'rgba(0,'+lightColor+',64,1)'},
           {start:1,rgba:'rgba(0,0,0,1)'}
       ])
       var particle = new THREE.Sprite(material);
       initParticle(particle, new THREE.Vector3(Math.random()*500-250,Math.random()*500-250,Math.random()*500-250),10);
       scene.add( particle );
   }
}


执行addParticles()后如图所示

1470302852235.png

粒子的运动

粒子的缓运动画也都是用上一节说到的Tween.js实现的。循环动画示例如下:

function addParticles(){//在场景中创建300个粒子,粒子颜色在一个范围内随机取色
           for ( var i = 0; i < 300; i++ ) {
               var deepColor=Math.round(Math.random()*255);
               var lightColor=Math.round(deepColor*32/255);
               var material= createMaterial(32,32,[
                   {start:0,rgba:'rgba(255,255,255,1)'},
                   {start:0.2,rgba:'rgba(0,'+deepColor+','+Math.round(Math.random()*80+175)+',1)'},
                   {start:0.4,rgba:'rgba(0,'+lightColor+',64,1)'},
                   {start:1,rgba:'rgba(0,0,0,1)'}
               ])
               var particle = new THREE.Sprite(material);
               _particles.push(particle);
               //initParticle(particle, new THREE.Vector3(Math.random()*500-250,Math.random()*500-250,Math.random()*500-250),10)
               var delay=i*5;
               particleLoop(particle,delay)
               scene.add( particle );
           }
       }
       function initParticle( particle,coord,size) {
           var particle = this instanceof THREE.Sprite ? this : particle;
           if(!size&&size!=0){
               size=Math.random() * 32 + 16;
           }
           particle.scale.x = particle.scale.y = size;
           particle.position.set( coord.x,coord.y,coord.z);    
       }

       function particleLoop(particle,delay){
           particle=particle?particle:this;
           initParticle(particle,new THREE.Vector3(Math.random()*500-250,Math.random()*500-250,Math.random()*500-250),Math.random() * 12 + 8);
           delay=delay?delay:0;
           new TWEEN.Tween( particle )
               .delay( delay )
               .to( {}, 1500 )
               .onComplete(particleLoop )
               .start();
           new TWEEN.Tween( particle.position )
               .delay( delay )
               .to( { x:0, y: 0, z: 0}, 1500 )
               .start();
           new TWEEN.Tween( particle.scale )
               .delay( delay )
               .to( { x: 8, y: 8 }, 1500 )
               .start();
       }

本章示例

<!DOCTYPE html>
<html>
   <head>
       <meta charset="UTF-8">
       <title></title>
   </head>
   <body>
   <div id="space"></div>  
   <script   src="https://code.jquery.com/jquery-1.12.4.min.js"   integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="   crossorigin="anonymous"></script>
   <script src="../js/lib/threejs/three.js"></script>

   <script src="../js/lib/threejs/OrbitControls.js"></script>
   <script src="../js/lib/Tween.js"></script>
   <script>


           var container, stats;

           var camera, scene, renderer,_particles=[];

           var mouseX = 0, mouseY = 0;

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


           init();
           animate();
           var mesh;

           function init() {

               container = document.getElementById("space")
               camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 5000 );
               camera.position.set(0, 0, 1500);

               scene = new THREE.Scene();

               var ambient = new THREE.AmbientLight( 0xffffff );
               scene.add( ambient );


               var directionalLight = new THREE.DirectionalLight( 0xffffff );
               directionalLight.position.set( -5, 5, 5).normalize();
               scene.add( directionalLight );

               var pointlight = new THREE.PointLight(0x63d5ff, 1, 200);
               pointlight.position.set(0, 0, 200);
               scene.add( pointlight );                
               var pointlight2 = new THREE.PointLight(0xffffff, 1, 200);
               pointlight2.position.set(-200, 200, 200);
               scene.add( pointlight2 );
               var pointlight3 = new THREE.PointLight(0xffffff, 1.5, 200);
               pointlight3.position.set(-200, 200, 0);
               scene.add( pointlight3 );

               var controls = new THREE.OrbitControls(camera,container);
           //controls.maxPolarAngle=1.5;
           //controls.minPolarAngle=1;
           controls.enableDamping=true;
           controls.enableKeys=false;
           controls.enablePan=false;
           controls.dampingFactor = 0.1;
           controls.rotateSpeed=0.1;
   //      controls.enabled = false;
           //controls.minDistance=1000;
           //controls.maxDistance=3000;



               var path = "../resource/sky/";
               var format = '.jpg';
               var urls = [
                       path + 'px' + format, path + 'nx' + format,
                       path + 'py' + format, path + 'ny' + format,
                       path + 'pz' + format, path + 'nz' + format
                   ];
               var skyMaterials = [];
               for (var i = 0; i < urls.length; ++i) {
                   var loader = new THREE.TextureLoader();
                   loader.setCrossOrigin( this.crossOrigin );
                   var texture = loader.load( urls[i], function(){}, undefined, function(){} );

                   skyMaterials.push(new THREE.MeshBasicMaterial({
                       //map: THREE.ImageUtils.loadTexture(urls[i], {},function() { }),
                       map: texture,
                       overdraw: true,
                       side: THREE.BackSide,
                       //transparent: true,
                       //needsUpdate:true,
                       premultipliedAlpha: true
                       //depthWrite:true,

       //              wireframe:false,
                   })
                   );

               }

               var cube = new THREE.Mesh(new THREE.CubeGeometry(500, 500,500), new THREE.MeshFaceMaterial(skyMaterials));
               cube.name="sky";
               //scene.add(cube);
               addParticles();

               renderer = new THREE.WebGLRenderer();
               renderer.setPixelRatio( window.devicePixelRatio );
               renderer.setSize( window.innerWidth, window.innerHeight );
               container.appendChild( renderer.domElement );

               document.addEventListener( 'mousemove', onDocumentMouseMove, false );
               window.addEventListener( 'resize', onWindowResize, false );

           }
           function createCanvas(width,height,colors){//创建画布并绘制精灵纹理
               var canvas = document.createElement( 'canvas' );
               canvas.width = width;
               canvas.height = height;
               var context = canvas.getContext( '2d' );
               var gradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2 );
               colors.forEach(function(color){
                   gradient.addColorStop( color.start, color.rgba );
               })
               context.fillStyle = gradient;
               context.fillRect( 0, 0, canvas.width, canvas.height );
               return canvas;
           }
           function createMaterial(width,height,colors){//使用画布创建材质
               var sprite=createCanvas(width,height,colors);
               return new THREE.SpriteMaterial( {
                   map: new THREE.CanvasTexture( sprite ),
                   blending: THREE.AdditiveBlending,
                   overdraw:false,
                   depthWrite:false
               } )
            }
           function addParticles(){//在场景中创建300个粒子,粒子颜色在一个范围内随机取色
               for ( var i = 0; i < 300; i++ ) {
                   var deepColor=Math.round(Math.random()*255);
                   var lightColor=Math.round(deepColor*32/255);
                   var material= createMaterial(32,32,[
                       {start:0,rgba:'rgba(255,255,255,1)'},
                       {start:0.2,rgba:'rgba(0,'+deepColor+','+Math.round(Math.random()*80+175)+',1)'},
                       {start:0.4,rgba:'rgba(0,'+lightColor+',64,1)'},
                       {start:1,rgba:'rgba(0,0,0,1)'}
                   ])
                   var particle = new THREE.Sprite(material);
                   _particles.push(particle);
                   //initParticle(particle, new THREE.Vector3(Math.random()*500-250,Math.random()*500-250,Math.random()*500-250),10)
                   var delay=i*5;
                   particleLoop(particle,delay)
                   scene.add( particle );
               }
           }
           function initParticle( particle,coord,size) {
               var particle = this instanceof THREE.Sprite ? this : particle;
               if(!size&&size!=0){
                   size=Math.random() * 32 + 16;
               }
               particle.scale.x = particle.scale.y = size;
               particle.position.set( coord.x,coord.y,coord.z);    
           }

           function particleLoop(particle,delay){
               particle=particle?particle:this;
               initParticle(particle,new THREE.Vector3(Math.random()*500-250,Math.random()*500-250,Math.random()*500-250),Math.random() * 12 + 8);
               delay=delay?delay:0;
               new TWEEN.Tween( particle )
                   .delay( delay )
                   .to( {}, 1500 )
                   .onComplete(particleLoop).onStart(function(){

                   })
                   .start();
               new TWEEN.Tween( particle.position )
                   .delay( delay )
                   .to( { x:0, y: 0, z: 0}, 1500 )
                   .start();

               new TWEEN.Tween( particle.scale )
                   .delay( delay )
                   .to( { x: 8, y: 8 }, 1500 )
                   .start();

           }
           function onWindowResize() {

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

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

           }

           function onDocumentMouseMove( event ) {

               mouseX = ( event.clientX - windowHalfX ) / 2;
               mouseY = ( event.clientY - windowHalfY ) / 2;

           }

           //

           function animate() {

               requestAnimationFrame( animate );
               render();
               TWEEN.update();
           }

           function render() {

//              camera.position.x += ( mouseX - camera.position.x ) ;
//              camera.position.y += ( mouseY - camera.position.y ) ;

//              for(var i=0,len=_particles.length; i<len; i++){
//                  var posx=(Math.random()-0.5)*1;
//                  var posy=(Math.random()-0.5)*1;
//                  var posz=(Math.random()-0.5)*1;
//                  _particles[i].position.set(_particles[i].position.x+posx,_particles[i].position.y+posy,_particles[i].position.z+posz)
//              }
               camera.lookAt( scene.position );

               renderer.render( scene, camera );

           }

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


本文由 w3cmark_前端笔记 版权所有,转载时请注明出处。
注明出处格式:w3cmark (http://www.w3cmark.com/2016/threejs-mark-04.html)

分享到:

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
关注w3cmark
微信公众号 w3cmark_com