Three.js入门教程4 - 创建粒子系统动画
嗨,又见面了。这么说我们已经开始学习Three.js了,如果你还没有看过之前三篇教程,建议你先读完。如果你已经读完前面的教程了,你可能会想做一些关于粒子的东西。让我们直面这个话题吧,每个人都爱粒子效果。不管你是否知道,你可以很轻易地创建它们。
1.创建一个粒子系统
Three.js将粒子系统视为一个基本的几何体,因为它就像基本几何体一样,即有形状,又有位置、缩放因子、旋转属性。粒子系统将geometry对象里的每一个点视为一个单独的粒子。为什么这样做?我想基于以下的原因:首先,整个粒子系统地绘制只需要调用一次某个绘制函数,而不是调用上千次;其次,这允许你设定一些全局的参数来影响你的粒子系统内的所有粒子。
即使是粒子系统被视为一个整体的对象,我们仍然可以为每个粒子单独地着色,因为在绘制粒子系统的过程中,Three.js通过attribute变量colour向着色器传递了每一个顶点的颜色。我在本篇教程里并不准备这样做,如果你想知道这是怎样完成的,你可以去GitHub上看Three.js的例程。
粒子系统可能还有一种特殊效果需要引起你的注意:Three.js在粒子系统第一次被渲染的时候,会将其数据缓存下来,之后你无法增加或减少系统中的粒子。如果你不希望看到某个粒子,你可以将它的颜色中的alpha值设置为0,但你无法删除它。所以你应当在创建粒子系统的时候,就将所有可能需要显示的粒子考虑进来。
开始创建一个粒子系统,只需要这么多:
// 创建粒子geometry var particleCount = 1800, particles = new THREE.Geometry(), pMaterial = new THREE.ParticleBasicMaterial({ color: 0xFFFFFF, size: 20 }); // 依次创建单个粒子 for(var p = 0; p < particleCount; p++) { // 粒子范围在-250到250之间 var pX = Math.random() * 500 - 250, pY = Math.random() * 500 - 250, pZ = Math.random() * 500 - 250, particle = new THREE.Vertex( new THREE.Vector3(pX, pY, pZ) ); // 将粒子加入粒子geometry particles.vertices.push(particle); } // 创建粒子系统 var particleSystem = new THREE.ParticleSystem( particles, pMaterial); // 将粒子系统加入场景 scene.addChild(particleSystem);
如果你运行:
1.你会发现粒子都是方的
2.粒子都不动
我们一个一个来修复。
2.风格
我们创建一个粒子基本材质时传入了颜色和尺寸。我们可能想做的是传入一张纹理图片用来显示粒子,而这样就可以很好地控制粒子看上去的样式了。
你也看到,粒子是以方块形状绘制的,所以我们也应当使用一张方形的纹理图片。为了看上去效果更好,我还会使用加法混合,但是这样做必须保证纹理图片的背景是黑色的而不是透明的。我理解的原因是:现在加法混合和透明材质之间不兼容。但是没关系,最后看上去会很棒。
我们来更新一下粒子基本材质和粒子系统,加入一些加法混合下透明的粒子。如果你喜欢,你也可以用我的粒子图片。
// 创建粒子基本材质 var pMaterial = new THREE.ParticleBasicMaterial({ color: 0xFFFFFF, size: 20, map: THREE.ImageUtils.loadTexture( "images/particle.png" ), blending: THREE.AdditiveBlending, transparent: true }); // 允许粒子系统对粒子排序,以达到我们想要的效果 particleSystem.sortParticles = true;
这看上去已经好多了。现在来引入一点物理,让粒子们动起来。
3.引入物理
默认情况下,粒子系统在三维空间中不运动,这很好。但我想让他们动起来,而且我要让粒子系统这样运动:让粒子绕着y轴旋转。而且粒子在每个轴的范围都在-250到250之间,所以绕着y轴旋转以为这它们绕着系统地中心旋转。
我还假定,你已经在某个地方有了帧循环的代码,和我在上一篇关于着色器中的教程中类似。所以这里我们只需这样:
// 帧循环 function update() { // 增加一点旋转量 particleSystem.rotation.y += 0.01; // 绘制粒子系统 renderer.render(scene, camera); // 设置下一次刷新帧时对update的调用 requestAnimFrame(update); }
现在我们开始定义单个粒子的运动(译者注:之前的旋转是整个粒子系统的运动)。我们来做个简单的雨点效果,这包含一下几步:
1.给每一个粒子赋一个初始为0的速度
2.在每一帧中,为每一个粒子赋一个随机的重力加速度
3.在每一帧中,通过通过加速度更新速度,通过速度更新位置
4.当一个粒子运动出了视线,重新设置初始位置和速度
听上去很多,其实代码写起来很少。首先,在创建粒子的过程中,我们为每个粒子增加一个水平速度:
// 为每个粒子创建一个水平运动速度 particle.velocity = new THREE.Vector3( 0, // x -Math.random(), // y: 随机数 0); // z
接下来,在帧缓冲中我们传递每个粒子,并且,当粒子离开屏幕底部需要重置时,重置其位置和速度。
// 帧循环 function update() { // 增加旋转量 particleSystem.rotation.y += 0.01; var pCount = particleCount; while(pCount--) { // 获取单个粒子 var particle = particles.vertices[pCount]; // 检查是否需要重置 if(particle.position.y < -200) { particle.position.y = 200; particle.velocity.y = 0; } // 用随机数更新水平速度分量,并根据速度更新位置 particle.velocity.y -= Math.random() * .1; particle.position.addSelf( particle.velocity); } // 告诉粒子系统我们改变了粒子位置 particleSystem.geometry.__dirtyVertices = true; // 画 renderer.render(scene, camera); // 设置下一次调用 requestAnimFrame(update); }
虽然不够震撼,但这个粒子至少展示了如何做。你完全应该自己创建一些美妙的粒子效果,然后让我知道。
这里有个警告你应该知道,在帧循环中,我越雷池了:我在一次循环中遍历了所有粒子,这实际上是种很粗放的方式。如果你的帧循环中做了太多的工作(译者注:注意帧循环的js代码是在cpu中运行的,它不像gpu,能一下子并发出成千上万个简单进程),浏览器就会卡顿,事实上如果你用了requestAnimationFrame,它视图每秒刷新60次。所以还是优化你的代码,在帧循环中做尽量少的事情。
4.小结
粒子效果太棒了,是个人都爱粒子效果,而现在你知道如何在Three.js中加入粒子效果了。我希望你能用得顺手,就跟前面一样!
同样,这里有源码下载。
[TECHBROOD注:你也可以访问我们的在线实例:http://wow.techbrood.com/fiddle/26706]


最新评论
- 相关文章
常用光照类型基本概念工作原理及其计算公式
在三维场景中,原理上物体的渲染效果取决于光照与物体表面的相互作用,对于渲染程序而言,可以通过把一些数学公式应用于像素着色来实现,从而模拟出真实生活中的...
WebGL Roadmap
Unity 5.0 shipped with a working preview of our WebGL technology in March this year. Since then, Google has disabled (by default) NPAPI support in the...
CSS3原生变量(Native Variables)新特性简介
对Web开发者来说,一个盼望已久的特性是CSS终于支持原生变量了!
变量是程序语言中用来解决代码重复和进行表达式计算的关键概念(想想数学方程式中的x)。...React JSX语法简介
JSX是一种类似XML的标签语法,用来简化代码,我们可以不使用JSX,但了解并使用也没什么坏处:)在React中,JSX是一个使用 React.createElement() API的快捷方式...
CSS3弹性布局弹性流(flex-flow)属性详解和实例
弹性布局是CSS3引入的强大的布局方式,用来替代以前Web开发人员使用的一些复杂而易错hacks方法(如使用float进行类似流式布局)。其中flex-flow是flex-direction...
使用HTML5 Canvas实现的界面元素截屏功能
WebGL入门教程6 - 光照效果和Phong光照模型
正是因为有了光,世界才能被我们看见,在3D的世界里,光照给物体带来真实的视觉感受。当光照射在某一表面上时,它可能被吸收、反射或投射。其中入射到表面上的一...
使用Canvas绘制完美的不完美圆形
真实世界是不完美的,当我们需要模拟真实世界时,经常需要引入不完美/不规则的形状。比如陨石、雨滴、行星、树叶、绵延的海岸线、云朵等。本文介绍如何基于Canva...
div 、section 、article的区别和使用场景
div 、section 、article的区别和使用场景
主要区别,以及适用场合如下:
1、div在html早期版本就支持了,section和article是html5提出的两个雨衣话标...如何使用CSS3/SCSS实现逼真的车窗雨滴效果
在天气预报类的Web移动应用中,常常需要实现屏幕的雨滴效果,表示阴雨天气。感觉上比较神奇,其实想通了,这个效果的实现只需要一点物理知识和CSS3的简单变换。实现一个小雨滴首先雨滴是一个个小的椭圆形元素:.raindrop
在PHP网页程序中执行Sass/Compass命令
我们需要在wow云开发平台支持sass/compass等预编译样式语言,为此我们首先尝试了scssphp扩展,但是在支持最新语法上,经常会出现异常。所以我们采用了代理的方式...
更多...