简体   繁体   中英

Animating a bezier curve in ThreeJS

I would like to animate a bezier curve in ThreeJS. The start, end and control points will update. Eventually I will need to have many curves animating at once. What's the most efficient way to do this?

If you run the code snippet below, you'll see that I'm creating the Bezier object, Geometry and Line each time the frame renders. I'm removing the previous line from the scene and then adding the new, updated line. Is there a better way? Perhaps updating only the geometry and not adding the line again?

 var camera, scene, renderer, geometry, material, mesh; init(); animate(); /** Create the scene, camera, renderer */ function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 500; scene.add(camera); addCurve(); renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); } /** Add the initial bezier curve to the scene */ function addCurve() { testPoint = 0; curve = new THREE.CubicBezierCurve3( new THREE.Vector3( testPoint, 0, 0 ), new THREE.Vector3( -5, 150, 0 ), new THREE.Vector3( 20, 150, 0 ), new THREE.Vector3( 10, 0, 0 ) ); curveGeometry = new THREE.Geometry(); curveGeometry.vertices = curve.getPoints( 50 ); curveMaterial = new THREE.LineBasicMaterial( { color : 0xff0000 } ); curveLine = new THREE.Line( curveGeometry, curveMaterial ); scene.add(curveLine); } /** On each frame render, remove the old line, create new curve, geometry and add the new line */ function updateCurve() { testPoint ++; scene.remove(curveLine); curve = new THREE.CubicBezierCurve3( new THREE.Vector3( testPoint, 0, 0 ), new THREE.Vector3( -5, 150, 0 ), new THREE.Vector3( 20, 150, 0 ), new THREE.Vector3( 10, 0, 0 ) ); curveGeometry = new THREE.Geometry(); curveGeometry.vertices = curve.getPoints( 50 ); curveLine = new THREE.Line( curveGeometry, curveMaterial ); scene.add(curveLine); } function animate() { requestAnimationFrame(animate); render(); } function render() { updateCurve(); renderer.render(scene, camera); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script> 

Creating new lines per each frame is very exepnsive opertation.

What is that the best way to create animated curves?

Probably using shaders . But it can take much more time to implement, so if my next suggestions will be enough for you, just them.

Improve curve updating in your code

I tried not to change a lot of your code. Marked edited places with " // EDITED " comment. I added an array cause you said that there will be many curves.

Explanation

  • As @WestLangley said, try to avoid using new keyword inside animation loop.
  • CubicBezierCurve3 has v0 , v1 , v2 and v3 attributes. Those are THREE.Vector3 `s that you provide from the beginning. .getPoints() uses them to return you vertices array. So you can simply change them and no new keyword is needed. See this line for more details.
  • Rather then recreating line, in your case you can simply update geometry. As you have a THREE.Line - your geometry only needs vertices. After changing vertices you should set geometry.verticesNeedUpdate = true or Three.js will ignore your changes.

 var camera, scene, renderer, geometry, material, mesh, curves = []; init(); animate(); /** Create the scene, camera, renderer */ function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 500; scene.add(camera); addCurve(); renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); } /** Add the initial bezier curve to the scene */ function addCurve() { testPoint = 0; curve = new THREE.CubicBezierCurve3( new THREE.Vector3( testPoint, 0, 0 ), new THREE.Vector3( -5, 150, 0 ), new THREE.Vector3( 20, 150, 0 ), new THREE.Vector3( 10, 0, 0 ) ); curveGeometry = new THREE.Geometry(); curveGeometry.vertices = curve.getPoints( 50 ); curveMaterial = new THREE.LineBasicMaterial( { color : 0xff0000 } ); curveLine = new THREE.Line( curveGeometry, curveMaterial ); scene.add(curveLine); // EDITED curves.push(curveLine); // Add curve to curves array curveLine.curve = curve; // Link curve object to this curveLine } /** On each frame render, remove the old line, create new curve, geometry and add the new line */ function updateCurve() { testPoint ++; // EDITED for (var i = 0, l = curves.length; i < l; i++) { var curveLine = curves[i]; // Update x value of v0 vector curveLine.curve.v0.x = testPoint; // Update vertices curveLine.geometry.vertices = curveLine.curve.getPoints( 50 ); // Let's three.js know that vertices are changed curveLine.geometry.verticesNeedUpdate = true; } } function animate() { requestAnimationFrame(animate); render(); } function render() { updateCurve(); renderer.render(scene, camera); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM