我正在使用遗留OpenGL绘制一个网格。现在,我正在尝试实现一个弧形类来用鼠标旋转对象。然而,当我移动鼠标时,物体要么不旋转,要么以太大的角度旋转。
这是在单击鼠标时调用的方法:
void ArcBall::startRotation(int xPos, int yPos) {
int x = xPos - context->getWidth() / 2;
int y = context->getHeight() / 2 - yPos;
startVector = ArcBall::mapCoordinates(x, y).normalized();
endVector = startVector;
rotating = true;
}此方法的目的是简单地将鼠标坐标映射到屏幕中心,并将其映射到边界球,从而生成一个起始向量。
这是鼠标移动时调用的方法:
void ArcBall::updateRotation(int xPos, int yPos) {
int x = xPos - context->getWidth() / 2;
int y = context->getHeight() / 2 - yPos;
endVector = mapCoordinates(x, y).normalized();
rotationAxis = QVector3D::crossProduct(endVector, startVector).normalized();
angle = (float)qRadiansToDegrees(acos(QVector3D::dotProduct(startVector, endVector)));
rotation.rotate(angle, rotationAxis.x(), rotationAxis.y(), rotationAxis.z());
startVector = endVector;
}此方法再次将鼠标坐标映射到屏幕中央,然后计算新的矢量,并根据这两个向量计算旋转轴和角度。
然后我用
glMultMatrixf(ArcBall::rotation.data());应用旋转
发布于 2019-02-03 09:13:56
我建议将鼠标位置存储在最初单击视图的位置。在窗口坐标中计算鼠标的移动量。运动的距离必须映射到一个角度。旋转轴与鼠标运动的方向垂直(正常)。结果是一个类似于这 WebGL演示的对象的旋转。
将当前鼠标位置存储在startRotation中。注意,存储位置鼠标位置的坐标,而不是归一化向量:
// xy normalized device coordinates:
float ndcX = 2.0f * xPos / context->getWidth() - 1.0f;
float ndcY = 1.0 - 2.0f * yPos / context->getHeight();
startVector = QVector3D(ndcX, ndcY, 0.0);获取updateRotation中的当前位置
// xy normalized device coordinates:
float ndcX = 2.0f * xPos / context->getWidth() - 1.0f;
float ndcY = 1.0 - 2.0f * yPos / context->getHeight();
endVector = QVector3D(ndcX, ndcY, 0.0);计算从起始位置到结束位置的向量:
QVector3D direction = endVector - startVector;旋转轴的运动方向是正常的:
rotationAxis = QVector3D(-direction.y(), direction.x(), 0.0).normalized();注意,即使direction的类型是QVector3D,它仍然是一个二维向量。它是视口的XY平面上的向量,表示视图上的鼠标移动。Z坐标是0。二维矢量(x,y),可以通过(-y,x)逆时针旋转90度。
方向矢量的长度表示旋转角度。鼠标在整个屏幕上的移动会产生一个长度为2.0的向量。因此,如果在整个屏幕上拖动会导致完全旋转,则向量的长度必须乘以PI。如果应该执行hlf旋转,则由PI/2执行:
angle = (float)qRadiansToDegrees(direction.length() * 3.141593);最后,新的轮调必须适用于现有的轮调,而不是适用于模式:
QMatrix4x4 addRotation;
addRotation.rotate(angle, rotationAxis.x(), rotationAxis.y(), rotationAxis.z());
rotation = addRotation * rotation; 方法startRotation和updateRotation的最终代码清单
void ArcBall::startRotation(int xPos, int yPos) {
// xy normalized device coordinates:
float ndcX = 2.0f * xPos / context->getWidth() - 1.0f;
float ndcY = 1.0 - 2.0f * yPos / context->getHeight();
startVector = QVector3D(ndcX, ndcY, 0.0);
endVector = startVector;
rotating = true;
}void ArcBall::updateRotation(int xPos, int yPos) {
// xy normalized device coordinates:
float ndcX = 2.0f * xPos / context->getWidth() - 1.0f;
float ndcY = 1.0 - 2.0f * yPos / context->getHeight();
endVector = QVector3D(ndcX, ndcY, 0.0);
QVector3D direction = endVector - startVector;
rotationAxis = QVector3D(-direction.y(), direction.x(), 0.0).normalized();
angle = (float)qRadiansToDegrees(direction.length() * 3.141593);
QMatrix4x4 addRotation;
addRotation.rotate(angle, rotationAxis.x(), rotationAxis.y(), rotationAxis.z());
rotation = addRotation * rotation;
startVector = endVector;
}如果你想围绕着物体的向上轴旋转--沿着视图空间x轴倾斜物体,那么计算就不一样了。首先应用y轴周围的旋转矩阵(向上向量),然后是当前视图矩阵,最后是x轴上的旋转:
view-matrix = rotate-X * view-matrix * rotate-Y函数更新轮转必须如下所示:
void ArcBall::updateRotation(int xPos, int yPos) {
// xy normalized device coordinates:
float ndcX = 2.0f * xPos / context->getWidth() - 1.0f;
float ndcY = 1.0 - 2.0f * yPos / context->getHeight();
endVector = QVector3D(ndcX, ndcY, 0.0);
QVector3D direction = endVector - startVector;
float angleY = (float)qRadiansToDegrees(-direction.x() * 3.141593);
float angleX = (float)qRadiansToDegrees(-direction.y() * 3.141593);
QMatrix4x4 rotationX;
rotationX.rotate(angleX, 1.0f 0.0f, 0.0f);
QMatrix4x4 rotationUp;
rotationX.rotate(angleY, 0.0f 1.0f, 0.0f);
rotation = rotationX * rotation * rotationUp;
startVector = endVector;
}https://stackoverflow.com/questions/54498361
复制相似问题