【问题标题】:How to tween 10,000+ particles in Three.js?如何在 Three.js 中补间 10,000 多个粒子?
【发布时间】:2016-05-21 14:46:27
【问题描述】:

我有一个 THREE.Points 对象,由许多 (10,000+) 个顶点(也称为粒子)组成。

但是,当我尝试对单个粒子的位置进行补间时遇到了性能问题。这是意料之中的,因为我正在使用以下代码循环所有粒子并为每个粒子分配一个补间。

var duration = 500;

for( var i = 0; i < particles.geometry.vertices.length; i++ ){

    // http://threejs.org/examples/css3d_sprites.html

    var currentVertex = particles.geometry.vertices[i];

    new TWEEN.Tween( currentVertex )
        .to( 
            {
                x: newVertices[i].x,
                y: newVertices[i].y,
                z: newVertices[i].z,
            },
            duration * ( Math.random() + 1 ) 
        )
        .easing( TWEEN.Easing.Exponential.InOut )
        .onUpdate( function(){

            particles.geometry.verticesNeedUpdate = true;
        })
        .start();
}

有没有更好的方法来解决这个问题?
我不介意是否所有粒子都在一次绘制调用中更新到它们的新中间位置。

【问题讨论】:

  • 首先,不要用math.rand,用math.sin比较慢(你可以查一下,这里手机不能链接)。接下来,不要在循环内分配。放置 var 和 new 外部循环并重用。

标签: three.js tween tween.js


【解决方案1】:

嚼了一会儿就跑起来了。

解决方案是结合使用缓冲区几何 (as seen here) 和使用 @2pha 建议的着色器。

补间函数已移至顶点着色器,可以在其中伪造每像素补间。补间函数所需的各种数据存储在ShaderMaterial uniforms和BufferGeometry属性中。

一些伪代码,

// Buffer Geometry

var geometry = new THREE.BufferGeometry();
geometry.addAttribute( 'position', new THREE.BufferAttribute( bPositions, 3 ) );
geometry.addAttribute( 'color', new THREE.BufferAttribute( bColors, 3 ) );
geometry.addAttribute( 'targetPosition', new THREE.BufferAttribute( bPositions2, 3 ) );


// Shader Material

var material = new THREE.ShaderMaterial({
    uniforms: {
        elapsedTime : {
            type: "f",
            value: 0.0
        },
        duration : {
            type: "f",
            value: 0.0
        }
    },
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent
});

// Vertex Shader

uniform float elapsedTime;
uniform float duration;
attribute vec3 targetPosition;

float exponentialInOut( float k ){
    // https://github.com/tweenjs/tween.js/blob/master/src/Tween.js
    if( k <= 0.0 ){
        return 0.0;
    }
    else if( k >= 1.0 ){
        return 1.0;
    }
    else if( ( k *= 2.0 ) < 1.0 ){
        return 0.5 * pow( 1024.0, k - 1.0 );
    }
    return 0.5 * ( - pow( 2.0, - 10.0 * ( k - 1.0 ) ) + 2.0 );
}

void main(){

    // calculate time value (also vary duration of each particle)
    float t = elapsedTime / ( duration * ( 1.0 + randomNum.x ) );

    // calculate progress
    float progress = exponentialInOut( t );

    // calculate new position (simple linear interpolation)
    vec3 delta = targetPosition - position;
    vec3 newPosition = position + delta * progress;

    // something
    gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}

【讨论】:

【解决方案2】:

您可能永远无法仅在 javascript 中获得您想要的动画效果。
您最好的选择可能是将您的动画代码移动到着色器,以便它由 GPU 处理,它应该能够轻松地为您提供所需的性能。

在Animating a Million Letters Using Three.js有一篇关于如何使用代码示例执行此操作的博客文章

【讨论】:

  • 我以前看过那篇文章。我无法(atm)听懂他在说什么。但是,我最终找到了一种方法,可以按照建议使用着色器。
猜你喜欢
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 2012-12-23
  • 2014-01-26
  • 2012-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多