c++ - OpenGL:Arcball 相机旋转问题
问题描述
我需要实现轨迹球相机。我得到了类似的东西,但它的工作原理非常弯曲(角度急剧变化,向右/向左转动时,相机强烈地向上/向下抬起)。
这是我的源代码,你能告诉我哪里出错了:
bool get_arcball_vec(double x, double y, glm::vec3& a)
{
glm::vec3 vec = glm::vec3((2.0 * x) / window.getWidth() - 1.0, 1.0 - (2.0 * y) / window.getHeight(), 0.0);
if (glm::length(vec) >= 1.0)
{
vec = glm::normalize(vec);
}
else
{
vec.z = sqrt(1.0 - pow(vec.x, 2.0) - pow(vec.y, 2.0));
}
a = vec;
return true;
}
...
void onMouseMove(double x, double y) {
if (rightMouseButtonPressed) {
glm::vec3 a,b;
cur_mx = x;
cur_my = y;
if (cur_mx != last_mx || cur_my != last_my)
if (get_arcball_vec(last_mx, last_my, a) && get_arcball_vec(cur_mx, cur_my, b))
viewport.getCamera().orbit(a,b);
last_mx = cur_mx;
last_my = cur_my;
...
void Camera::orbit(glm::vec3 a, glm::vec3 b)
{
forward = calcForward();
right = calcRight();
double alpha = acos(glm::min(1.0f, glm::dot(b, a)));
glm::vec3 axis = glm::cross(a, b);
glm::mat4 rotationComponent = glm::mat4(1.0f);
rotationComponent[0] = glm::vec4(right, 0.0f);
rotationComponent[1] = glm::vec4(up, 0.0f);
rotationComponent[2] = glm::vec4(forward, 0.0f);
glm::mat4 toWorldCameraSpace = glm::transpose(rotationComponent);
axis = toWorldCameraSpace * glm::vec4(axis, 1.0);
glm::mat4 orbitMatrix = glm::rotate(glm::mat4(1.0f), (float)alpha, axis);
eye = glm::vec4(target, 1.0) + orbitMatrix * glm::vec4(eye - target, 1.0f);
up = orbitMatrix * glm::vec4(up, 1.0f);
}
解决方案
我使用此代码将 2D 鼠标位置映射到球体:
Vector3 GetArcBallVector(const Vector2f & mousePos) {
float radiusSquared = 1.0; //squared radius of the sphere
//compute mouse position from the centre of screen to interval [-half, +half]
Vector3 pt = Vector3(
mousePos.x - halfScreenW,
halfScreenH - mousePos.y,
0.0f
);
//if length squared is smaller than sphere diameter
//point is inside
float lengthSqr = pt.x * pt.x + pt.y * pt.y;
if (lengthSqr < radiusSquared){
//inside
pt.z = std::sqrtf(radiusSquared - lengthSqr);
}
else {
pt.z = 0.0f;
}
pt.z *= -1;
return pt;
}
为了计算旋转,我使用最后一个 ( startPt
) 和当前 ( endPt
) 映射位置并执行以下操作:
Quaternion actRot = Quaternion::Identity();
Vector3 axis = Vector3::Cross(endPt, startPt);
if (axis.LengthSquared() > MathUtils::EPSILON) {
float angleCos = Vector3::Dot(endPt, startPt);
actRot = Quaternion(axis.x, axis.y, axis.z, angleCos);
}
我更喜欢在矩阵上使用四元数,因为它们很容易相乘(用于累积旋转)和插值(用于一些 smooting)。
推荐阅读
- python - MobileNet 和 Bahdanau 注意
- sql - 如何在 SQL Server 中除最后一行之外的列中附加逗号?
- gitlab - gitlab中页面的工件太大
- php - PHP - Telegram Bot 交互式查询
- node.js - 使用 MongoDB $graphLookup 进行递归搜索不适用于对象内的字段
- visual-studio-code - vscode 扩展使用 JS 语言图标用于 treeItem 文件夹
- laravel - URL Blocked:此重定向失败,因为重定向 URI 未在应用程序的客户端 OAuth 设置 bin laravel 中列入白名单;名媛
- javascript - HCL Domino 11 - Javascript - 文档提交后如何重定向到同一个文档?- 视图未刷新
- php - 该功能不适用于产品类别
- python - Python Telegram Bot 如何让机器人在一个函数中响应多条消息