Я рекомендую сохранять положение мыши в той точке, где вы изначально щелкаете в представлении. Рассчитайте количество движения мыши в координатах окна. Расстояние движения должно быть отображено под углом. Ось вращения перпендикулярна (перпендикулярна) направлению движения мыши. Результатом является вращение объекта, аналогичного этому 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), может быть повернут на 90 градусов против часовой стрелки на (-y, x).
Длина вектора направления представляет угол поворота. Движение мыши по всему экрану приводит к созданию вектора длиной 2,0. Поэтому, если перетаскивание на весь экран должно привести к полному вращению, длину вектора необходимо умножить на PI. Если необходимо выполнить ротацию полутонов, то с помощью 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;
}
person
Rabbid76
schedule
03.02.2019