javascript 使用轴和角度进行 3D 旋转
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3809788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
3D rotation with Axis & Angle
提问by Casey
I know 3D rotation is well documented on SO and many other sites, but despite reading countless explanations I still haven't figured out where I'm going wrong. My background is in art and design, not math and programming, and I'm never really certain if my angle of attack (no pun intended) is the right one. Rather than paste a patchwork of my dismal code, I'm including an image describing my problem. What I'd really like is a step-by-step worded breakdown of how to solve it. Pseudo code is useful, but I will learn more if someone will just aim me in the right direction or point out common pitfalls.
我知道 3D 旋转在 SO 和许多其他网站上都有很好的记录,但是尽管阅读了无数的解释,我仍然没有弄清楚我哪里出错了。我的背景是艺术和设计,而不是数学和编程,我从来不确定我的攻击角度(没有双关语)是否正确。我没有粘贴我那令人沮丧的代码的拼凑而成,而是包含了一张描述我的问题的图像。我真正想要的是如何解决它的逐步措辞细分。伪代码很有用,但如果有人将我瞄准正确的方向或指出常见的陷阱,我会学到更多。


Red = X-Axis, Green = Y-Axis, Blue = Z-Axis
红色 = X 轴,绿色 = Y 轴,蓝色 = Z 轴
Magenta vectors = origin --> some X,Y,Z point
洋红色矢量 = 原点 --> 一些 X、Y、Z 点
Magenta cube = average of the endpoints of the two magenta vectors (is there a better name for this?)
洋红色立方体 = 两个洋红色向量端点的平均值(有更好的名称吗?)
White vector = cross product of the two magenta vectors (extended for display, actual vector is normalized)
白色向量 = 两个品红色向量的叉积(扩展显示,实际向量归一化)
Cyan cube object = rotation fail
青色立方体对象 = 旋转失败
I've previously used Away3D and Papervision; in these libraries, applying Euler angles to an object's rotationX, rotationY, or rotationZ properties will rotate the object locally, as if it's at the origin regardless of its actual position. With Three.js, this is not the case. Modifying an object's rotation.x and rotation.y properties produces a bizarre effect where the object apparently tilts a bit on the Z axis. Even more confusing is that this happens when the object rests at the origin. I thought that maybe using Quaternion-->Matrix or Axis/Angle-->Matrix functions would solve my problem, but no dice. It seems there's a core concept I'm not getting.
我以前使用过 Away3D 和 Papervision;在这些库中,将欧拉角应用于对象的rotationX、rotationY 或rotationZ 属性将局部旋转对象,就好像它位于原点而不管其实际位置如何。使用 Three.js,情况并非如此。修改对象的 rotation.x 和 rotation.y 属性会产生一种奇怪的效果,其中对象在 Z 轴上明显倾斜了一点。更令人困惑的是,当物体停留在原点时会发生这种情况。我认为也许使用 Quaternion-->Matrix 或 Axis/Angle-->Matrix 函数可以解决我的问题,但没有骰子。似乎有一个我没有理解的核心概念。
Anyway, what I'd like to do is orient the cube to the cross product vector (white), so that the top of the cube is facing the direction of that vector. Then I'd like to rotate the cube along the same axis. The image I've attached shows the result of more hours than I'd like to admit trying to achieve this result. My code loosely looks like this:
无论如何,我想做的是将立方体定向到叉积向量(白色),以便立方体的顶部面向该向量的方向。然后我想沿同一轴旋转立方体。我附上的图片显示的结果比我想承认的试图达到这个结果的时间要长。我的代码大致如下所示:
axis = Vector3.cross(a, b)
axis.normalize()
angle = 45 * TO_RADIANS;
quat = AxisAngle2Quaternion(axis, angle)
rot = Quaternion2Matrix(quat)
cube.matrix = rot
Thanks in advance,
提前致谢,
Casey
凯西
Edit: Starting a bounty
编辑:开始赏金
Maybe I am misunderstanding how this is supposed to work. Here's another image:
也许我误解了这应该如何工作。这是另一张图片:


Am I incorrect in thinking that this magenta vector is the axis, and the orange arrows indicate rotation about this axis based on the angle? One way or another, I want to orient the cyan cube based on some directional vector and spin it. What am I doing wrong!?
我认为这个洋红色矢量是轴,橙色箭头表示基于角度围绕该轴的旋转是错误的吗?以一种或另一种方式,我想根据某个方向矢量确定青色立方体的方向并旋转它。我究竟做错了什么!?
采纳答案by Trochoid
Your approach sounds correct but you don't show what the a, b vectors are and the constant angle is, I'm guessing, just for testing. I did this before so I dug up my code and this is the math I found...
你的方法听起来是正确的,但你没有显示 a、b 向量是什么,恒定角度是什么,我猜,只是为了测试。我以前这样做过,所以我挖掘了我的代码,这是我发现的数学...
given:
originalVec = unit vector pointing up Y axis (direction of cube top/normal)
targetVec = white vector
给定:
originalVec = 指向 Y 轴的单位向量(立方体顶部/法线的方向)
targetVec = 白色向量
Now you want the axis and angle that will rotate originalVec to align with targetVec. The most direct axis of rotation is perpendicular to both input vectors, so take their cross product. That axis is not a unit vector so also normalise it. The angle to rotate (in radians) is the inverse-cosine of the dot-product.
现在,您希望将旋转 originalVec 的轴和角度与 targetVec 对齐。最直接的旋转轴垂直于两个输入向量,因此取它们的叉积。该轴不是单位向量,因此也对其进行归一化。旋转的角度(以弧度为单位)是点积的反余弦值。
axis = Vector3.cross(originalVec, targetVec)
axis.normalise
angle = inversecos(Vector3.dot(originalVec, targetVec))
quat = AxisAngle2Quaternion(axis, angle)
rot = Quaternion2Matrix(quat)
cube.matrix = rot
Instead of replacing the cube's matrix I think you want to compose it with the new transform...
而不是替换立方体的矩阵,我认为你想用新的变换来组合它......
cube.matrix.multiplyBy(rot)
...but I'm not 100% sure about that. Also, I've seen implementations where AxisAngle2Quaternion takes an angle in degrees. When the input vectors are parallel or opposite the axis is <0,0,0> so that should be tested for. If the cube rotates the wrong way then the cross-product vector parameters are in the wrong order, I never remember which and just try them both. hth.
……但我不是 100% 确定这一点。此外,我还看到了 AxisAngle2Quaternion 以度为单位取角度的实现。当输入向量平行或相反时,轴为 <0,0,0>,因此应进行测试。如果立方体旋转错误,则叉积向量参数的顺序错误,我不记得是哪个,只是尝试两个。嗯。
Edit
I've had a chance to play with Three.js and hacked one of the examples to orient a cube. Comments show where I added stuff and all the orienting math happens in alignCube().
Align and Spin example
Mousing up/down moves the target line. Mousing left/right spins on the line.
编辑
我有机会使用 Three.js 并破解了一个示例来定位立方体。评论显示了我添加内容的位置,所有定向数学都发生在 alignCube() 中。
对齐和旋转示例
上/下鼠标移动目标线。鼠标左/右旋转在线。
Scene objects in Three.js seem to all inherit from Object3D which has a autoUpdateMatrix property set true by default. This needs to be set false otherwise the updateMatrix function gets called which recalculates the matrix from the objects position, scale and rotation properties. Alternately you could assign a different updateMatrix function.
Three.js 中的场景对象似乎都继承自 Object3D,它的 autoUpdateMatrix 属性默认设置为 true。这需要设置为 false 否则会调用 updateMatrix 函数,它会根据对象的位置、缩放和旋转属性重新计算矩阵。或者,您可以分配不同的 updateMatrix 函数。
It'd be nice if Three.js had some documentation :)
如果 Three.js 有一些文档就好了 :)
回答by Casey
From Trochoid's example, here's the function that I use to achieve the alignment and spin from the second image:
从 Trochoid 的示例中,这是我用来实现第二张图像的对齐和旋转的函数:
//object, normalized direction vector, rotation in radians
function align(target, dir, rot) {
//Three.js uses a Y up coordinate system, so the cube inits with this vector
var up = new THREE.Vector3(0, 1, 0);
//euler angle between direction vector and up vector
var angle = Math.acos(up.dot(dir));
//cross product of the up vector and direction vector
var axis = new THREE.Vector3();
axis.cross(up, dir);
axis.normalize();
//rotation to aligns the target with the direction vector
var rotate = THREE.Matrix4.rotationAxisAngleMatrix(axis, angle);
//rotation around direction vector
var revolve = THREE.Matrix4.rotationAxisAngleMatrix(dir, rot);
//compose the rotations (order matters, can be done other ways)
revolve.multiplySelf(rotate);
//assign matrix (autoUpdateMatrix = false)
target.matrix = revolve;
}
回答by erikbwork
Because nobody has a really good solution, I can at least advice you on how to get closer.
因为没有人有真正好的解决方案,我至少可以建议你如何接近。
There are 3 possible problems and you have one of them:
有 3 种可能的问题,您有其中之一:
- The math is not right, or you don't understand it. (Should not be so much a problem here)
- Floating points arithmetics are always a problem for computers (Should also not be a problem, because it is a pretty basic one. If your framework can not deliver a solution, then the framework has no value at all for 3d programming)
- You don't use the framework right
- 数学不正确,或者你不明白。(这里应该问题不大)
- 浮点运算对于计算机来说一直是个问题(也应该不是问题,因为它是一个非常基本的问题。如果你的框架不能提供解决方案,那么该框架对于 3d 编程根本没有价值)
- 你没有正确使用框架
Because it is pretty likely that No. 3 is the case, try finding a mailing list or support forum or whatever for the framework and talk to the people there. They should be able to explain to you, what you do wrong with their framework. Then come back and post the solution here!
因为很可能是第 3 种情况,请尝试为该框架查找邮件列表或支持论坛或其他任何内容,并与那里的人交谈。他们应该能够向你解释你在他们的框架中做错了什么。然后回来在这里发布解决方案!

