【发布时间】:2014-03-07 03:59:21
【问题描述】:
所以,我正在编写一个使用 SSE 内在函数的数学库,以便与我的 OpenGL 应用程序一起使用。现在我正在实现一些更重要的功能,比如lookAt,使用glm 库来检查正确性,但由于某种原因,我的lookAt 实现不能正常工作。
这里是源代码:
inline void lookAt(__m128 position, __m128 target, __m128 up)
{
/* Get the target vector relative to the camera position */
__m128 t = vec4::normalize3(_mm_sub_ps(target, position));
__m128 u = vec4::normalize3(up);
/* Get the right vector by crossing target and up. */
__m128 r = vec4::normalize3(vec4::cross(t, u));
/* Correct the up vector by crossing right and target. */
u = vec4::cross(r, t);
/* Negate the target vector. */
t = _mm_sub_ps(_mm_setzero_ps(), t);
/* Treat the right, up, and target vector as a matrix, and transpose it. */
/* Conveniently, this also sets the w component of all four to 0.0f */
_MM_TRANSPOSE4_PS(r, u, t, _mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f));
vec4 pos = _mm_sub_ps(_mm_setzero_ps(), position);
pos.w = 1.0f;
/* Multiply our matrix by the transposed vectors. */
mat4 temp;
temp.col0 = r;
temp.col1 = u;
temp.col2 = t;
temp.col3 = _mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f);
multiply(temp);
translate(pos);
}
我的矩阵是列优先的,内部存储为“__m128 col0, col1, col2, col3;”。
我是在阅读了 gluLookAt 的手册页 Here 后制作的。一旦我意识到右向量、上向量和目标向量看起来非常像行优先矩阵,我就可以很简单地将它们转置,这样我就可以将它们分配给旋转矩阵。
normalize3 的代码,如果有帮助的话:
inline static __m128 normalize3(const __m128& vec)
{
__m128 v = _mm_mul_ps(vec, vec);
v = _mm_add_ps(
_mm_add_ps(
_mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)),
_mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1))),
_mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)));
return _mm_mul_ps(vec, _mm_rsqrt_ps(v));
}
它通过忽略向量的 w 分量节省了几次调用。
我做错了什么?
这是一些示例输出。使用 position(5.0, 5.0, 0.0), target(10.0, 20.0, 55.0) 和 up (0.0, 1.0, 0.0),我得到:
来自 GLM:
- [-0.9959] [ 0.0000] [ 0.0905] [ 4.9795]
- [-0.0237] [ 0.9650] [-0.2610] [-4.7065]
- [-0.0874] [-0.2621] [-0.9611] [1.7474]
- [0.0000][0.0000][0.0000][1.0000]
从我的lookAt():
- [-0.9959] [ 0.0000] [ 0.0905] [-5.0000]
- [-0.0237] [ 0.9651] [-0.2610] [-5.0000]
- [-0.0874] [-0.2621] [-0.9611] [0.0000]
- [0.0000][0.0000][0.0000][1.0000]
似乎唯一的区别在于第三列,但老实说,我不确定两者中哪一个是正确的。我倾向于说 GLM 是正确的,因为它被设计为与 glu 版本相同。
编辑: 我刚刚发现了一些有趣的事情。如果我调用“translate(pos);”在调用“multiply(temp);”之前,我得到的矩阵与 glm 的完全相同。哪个是对的?根据 gluLookAt 上的 OpenGL 手册页,这(以及 glm)正在倒退。我是以前做对了,还是现在做对了?
【问题讨论】:
-
能否包含实际的输出矩阵?这是调试此类内容的最佳起点;使用
gluLookAt (...)的输出作为参考。 -
-
是的,我确实需要修复它,但在这种情况下,这并不重要,因为 _MM_TRANSPOSE4_PS 无论如何都会用 0 替换 w 分量。
-
在尝试了一些不同的输出后,我的版本与应有的版本相差 0.000243。这只是舍入错误的情况吗?
-
问题可能出在
_mm_rsqrt_ps(v)内在函数中。不够准确。