PyBullet и OpenGL - в OpenGL вращения меняются местами
Я пишу базовый игровой движок, чтобы помочь со своей докторской диссертацией по многоагентному обучению. Я использую PyBullet в качестве внутреннего физического движка и OpenGL для визуального отображения. У меня есть буферы OpenGL, настроенные для хранения информации об объекте, такой как положение (vec3) и вращение (matrix4x4), при этом вращения выполняются с использованием кватернионов, но для удобства хранятся с использованием углов Эйлера.
Моя проблема в том, что когда я вращаю объект в игровом мире OpenGL (вокруг любой оси), вращение pyBullet (как видно из графического интерфейса pyBullet) происходит в противоположном направлении и иногда полностью выключается. Мне, должно быть, не хватает чего-то простого, и я извиняюсь, если это простое решение. Я также предоставил видео, чтобы показать проблему, с которой я столкнулся - ссылка на видео об ошибке ( https://youtu.be/4VpBUx5LBYQ):
Когда я извлекаю поворот из PyBullet, используя getBasePositionAndOrientation()
и преобразовать кватернион в углы Эйлера, используя pybullet.getEulerFromQuaternion()
, результатом будет правильный vec3, но после преобразования в матрицу вращения pybullet.getMatrixFromQuaternion()
, кажется, меняет направление вращения.
Пожалуйста, посмотрите мой код ниже:
'obj = Class BaseSceneObject'
'action = Euler rotation angle in degrees to apply vec3(x, y, z) e.g.(1., 0., 0.) apply +1 degree rotation to x-axis'
'Collect current position and rotation of object and update PyBullet'
# get the rotation - euler angles in degrees vec3(x,y,z)
rot = obj.get_rotation()
# add rotation action (e.g. +1 degree to x = vec3(1., 0., 0.)) and convert to radians
rot = math.radians(rot[0] + action[0]), math.radians(rot[1] + action[1]), math.radians(rot[2] + action[2])
# convert rotation from euler to quaternion
quat = pybullet.getQuaternionFromEuler(rot)
# update position and orientation
pybullet.resetBasePositionAndOrientation(bodyUniqueId=obj.get_rigid_body_id(),
posObj=obj.get_position(),
ornObj=quat)
'Collect PyBullet results and update OpenGL'
# get position and rotation from PyBullet
position, rotation = pybullet.getBasePositionAndOrientation(bodyUniqueId=obj.get_rigid_body_id())
# update object position
obj.set_position(position=position)
# convert rotation quaternion to euler angles
rot_r = pybullet.getEulerFromQuaternion(rotation)
# convert radians to degrees
rot_d = math.degrees(rot_r[0]), math.degrees(rot_r[1]), math.degrees(rot_r[2])
# construct OpenGL object rotation matrix
rot_m_final = numpy.identity(4)
rot_mr = numpy.array(pybullet.getMatrixFromQuaternion(rotation)).reshape(3, 3)
rot_m_final[:3, :3] = rot_mr
# update OpenGL rotation matrix
obj.set_rotation(rotation=rot_d,
rotation_matrix=rot_m_final)
1 ответ
Оказывается, приведенный выше код верен. Проблема заключалась в шейдере OpennGL, где я забыл, что вычисления матриц некоммутивны, т.е. numpy.matmul(Mat4(вращение), Vec4(положение)) не то же самое, что numpy.matmul(Vec4(положение), Mat4(вращение))).
После обновления моего кода шейдера: vec4 aRPos = vec4(aRotation * aVertex); Кому: vec4 aRPos = vec4(aVertex * aRotation);
Это сработало отлично. Спасибо.