沿曲线路径行进时旋转的物体

时间:2018-04-02 03:14:12

标签: three.js

我正在创建一个飞行动画,我有一些物体(飞机)沿曲线路径移动。我的问题是我的一些物体在沿着曲线路径行进时正在旋转。

Screenshot

function createPlane(image) {
    return new THREE.Mesh(
        new THREE.PlaneGeometry(5, 5),
        new THREE.MeshPhongMaterial({ map: new THREE.TextureLoader().load('textures/planes/' + image), side: THREE.DoubleSide, transparent: true })
    );
}

// this is how we get the line.vertices
// var curve = new THREE.Curve();
// line.vertices = curve.getPoints(50);

function animatePlane(plane, line, key) {

    if (key > 1) {
        key = 1;
    } else {
        key = Math.round(key * 100) / 100;
    }

    var curve = new THREE.CatmullRomCurve3(line.vertices), up = new THREE.Vector3(0, 1, 0), axis = new THREE.Vector3();
    var angle, duration = 300, position = curve.getPointAt(key), tangent = curve.getTangentAt(key).normalize();

    // rotation
    axis.crossVectors(up, tangent).normalize();
    angle = Math.acos(up.dot(tangent));

    plane.quaternion.setFromAxisAngle(axis, angle);

    // position
    new TWEEN.Tween(plane.position)
        .to({ x: position.x, y: position.y, z: position.z }, duration)   
        .onUpdate(function() {
            plane.position.set(this.x, this.y, this.z);
        })
        .onComplete(function() {

            if (key < 1) {
                key += 0.02;
            } else {
                key = 0;
            }

            animatePlane(plane, line, key);
        })
        .start();
}

// lines
var point = latLongToVector3(14.512274, 121.016508, radius, 0), // Philippines
    line1 = createCurveLine(createSphereArc(point, latLongToVector3(2.745364, 101.707079, radius, 0), 0.3), green, 'MALAYSIA');

animatePlane(createPlane('airplane.png'), line1, 0);

以上代码是我创建的方式以及沿曲线路径移动对象的方式。

请注意,曲线路径是动态创建的,从上面的屏幕截图是从菲律宾到其他国家,但它可能来自其他国家/地区。 曲线路径可能位于地球的不同部分,例如,来自澳大利亚(位于地球的底部)前往其他国家。

当我的飞机沿曲线路径移动时,我能做些什么来保持我的飞机直立吗?

1 个答案:

答案 0 :(得分:0)

我现在通过使用Frenet-Serret公式(TNB Frame)来实现它。 我使用Tangent,Normal和Binormal来创建矩阵(Matrix4),然后使用该矩阵通过使用.setRotationFromMatrix()来设置平面的旋转。

现在这是为飞机设置动画的代码:

function animatePlane(plane, line, key) {

        if (key > 1) {
            key = 1;
        } else {
            key = Math.round(key * 100) / 100;
        }

        var curve = new THREE.CatmullRomCurve3(line.vertices), matrix = new THREE.Matrix4();
        var duration = 300, position = curve.getPointAt(key);

        if ((key > 0) && (key < 1)) {

            var D = curve.getPointAt(1).normalize(), X = plane.position.clone().normalize();
            var T = position.clone().normalize(), B = curve.getTangentAt(key), N = new THREE.Vector3();

            N.crossVectors(D, T).normalize();

            matrix.set(
                N.x, B.x, T.x, X.x,
                N.y, B.y, T.y, X.y,
                N.z, B.z, T.z, X.z,
                0, 0, 0, 1
            );

            plane.setRotationFromMatrix(matrix);
        }   

        new TWEEN.Tween(plane.position)
            .to({ x: position.x, y: position.y, z: position.z }, duration)
            .onUpdate(function() {
                plane.position.set(this.x, this.y, this.z);
            })
            .onComplete(function() {

                if (key < 1) {
                    key += 0.02;
                } else {
                    key = 0;
                }

                animatePlane(plane, line, key);
            })
            .start();
    }

并添加此项以使平面位于曲线路径上方:

var plane1 = createPlane('airplane.png');

plane1.renderOrder = 1;
plane1.onBeforeRender = function(renderer) {
    renderer.clearDepth(); 
}

animatePlane(plane1, line1, 0);