Three.js:如何沿着一条线动画粒子

3
我正在尝试沿着路径动画粒子,类似于这个Chrome实验: http://armsglobe.chromeexperiments.com/ 我已经尝试研究这个项目的源代码,目前我所理解的是他们使用内置曲线方法.getPoitns()在他们的线条上生成大约30个点。
是否有更好的示例可以展示我想要实现的内容?有没有获取线上点的方法,而不是使用.lerp()方法30次来获得30个点?我应该只是使用TWEEN动画吗?
感谢任何帮助或指引。

2
作者写了一篇关于武器贸易的博客文章,你可能会发现它很有帮助或者至少很有趣。http://mflux.tumblr.com/post/28367579774/armstradeviz - 2pha
这是一篇很棒的文章,但他没有详细介绍粒子动画。谢谢分享。 - jigglebilly
我记得看过另一篇更详细介绍粒子的文章,如果我找到了,我会发布它。 - 2pha
我找不到它,但他似乎更新了每个粒子系统粒子所附着线条的每个顶点的位置。您可以在此处查看:http://armsglobe.chromeexperiments.com/js/visualize.js。 似乎更新顶点位置的部分是pSystem.update函数。 - 2pha
2个回答

7
我已经想出了一个解决方案,不确定它是否是最好的,但它运行良好。
您可以在JsFiddle上找到演示:https://jsfiddle.net/L4beLw26/

//First create the line that we want to animate the particles along
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(-800, 0, -800));
geometry.vertices.push(new THREE.Vector3(800, 0, 0));

var line = new THREE.Line(geometry, material);
var startPoint = line.geometry.vertices[0];
var endPoint = line.geometry.vertices[1];
scene.add(line);


//next create a set of about 30 animation points along the line
var animationPoints = createLinePoints(startPoint, endPoint);

//add particles to scene
for ( i = 0; i < numParticles; i ++ ) {
  var desiredIndex = i / numParticles * animationPoints.length;
  var rIndex = constrain(Math.floor(desiredIndex),0,animationPoints.length-1);
  var particle = new THREE.Vector3();
  var particle = animationPoints[rIndex].clone();
  particle.moveIndex = rIndex;
  particle.nextIndex = rIndex+1;
  if(particle.nextIndex >= animationPoints.length )
    particle.nextIndex = 0;
  particle.lerpN = 0;
  particle.path = animationPoints;
  particleGeometry.vertices.push( particle );
}

//set particle material
var pMaterial = new THREE.ParticleBasicMaterial({
  color: 0x00FF00,
  size: 50,
  map: THREE.ImageUtils.loadTexture(
    "assets/textures/map_mask.png"
  ),
  blending: THREE.AdditiveBlending,
  transparent: true
});


var particles = new THREE.ParticleSystem( particleGeometry, pMaterial );
particles.sortParticles = true;
particles.dynamic = true;
scene.add(particles);


//update function for each particle animation
particles.update = function(){
  // var time = Date.now()
  for( var i in this.geometry.vertices ){
    var particle = this.geometry.vertices[i];
    var path = particle.path;
    particle.lerpN += 0.05;
    if(particle.lerpN > 1){
      particle.lerpN = 0;
      particle.moveIndex = particle.nextIndex;
      particle.nextIndex++;
      if( particle.nextIndex >= path.length ){
        particle.moveIndex = 0;
        particle.nextIndex = 1;
      }
    }

    var currentPoint = path[particle.moveIndex];
    var nextPoint = path[particle.nextIndex];


    particle.copy( currentPoint );
    particle.lerp( nextPoint, particle.lerpN );
  }
  this.geometry.verticesNeedUpdate = true;
};




function createLinePoints(startPoint, endPoint){
  var numPoints = 30;
  var returnPoints = [];
  for(i=0; i <= numPoints; i ++){
    var thisPoint = startPoint.clone().lerp(endPoint, i/numPoints);
    returnPoints.push(thisPoint);
  }
  return returnPoints;
}

function constrain(v, min, max){
  if( v < min )
    v = min;
  else
    if( v > max )
      v = max;
  return v;
}

在动画循环中:

particles.update();


2

我不知道是否有其他人无法看到片段的工作情况,但我采用jigglebilly提供的答案并将其放入完整的HTML页面中,它正在工作。这样,如果您想查看工作版本。


        粒子测试
    

<script src="../js/three.js"></script>

<script type="text/javascript">

    var renderer = new THREE.WebGLRenderer( { antialias: true } );
    var camera = new THREE.PerspectiveCamera( 45, (window.innerWidth) / (window.innerHeight), 100, 10000);
    var container = document.getElementById("containerElement");
    var numParticles = 40;
    container.appendChild( renderer.domElement );
    var scene = new THREE.Scene();

    var material = new THREE.LineBasicMaterial({color: 0x0000ff });
    //First create the line that we want to animate the particles along
    var geometry = new THREE.Geometry();
    geometry.vertices.push(new THREE.Vector3(-800, 0, -800));
    geometry.vertices.push(new THREE.Vector3(800, 0, 0));

    var line = new THREE.Line(geometry, material);
    var startPoint = line.geometry.vertices[0];
    var endPoint = line.geometry.vertices[1];
    scene.add(line);


    //next create a set of about 30 animation points along the line
    var animationPoints = createLinePoints(startPoint, endPoint);
    var particleGeometry = new THREE.Geometry();
    //add particles to scene
    for ( i = 0; i < numParticles; i ++ ) {

        var desiredIndex = i / numParticles * animationPoints.length;
        var rIndex = constrain(Math.floor(desiredIndex),0,animationPoints.length-1);
        var particle = new THREE.Vector3();
        var particle = animationPoints[rIndex].clone();
        particle.moveIndex = rIndex;
        particle.nextIndex = rIndex+1;
        if(particle.nextIndex >= animationPoints.length )
            particle.nextIndex = 0;
        particle.lerpN = 0;
        particle.path = animationPoints;
        particleGeometry.vertices.push( particle );
    }

    //set particle material
    var pMaterial = new THREE.ParticleBasicMaterial({
        color: 0x00FF00,
        size: 50,
        blending: THREE.AdditiveBlending,
        transparent: true
    });


    var particles = new THREE.ParticleSystem( particleGeometry, pMaterial );
    particles.sortParticles = true;
    particles.dynamic = true;
    scene.add(particles);

    function UpdateParticles(){
        // var time = Date.now()
        for( var i = 0; i < particles.geometry.vertices.length; i++ ){
            var particle = particles.geometry.vertices[i];
            var path = particle.path;
            particle.lerpN += 0.05;
            if(particle.lerpN > 1){
                particle.lerpN = 0;
                particle.moveIndex = particle.nextIndex;
                particle.nextIndex++;
                if( particle.nextIndex >= path.length ){
                    particle.moveIndex = 0;
                    particle.nextIndex = 1;
                }
            }

            var currentPoint = path[particle.moveIndex];
            var nextPoint = path[particle.nextIndex];


            particle.copy( currentPoint );
            particle.lerp( nextPoint, particle.lerpN );
        }
        particles.geometry.verticesNeedUpdate = true;
    };

    animate();

    function createLinePoints(startPoint, endPoint){
        var numPoints = 30;
        var returnPoints = [];
        for(i=0; i <= numPoints; i ++){
            var thisPoint = startPoint.clone().lerp(endPoint, i/numPoints);
            returnPoints.push(thisPoint);
        }
        return returnPoints;
    }

    function constrain(v, min, max){
        if( v < min )
            v = min;
        else
        if( v > max )
            v = max;
        return v;
    }

    function animate() {
        requestAnimationFrame(animate);
        render();
    }

    function render() {
        renderer.render(scene, camera);
        UpdateParticles();
    }
</script>

这里使用的是 three.js R67 版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接