Я рекомендую сохранить положение мыши в точке, где вы изначально щелкнули в представлении.Рассчитать количество движения мыши в координатах окна.Расстояние движения должно быть отображено на угол.Ось вращения перпендикулярна (в норме) направлению движения мыши.В результате получается поворот объекта, похожего на this WebGL demo.
Сохранение текущей позиции мыши в 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
, он по-прежнему равен 2мерный вектор.Это вектор в плоскости XY области просмотра, представляющий движение мыши в области просмотра.Координата z равна 0. Двумерный вектор (x, y) , может быть повернут на 90 градусов против часовой стрелки, на (- y, x) .
Длина вектора направления представляет угол поворота.Движение мыши по всему экрану приводит к вектору с длиной 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;
}
Если вы хотите вращение вокруг оси объекта вверх, наклонитеобъект вдоль области просмотра ось х, то расчет отличается.Сначала примените матрицу вращения вокруг оси 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;
}