0

我正在使用 jsc3d 在画布上加载和显示一些 3d 对象。查看器已经有一个内置功能,允许通过拖动鼠标围绕 Y 轴旋转“视图坐标”(如果我错了,请纠正我)。

旋转是通过一个经典的旋转矩阵进行的,最后将变换矩阵乘以这个旋转矩阵。

围绕 Y 轴的总位移的计算方式类似于围绕加载对象的整个场景的圆周运动:

JSC3D.Matrix3x4.prototype.rotateAboutYAxis = function(angle) {
    if(angle != 0) {
        angle *= Math.PI / 180;
        var c = Math.cos(angle);
        var s = Math.sin(angle);

        var m00 = c * this.m00 + s * this.m20;
        var m01 = c * this.m01 + s * this.m21;
        var m02 = c * this.m02 + s * this.m22;
        var m03 = c * this.m03 + s * this.m23;
        var m20 = c * this.m20 - s * this.m00;
        var m21 = c * this.m21 - s * this.m01;
        var m22 = c * this.m22 - s * this.m02;
        var m23 = c * this.m23 - s * this.m03;

        this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03;
        this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23;
    }
};

现在,拖动鼠标将在整个世界上应用围绕 Y 轴的旋转,如下图左侧。有没有一种方法可以围绕 Up 向量进行旋转以使其保持在初始位置,就像它出现在右侧一样?

在此处输入图像描述

我尝试过这样的事情:

var rotY = (x - viewer.mouseX) * 360 / viewer.canvas.height;       
var rotMat = new JSC3D.Matrix3x4; // identity
rotMat.rotateAboutYAxis(rotY);
viewer.rotMatrix.multiply(rotMat);

但它没有效果。

应该对我的旋转矩阵应用哪些操作以实现围绕向上向量的旋转?

示例:https ://jsfiddle.net/4xzjnnar/1/

4

1 回答 1

0

这个 3D 库已经内置了一些函数可以让场景围绕 X、Y 和 Z 轴旋转,所以不需要为此实现新的矩阵运算,我们可以使用现有的函数 rotateAboutXAyis、rotateAboutYAxis 和 rotateAboutZAxis,它们适用以度为单位的所需旋转角度的就地矩阵乘法。

JSC3D 中的场景由 3x4 矩阵转换,其中旋转存储在每行的前 3 个值中。在应用场景旋转和/或平移之后,应用围绕向上向量的后续旋转是计算围绕任意轴的旋转的问题。

此处描述了如何解决此问题的非常简洁和教学性的解释:http: //ami.ektf.hu/uploads/papers/finalpdf/AMI_40_from175to186.pdf

  1. 将 P 0 (x 0 ,y 0 ,z 0 ) 轴点平移到坐标系的原点。
  2. 执行适当的旋转以使旋转轴与 z 坐标轴重合。
  3. 绕 z 轴旋转角度 θ。
  4. 执行组合旋转变换的逆。
  5. 执行翻译的逆操作。

现在,为此编写一个函数很容易,因为我们使用了 JSC3D 中已有的函数(这里省略了翻译部分)。

JSC3D.Viewer.prototype.rotateAboutUpVector = function(angle) {
    angle %= 360;

    /* pitch, counter-clockwise rotation about the Y axis */

    var degX = this.rpy[0], degZ = this.rpy[2];
    this.rotMatrix.rotateAboutXAxis(-degX);
    this.rotMatrix.rotateAboutZAxis(-degZ);
    this.rotMatrix.rotateAboutYAxis(angle);
    this.rotMatrix.rotateAboutZAxis(degZ);
    this.rotMatrix.rotateAboutXAxis(degX);

}

因为上述所有函数都使用度数,所以我们需要从旋转矩阵(简化)中取回实际的欧拉角:

JSC3D.Viewer.prototype.calcRollPitchYaw = function() {
    var m = this.rotMatrix;
    var radians = 180 / Math.PI;

    var angleX = Math.atan2(-m.m12, m.m22) * radians;
    var angleY = Math.asin(m.m01) * radians;
    var angleZ = Math.atan2(-m.m01, m.m00) * radians;

    this.rpy[0] = angleX;
    this.rpy[1] = angleY;
    this.rpy[2] = angleZ;
}

这里棘手的部分是,我们总是需要取回当前的旋转角度,因为它们是由应用的旋转产生的,因此每次对场景应用旋转时,必须使用一个单独的函数来存储当前的欧拉角。

为此,我们可以使用一个非常简单的结构:

JSC3D.Viewer.prototype.rpy = [0, 0, 0];

这将是最终结果:

在此处输入图像描述

于 2015-07-24T12:28:17.080 回答