我有一个THREE.Points个对象,包含许多(10,000多个)顶点(a.k.a.粒子)。
但是,当我尝试补间单个粒子的位置时,我遇到了性能问题。这是预期的,因为我使用以下代码循环遍历所有粒子并为每个粒子指定一个补间。
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();
}
有没有更好的方法来解决这个问题? 我不介意是否所有粒子都在一次平局调用中更新到新的中间位置。
答案 0 :(得分:1)
你可能永远不会在javascript中获得想要动画那么多粒子的性能 您最好的选择可能是将动画代码移动到着色器,以便由GPU处理,这样可以轻松地为您提供所需的性能。
有一篇关于如何使用代码示例执行此操作的博文:Animating a Million Letters Using Three.js
答案 1 :(得分:1)
在咀嚼一会儿之后让它运转。
解决方案是使用缓冲几何(as seen here)和使用@ 2pha建议的着色器的组合。
补间功能被移动到顶点着色器,在那里可以伪造每像素补间。补间函数所需的各种数据存储在ShaderMaterial制服和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 );
}