В настоящее время я работаю с узлами в иерархическом графике сцены, и у меня возникают трудности с правильным переводом/вращением node по отношению к определенному пространству преобразования (например, родительскому node).
Как правильно перевести/повернуть node относительно родительского node в графе сцены?
Проблема
Рассмотрим следующую диаграмму молекулы воды (без соединительных линий) для родительской/дочерней структуры узлов сцены, причем O xygen атом является родительским node и 2 H атомы идрогена являются дочерними узлами.
Проблема с переводом
Если вы захватите родительский O xygen атом и переведите структуру, вы ожидаете, что дети H ydrogen последуют за ними и останутся в одинаковой относительной позиции от своего родителя. Если вместо этого вы захватите дочерний элемент H и переведите его, тогда будет затронут только ребенок. Обычно это работает. Когда транслируются атомы O, атомы H автоматически перемещаются вместе с ним, как и ожидалось из иерархического графика.
Однако при переводе родителя дети также в конечном итоге накапливают дополнительный перевод, что существенно заставляет детей "переводить дважды" в одном направлении и отходить от своего родителя вместо того, чтобы оставаться на том же относительном расстоянии.
Проблема с вращением
Если вы захватите родительский O node и повернете его, вы ожидаете, что дочерние узлы H также будут вращаться, но на орбите, поскольку вращение выполняемый родителем. Это работает по назначению.
Однако, если вы возьмете дочерний элемент H node и скажите ему, чтобы он вращался относительно его родителя, я ожидал, что только ребенок будет вращаться вокруг своего родителя таким же образом, но это не происходит. Вместо этого ребенок вращается на своей собственной оси с более высокой скоростью (например, в два раза быстрее, чем вращается относительно своего собственного локального пространства) в своем текущем положении.
Я действительно надеюсь, что это описание достаточно справедливо, но дайте мне знать, если это не так, и я уточню по мере необходимости.
Математика
Я использую матрицы размером 4x4 столбца (т.е. Matrix4
) и векторы столбцов (т.е. Vector3
, Vector4
).
Ниже приведена некорректная логика, которая ближе всего подходит к правильному поведению. Обратите внимание, что я решил использовать синтаксис, подобный Java, с перегрузкой оператора, чтобы упростить чтение математики. Я пробовал разные вещи, когда думал, что понял, но я этого не сделал.
Текущая логика перевода
translate(Vector3 tv /* translation vector */, TransformSpace relativeTo):
switch (relativeTo):
case LOCAL:
localTranslation = localTranslation * TranslationMatrix4(tv);
break;
case PARENT:
if parentNode != null:
localTranslation = parentNode.worldTranslation * localTranslation * TranslationMatrix4(tv);
else:
localTranslation = localTranslation * TranslationMatrix4(tv);
break;
case WORLD:
localTranslation = localTranslation * TranslationMatrix4(tv);
break;
Логика текущего вращения
rotate(Angle angle, Vector3 axis, TransformSpace relativeTo):
switch (relativeTo):
case LOCAL:
localRotation = localRotation * RotationMatrix4(angle, axis);
break;
case PARENT:
if parentNode != null:
localRotation = parentNode.worldRotation * localRotation * RotationMatrix4(angle, axis);
else:
localRotation = localRotation * RotationMatrix4(angle, axis);
break;
case WORLD:
localRotation = localRotation * RotationMatrix4(angle, axis);
break;
Вычисление космических преобразований мира
Для полноты преобразования мира для this
node вычисляются следующим образом:
if parentNode != null:
worldTranslation = parent.worldTranslation * localTranslation;
worldRotation = parent.worldRotation * localRotation;
worldScale = parent.worldScale * localScale;
else:
worldTranslation = localTranslation;
worldRotation = localRotation;
worldScale = localScale;
Кроме того, полное/скопированное преобразование node для this
:
Matrix4 fullTransform():
Matrix4 localXform = worldTranslation * worldRotation * worldScale;
if parentNode != null:
return parent.fullTransform * localXform;
return localXform;
Когда требуется преобразование node для отправки в форму шейдера OpenGL, используется матрица fullTransform
.