前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Three.js 粒子系统学习小记:礼花效果实现

Three.js 粒子系统学习小记:礼花效果实现

原创
作者头像
郭诗雅
修改2018-10-08 15:39:16
19.5K2
修改2018-10-08 15:39:16
举报
文章被收录于专栏:郭诗雅的专栏郭诗雅的专栏

背景知识

在3D建模过程中,当我们需要创建很多细小的物体时,并不会一个个地创建这些物体,而是通过创建粒子,粒子可以模拟很多效果,例如烟花、火焰、雨滴、雪花、云朵等等。Three.js提供了各种的粒子系统创建方式。从官网例子的demo来看,可以总结分为两类,分别是Points和Sprite。

Points粒子系统的创建

首先看看threejs官网对Points的解释:

A class for displaying points. The points are rendered by the WebGLRenderer using gl.POINTS.

也就是说,points必须要通过WebGLRenderer渲染方式来创建(重点强调这个是因为官网的demo中粒子的创建一般通过两种方式WebGLRendererCanvasRenderer

代码语言:txt
复制
renderer = new THREE.WebGLRenderer( );

points粒子系统的创建过程一般可以总结为三步:

1.创建一个几何对象Geometry(也可以是外部导入的模型),然后基于几何体自身的顶点集合geometry.vertices创建粒子(即 将网格转化为粒子),每个顶点将代表粒子系统中的每个粒子。

代码语言:txt
复制
var geometry = new THREE.SphereGeometry( 500, 50, 50 );

2.创建粒子材质,Points对应PointsMaterial,来实现每个粒子的图案。实现的方式可以是加载图片纹理(demo地址)或者canvas纹理,又或者不采用纹理直接创建正方体粒子(demo地址)。

代码语言:txt
复制
var material = new THREE.PointsMaterial( { ... } ) ;

3.通过以上两步的创建一个Points类的物体,这个物体则代表了整个粒子系统。

代码语言:txt
复制
var mesh = new THREE.Points( geometry, material );

下图展示了将一个球形网格模型转化成一个球形粒子系统:

另外,也可以创建一个自定义的几何体为其添加顶点集合。

Sprite粒子系统的创建

A sprite is a plane that always faces towards the camera, generally with a partially transparent texture applied.

threejs官网如是说,sprite是一直面向camera的平面,并且我们可以用其创建基于屏幕坐标移动、定位和缩放的对象,而不影响三维场景中的其他物体(做到互不影响必须单独创建一个用于sprite对象的camera和render)。另外sprite对象还有一个特点是不能生成阴影。

创建过程:

1.创建粒子材质,如果渲染器是canvasRender则可以直接引用canvas画布,另外也可以加载图片纹理和canvas纹理。

代码语言:txt
复制
var spriteMaterial = new THREE.SpriteMaterial( { ... } );

2.创建粒子

代码语言:txt
复制
var sprite = new THREE.Sprite( spriteMaterial );

3.另外还可以为粒子设置position(如果将每个粒子设置为一个几何体的每个顶点,则效果和point粒子系统相似)。

代码语言:txt
复制
sprite.position.x = 0;
sprite.position.y = 0;
sprite.position.z = 0;

4.为了方便控制,还可以将粒子加进同一个组内,变成一个粒子系统。

代码语言:txt
复制
for ( var i = 0; i < len; i++ ) { //len表示粒子数目
    ...
    group.add( sprite );
}

粒子材质

先说说每个粒子材质图形的创建,一般是通过canvas描绘或通过加载图片的方式来格式化粒子:

1.直接引用画布,当通过CanvasRenderer渲染时:

代码语言:txt
复制
renderer = new THREE.CanvasRenderer();

你可以直接在每个粒子的材质对象里直接引用HTML5画布。例如:

代码语言:txt
复制
//画点
var PI2 = Math.PI * 2;
var program = function ( context ) {
    context.beginPath();
    context.arc( 0, 0, 0.5, 0, PI2, true );
    context.fill();
};
//为每个点附上材质
var material = new THREE.SpriteCanvasMaterial( {
    color: Math.random() * 0x808008 + 0x808080,
    program: program
} );

上文提到,points对象只能通过WebGLRender进行渲染,所以pointsmaterial和这种方式是无缘了。WebGLRender渲染时的粒子如果需要用canvas实现,则必须加多一步将canvas转化为纹理,在通过map属性加载进来。

2.加载图片纹理:

代码语言:txt
复制
var textureLoader = new THREE.TextureLoader();
var sprite = textureLoader.load( "textures/sprites/snowflake.png" );
var material = new THREE.PointsMaterial( { size: size, map: sprite, blending: THREE.AdditiveBlending, depthTest: false, transparent : true } );

从上面的代码可以看到,粒子材质的属性还有很多,详情点击:pointsMaterial spriteMaterial

礼花效果实现

应用上面的知识点,小编做了一个礼花的小demo,礼花的展示效果大致分为三步:

  1. 绽放前,飞线动画向上运动。
  2. 绽放出球形礼花。
  3. 往下往外坠落礼花消失。

实现过程如下:

  1. 创建粒子,在这个例子中小编应用了canvasRender结合spriteMaterial,用canvas画出每个粒子(圆点),然后为它们设置初始位置都在同一点。
代码语言:txt
复制
var PI2 = Math.PI * 2;
//画点
var program = function ( context ) {

    context.beginPath();
    context.arc( 0, 0, 0.5, 0, PI2, true );
    context.fill();

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

for ( var i = 0; i < vl; i++ ) {
    //为每个点附上材质
    var material = new THREE.SpriteCanvasMaterial( {
        color: Math.random() * 0x808008 + 0x808080,
        program: program
    } );

    particle = new THREE.Sprite( material );
    particle.position.x = 0;
    particle.position.y = -500;
    particle.position.z = 0;
    particle.scale.x = particle.scale.y = Math.random() * 4 + 2;
    ...
    group.add(particle);
}
  1. 飞线动画实现

在每一帧的render中,判断每个粒子的y坐标小于一定值时,以不同的速度按照正弦曲线的轨迹向上运动,形成飞线动画的效果。

代码语言:txt
复制
function fsin(x){     //正弦函数
    return 50*Math.sin(0.8*x*Math.PI/180);
}
delta = 10 * clock.getDelta();
var speed = 80;
delta = delta < 2 ? delta : 2;
var dur = new Date().getTime() - t1; 
if (dur < 1800) {     //控制飞线动画时间
    var k = 0;
    group.traverse(function(child) {
        if (child.position.y < 0) {
            child.position.y += delta * speed * Math.random();
            child.position.x = fsin(child.position.y);    
        }            
    });
}
renderer.render( scene, camera );
  1. 绽放效果是结合tweenMax实现的,在粒子初始化的时候,为了实现绽放时的球形效果,定义了一个球体几何体,得到球体的总顶点数作为粒子的总数,用tweenMax设置了每个粒子在绽放到最大时的位置,即了相应的球体的顶点位置再增减一些随机数,并设置随机的绽放时间,来达到错落有致的效果。
代码语言:txt
复制
//创建一个球型用作最后的形状
var geometry = new THREE.SphereGeometry( 500, 50, 50 );
var vl = geometry.vertices.length;

for ( var i = 0; i < vl; i++ ) {

    ...
    particle = new THREE.Sprite( material );
    ...

    var timerandom = 1*Math.random();
    //为每个点加动画
    TweenMax.to(
        particle.position,
        timerandom,
        {x:geometry.vertices[i].x+(0.5-Math.random())*100,y:geometry.vertices[i].y+(0.5-Math.random())*100,z:geometry.vertices[i].z+Math.random()*100,delay:1.8,} 
    );

    group.add( particle );
}

4.礼花消失,同样是使用tweenMax

代码语言:txt
复制
TweenMax.to(
          particle.position,
           2*timerandom,
          {y:'-600',z:'300',delay:1.8+timerandom,} 
 );

demo展示:地址

整个花的形状:地址

花的形状是用极坐标函数写的:传送门

项目代码地址:

https://github.com/kiroroyoyo/threejsexample/tree/master/particle

学习心得

  1. 在threejs的粒子系统中,每个粒子其实是一张图片或者一个canvas而不是3D的物体。
  2. 当粒子量级非常大时,可以用BufferGeometry来代替Geometry的顶点,因为它可以将数据存储在缓冲区中,减少数据传递到GPU的成本,同时因为在缓冲区,所以更适合静态的物体。
  3. threejs版本更新了很多次,粒子系统的创建也改了很多次名字,从THREE.ParticleSystem到THREE.PointCloud到THREE.Points,在学习实例时应注意。本文例子应用的是目前最新的r84。

参考文章:

  1. https://threejs.org/docs/
  2. https://www.solutiondesign.com/blog/-/blogs/webgl-and-three-js-particles
  3. 《Three.js开发指南》

谢谢阅读,如有问题请各位大大指正!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景知识
  • Points粒子系统的创建
  • Sprite粒子系统的创建
  • 粒子材质
  • 礼花效果实现
  • 学习心得
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档