【发布时间】:2017-02-08 12:28:42
【问题描述】:
我的目标是允许用户上传 3D 模型并使用他们的网络浏览器定位它们。为此,我使用的是 BabylonJS - 并且工作正常。在那之后,我希望我的用户能够在本地应用程序中查看相同的模型,并且使用 Web 浏览器设置相同的位置。我用于本机应用程序的框架是 OpenSceneGraph (OSG)。我遇到的问题是我无法让旋转正常工作,以便 OpenSceneGraph 正确反映 BabylonJS 中发生的事情。
我在 BabylonJS 中使用欧拉角 - 因为它们很容易让网站用户理解(例如,围绕 X 轴旋转 90 度,围绕 Y 轴旋转 180 度,围绕 Z 轴旋转 0 度;例如 model.rotation = 新 BABYLON.Vec3(90,180,0))。然而,OSG 使用 OpenGL glrotate() 函数,该函数需要旋转轴和旋转角度。为此,我使用 BabylonJS 从欧拉角创建四元数;然后使用我根据此页面上的 Java 示例编写的函数:
http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
function getAxisAngle(){
var q = BABYLON.Quaternion.RotationYawPitchRoll(m.rotation.y, m.rotation.x, m.rotation.z),s,r={};
/*Convert quaternion to axis+angle*/
if(q.w > 1){
q = q.normalise();
}
r.angle = BABYLON.Tools.ToDegrees(2 * Math.acos(q.w));
s = Math.sqrt(1-q.w*q.w);
if(s < 0.001){
r.ax = q.x;
r.ay = q.y;
r.az = q.z;
}else{
r.ax = q.x / s;
r.ay = q.y / s;
r.az = q.z / s;
}
return r;
}
我意识到 BJS 和 OSG 的根本区别在于 BJS 是左手坐标系; OSG 是右撇子;所以我通过将面绕线设置为顺时针来制作左手 OSG;并将模型的 z 轴缩放 -1。
如果我一次隔离 1 个轴,它在基本级别上工作;例如如果我只绕 y 轴旋转;并且不要围绕任何其他轴旋转 - 它看起来很好。但是,如果我尝试同时组合两个或三个欧拉角;我无法让它在 OSG 中看起来一样。
我了解到不推荐使用欧拉角;部分原因是旋转应用于每个轴的顺序很重要。这是可能的原因吗?
【问题讨论】:
-
我猜,因为您在一端使用四元数并在另一端使用欧拉角,所以您熟悉由于万向节锁定而使用四元数与欧拉角之间的优势差异。如果您的应用程序使用欧拉角在多个旋转轴上进行旋转并且发生万向节锁定,那么您的旋转将停止工作。如果您更喜欢继续使用欧拉角在您的轴上进行旋转,那么您需要将它们限制在它们之间以防止万向节锁定,例如 [-89.99, 89.99]。 (...继续)
-
(...续) 云台锁定的原因是 90 度或 PI/4 为直角或正交。 Sine (90) or Sine (PI/4) = 1, Cosine(90) or Cosine(PI/4) = 0 and since Tangent = Sine / Cosine here you Tangent is undefined because of Division by 0. 所以当你旋转一个X - 轴上的对象由 90 然后由 Y 或 Z 由 90 或 -90 发生的是这两个轴变得互锁,并且当您从两个锁定的轴中的任何一个再次旋转时;该函数无法确定要旋转哪个轴。 (...继续)
-
(...继续)您可以查看此视频以清楚地了解四元数,可能不是数学上的,但至少是视觉上的。 youtube.com/watch?v=zc8b2Jo7mno
-
@Francis Cugler 你应该把它作为一个答案。
-
是的,我熟悉万向节锁定的概念以及四元数在这方面的优越性。实际上我在一端使用四元数和欧拉,另一端使用轴+角度。我只是使用四元数作为一种交换格式,根据欧拉角计算轴+角度旋转。
标签: opengl 3d openscenegraph babylonjs