OpenGL трансформирует объекты с несколькими поворотами разных осей

Я строю программу моделирования, и я хотел бы сделать преобразования для объектов в их собственном пространстве, а затем назначить этот единственный объект группе для вращения вокруг другой оси, вокруг которой вращается группа. Однако я также хотел бы иметь возможность выполнять преобразования в собственном пространстве объекта при его объединении.

Манипулируя отдельным объектом, я выбираю центр объекта.

glm::mat4 transform;
transform = glm::translate(transform, - obj.meshCenter);
glm::mat4 transform1;
transform1 = glm::translate(transform1, obj.meshCenter);
obj.rotation =  transform1*obj.thisRot*transform;

Затем я отправляю это в шейдер,

glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(obj.translation*obj.rotation*objscale);

Теперь я хотел бы повернуть этот объект вокруг другой оси, скажем, оси (5,0,0) из 45 градусов.

Теперь у меня есть:

glm::mat4 groupR;
groupR = glm::rotate(groupR,glm::degrees(45.0f),glm::vec3(5,0,0));
obj.groupRotation = groupR;
glUniformMatrix4fv(modelLoc, 1, GL_FALSE,
glm::value_ptr(obj.groupRotation*obj.translation*obj.rotation*objscale)

Теперь я переместил объект из его локального пространства в пространство группы.
У меня возникли некоторые трудности, связанные с преобразованием в собственном пространстве объекта в сочетании с вращением группы.
У меня был ограниченный успех, когда я установил ось groupR в (0,1,0) следующим образом:

///Translating object in its own space///
glm::mat4 R = obj.groupRotation;
obj.translation = glm::inverse(R) * obj.translate * R;

проблема здесь в том, что это будет корректно переводить объект только в его собственное пространство, если ось вращения R (вращение группы) равна (0,1,0):

///Rotating object in its own space///
glm::mat4 R = obj.groupRotation;
obj.rotation = glm::inverse(R) * obj.rot * R;

Опять же, вращения неправильны. Я думаю, что, возможно, мне нужно отменить перевод оси groupR? а потом заново применить где-нибудь?

2

Решение

Давайте предположим, что у нас есть объект, который перемещается, вращается и масштабируется, и мы определяем матрицу преобразования следующим образом:

glm::mat4 objTrans ...; // translation
glm::mat4 objRot ...;   // roation
glm::mat4 objScale ...; // scaling

glm::mat4 objMat = objTrans * objRot * objScale;

И у нас есть матрица вращения, которую мы хотим запустить на объекте. В этом случае мы имеем вращение вокруг оси Z:

foat angle ...; // rotation angle

glm::mat4 rotMat = glm::rotate( angle, glm::vec3( 0.0, 0.0, 1.0 ) );

У нас есть несколько поворотов, которые мы можем сделать с этой информацией.
Сначала мы хотим повернуть объект на его локальной оси:

введите описание изображения здесь

glm::mat4 modelMat = objMat * rotMat;

Вращение вокруг происхождения миров может быть выполнено так:

введите описание изображения здесь

glm::mat4 modelMat = rotMat * objMat;

Чтобы вращаться вокруг начала координат объекта в мировой системе координат, мы должны исключить вращение объекта:

введите описание изображения здесь

glm::mat4 modelMat = objMat * (glm::inverse(objRot) * rotMat * objRot);

Вращение вокруг происхождения миров относительно объекта вы должны сделать наоборот:

введите описание изображения здесь

glm::mat4 modelMat = (objRot * rotMat * glm::inverse(objRot)) * objMat;

Если у вас есть полная матрица преобразований для объекта и вы не знаете часть вращения, то ее можно легко определить.

Обратите внимание, что матрица преобразования обычно выглядит так:

( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x,  trans.y,  trans.z,  1 )

Чтобы сгенерировать матрицу только вращения, вы должны извлечь нормализованные векторы осей:

glm::mat4 a ...; // any matrix
glm::vec3 x = glm::normalize( a[0][0], a[0][1], a[0][2] );
glm::vec3 y = glm::normalize( a[1][0], a[1][1], a[1][2] );
glm::vec3 z = glm::normalize( a[2][0], a[2][1], a[2][2] );

glm::mat4 r;
r[0][0] = x[0]; r[0][1] = x[1]; r[0][2] = x[2]; r[0][3] = 0.0f;
r[1][0] = y[0]; r[1][1] = y[1]; r[1][2] = y[2]; r[0][3] = 0.0f;
r[2][0] = z[0]; r[2][1] = z[1]; r[2][2] = z[2]; r[0][3] = 0.0f;
r[3][0] = 0.0f; r[3][1] = 0.0f; r[3][2] = 0.0f; r[0][3] = 1.0f;
4

Другие решения

Вот частичный ответ на поведение, которое я хочу, и настройку, которую я использовал. Похоже, это то, что мне нужно сделать, чтобы получить правильные преобразования в пространстве объектов, не считая группового вращения.
Здесь у меня есть модель, состоящая из 7 различных отдельных сеток, которые вращаются вокруг начала координат (0,5,0) по оси Y, это просто произвольное вращение, которое я выбираю для тестирования.

 for (int i = 0; i < models.at(currentSelectedPointer.x)->meshes.size()i++)
{
glm::mat4 rotMat;
rotMat = glm::translate(rotMat, glm::vec3(5, 0, 0));
rotMat = glm::rotate(rotMat, f, glm::vec3(0, 1.0, 0.0));
rotMat = glm::translate(rotMat, glm::vec3(-5, 0, 0));
models.at(currentSelectedPointer.x)->meshes.at(i).groupRotation = rotMat;
}

все сетки теперь вращаются вокруг (0,5,0) как группа, а не в (0,5,0) по оси Y.

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

     //These will be used to shift the groupRotation origin back to the
// origin in order to rotate around the object's origin.

glm::mat4 gotoGroupAxis;
gotoGroupAxis= glm::translate(gotoGroupAxis, glm::vec3(5, 0, 0));
glm::mat4 goBack ;
goBack = glm::translate(goBack , glm::vec3(-5, 0, 0));

////////Group rotation and it's inverse
glm::mat4 tempGroupRot = goBack *obj.groupRotation*gotoGroupAxis;
glm::mat4 tempGroupRotInverse= glm::inverse(tempGroupRot);

//thisRot and lastRot are matrix variables I use to accumulate and
//save rotations
obj.thisRot = tempGroupRotInverse*
glm::toMat4(currentRotation)*tempGroupRot *
obj.lastRot;

//now I translate the object's rotation origin to it's center.

glm::mat4 transform = glm::translate(transform, -obj.meshCenter);
glm::mat4 transform1 = glm::translate(transform1, obj.meshCenter);
//Finally I rotate the object in it's own space.
obj.rotation =  transform1*obj.thisRot*transform;

Обновить:

 //Translation works as well with
obj.finalTranslation= tempGroupRotInverse*
obj.translation * tempGroupRot ;

Это только частичный ответ, потому что я собираюсь делать преобразования на уровне объекта и на уровне группы, и я почти уверен, что что-то пойдет не так, что не было учтено ответом, который я вывешенный.

1