Kiel Mutschelknaus
Kiel Mutschelknaus

Reputation: 23

Animating a line in Three.js with lineTo and curveTo

I'm a three.js newbie and I'm coming from Processing/p5.js (so I'm a bit spoiled on animating loops). I'm trying to create something like this simple stretching pill shape:

Stretching pill shape

This is what I cobbled together from some things I found online. I just have the 'O' shape. I'm trying to get the variable oHeight to be the variable that causes the fluxing back and forth with a Math.sin.

Do I need to update the path? Or the bufferGeometry? Or the THREE.path?

Sorry this code is so messy. Just starting out!

        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 );
        }

Upvotes: 2

Views: 693

Answers (1)

Rabbid76
Rabbid76

Reputation: 210880

There is no object line in your code and there is no mystic reference from the object geometry to the oHeight. The THREE.Path is only a temporary object, which contains the information, that is needed to create the BufferGeoemtry. Note, at the end the vertices of the geometry are stored in an array buffer on the GPU.

You have to create the path in the animate function and to set it to the BufferGeoemtry. So the geometry is recreated in every frame:

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>

Upvotes: 1

Related Questions