我在OpenGL中实现轨迹球旋转时遇到了问题。当我使用轨迹球旋转将我的立方体向右沿着X轴旋转90度(在屏幕上从左向右拖动鼠标),然后尝试通过将鼠标从屏幕顶部向底部拖动来旋转它,我希望立方体沿着我的视角的y轴旋转。但是,在旋转后,它沿着自己的y轴旋转,从我的视角侧面旋转。
有人能告诉我可能做错了什么吗?
我在OpenGL中实现轨迹球旋转时遇到了问题。当我使用轨迹球旋转将我的立方体向右沿着X轴旋转90度(在屏幕上从左向右拖动鼠标),然后尝试通过将鼠标从屏幕顶部向底部拖动来旋转它,我希望立方体沿着我的视角的y轴旋转。但是,在旋转后,它沿着自己的y轴旋转,从我的视角侧面旋转。
有人能告诉我可能做错了什么吗?
这是一个非常古老的问题,但我恰好遇到了完全相同的问题,因为我正在尝试从learnopengl.com调整相机代码以适应Arcball模型...
重要的是,我不想转向使用四元数,因为任何使用四元数实现的操作也可以使用标准的线性代数来实现。
我找到的解决方案是将弧球坐标系转换为相机坐标系(就像弧球和相机一起旋转一样)。
我还使用Rodrigues公式旋转了相机的位置、前向和上向量,然后使用glm:LookAt返回最终的ViewMatrix(即传递到顶点着色器中的Matrix)。
目前,我有一个快速而不太规范的解决方案,如下所示:
// Processes input received from a mouse input system.
void ProcessMouseMovement(glm::vec2 prevMouse, glm::vec2 curMouse)
{
glm::vec3 p1 = screen_to_arcball( curMouse );
glm::vec3 p2 = screen_to_arcball( prevMouse );
// Rotate arcball to camera coordinates
p1 = glm::vec3( glm::inverse(ViewMatrix) * glm::vec4(p1, 0.0));
p2 = glm::vec3( glm::inverse(ViewMatrix) * glm::vec4(p2, 0.0));
glm::vec3 axis = glm::cross(p1, p2);
float angle = std::acos(glm::dot(p1,p2));
if ( angle > 0.001f)
{
// Rotate
Position = rotate_axis_angle(Position, axis, angle);
Front = rotate_axis_angle(Front, axis, angle);
Up = rotate_axis_angle(Up, axis, angle);
ViewMatrix = glm::lookAt(Position, Position + Front, Up);
}
}
// Get Arcball coordinates from screen
glm::vec3 screen_to_arcball(const glm::vec2 &p)
{
const float dist = glm::dot(p, p);
if (dist < 0.999f)
{
// If we're on/in the sphere return the point on it
return glm::vec3(p.x, p.y, std::sqrt(1.f - dist));
}
else
{
// otherwise we project the point onto the sphere
const glm::vec2 proj = glm::normalize(p);
return glm::vec3(proj.x, proj.y, 0.f);
}
}
// Rotate vector given (angle,axis) using Rodrigues' formula
glm::vec3 rotate_axis_angle(glm:: vec3 &vec, glm:: vec3 axis, float angle)
{
axis = glm::normalize(axis);
glm::vec3 cross_axis = glm::cross(axis, vec);
vec = vec * std::cos(angle) + axis * glm::dot(axis,vec) * (1.0f - std::cos(angle)) + cross_axis * std::sin(angle);
return vec;
}
我找到了一种非常便宜且不太正规的方法来实现它。
在OpenGL中,矩阵如下所示:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
如果您将3个垂直数字作为旋转向量,则会获得所需的效果。例如:
如果您围绕向量(0、4、8)旋转,则会绕x轴旋转。
同样,(1、5、9)将是y,(3、6、10)将是z。
为什么它有效?……当您取垂直数字时,您制作了原始矩阵的转置副本,这使您与旋转矩阵相比具有某种起点矩阵……抱歉,我不是数学家,但它确实有效。相信我 ;)
我的OpenGL ES示例代码:
Matrix.rotateM(Settings.anchorMatrix, 0, rX, Settings.anchorMatrix[0], Settings.anchorMatrix[4], Settings.anchorMatrix[8]);
Matrix.rotateM(Settings.anchorMatrix, 0, rY, Settings.anchorMatrix[1], Settings.anchorMatrix[5], Settings.anchorMatrix[9]);
Matrix.rotateM(Settings.anchorMatrix, 0, rZ, Settings.anchorMatrix[2], Settings.anchorMatrix[6], Settings.anchorMatrix[10]);
anchorMatrix 技术上是我为了跟踪记录而在旁边创建的主矩阵。Android OpenGL ES 不允许我从状态机中获取当前矩阵。