C++ 平行于上方向向量时Arcball相机锁定

C++ 平行于上方向向量时Arcball相机锁定,c++,camera,rotation,arcball,C++,Camera,Rotation,Arcball,我目前正在完成摄影机的实现,该摄影机的功能与Maya中的摄影机相同。我被困在翻滚功能中的部分 问题在于:只要相机的位置与上方向向量(当前定义为(0,1,0))不平行,翻滚功能就可以正常工作。一旦摄影机与该向量平行(因此它是垂直向上或向下),摄影机将锁定到位,并仅围绕上向量旋转,而不会继续滚动 这个问题已经被提出,不幸的是,这个问题没有实际的解决办法。作为参考,我还尝试在旋转摄影机时更新上方向向量,但结果行为不是我所需要的(视图由于新方向而滚动) 以下是我相机的代码: using namespac

我目前正在完成摄影机的实现,该摄影机的功能与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的任何影响都不应改变您的上方向向量

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
如果你得到了一些三角形,你可以向上方向旋转(围绕右方向)并更新它。(这对右向量没有影响)

在旋转矩阵中,从轴和角度可以找到一个重要的公式

你说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 .

我遇到的问题不是万向节锁。万向节锁使你在旋转中失去两个自由度,而我只失去一个。我可以移动鼠标,相机仍将围绕上方向向量作为轴旋转,但我无法继续旋转超过该轴。编辑:为类似问题添加了缺少的链接。