找到一个 Vector3 相对于另一个的 Axis/Angle
Find Axis/Angle of one Vector3 relative to another
这似乎是一项简单且有据可查的任务。
我有两个代表模型位置的 Vector3 对象。
我希望指向位于一个 Vector3 位置的对象,以便它查看另一个 Vector3 位置。
最初我查看了一些来源,例如;
http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/
这似乎记录了寻找角度的点积和轴的叉积的方法。
查看四元数源代码 "setFromCross" 似乎为我做了这个。
所以我尝试了以下代码;
Vector3 thisPoint = this.transState.position.cpy();
Vector3 targetPoint = target.transState.position.cpy();
targetPoint.nor();
thisPoint.nor();
Quaternion result = new Quaternion();
result.setFromCross(targetPoint,thisPoint);
这看起来很简单但没有用 - 显然指向了错误的方向。
然后我尝试手动实现它;
float theirDotProduct = thisPoint.dot(targetPoint);
float angle = (float) Math.acos(theirDotProduct);
Vector3 theirCrossProduct = thisPoint.crs(targetPoint);
Vector3 axis = theirCrossProduct.nor();
//now make a Quaternion from it and return
Quaternion result = new Quaternion();
result.setFromAxisRad(axis, angle);
也没有用,再次指出错误的方向(并且不是偏离 90 度或固定量的任何东西,方向和矢量之间的关系似乎是错误的)
作为参考,我正在使用一个系统,我的模型将它们的位置和旋转存储为 vector3s 和 Quaterions - 为了动画,我只在最后一步转换为矩阵。
用于获取该 Quaterion 并设置模型旋转的确切代码是;
/** lookat the target models vector3 location (currently doesn't work) **/
public void lookAt(AnimatableModelInstance target){
Quaternion angle = getAngleTo(target);
setToRotation(angle);
}
/*** Set the rotation. If doing a more complex change make a PosRotScale and call setTransform **/
public void setToRotation(Quaternion angle) {
transState.rotation.set(angle);
sycnTransform();
}
public void sycnTransform() {
super.transform.set(transState.position, transState.rotation, transState.scale);
}
这似乎适用于我正在做的所有其他旋转动画,所以我认为错误不在那个区域。
我猜这是我在这里遗漏的一些基本步骤或概念。
谢谢,
-托马斯
我不熟悉 libgdx。我的回答没有帮助或明显错误,也许我可以抓住这个 peer pressure 徽章。
好像对计算的角度有误解。你说你存储的是对象的位置。然后,您正在计算点积
float theirDotProduct = thisPoint.dot(targetPoint);
但是,您根据此点积计算的角度与将一个对象沿另一个方向对齐所需的角度无关。您在那里计算的角度基本上是 从原点开始并通过对象位置的线之间的角度 (也如您链接到的网站上的图像所示) .
我假设有一个对象的默认方向,旋转角度为零,并且对象 "points along the x-axis",例如。然后,为了对齐这样一个对象,使其 "points into the direction of another object",您必须按如下方式设置此对象的方向:
您必须计算对象之间的差异 - 就像在对象之间画一条线一样。然后,您可以计算这条线与 x 轴之间的角度。
这是旋转对象 A 使其指向对象 B 所需的角度。
旋转的轴是通过叉积计算的,但再次不是在对象的位置之间,而是在对象之间x 轴和对象位置的 差异。
代码,涉及一些关于 libgdx 用法的猜测,因此大致如下所示:
Vector3 thisPoint = ...;
Vector3 targetPoint = ...;
Vector3 difference = targetPoint.sub(thisPoint);
if (difference.len() < someSmallEpsilon)
{
// Objects are at the same location - can't
// sensibly compute a direction to look at
return;
}
Vector3 direction = difference.nor()
Vector3 xAxis = new Vector3(1,0,0);
float dotProduct = xAxis.dot(direction);
float angle = (float) Math.acos(dotProduct);
if (angle < someSmallEpsilon)
{
// Angle is already right. Nothing to do
return;
}
Vector3 axis = xAxis.crs(direction).nor();
Quaternion result = new Quaternion();
result.setFromAxisRad(axis, angle);
(不要把我固定在标志上——可能是角度(或轴)可能必须取反——但这应该是基本方法)
两个地点之间没有 axis/angle 这样的东西。计算两个向量的旋转只有在它们具有相同的位置(原点)时才有用。
请记住,矢量不代表位置,而是代表如何从原点到达特定位置(尽管在您的情况下这实际上可能是同一件事,但在数学上却非常不同)。您可能已经尝试使用它,因为您正在规范化向量(这在您的代码中实际上删除了相当多的重要信息)。
计算位置之间的角度将使您获得这些位置之间相对于原点(位置 0,0,0)的旋转。换句话说:它会让你旋转 thisPoint
矢量应该旋转 大约 0,0,0 以匹配 方向 (不是 targetPoint
的 长度 )。注意 direction 和 length 的使用,这是表达同一事物的另一种方式。例如。 x:5,y:0,z:0 的向量方向为 x:1,y:0,z:0,长度为 5.
在您的情况下,您需要 targetPoint
的向量(尤其是 方向 ,但不需要 长度 )相对于 thisPoint
。或者换句话说:如果您从 thisPoint
开始,您应该朝哪个方向到达 targetPoint
。这可以通过减去向量然后对结果进行归一化来轻松计算。需要规范化以删除 length(将其设置为 1),因此我们只保留 direction.
Vector3 direction = new Vector3();
direction.set(targetPoint).sub(thisPoint).nor();
现在我们有了您希望模型看到的方向。要计算旋转,我们首先需要知道它在未旋转时注视的位置。这显然取决于您的模型及其建模方式。假设它的基向量(未旋转的方向)是Vector3.X
,那么你可以使用:
result.setFromCross(Vector3.X,t direction);
这似乎是一项简单且有据可查的任务。 我有两个代表模型位置的 Vector3 对象。
我希望指向位于一个 Vector3 位置的对象,以便它查看另一个 Vector3 位置。
最初我查看了一些来源,例如; http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/
这似乎记录了寻找角度的点积和轴的叉积的方法。
查看四元数源代码 "setFromCross" 似乎为我做了这个。 所以我尝试了以下代码;
Vector3 thisPoint = this.transState.position.cpy();
Vector3 targetPoint = target.transState.position.cpy();
targetPoint.nor();
thisPoint.nor();
Quaternion result = new Quaternion();
result.setFromCross(targetPoint,thisPoint);
这看起来很简单但没有用 - 显然指向了错误的方向。 然后我尝试手动实现它;
float theirDotProduct = thisPoint.dot(targetPoint);
float angle = (float) Math.acos(theirDotProduct);
Vector3 theirCrossProduct = thisPoint.crs(targetPoint);
Vector3 axis = theirCrossProduct.nor();
//now make a Quaternion from it and return
Quaternion result = new Quaternion();
result.setFromAxisRad(axis, angle);
也没有用,再次指出错误的方向(并且不是偏离 90 度或固定量的任何东西,方向和矢量之间的关系似乎是错误的)
作为参考,我正在使用一个系统,我的模型将它们的位置和旋转存储为 vector3s 和 Quaterions - 为了动画,我只在最后一步转换为矩阵。 用于获取该 Quaterion 并设置模型旋转的确切代码是;
/** lookat the target models vector3 location (currently doesn't work) **/
public void lookAt(AnimatableModelInstance target){
Quaternion angle = getAngleTo(target);
setToRotation(angle);
}
/*** Set the rotation. If doing a more complex change make a PosRotScale and call setTransform **/
public void setToRotation(Quaternion angle) {
transState.rotation.set(angle);
sycnTransform();
}
public void sycnTransform() {
super.transform.set(transState.position, transState.rotation, transState.scale);
}
这似乎适用于我正在做的所有其他旋转动画,所以我认为错误不在那个区域。
我猜这是我在这里遗漏的一些基本步骤或概念。
谢谢, -托马斯
我不熟悉 libgdx。我的回答没有帮助或明显错误,也许我可以抓住这个 peer pressure 徽章。
好像对计算的角度有误解。你说你存储的是对象的位置。然后,您正在计算点积
float theirDotProduct = thisPoint.dot(targetPoint);
但是,您根据此点积计算的角度与将一个对象沿另一个方向对齐所需的角度无关。您在那里计算的角度基本上是 从原点开始并通过对象位置的线之间的角度 (也如您链接到的网站上的图像所示) .
我假设有一个对象的默认方向,旋转角度为零,并且对象 "points along the x-axis",例如。然后,为了对齐这样一个对象,使其 "points into the direction of another object",您必须按如下方式设置此对象的方向:
您必须计算对象之间的差异 - 就像在对象之间画一条线一样。然后,您可以计算这条线与 x 轴之间的角度。
这是旋转对象 A 使其指向对象 B 所需的角度。
旋转的轴是通过叉积计算的,但再次不是在对象的位置之间,而是在对象之间x 轴和对象位置的 差异。
代码,涉及一些关于 libgdx 用法的猜测,因此大致如下所示:
Vector3 thisPoint = ...;
Vector3 targetPoint = ...;
Vector3 difference = targetPoint.sub(thisPoint);
if (difference.len() < someSmallEpsilon)
{
// Objects are at the same location - can't
// sensibly compute a direction to look at
return;
}
Vector3 direction = difference.nor()
Vector3 xAxis = new Vector3(1,0,0);
float dotProduct = xAxis.dot(direction);
float angle = (float) Math.acos(dotProduct);
if (angle < someSmallEpsilon)
{
// Angle is already right. Nothing to do
return;
}
Vector3 axis = xAxis.crs(direction).nor();
Quaternion result = new Quaternion();
result.setFromAxisRad(axis, angle);
(不要把我固定在标志上——可能是角度(或轴)可能必须取反——但这应该是基本方法)
两个地点之间没有 axis/angle 这样的东西。计算两个向量的旋转只有在它们具有相同的位置(原点)时才有用。
请记住,矢量不代表位置,而是代表如何从原点到达特定位置(尽管在您的情况下这实际上可能是同一件事,但在数学上却非常不同)。您可能已经尝试使用它,因为您正在规范化向量(这在您的代码中实际上删除了相当多的重要信息)。
计算位置之间的角度将使您获得这些位置之间相对于原点(位置 0,0,0)的旋转。换句话说:它会让你旋转 thisPoint
矢量应该旋转 大约 0,0,0 以匹配 方向 (不是 targetPoint
的 长度 )。注意 direction 和 length 的使用,这是表达同一事物的另一种方式。例如。 x:5,y:0,z:0 的向量方向为 x:1,y:0,z:0,长度为 5.
在您的情况下,您需要 targetPoint
的向量(尤其是 方向 ,但不需要 长度 )相对于 thisPoint
。或者换句话说:如果您从 thisPoint
开始,您应该朝哪个方向到达 targetPoint
。这可以通过减去向量然后对结果进行归一化来轻松计算。需要规范化以删除 length(将其设置为 1),因此我们只保留 direction.
Vector3 direction = new Vector3();
direction.set(targetPoint).sub(thisPoint).nor();
现在我们有了您希望模型看到的方向。要计算旋转,我们首先需要知道它在未旋转时注视的位置。这显然取决于您的模型及其建模方式。假设它的基向量(未旋转的方向)是Vector3.X
,那么你可以使用:
result.setFromCross(Vector3.X,t direction);