上次拿了一个小球实验,小球和随机线的相依相恋
这次捉来了几只粒子,效果嘛,有点魔幻,不过也还行。效果在这里0.0
刚开始的粒子会比较紧密一点,像这样
这是运行一段时间比较稳定的样子
套个半透明的管子模拟个水流啥的应该也还行
主要的代码总结一下:
主要变量:
//粒子
var particles;//粒子系统,new Point类型
var pointsGomtry = new THREE.Geometry(); //粒子顶点信息
var particlesNum = 60; //粒子数量
var particlesPos = []; //粒子位置
var posLocal = []; // 随机线在粒子坐标系内的位置
var posIndex = []; // 粒子所在的随机点索引
var colors = []; //粒子的颜色们
var color = new THREE.Color();
var colorde = 3; // 粒子颜色的衰减值,减少亮度和饱和度
粒子的位置是在一个圆内随机生成的:
for ( var i = 0; i < particlesNum; i ++ ) {
var x = Math.sin(6 * i * 2 * Math.PI/ 180) * Math.random(0,1);
var z = 0;
var y = Math.cos(6 * i * 2 * Math.PI/ 180) * Math.random(0,1);
particlesPos.push( x, y, z );
// colors 彩色
/*var vx = ( x / colorde ) + 0.5;
var vy = ( y / colorde ) + 0.5;
var vz = ( z / colorde ) + 0.5;*/
//天蓝色
var vx = 0;
var vy = 174;
var vz = 255;
color.setRGB( vx, vy, vz );
colors.push( color.r, color.g, color.b );
posIndex.push(0);
}
有了点就可以生成BufferGeometry和Geometry了,如果只是生成粒子的话, BufferGeometry 就可以了, BufferGeometry 里面的位置信息是 Float32Array ,变换和操作起来都有一些难度,转换为 Geometry 的话,有v3类型的vertices,操作要方便很多。
var pointsGeometry = new THREE.BufferGeometry();
pointsGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( particlesPos, 3 ) );
pointsGeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
pointsGeometry.computeBoundingSphere();
pointsGomtry = pointsGomtry.fromBufferGeometry(pointsGeometry);
默认的粒子系统里面粒子是方形,我想要圆形的,所以要自己配一下材质,材质配置说明详见
var material = new THREE.PointsMaterial(
{
size: 6,
vertexColors: THREE.VertexColors,
map:new THREE.TextureLoader().load( "dot.png"),
//blending:THREE.MultiplyBlending,
transparent:true,
opacity:1.0,
depthTest: false,
});
particles = new THREE.Points( pointsGomtry, material );
scene.add( particles );
放一个坐标轴方便定位
var axes2 = new THREE.AxesHelper( 5 );
axes.name = "AxesHelper2";
particles.add( axes2 );
把粒子系统放到随机线的初始位置,
particles.position.set(pointsV3[0].x,pointsV3[0].y,pointsV3[0].z);
particles.lookAt(pointsV3[1]);
particles.updateMatrixWorld(true,true);
计算随机线上的点在粒子系统里的坐标位置
for(let i = 0;i < pointsV3.length; i++)
{
posLocal.push(particles.worldToLocal(pointsV3[i].clone()));
}
在animate()里面定时给每个点变换一下位置,线的走向就是每个点应该走的方向,把方向normalize一下,乘一个类似速度的偏随机的数字就是每个点的下一个位置
var vs = particles.geometry.vertices;
for(var i = 0; i < vs.length; i++) {
let pos = vs[i];
n=posLocal[posIndex[i]+1].clone().sub(posLocal[posIndex[i]].clone()).normalize().multiplyScalar(Math.random(0,1) * 1);
let vv = posLocal[posIndex[i]+1].clone().sub(vs[i].clone());
if(vv.length() < 1 || vv.clone().dot(n.clone()) < 0 )
{
vs[i].add(vv.clone().projectOnVector(n.clone()));
if(posIndex[i] < posLocal.length - 2)
posIndex[i]+=1;
else
{
posIndex[i]=0;
let r = (Math.random(0,1) - 0.5)*360;
let x = Math.sin(r * Math.PI/ 180);
let z = 0;
let y = Math.cos(r * Math.PI/ 180);
vs[i] = new THREE.Vector3(x,y,z);
}
}
else
{
vs[i].add(n);
}
}
particles.geometry.verticesNeedUpdate = true;
有些临时变量名字起的随意了一些,不过也不难理解。
分割线更一波,上面的粒子有的时候操作着会产生突然看不见的问题,我知道应该是相机裁剪的问题,调了一下参数还是不行,今天发现一个函数可以解决这个问题,就是直接把裁剪关了。
particles = new THREE.Points( pointsGomtry, material );
particles.frustumCulled = false;
scene.add( particles );