【发布时间】:2015-07-07 20:32:19
【问题描述】:
我正在尝试在 opengl 中创建一个基于 uvn 四元数的相机,使用了下面列出的各种教程,并阅读了四元数和轴角旋转。我留下了一个我似乎无法修复的特殊错误。
基本上,相机似乎可以正常工作,直到相机从 +z 旋转大约 45 度,此时向上或向下倾斜相机似乎会使相机围绕其目标轴倾斜,从而转动向上的矢量。
当相机面向 -z 向上或向下倾斜时,会产生相反的错觉,向上向下倾斜,向下向上倾斜。
我已经看到其他实现建议使用非 uvn 系统,其中四元数被累积成一个,它将当前方向描述为从某个任意起始角度的增量。这听起来不错,但我似乎无法确切地知道我将如何实现它,特别是从它到视图矩阵的转换。
在其他地方,我读到关于将旋转分成两个分别代表偏航和俯仰的四元数,但我不相信这是问题的原因,因为在这种情况下,如果我错了,请纠正我,但我的理解是不是你应用两次旋转的顺序无关紧要。
相关源代码片段:
四元数运算
Quaternion<TValue> conjugate() const{
return Quaternion({ { -m_values[X], -m_values[Y], -m_values[Z], m_values[W] } });
};
Quaternion<TValue>& operator*=(const Quaternion<TValue>& rhs) {
TValue x, y, z, w;
w = rhs[W] * m_values[W] - rhs[X] * m_values[X] - rhs[Y] * m_values[Y] - rhs[Z] * m_values[Z];
x = rhs[W] * m_values[X] + rhs[X] * m_values[W] - rhs[Y] * m_values[Z] + rhs[Z] * m_values[Y];
y = rhs[W] * m_values[Y] + rhs[X] * m_values[Z] + rhs[Y] * m_values[W] - rhs[Z] * m_values[X];
z = rhs[W] * m_values[Z] - rhs[X] * m_values[Y] + rhs[Y] * m_values[X] + rhs[Z] * m_values[W];
m_values[X] = x;
m_values[Y] = y;
m_values[Z] = z;
m_values[W] = w;
return *this;
};
static Quaternion<TValue> rotation(Vector<3, TValue> axis, TValue angle){
float x, y, z, w;
TValue halfTheta = angle / 2.0f;
TValue sinHalfTheta = sin(halfTheta);
return Quaternion<TValue>({ { axis[X] * sinHalfTheta, axis[Y] * sinHalfTheta, axis[Z] * sinHalfTheta, cos(halfTheta) } });
};
矢量旋转运算
Vector<dimensions, TValue> rotate(const Vector<3, TValue> axis, float angle){
Quaternion<TValue> R = Quaternion<TValue>::rotation(axis, angle);
Quaternion<TValue> V = (*this);
Vector<dimensions, TValue> result = R * V * R.conjugate();
return result;
}
相机方法
Camera::Camera(Vector<2, int> windowSize, float fov, float near, float far):
m_uvn(Matrix<4, float>::identity()),
m_translation(Matrix<4, float>::identity()),
m_ar(windowSize[Dimensions::X] / (float)windowSize[Dimensions::Y]),
m_fov(fov),
m_near(near),
m_far(far),
m_position(),
m_forward({ { 0, 0, 1 } }),
m_up({ { 0, 1, 0 } })
{
setViewMatrix(Matrix<4, float>::identity());
setProjectionMatrix(Matrix<4, float>::perspective(m_ar, m_near, m_far, m_fov));
};
Matrix<4, float> Camera::getVPMatrix() const{
return m_vp;
};
const Vector<3, float> Camera::globalY = Vector<3, float>({ { 0, 1, 0 } });
void Camera::setProjectionMatrix(const Matrix<4, float> p){
m_projection = p;
m_vp = m_projection * m_view;
};
void Camera::setViewMatrix(const Matrix<4, float> v){
m_view = v;
m_vp = m_projection * m_view;
};
void Camera::setTranslationMatrix(const Matrix<4, float> t){
m_translation = t;
setViewMatrix(m_uvn * m_translation);
}
void Camera::setPosition(Vector<3, float> position){
if (position != m_position){
m_position = position;
setTranslationMatrix(Matrix<4, float>::translation(-position));
}
};
void Camera::moveForward(float ammount){
setPosition(m_position + (m_forward * ammount));
}
void Camera::moveRight(float ammount){
setPosition(m_position + (getRight() * ammount));
}
void Camera::moveUp(float ammount){
setPosition(m_position + (m_up * ammount));
}
void Camera::setLookAt(Vector<3, float> target, Vector<3, float> up){
Vector<3, float> newUp = up.normalize();
Vector<3, float> newForward = target.normalize();
if (newUp != m_up || newForward != m_forward){
m_up = newUp;
m_forward = newForward;
Vector<3, float> newLeft = getLeft();
m_up = newLeft * m_forward;
m_uvn = generateUVN();
setViewMatrix(m_uvn * m_translation);
}
};
void Camera::rotateX(float angle){
Vector<3, float> hAxis = (globalY * m_forward).normalize();
m_forward = m_forward.rotate(hAxis, angle).normalize();
m_up = (m_forward * hAxis).normalize();
m_uvn = generateUVN();
setViewMatrix(m_translation * m_uvn);
}
void Camera::rotateY(float angle){
Vector<3, float> hAxis = (globalY * m_forward).normalize();
m_forward = m_forward.rotate(globalY, angle).normalize();
m_up = (m_forward * hAxis).normalize();
m_uvn = generateUVN();
setViewMatrix(m_translation * m_uvn);
}
Vector<3, float> Camera::getRight(){
return (m_forward * m_up).normalize();
}
Vector <3, float> Camera::getLeft(){
return (m_up * m_forward).normalize();
}
};
我猜测问题出在我对四元数的实现或我使用它的方式上,但由于系统的复杂性,我似乎无法进一步确定问题所在。由于遇到了奇怪的错误,我不确定我尝试实现相机的方式是否有问题?
教程
- https://www.youtube.com/watch?v=1Aw1PDu33PI
- http://www.gamedev.net/page/resources/_/technical/math-and-physics/a-simple-quaternion-based-camera-r1997
四元数/向量数学
【问题讨论】:
-
我认为最好的办法是分解你的函数过程——尝试编写数学过程与代码的 1:1 映射,并将文档与数学进行比较。
-
这个问题需要一个太长的答案(据我所知 - 我不能因为所有的代码)。您应该提供 stackoverflow.com/help/mcve 而不是您的整个实现。尝试确定错误,然后在此处寻求帮助。
标签: c++ opengl camera quaternions