首页 > 解决方案 > 使用 lineTo 和 curveTo 在 Three.js 中为线条制作动画

问题描述

我是一个three.js 新手,我来自Processing/p5.js(所以我对动画循环有点宠坏了)。我正在尝试创建类似这种简单的拉伸药丸形状的东西:

拉伸药丸形状

这是我从网上找到的一些东西拼凑而成的。我只有“O”形。我试图让变量 oHeight 成为导致 Math.sin 来回流动的变量。

我需要更新路径吗?还是bufferGeometry?还是三条路径?

抱歉,这段代码太乱了。刚开始!

        var camera, scene, renderer;
        var curve;
        var path;
        var oHeight = 0;
        var delta = 0;

        init();
        animate();

        function init() {
            camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 1000 );
            camera.position.z = 600;
            scene = new THREE.Scene();

            path = new THREE.Path();

            path.lineTo( 0, 0 );
            path.quadraticCurveTo( 0, 20, 20, 20 );
            path.lineTo( 40, 20 );
            path.quadraticCurveTo( 60,20, 60,0);
            path.lineTo(60,-40-oHeight);
            path.quadraticCurveTo( 60,-60-oHeight, 40,-60-oHeight);
            path.lineTo(20,-60-oHeight);
            path.quadraticCurveTo(0,-60,0,-40-oHeight);
            path.lineTo(0,0);

            var points = path.getPoints();

            var geometry = new THREE.BufferGeometry().setFromPoints( points );
            var material = new THREE.LineBasicMaterial( { color: 0xffffff } );

            curve = new THREE.Line( geometry, material );

            scene.add( curve );

            renderer = new THREE.WebGLRenderer( { antialias: true } );
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( window.innerWidth, window.innerHeight );
            document.body.appendChild( renderer.domElement );
        }

        function animate() {
            requestAnimationFrame( animate );

            delta +=.1;
            oHeight = Math.sin(delta)*20;
            line.needUpdate = true; //is this where I went wrong?

            renderer.render( scene, camera );
        }

标签: three.js

解决方案


您的代码中没有对象line,也没有从对象geometryoHeight. 只是一个临时对象,其中THREE.Path包含创建BufferGeoemtry. 请注意,最后的顶点geometry存储在 GPU 上的数组缓冲区中。

您必须在animate函数中创建路径并将其设置为BufferGeoemtry. 所以几何图形在每一帧中重新创建:

function animate() {
    requestAnimationFrame( animate );

    delta +=.1;
    oHeight = Math.sin(delta)*20;

    path = new THREE.Path();
    path.lineTo( 0, 0 );
    path.quadraticCurveTo( 0, 20, 20, 20 );
    path.lineTo( 40, 20 );
    path.quadraticCurveTo( 60,20, 60,0);
    path.lineTo(60,-40-oHeight);
    path.quadraticCurveTo( 60,-60-oHeight, 40,-60-oHeight);
    path.lineTo(20,-60-oHeight);
    path.quadraticCurveTo(0,-60-oHeight,0,-40-oHeight);
    path.lineTo(0,0);

    geometry.dispose();
    geometry.setFromPoints( path.getPoints() );

    renderer.render( scene, camera );
}

var camera, scene, renderer;
var curve;
var path;
var oHeight = 0;
var delta = 0;
var geometry;

init();
animate();

function init() {
    camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.z = 600;
    scene = new THREE.Scene();

    geometry = new THREE.BufferGeometry();
    var material = new THREE.LineBasicMaterial( { color: 0xffffff } );

    curve = new THREE.Line( geometry, material );

    scene.add( curve );

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    window.onresize = resize;
}

function animate() {
    requestAnimationFrame( animate );

    delta +=.1;
    oHeight = Math.sin(delta)*20;

    path = new THREE.Path();
    path.lineTo( 0, 0 );
    path.quadraticCurveTo( 0, 20, 20, 20 );
    path.lineTo( 40, 20 );
    path.quadraticCurveTo( 60,20, 60,0);
    path.lineTo(60,-40-oHeight);
    path.quadraticCurveTo( 60,-60-oHeight, 40,-60-oHeight);
    path.lineTo(20,-60-oHeight);
    path.quadraticCurveTo(0,-60-oHeight,0,-40-oHeight);
    path.lineTo(0,0);
    
    geometry.dispose();
    geometry.setFromPoints( path.getPoints() );
    
    renderer.render( scene, camera );
}

function resize() {   
    var aspect = window.innerWidth / window.innerHeight;
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = aspect;
    camera.updateProjectionMatrix();
}
<script src="https://threejs.org/build/three.min.js"></script>


推荐阅读