Russian Qt Forum

Программирование => Алгоритмы => Тема начата: kuzulis от Март 19, 2021, 13:47



Название: Определить конечный угол вращения составного объекта
Отправлено: kuzulis от Март 19, 2021, 13:47
Всем привет еще раз.

Этот вопрос следует из предыдущего поста (http://www.prog.org.ru/topic_32989_0.html),
где речь шла об определении проекций вектора гравитации на оси акселерометра.

Но теперь задачка немного другая..

А допустим что акселерометр (условно - некий объект) находится внутри какого-то другого объекта (ну, или лежит на нем).
И у каждого из объектов есть возможность их поворота по трем осям X,Y,Z (см рисунок).

1. Изначально угол поворота акселерометра и его "контейнера" равны нулю, относительно земли (некоей неподвижной системы отсчета).

2. Далее, допустим, что акселерометр крутанули вокруг какой-то оси на какой то угол, например на 30 градусов.

3. Теперь мы повернули и сам контейнер вокруг той же оси на какой-то угол, например 30 градусов.

4. Вопрос, а каким теперь будет угол поворота акселерометра вокруг этой же оси относительно земли?


Очевидно, что в этом частном случае что на картинке - он будет 60 градусов?
Но как быть в общем случае, когда вращение идет в пространстве?

Можно ли просто суммировать углы поворота вокруг осей каждого из объектов (а вдруг их будут больше двух, например,
акселерометр может лежать на черепахе, которая может наклоняться в любую сторону, и сама черепаха стоит на слонах,
которые тоже могут играть в присядки)?

Или же опять нужно что-то городить в матрицами? Если да, то как это делается?  ::)

При этом, как я понимаю, каждый объект имеет свою матрицу и прочие 3-д параметры

 



Название: Re: Определить конечный угол вращения составного объекта
Отправлено: kuzulis от Март 19, 2021, 14:01
Т.е. грубо говоря, что то вроде:

Код
Entity { // Некий контейнер - большой куб, содержит под-объект - малый куб.
   components: [
       Mesh { source: "qrc:/assets/models/big-cube.obj" },
       Transform {
             // Содержит все 3-д свойства большого куба (матрицы и прочее)
       },
       PhongMaterial { ambient: "green" }
   ]
 
   Entity { // Некий чайлд - малый куб
       components: [
           Mesh { source: "qrc:/assets/models/small-cube.obj" },
           Transform {
                 // Содержит все 3-д свойства малого куба (матрицы и прочее)
           },
           PhongMaterial { ambient: "red" }
       ]
   }
}
 

Так вот, надо как то найти углы поворота малого куба относительно глобальной неподвижной системы координат (или как там она называется),
после того как мы повращали большой куб, а в нем - еще и малый вокруг их локальных координат.


Название: Re: Определить конечный угол вращения составного объекта
Отправлено: Igors от Март 19, 2021, 14:43
Так вот, надо как то найти углы поворота малого куба относительно глобальной неподвижной системы координат (или как там она называется),
"Мир" :)

Можно ли просто суммировать углы поворота вокруг осей каждого из объектов
НЕТ, углы Эйлера нельзя суммировать, рез-т неверен (причем подленько,  много частных случаев где работает)

Так вот, надо как то найти углы поворота малого куба относительно глобальной неподвижной системы координат (или как там она называется),
после того как мы повращали большой куб, а в нем - еще и малый вокруг их локальных координат.
Если есть отношение parent-child, то матрица чайлда может уже и включать матрицу парента, убедитесь что в Вашей системе это так (поверните только парент и напечатайте матрицу чайлда).  Если нет, то просто перемножить матрицы. Дальше извлекаете углы Эйлера из матрицы.

И вот тут Вы вступили в бооольшое говно.

1) Извлечения углов я в букваре не помню, может придется искать в инете. Ну это еще цветочки

2) Эта операция неоднозначна. Вот если "из углов сделать матрицу" - все норм, но одна и та же матрица может быть получена из неск комбинаций углов. Любая реализация может выдать "странный" рез-т, типа 10 + 10 = 100. Формально он корректен, вращение получается то же самое, но возникают проблемы с UI и.т.п.

Собсно это то за что и матюкают углы Эйлера (и хвалят кватернионы)


Название: Re: Определить конечный угол вращения составного объекта
Отправлено: kuzulis от Март 19, 2021, 15:24
Цитата: Igors
Если есть отношение parent-child, то матрица чайлда может уже и включать матрицу парента,

К сожалению, не включает.

Цитата: Igors
Если нет, то просто перемножить матрицы.

Да, спс, я попробовал так:

Код
C++ (Qt)
   QMatrix4x4 m =  matrix1 * matrix2;
   QVector3D gravity(0, -1, 0);
   QVector3D v = m.mapVector(gravity);
   qDebug() << v;
 

но почему то это не работает в случае, если :

0. Начальная позиция - все ок, вектор гравитации вдоль оси Y - QVector3D(0, -1, 0)
1. Потом повернули большой куб вокруг оси X - на 90 град - все ок, теперь вектор гравитации вдоль оси Z - QVector3D(0, 0, -1)
2. Теперь вращаем малый куб вокруг оси Y - и результат не меняется, хотя теперь вектор гравитации должен распределяться между осями X и Z

Может надо еще что-то делать с матрицами, а не только перемножать?

Цитата: Igors
Собсно это то за что и матюкают углы Эйлера (и хвалят кватернионы)

И как их можно использовать? Есть мысли? т.к. у каждого объекта также есть свойство `rotation`, которое является кватернионом.




Название: Re: Определить конечный угол вращения составного объекта
Отправлено: kuzulis от Март 19, 2021, 16:18
Я даже картинки приататчил.

И вот код (QML):

Код
import Qt3D.Core 2.0
import Qt3D.Extras 2.15
import Qt3D.Input 2.0
import Qt3D.Render 2.15
 
import QtQuick.Scene3D 2.0
 
Scene3D {
   focus: true
   aspects: ["input", "logic"]
   cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
 
   property alias bigCubeRotationX: bigCuberansform.rotationX
   property alias bigCubeRotationZ: bigCuberansform.rotationZ
   property alias smallCubeRotationY: smallCuberansform.rotationY
 
   function calculateMatrix(bigMatrix, smallMatrix) {
       detector.setupObjectMatrix(bigMatrix, smallMatrix);
   }
 
   Entity {
       components: [
           RenderSettings {
               activeFrameGraph: ForwardRenderer {
                   camera: camera
                   clearColor: "white"
               }
           },
           InputSettings { }
       ]
 
       Camera {
           id: camera
           projectionType: CameraLens.PerspectiveProjection
           fieldOfView: 45
           position: Qt.vector3d(0.0, 1, 3.0)
           upVector: Qt.vector3d(0.0, 1.0, 0.0)
           viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
       }
 
       FirstPersonCameraController {
           camera: camera
           linearSpeed: 10.0
           acceleration: 5.0
           deceleration: 5.0
       }
 
       Entity {
           components: [
               PointLight {},
               Transform { translation: camera.position }
           ]
       }
 
       Entity {
           components: [
               CuboidMesh {
                   xExtent: 1
                   yExtent: 0.2
                   zExtent: 0.5
               },
               Transform {
                   id: bigCuberansform
                   onMatrixChanged: calculateMatrix(bigCuberansform.matrix, smallCuberansform.matrix)
               },
               PhongAlphaMaterial {
                   alpha: 0.8
                   diffuse: "red"
               }
           ]
 
           Entity {
               components: [
                   CuboidMesh {
                       xExtent: 0.5
                       yExtent: 0.1
                       zExtent: 0.2
                   },
                   Transform {
                       id: smallCuberansform
                       onMatrixChanged: calculateMatrix(bigCuberansform.matrix, smallCuberansform.matrix)
                   },
                   PhongAlphaMaterial {
                       alpha: 0.8
                       diffuse: "green"
                   }
               ]
           }
       }
   }
}
 
 

И CPP:

Код
C++ (Qt)
void OrientationDetector::setupObjectMatrix(const QMatrix4x4 &matrix1, const QMatrix4x4 &matrix2)
{
   QMatrix4x4 m =  matrix1 * matrix2;
   QVector3D gravity(0, -1, 0);
   QVector3D v = m.mapVector(gravity);
   qDebug() << v;
}
 



Название: Re: Определить конечный угол вращения составного объекта
Отправлено: Igors от Март 20, 2021, 12:41
Может надо еще что-то делать с матрицами, а не только перемножать?
Могут быть определены доп правила трансформа иерархии (напр "наследовать scale парента или нет" и.т.п). Если их нет - то только умножение

но почему то это не работает в случае, если :
Замечания:

1) Для тестов есть хороший угол 30 градусов (cos = 0.866, sin = 0.5, эти числа легко узнать). А вoт с углами 90 легко заблудиться.

2) Обратите внимание что базис (как направлены оси в мире, Вы нарисовали тройку XYZ) не совпадает с тем что Вы показывали для прибора.

Теперь по картинкам. Первый поворот: локальная ось Y (произведения матриц) теперь направлена "на нас" (или "от нас", здесь не играет роли) в мире. Вектор гравитации в мире (0, -1, 0) "вниз", но в локальной СК это (0, 0, -1).

Второй поворот: а теперь Вы вокруг той же самой локальной оси Y и крутите. Конечно сама она никак не меняется. Др словами второй поворот вокруг самого вектора гравитации

Итого: все работает, никакого "касяка" нет  :)

И как их можно использовать? Есть мысли? т.к. у каждого объекта также есть свойство `rotation`, которое является кватернионом.
Ну если Вы хотите получить/иметь именно "углы" - то проблема неизбежна. Поэтому

1) Попробовать "обойти" проблему. Убедитесь что углы совершенно необходимы. В принципе они нужны только для одного: предъявить их юзверю в UI, кватернионы для этого не подходят, матрицы тем более. Если же нужен "просто поворот", то его можно (и нужно) делать матрицей, все равно ее придется делать из углов

2) Найти в инете "matrix to euler angles XYZ" и реализовать. Возможно "прыжки углов" для Вас вовсе не проблема, вращение остается корректным.

Edit: да, и убедитесь что матрицы помножены верно (парент x чайлд)