平行于上方向向量时,Arcball摄影机被锁定

Arcball camera locked when parallel to up vector

本文关键字:Arcball 摄影机 锁定 方向向量      更新时间:2023-10-16

我目前正在完成相机的实现,该相机的功能与Maya中的相机相同。我陷入翻滚功能的部分。

问题如下:只要摄影机的位置与上方向向量(当前定义为(0, 1, 0))不平行,翻滚功能就可以正常工作。一旦摄影机与该向量平行(因此它看起来是直向上或直向下),摄影机就会锁定在适当位置,并且只围绕上向量旋转,而不是继续滚动。

这个问题已经在这里被提出了,不幸的是,这个问题没有实际的解决方案。作为参考,我还尝试在旋转相机时更新向上矢量,但最终的行为不是我所需要的(视图会因新方向而滚动)。

这是我相机的代码:

using namespace glm;
// point is the position of the cursor in screen coordinates from GLFW
float deltaX = point.x - mImpl->lastPos.x;
float deltaY = point.y - mImpl->lastPos.y;
// Transform from screen coordinates into camera coordinates
Vector4 tumbleVector = Vector4(-deltaX, deltaY, 0, 0);
Matrix4 cameraMatrix = lookAt(mImpl->eye, mImpl->centre, mImpl->up);
Vector4 transformedTumble = inverse(cameraMatrix) * tumbleVector;
// Now compute the two vectors to determine the angle and axis of rotation.
Vector p1 = normalize(mImpl->eye - mImpl->centre);
Vector p2 = normalize((mImpl->eye + Vector(transformedTumble)) - mImpl->centre);
// Get the angle and axis
float theta = 0.1f * acos(dot(p1, p2));
Vector axis = cross(p1, p2);
// Rotate the eye.
mImpl->eye = Vector(rotate(Matrix4(1.0f), theta, axis) * Vector4(mImpl->eye, 0));

我使用的矢量库是GLM。这里有一个关于这里使用的自定义类型的快速参考:

typedef glm::vec3 Vector;
typedef glm::vec4 Vector4;
typedef glm::mat4 Matrix4;
typedef glm::vec2 Point2;

mImpl是包含以下成员的PIMPL:

Vector eye, centre, up;
Point2 lastPoint;

以下是我的想法。这与万向节锁定有关,万向节锁定发生在欧拉角(以及球面坐标)上。

如果超过最小值(0,-zoom,0)或最大值(0、zoom,0),则必须切换布尔值。这个布尔值将告诉您是否必须将deltaY处理为阳性。

它也可能只是由奇点引起的,因此只需将极角值限制在89.99°和-89.99°之间。

你的问题可以这样解决。

因此,如果你的相机正好位于对象的上方(0,zoom,0)或下方(0,-zoom,0),那么相机只会滚动。(我还假设您的对象位于(0,0,0),上方向向量设置为(0,1,0)。)

也许有一些数学技巧可以解决这个问题,不过我会用线性代数来解决。

你需要引入一个新的右向量。如果你做一个叉积,你会得到相机向量。摄影机向量=向上向量x摄影机向量。想象一下,这些向量从(0,0,0)开始,然后很容易地,为了得到你的相机位置,只需做这个减法(0,0,0)-(相机向量)。

因此,如果你得到一些deltaX,你就朝着右向量旋转(围绕上向量)并更新它

deltaX的任何影响都不应该改变你的上方向向量。

如果你得到了一些deltaY,你就向上向量(围绕右向量)旋转并更新它。(这对右向量没有影响)。

https://en.wikipedia.org/wiki/Rotation_matrix在旋转矩阵中,从轴和角度可以找到一个重要的公式。

你说u是你想要旋转的向量,θ是你想要绕轴旋转的量。θ的大小与deltaX/Y成比例。

例如:我们从deltaX得到一个输入,所以我们围绕上方向向量旋转。

up-vector:= (0,1,0)
right-vector:= (0,0,-1)
cam-vector:= (0,1,0)
theta:=-1*30° // -1 due to the positive mathematical direction of rotation

R={[cos(-30°),0,-sin(-30°)],[0,1,0],[sin(-30°),0,cos(-30°)]}
new-cam-vector=R*cam-vector // normal matrix multiplication

还有一件事要做:更新右向量。

right-vector=camera-vector x up-vector .