简体   繁体   English

在ThreeJS中设置贝塞尔曲线的动画

[英]Animating a bezier curve in ThreeJS

I would like to animate a bezier curve in ThreeJS. 我想在ThreeJS中为bezier曲线制作动画。 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. 如果你运行下面的代码片段,你会看到每次帧渲染时我都在创建Bezier对象,Geometry和Line。 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. 标记已编辑的地点,并带有“ // EDITED ”评论。 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. 正如@WestLangley所说,尽量避免在动画循环中使用new关键字。
  • CubicBezierCurve3 has v0 , v1 , v2 and v3 attributes. CubicBezierCurve3具有v0v1v2v3属性。 Those are THREE.Vector3 `s that you provide from the beginning. 那些是你从一开始就提供的THREE.Vector3 .getPoints() uses them to return you vertices array. .getPoints()使用它们返回顶点数组。 So you can simply change them and no new keyword is needed. 因此,您只需更改它们,就不需要new关键字。 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. 因为你有一个THREE.Line - 你的几何只需要顶点。 After changing vertices you should set geometry.verticesNeedUpdate = true or Three.js will ignore your changes. 更改顶点后,您应设置geometry.verticesNeedUpdate = true或Three.js将忽略您的更改。

 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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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