在3D建模过程中,当我们需要创建很多细小的物体时,并不会一个个地创建这些物体,而是通过创建粒子,粒子可以模拟很多效果,例如烟花、火焰、雨滴、雪花、云朵等等。Three.js提供了各种的粒子系统创建方式。从官网例子的demo来看,可以总结分为两类,分别是Points和Sprite。
首先看看threejs官网对Points的解释:
A class for displaying points. The points are rendered by the WebGLRenderer using gl.POINTS.
也就是说,points必须要通过WebGLRenderer渲染方式来创建(重点强调这个是因为官网的demo中粒子的创建一般通过两种方式WebGLRenderer和CanvasRenderer
renderer = new THREE.WebGLRenderer( );
points粒子系统的创建过程一般可以总结为三步:
1.创建一个几何对象Geometry(也可以是外部导入的模型),然后基于几何体自身的顶点集合geometry.vertices创建粒子(即 将网格转化为粒子),每个顶点将代表粒子系统中的每个粒子。
var geometry = new THREE.SphereGeometry( 500, 50, 50 );
2.创建粒子材质,Points对应PointsMaterial,来实现每个粒子的图案。实现的方式可以是加载图片纹理(demo地址)或者canvas纹理,又或者不采用纹理直接创建正方体粒子(demo地址)。
var material = new THREE.PointsMaterial( { ... } ) ;
3.通过以上两步的创建一个Points类的物体,这个物体则代表了整个粒子系统。
var mesh = new THREE.Points( geometry, material );
下图展示了将一个球形网格模型转化成一个球形粒子系统:
另外,也可以创建一个自定义的几何体为其添加顶点集合。
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纹理。
var spriteMaterial = new THREE.SpriteMaterial( { ... } );
2.创建粒子
var sprite = new THREE.Sprite( spriteMaterial );
3.另外还可以为粒子设置position(如果将每个粒子设置为一个几何体的每个顶点,则效果和point粒子系统相似)。
sprite.position.x = 0;
sprite.position.y = 0;
sprite.position.z = 0;
4.为了方便控制,还可以将粒子加进同一个组内,变成一个粒子系统。
for ( var i = 0; i < len; i++ ) { //len表示粒子数目
...
group.add( sprite );
}
先说说每个粒子材质图形的创建,一般是通过canvas描绘或通过加载图片的方式来格式化粒子:
1.直接引用画布,当通过CanvasRenderer渲染时:
renderer = new THREE.CanvasRenderer();
你可以直接在每个粒子的材质对象里直接引用HTML5画布。例如:
//画点
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.加载图片纹理:
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,礼花的展示效果大致分为三步:
实现过程如下:
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);
}
在每一帧的render中,判断每个粒子的y坐标小于一定值时,以不同的速度按照正弦曲线的轨迹向上运动,形成飞线动画的效果。
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 );
//创建一个球型用作最后的形状
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
TweenMax.to(
particle.position,
2*timerandom,
{y:'-600',z:'300',delay:1.8+timerandom,}
);
demo展示:地址
整个花的形状:地址
花的形状是用极坐标函数写的:传送门
项目代码地址:
https://github.com/kiroroyoyo/threejsexample/tree/master/particle
参考文章:
谢谢阅读,如有问题请各位大大指正!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。