在 jsc3d 中围绕向上矢量旋转场景
Rotate scene about Up vector in jsc3d
我正在使用 jsc3d 在 canvas 上加载和显示一些 3d 对象。查看器已经有一个内置功能,允许通过拖动鼠标绕 Y 轴旋转 "view coordinates"(如果我错了请纠正我)。
通过一个经典的旋转矩阵进行旋转,最后将变换矩阵乘以这个旋转矩阵
关于 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 轴的旋转,如下图左侧所示。有没有办法围绕向上向量应用旋转以将其保持在初始位置,就像它出现在右侧一样?
我试过类似的东西:
var rotY = (x - viewer.mouseX) * 360 / viewer.canvas.height;
var rotMat = new JSC3D.Matrix3x4; // identity
rotMat.rotateAboutYAxis(rotY);
viewer.rotMatrix.multiply(rotMat);
但是没有效果
应该对我的旋转矩阵应用什么操作来实现关于 Up 向量的旋转?
这个3D库已经有一些内置的函数可以让场景绕X,Y,Z轴旋转,所以不需要为此实现新的矩阵运算,我们可以使用现有的函数rotateAboutXAyis, rotateAboutYAxis和 rotateAboutZAxis,它应用所需旋转角度的就地矩阵乘法(以度为单位)。
JSC3D 中的场景由 3x4 矩阵转换,其中旋转存储在每行的前 3 个值中。
应用场景旋转and/or平移后,应用后续关于Up向量的旋转,是计算关于任意轴的旋转的问题。
此处描述了如何解决此问题的非常清晰且具有指导意义的解释:http://ami.ektf.hu/uploads/papers/finalpdf/AMI_40_from175to186.pdf
- 将P 0 (x 0 ,y 0 ,z 0 )轴点平移到坐标系原点。
- 进行适当的旋转,使旋转轴与
z坐标轴.
- 绕z轴旋转角度θ
- 执行组合旋转变换的逆
- 执行反向翻译。
现在,很容易为此编写一个函数,因为我们使用了 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];
这将是最终结果:
我正在使用 jsc3d 在 canvas 上加载和显示一些 3d 对象。查看器已经有一个内置功能,允许通过拖动鼠标绕 Y 轴旋转 "view coordinates"(如果我错了请纠正我)。
通过一个经典的旋转矩阵进行旋转,最后将变换矩阵乘以这个旋转矩阵
关于 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 轴的旋转,如下图左侧所示。有没有办法围绕向上向量应用旋转以将其保持在初始位置,就像它出现在右侧一样?
我试过类似的东西:
var rotY = (x - viewer.mouseX) * 360 / viewer.canvas.height;
var rotMat = new JSC3D.Matrix3x4; // identity
rotMat.rotateAboutYAxis(rotY);
viewer.rotMatrix.multiply(rotMat);
但是没有效果
应该对我的旋转矩阵应用什么操作来实现关于 Up 向量的旋转?
这个3D库已经有一些内置的函数可以让场景绕X,Y,Z轴旋转,所以不需要为此实现新的矩阵运算,我们可以使用现有的函数rotateAboutXAyis, rotateAboutYAxis和 rotateAboutZAxis,它应用所需旋转角度的就地矩阵乘法(以度为单位)。
JSC3D 中的场景由 3x4 矩阵转换,其中旋转存储在每行的前 3 个值中。 应用场景旋转and/or平移后,应用后续关于Up向量的旋转,是计算关于任意轴的旋转的问题。
此处描述了如何解决此问题的非常清晰且具有指导意义的解释:http://ami.ektf.hu/uploads/papers/finalpdf/AMI_40_from175to186.pdf
- 将P 0 (x 0 ,y 0 ,z 0 )轴点平移到坐标系原点。
- 进行适当的旋转,使旋转轴与 z坐标轴.
- 绕z轴旋转角度θ
- 执行组合旋转变换的逆
- 执行反向翻译。
现在,很容易为此编写一个函数,因为我们使用了 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];
这将是最终结果: