如何为插值制作动画

时间:2019-05-30 09:52:00

标签: javascript three.js interpolation

我正在Three.js中制作一个简单的多维数据集动画,但我被困住了。如何使动画到达1时停止播放,然后以另一种方式反复播放-1

"use strict";

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x404040, 1);
document.body.appendChild(renderer.domElement);

var clock = new THREE.Clock();
clock.start();
var t = 0;

var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshPhongMaterial({
    color: 0x008080,
    specular: 0xffffff,
});
var cube = new THREE.Mesh(geometry, material);
var light = new THREE.PointLight(0xffffff, 6, 40);
var alight = new THREE.AmbientLight(0xffffff);
scene.add(alight);
light.position.set(20, 20, 20);
scene.add(light);
cube.add(createAxes(1));
scene.add(cube);

scene.add(createAxes(5));
renderer.render(scene, camera);

var controls = new THREE.TrackballControls(camera);
controls.addEventListener('change', render);
animate();

function render() {
    renderer.render(scene, camera);
}

function animate() {
    var dt = clock.getDelta();
    t += dt;

    var v = THREE.Math.lerp(-1, 1, t);
    cube.position.x = v;

    render();
    requestAnimationFrame(animate);
    controls.update();
}

我尝试在animate()中使用循环来更改v1时的-1

var v = THREE.Math.lerp(-1, 1, t);

if (v > 1) {
    v = THREE.Math.lerp(1, -1, t);
}
if (v < -1) {
    clock.stop();
}
cube.position.x = v;

我只想让多维数据集来回摆动,但它会平稳地转到1,并立即压缩到-1。任何回答都将不胜感激。

1 个答案:

答案 0 :(得分:0)

最简单的解决方案是(如评论中所述)使用Math.sin()

cube.position.x = Math.sin(t);

但是,如果要实现从开始到结束再到向后的线性插值,则必须在当前相对位置(dir)旁边定义当前方向(t)。 :

var t = 0, dir = 1;

根据当前方向和.clamp到[0,1]范围的位置来计算新的相对位置:

var new_t = t + dt * dir;
t = THREE.Math.clamp(new_t, 0, 1);

当相对位置超出限制时,更改方向:

if (t != new_t)
    dir *= -1

功能animate

function animate() {
    var dt = clock.getDelta();
    var new_t = t + dt * dir;

    t = THREE.Math.clamp(new_t, 0, 1);
    if (t != new_t)
        dir *= -1

    var v = THREE.Math.lerp(-1, 1, t);
    cube.position.x = v;

    // [...]
}

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x404040, 1);
document.body.appendChild(renderer.domElement);

var clock = new THREE.Clock();
clock.start();
var t = 0, dir = 1;

var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshPhongMaterial({
    color: 0x008080,
    specular: 0xffffff,
});
var cube = new THREE.Mesh(geometry, material);
var light = new THREE.PointLight(0xffffff, 6, 40);
var alight = new THREE.AmbientLight(0xffffff);
light.position.set(20, 20, 20);
scene.add(alight);
scene.add(light);
cube.add(new THREE.AxesHelper());
scene.add(cube);
scene.add(new THREE.AxesHelper());
renderer.render(scene, camera);

var controls = new THREE.TrackballControls(camera);
controls.addEventListener('change', render);

window.onresize = function() {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
}

animate();

function render() {
    renderer.render(scene, camera);
}

function animate() {
    var dt = clock.getDelta();
    var new_t = t + dt * dir;
    
    t = THREE.Math.clamp(new_t, 0, 1);
    if (t != new_t)
        dir *= -1

    var v = THREE.Math.lerp(-1, 1, t);     
    cube.position.x = v;
    //cube.position.x = Math.sin(t);

    render();
    requestAnimationFrame(animate);
    controls.update();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/104/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>