如何在Three.JS中控制网格的偏航和俯仰?

时间:2013-06-10 16:40:06

标签: javascript 3d three.js

我有一个网格,其偏航和俯仰我希望由用户输入控制。我天真地尝试围绕z轴和y轴旋转网格,这似乎控制了偏航,但上下不稳定。

function checkKeys(keys) {
    if (keys.left) spaceship.rotation.z += .05;
    if (keys.right) spaceship.rotation.z -= .05;
    if (keys.up) spaceship.rotation.y += .05;
    if (keys.down) spaceship.rotation.y -= .05;
}

如何左/右控制飞机的偏航和上/下控制俯仰?

http://jsfiddle.net/trevordixon/d9BN9/2/

更新:我简化了Wagerfield提到的FlyControls.js,因此它只服从我的游戏手柄并处理旋转。这是我最终得到的结果(https://gist.github.com/trevordixon/5783321):

THREE.FlyControls = function(object) {
    this.object = object;

    // API

    this.movementSpeed = 1.0;
    this.rollSpeed = 0.005;

    // disable default target object behavior

    this.object.useQuaternion = true;

    // internals

    this.tmpQuaternion = new THREE.Quaternion();

    this.moveState = {up: 0, down: 0, left: 0, right: 0, forward: 0, back: 0, pitchUp: 0, pitchDown: 0, yawLeft: 0, yawRight: 0, rollLeft: 0, rollRight: 0};
    this.moveVector = new THREE.Vector3(0, 0, 0);
    this.rotationVector = new THREE.Vector3(0, 0, 0);

    this.handleEvent = function(event) {
        if (typeof this[event.type] == 'function') {
            this[event.type](event);
        }
    };

    this.update = function(delta) {
        this.moveState.yawLeft   = -gamepad.axes[2];
        this.moveState.pitchDown =   gamepad.axes[3];

        this.moveState.rollLeft = (Math.abs(gamepad.axes[0]) < 0.15 ? 0 : gamepad.axes[0]) ||
                              gamepad.buttons[15]/2;

        this.moveState.rollRight = (Math.abs(gamepad.axes[1]) < 0.15 ? 0 : gamepad.axes[1]) ||
                               gamepad.buttons[14]/2;

        this.updateRotationVector();

        var moveMult = delta * this.movementSpeed;
        var rotMult = delta * this.rollSpeed;

        this.object.translateX(this.moveVector.x * moveMult);
        this.object.translateY(this.moveVector.y * moveMult);
        this.object.translateZ(this.moveVector.z * moveMult);

        this.tmpQuaternion.set(this.rotationVector.x * rotMult, this.rotationVector.y * rotMult, this.rotationVector.z * rotMult, 1).normalize();
        this.object.quaternion.multiply(this.tmpQuaternion);

        // expose the rotation vector for convenience
        this.object.rotation.setEulerFromQuaternion(this.object.quaternion, this.object.eulerOrder);
    };

    this.updateRotationVector = function() {
        this.rotationVector.x = ( -this.moveState.pitchDown + this.moveState.pitchUp );
        this.rotationVector.y = ( -this.moveState.yawRight  + this.moveState.yawLeft );
        this.rotationVector.z = ( -this.moveState.rollRight + this.moveState.rollLeft );
    };

    function bind(scope, fn) {
        return function () {
            fn.apply( scope, arguments );
        };
    };

    this.updateRotationVector();
};

2 个答案:

答案 0 :(得分:2)

在这种情况下,偏航轴是向上轴或y轴,因此您需要旋转您的飞船几何体,使其水平开始于:

geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); 

然后你需要改变宇宙飞船的eulerOrder,因此偏航(Y)是第一个,而俯仰(X)是第二个:

spaceship.rotation.order = "YXZ"; // three.js r.65

然后你需要相应地调整你的密码。

three.js r.65

答案 1 :(得分:1)

您遇到的问题是由于计算旋转的方式并将其应用于three.js中的对象(通常是3D引擎)。对于每个旋转轴(x,y和amp; z),旋转矩阵乘以对象的矩阵(包含它的位置,比例和旋转)。

由于矩阵是非交换的;意思是A * B!= B * A,乘法的顺序很重要。默认情况下,这个'欧拉顺序'是X然后是Y然后是Z.这就是为什么你的Z旋转似乎有意义,但你的Y旋转不是你想象的那样。

没有恐惧,有一个解决方案!我假设您希望您的飞机以与此演示中的相机相同的方式旋转,其中相对于当前旋转应用旋转的每个附加变化。在3D Studio Max等3D程序中,这称为局部旋转:

http://threejs.org/examples/webgl_geometry_terrain.html

如果您检查此演示的来源,您会看到相机的控件是在第76行上创建的:

controls = new THREE.FirstPersonControls( camera );

还有FlyControls,它可能更适合你?

http://threejs.org/examples/misc_controls_fly.html

无论哪种方式,我都会开始使用这些现成的控件并在构造函数而不是相机中使用平面对象。

希望有所帮助。