模型查看矩阵 - C++, OpenGL
我成功地为相机实现了 LookAt 矩阵,因为有很多来源描述了它。
我一直在尝试将其从相机外观转换为模型外观。我似乎无法让它工作,并且我认为我对矩阵的构建方式有轻微的误解。我假设我不需要更改模型的翻译来查看某个点,因为它的位置应该保持不变。
首先,这是相关代码。 LookAtRadians 函数应该查看在与其平移相同的参考系中指定的点(即,位置 = 方向)。但是,存在一些问题,我将通过屏幕截图来展示。它不会检查 Direction.y() 是否为 1.0f 或 -1.0f,但这很简单。
void TransformMatrix3D::lookAtRadians(float atX, float atY, float atZ, float toZRadians)
{
Vector3D direction(atX - x(), atY - y(), atZ - z());
direction.normalize();
Vector3D up(0.0f, 1.0f, 0.0f);
Vector3D right(direction.crossProduct(up));
right.normalize();
up = direction.crossProduct(right);
mMatrix[0] = right.x();
mMatrix[4] = right.y();
mMatrix[8] = right.z();
mMatrix[1] = up.x();
mMatrix[5] = up.y();
mMatrix[9] = up.z();
mMatrix[2] = direction.x();
mMatrix[6] = direction.y();
mMatrix[10] = direction.z();
}
以下是叉积和标准化函数,以防它们不正确。
Vector3D Vector3D::crossProduct(const Vector3D& rightVector) const
{
const float NEW_X(y() * rightVector.z() - z() * rightVector.y());
const float NEW_Y(z() * rightVector.x() - x() * rightVector.z());
const float NEW_Z(x() * rightVector.y() - y() * rightVector.x());
return Vector3D(NEW_X, NEW_Y, NEW_Z);
}
void Vector3D::normalize()
{
float length(x() * x() + y() * y() + z() * z());
if(fabs(length) == 1.0f)
return;
length = 1.0f / sqrt(length);
moveTo(x() * length, y() * length, z() * length);
}
这是一些屏幕截图来描述我的问题。白色球体表示观察点。
我创建了一个沿 Z 轴平移 -10.0f 的立方体(这将设置 mMatrix[12]
、mMatrix[13]
和 mMatrix[14]
分别为 0.0f、0.0f、-10.0f。矩阵的其余部分是恒等式。我已检查情况是否如此),我将用它来演示问题。
屏幕截图: 无旋转
如果我仅沿 X 轴和 Y 轴移动 viewAt 点,lookAt 似乎才能正常工作。
屏幕截图:X 轴(Y 旋转)
屏幕截图: X 轴(Y 旋转) sstatic.net/2RZHW.jpg" rel="noreferrer">Y 轴(X 旋转)
但是,当我将两者结合起来时(即移动 LookAt 点,使 X 和 Y 都不是 0.0f),一些应用 Z 轴旋转,其中不应该发生,因为 UP x DIRECTION 应始终导致 RIGHT.y() 为 0.0f。 Z 旋转将使用 toZRadians (尚未实现)应用。
屏幕截图: 添加 Z 旋转
另外我发现,如果我将 viewAt 点向下移动 Y轴,模型仍然遵循 LookAt 点,但它实际上绕全局 X 轴旋转(或至少等效于该轴)。
屏幕截图: 全局 X 旋转
现在,当 LookAt 点移动到 -Z 时,模型具有正确的旋转Y 轴旋转,但 X 轴旋转相反。我此时检查了我的向量,发现 UP.y() 是负数,这应该是不可能的(它可以是 0.0f,但不是负数),因为 DIRECTION 和 RIGHT 应该始终以相同的方式缠绕(即从方向向右)。 UP.y() 可能为负的唯一情况是 RIGHT 实际上是 LEFT。
屏幕截图:反向 X 旋转
模型仍然围绕全局 X 轴旋转,就像在查看点时一样是+Z。
屏幕截图: 全局 X 旋转 (lookAt -Z)
正如我所提到的,这可能是对矩阵的工作方式,但也可能是别的东西。我环顾了好几天,似乎只能找到基于相机的 LookAt 功能。任何解释矩阵中包含的轴的来源都会导致本文中提供的代码。
I managed to implement a lookAt matrix for a camera successfully, since there are many sources describing it.
I've been trying to translate this from camera lookAt to model lookAt. I cannot seem to get it to work, and I assume I have a slight misunderstanding as to how a matrix is constructed. I am under the assumption that I don't need to change the translation for a model to look at a point, since it's position should remain unchanged.
First of all, here is the relevant code. The lookAtRadians function should look at the point specified in the same frame of referance as it's translation (i.e. at - position = direction). However, there are some issues, which I'll show with screenshots. It does not check for direction.y() being 1.0f or -1.0f, but that is trivial.
void TransformMatrix3D::lookAtRadians(float atX, float atY, float atZ, float toZRadians)
{
Vector3D direction(atX - x(), atY - y(), atZ - z());
direction.normalize();
Vector3D up(0.0f, 1.0f, 0.0f);
Vector3D right(direction.crossProduct(up));
right.normalize();
up = direction.crossProduct(right);
mMatrix[0] = right.x();
mMatrix[4] = right.y();
mMatrix[8] = right.z();
mMatrix[1] = up.x();
mMatrix[5] = up.y();
mMatrix[9] = up.z();
mMatrix[2] = direction.x();
mMatrix[6] = direction.y();
mMatrix[10] = direction.z();
}
Here are the cross product and normalize functions, in case they are incorrect.
Vector3D Vector3D::crossProduct(const Vector3D& rightVector) const
{
const float NEW_X(y() * rightVector.z() - z() * rightVector.y());
const float NEW_Y(z() * rightVector.x() - x() * rightVector.z());
const float NEW_Z(x() * rightVector.y() - y() * rightVector.x());
return Vector3D(NEW_X, NEW_Y, NEW_Z);
}
void Vector3D::normalize()
{
float length(x() * x() + y() * y() + z() * z());
if(fabs(length) == 1.0f)
return;
length = 1.0f / sqrt(length);
moveTo(x() * length, y() * length, z() * length);
}
Here are some screenshots to describe my issue. The white sphere indicates the lookAt point.
I created a cube translated -10.0f down the Z axis (this will set mMatrix[12]
, mMatrix[13]
and mMatrix[14]
to 0.0f, 0.0f, -10.0f respectively. The rest of the matrix is identity. I have checked that this is the case) which I will use for demonstrating the problems.
Screenshot: No rotation
If I move the lookAt point along just the X and Y axes, the lookAt seems to work correctly.
Screenshot: X axis (Y rotation)
Screenshot: Y axis (X rotation)
However, when I combine the two (i.e. move the lookAt point so both X and Y aren't 0.0f), some Z rotation is applied, which shouldn't happen since UP x DIRECTION should always result in the RIGHT.y() being 0.0f. The Z rotation will be applied using toZRadians
(which is not yet implemented).
Screenshot: Added Z rotation
Also I've found that if I then move the lookAt point down the Y axis, the model still follows the lookAt point, but it actually rotates around the global X axis (or equivilant to that, at least).
Screenshot: Global X rotation
Now, when the lookAt point moves to -Z, the model has the correct Y rotation, but it's X rotation is inverted. I checked my vectors at this point and I found that UP.y() is negative, which shouldn't be possible (it can be 0.0f, but not negative) since DIRECTION and RIGHT should always wind the same way (i.e. clockwise from DIRECTION to RIGHT). The only way UP.y() could possibly be negative is if RIGHT is actually LEFT.
Screenshot: Inverted X rotation
The model still rotates around the global X axis as it did when the lookAt point was +Z.
Screenshot: Global X rotation (lookAt -Z)
As I mentioned, this is likely a misunderstanding on the way matrices work, but it could be something else. I've looked around for several days and I can only seem to find camera based lookAt functions. Any sources explaining the axes contained in the matrix have lead to the code presented in this post.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
啊,我发现问题了。这么简单我就忽略了。
我的矩阵:
是在内存中定义的列专业。应该是:
而且效果很好。极其愚蠢的错误,我什至没有想到要检查一下。这也解释了轴上奇怪的反转。
Ah, I found the problem. So simple I overlooked it.
My matrix:
is defined column major in memory. It should be:
And that works perfectly. Extremely silly mistake, I didn't even think to check that. This also explains the wierd inversions in the axes.