THREE.JS入门教程(4)创建粒子系统


Posted in Javascript onJanuary 24, 2013

译序
Three.js是一个伟大的开源WebGL库,WebGL允许JavaScript操作GPU,在浏览器端实现真正意义的3D。但是目前这项技术还处在发展阶段,资料极为匮乏,爱好者学习基本要通过Demo源码和Three.js本身的源码来学习。
0.简介
嗨,又见面了。这么说我们已经开始学习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中加入粒子效果了。我希望你能用得顺手,就跟前面一样!
同样,这里有源码下载,而且,让我知道你喜欢它!
Javascript 相关文章推荐
静态图片的十一种滤镜效果--不支持Ie7及非IE浏览器。
Mar 06 Javascript
js实现页面跳转的五种方法推荐
Mar 10 Javascript
基于RequireJS和JQuery的模块化编程——常见问题全面解析
Apr 14 Javascript
JavaScript知识点总结(十一)之js中的Object类详解
May 31 Javascript
jQuery EasyUI 入门必看
Jun 03 Javascript
Jquery揭秘系列:ajax原生js实现详解(推荐)
Jun 08 Javascript
Vue.js实例方法之生命周期详解
Jul 03 Javascript
微信小程序request请求后台接口php的实例详解
Sep 20 Javascript
微信小程序生成二维码的示例代码
Mar 29 Javascript
eslint 的三大通用规则详解
May 16 Javascript
如何HttpServletRequest文件对象并储存
Aug 14 Javascript
javascript实现贪吃蛇游戏(娱乐版)
Aug 17 Javascript
THREE.JS入门教程(3)着色器-下
Jan 24 #Javascript
THREE.JS入门教程(2)着色器-上
Jan 24 #Javascript
THREE.JS入门教程(1)THREE.JS使用前了解
Jan 24 #Javascript
(跨浏览器基础事件/浏览器检测/判断浏览器)经验代码分享
Jan 24 #Javascript
jQuery ajax(复习)—Baidu ajax request分离版
Jan 24 #Javascript
javascript游戏开发之《三国志曹操传》零部件开发(五)可移动地图的实现
Jan 23 #Javascript
javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图
Jan 23 #Javascript
You might like
php自定义函数实现统计中文字符串长度的方法小结
2017/04/15 PHP
php+ajax实现异步上传文件或图片功能
2017/07/18 PHP
php实现的证件照换底色功能示例【人像抠图/换背景图】
2020/05/29 PHP
多广告投放代码 推荐
2006/11/13 Javascript
Javascript &amp; DHTML 实例编程(教程)DOM基础和基本API
2007/06/02 Javascript
JS setCapture 区域外事件捕捉
2010/03/18 Javascript
纯js写的分页表格数据为json串
2014/02/18 Javascript
JavaScript返回网页中锚点数目的方法
2015/04/03 Javascript
Javascript实现字数统计
2015/07/03 Javascript
vue 页面加载进度条组件实例
2018/02/05 Javascript
如何实现一个webpack模块解析器
2018/10/24 Javascript
js删除对象/数组中null、undefined、空对象及空数组方法示例
2018/11/14 Javascript
Jquery的autocomplete插件用法及参数讲解
2019/03/12 jQuery
vue中使用vue-cli接入融云实现即时通信
2019/04/19 Javascript
jQuery鼠标滑过横向时间轴样式(代码详解)
2019/11/01 jQuery
VsCode里的Vue模板的实现
2020/08/12 Javascript
[01:53]2016完美“圣”典风云人物:Maybe专访
2016/12/05 DOTA
python实现简单的TCP代理服务器
2014/10/08 Python
探究Python多进程编程下线程之间变量的共享问题
2015/05/05 Python
Python for Informatics 第11章之正则表达式(二)
2016/04/21 Python
python实现猜数字小游戏
2020/03/24 Python
Python 使用 attrs 和 cattrs 实现面向对象编程的实践
2019/06/12 Python
python字符串分割及字符串的一些常规方法
2019/07/24 Python
Python基础之函数原理与应用实例详解
2020/01/03 Python
pytorch之ImageFolder使用详解
2020/01/06 Python
完美解决pyinstaller打包报错找不到依赖pypiwin32或pywin32-ctypes的错误
2020/04/01 Python
HTML 5.1来了 9月份正式发布 更新内容预览
2016/04/26 HTML / CSS
html5中使用hotcss.js实现手机端自适配的方法
2020/04/23 HTML / CSS
全球航班旅行搜索网站:Cheapflights
2017/05/19 全球购物
皇家阿尔伯特英国官方商店:Royal Albert骨瓷
2019/03/25 全球购物
2014年工人工作总结
2014/11/25 职场文书
2015教师年度考核评语
2015/03/25 职场文书
2015年乡镇残联工作总结
2015/05/13 职场文书
节水宣传标语口号
2015/12/26 职场文书
CSS3 制作的书本翻页特效
2021/04/13 HTML / CSS
Go微服务项目配置文件的定义和读取示例详解
2022/06/21 Golang