在jsc3d中旋转关于向上矢量的场景

时间:2015-06-22 11:19:52

标签: matrix rotation jsc3d

我使用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向量应用旋转以使其保持在初始位置,就像它出现在右侧一样?

enter image description here

我尝试过类似的东西:

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/

1 个答案:

答案 0 :(得分: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. 执行翻译的反向。
  6. 现在,它很容易编写一个函数,因为我们使用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];
    

    这将是最终结果:

    enter image description here