首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >旋转网格的OpenGL ArcBall

旋转网格的OpenGL ArcBall
EN

Stack Overflow用户
提问于 2019-02-02 23:03:51
回答 1查看 776关注 0票数 4

我正在使用遗留OpenGL绘制一个网格。现在,我正在尝试实现一个弧形类来用鼠标旋转对象。然而,当我移动鼠标时,物体要么不旋转,要么以太大的角度旋转。

这是在单击鼠标时调用的方法:

代码语言:javascript
复制
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;
}

此方法的目的是简单地将鼠标坐标映射到屏幕中心,并将其映射到边界球,从而生成一个起始向量。

这是鼠标移动时调用的方法:

代码语言:javascript
复制
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;
}

此方法再次将鼠标坐标映射到屏幕中央,然后计算新的矢量,并根据这两个向量计算旋转轴和角度。

然后我用

代码语言:javascript
复制
glMultMatrixf(ArcBall::rotation.data());

应用旋转

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-03 09:13:56

我建议将鼠标位置存储在最初单击视图的位置。在窗口坐标中计算鼠标的移动量。运动的距离必须映射到一个角度。旋转轴与鼠标运动的方向垂直(正常)。结果是一个类似于 WebGL演示的对象的旋转。

将当前鼠标位置存储在startRotation中。注意,存储位置鼠标位置的坐标,而不是归一化向量:

代码语言:javascript
复制
// 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中的当前位置

代码语言:javascript
复制
// 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);

计算从起始位置到结束位置的向量:

代码语言:javascript
复制
QVector3D direction = endVector - startVector;

旋转轴的运动方向是正常的:

代码语言:javascript
复制
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执行:

代码语言:javascript
复制
angle = (float)qRadiansToDegrees(direction.length() * 3.141593);

最后,新的轮调必须适用于现有的轮调,而不是适用于模式:

代码语言:javascript
复制
QMatrix4x4 addRotation;
addRotation.rotate(angle, rotationAxis.x(), rotationAxis.y(), rotationAxis.z());
rotation = addRotation * rotation; 

方法startRotationupdateRotation的最终代码清单

代码语言:javascript
复制
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;
}
代码语言:javascript
复制
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轴上的旋转:

代码语言:javascript
复制
view-matrix = rotate-X * view-matrix * rotate-Y

函数更新轮转必须如下所示:

代码语言:javascript
复制
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;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54498361

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档