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 相关文章推荐
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
Sep 04 Javascript
javascript 遍历验证所有文本框的值
Aug 27 Javascript
jquery插件tooltipv顶部淡入淡出效果使用示例
Dec 05 Javascript
js的匿名函数使用介绍
Dec 11 Javascript
使用Jquery获取带特殊符号的ID 标签的方法
Apr 30 Javascript
JavaScript获取图片真实大小代码实例
Sep 24 Javascript
返回顶部按钮响应滚动且动态显示与隐藏
Oct 14 Javascript
全面解析Javascript无限添加QQ好友原理
Jun 15 Javascript
jQuery+ajax的资源回收处理机制分析
Jan 07 Javascript
webpack学习--webpack经典7分钟入门教程
Jun 28 Javascript
jquery操作select常见方法大全【7种情况】
May 28 jQuery
HTML+JS实现在线朗读器
Feb 15 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下图片文字混合水印与缩略图实现代码
2009/12/11 PHP
PHP获取windows登录用户名的方法
2014/06/24 PHP
PHP的Yii框架使用中的一些错误解决方法与建议
2015/08/21 PHP
Zend Framework框架实现类似Google搜索分页效果
2016/11/25 PHP
PHP实现时间日期友好显示实现代码
2019/09/08 PHP
鼠标经过的文本框textbox变色
2009/05/21 Javascript
JQuery 插件模板 制作jquery插件的朋友可以参考下
2010/03/17 Javascript
使用node+vue.js实现SPA应用
2016/01/28 Javascript
jQuery EasyUI 获取tabs的实例解析
2016/12/06 Javascript
javascript 秒表计时器实现代码
2017/03/09 Javascript
JS查找英文文章中出现频率最高的单词
2017/03/20 Javascript
用node和express连接mysql实现登录注册的实现代码
2017/07/05 Javascript
jQuery remove()过滤被删除的元素(推荐)
2017/07/18 jQuery
vue实现element-ui对话框可拖拽功能
2018/08/17 Javascript
vue实现动态按钮功能
2019/05/13 Javascript
Mpvue中使用Vant Weapp组件库的方法步骤
2019/05/16 Javascript
前端插件之Bootstrap Dual Listbox使用教程
2019/07/23 Javascript
Vue + Element-ui的下拉框el-select获取额外参数详解
2020/08/14 Javascript
[03:12]完美世界DOTA2联赛PWL DAY7集锦
2020/11/06 DOTA
Python Pexpect库的简单使用方法
2019/01/29 Python
python 自动批量打开网页的示例
2019/02/21 Python
python 通过手机号识别出对应的微信性别(实例代码)
2019/12/22 Python
使用Django和Postgres进行全文搜索的实例代码
2020/02/13 Python
基于spring boot 日志(logback)报错的解决方式
2020/02/20 Python
用Python在Excel里画出蒙娜丽莎的方法示例
2020/04/28 Python
matlab、python中矩阵的互相导入导出方式
2020/06/01 Python
css3实现文字首尾衔接跑马灯的示例代码
2020/10/16 HTML / CSS
Farfetch巴西官网:奢侈品牌时尚购物平台
2020/10/19 全球购物
大学生通用个人的自我评价
2014/02/10 职场文书
爱情保证书大全
2014/04/29 职场文书
秋季运动会演讲稿
2014/09/16 职场文书
个人委托书怎么写
2014/09/17 职场文书
战略性融资合作协议书范本
2014/10/17 职场文书
酒店仓管员岗位职责
2015/04/01 职场文书
低版本Druid连接池+MySQL驱动8.0导致线程阻塞、性能受限
2021/07/01 MySQL
GoFrame基于性能测试得知grpool使用场景
2022/06/21 Golang