Search code examples
three.jsglslshaderwebglvertex-shader

Three.js what is the most performant way of changing a vertex position?


I'm new to Three.js and I ended up with 2 ways of moving the vertices of a plane. I was wondering which one of the two ways should I use in terms of performance or simply in terms of best practices.

In the first function, I update the vertices position with a vertexShader, and the second one I update the position of the vertices by using the bufferGeometry position attribute of the THREE.mesh.

demo: https://olivierlarose.github.io/Threejs-Wave-Animation/

code: https://github.com/olivierlarose/Threejs-Wave-Animation

  1. Using the vertexShader:
void main() {
  vUv = uv;
  float calc = height * sin(position.x * 10.0 + time);   
  vec3 newPosition = position;
  newPosition.z = newPosition.z + calc; 
                    
  gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}

  1. Using the bufferGeometry attribute position:
animate(){
    const time = this.clock.getElapsedTime() * 3;
    const position = this.cube.geometry.attributes.position;

    for(let i = 0 ; i < position.count ; i++){
        const calc = this.height * Math.sin(position.getX(i) * 10 + time);     
        position.setZ(i, calc);
        position.needsUpdate = true; 
    }

    requestAnimationFrame(this.animate.bind(this));
    this.renderer.render(this.scene, this.camera);
}

Thank you


Solution

  • If you re-calculate your positions in JavaScript, you'll need to upload these new positions to the GPU on each new frame, which can create a big bottleneck as your vertex count goes higher. Plus, you'll need to perform Math.sin() once per vertex, which can become costly in a single thread when you have thousands and thousands of vertices.

    The best way in terms of performance is to update the positions in the vertex shader. This is because your geometry's position attribute gets uploaded to the GPU only once. Additionally, you get the boost in performance from calculating sin() in parallel, which is super fast in the GPU, compared to the CPU.