Есть классический граф сцены (в 2D), у каждого узла соответственно имеется позиция, поворот и масштаб в локальных координатах из которых строится локальная матрица трансформации. Глобальная матрица трансформации для каждого узла строится перемножением матриц по иерархии. Для примера возьмем дерево из N узлов - каждый последующий узел является потомком предыдущего узла. Теперь в произвольное место иерархии вводим дополнительного потомка. Как в таком случае правильно вычислить новые локальные позицию, поворот и масштаб для этого потомка так, чтобы в глобальных координатах объект остался с прежней глобальной матрицей трансформации?
Как я делаю сейчас: беру обратную глобальную матрицу трансформации объекта к которому будет прикреплен новый объект и умножаю на глобальную матрицу нового объекта. Затем полученную матрицу раскладываю на составляющие (TRS-decomposition):
auto relativeTransform = parent->GetGlobalTransform().getInverse( ) * node->GetGlobalTransform( ); ... void DecomposeTransform( const sf::Transform &t, Vec2f *p, Vec2f *s, float *r) { auto m = t.getMatrix( ); if ( p) { p->x = m[12]; p->y = m[13]; } if ( s) { s->x = Sign( m[0]) * sqrt( m[0] * m[0] + m[4] * m[4]); s->y = Sign( m[5]) * sqrt( m[1] * m[1] + m[5] * m[5]); } if ( r) { *r = Math::Rad2Deg( atan2f( -m[4], m[0])); } }
mr.DIMAS
От задачи зависит. Если после добавления объекта к родителю ты хочешь чтобы например при обнулении поворота объект выравнивался, то тогда только декомпозиция. Иначе можно сохранить матрицу relativeTransform как некую offsetMatrix для объекта, и для вычисления глобальной матрицы потом еще локальную домножать на оффсет, а потом на родителя. Но собственно хоть и нельзя разложить матрицу однозначно на компоненты, какая разница?
mr.DIMAS
> Затем полученную матрицу раскладываю на составляющие (TRS-decomposition):
Произвольную матрицу разложить в TRS невозможно, только в TRSR'.
alorken
Мне нужно получать именно локальные позицию, поворот и масштаб. Из них я потом уже и собираю матрицы.
}:+()___ [Smile]
Можно немного поподробнее, пожалуйста. Что здесь R' ?
Я так понимаю, проблема в том, что может существовать новый объект с такими смещением, поворотом и скейлом, что его введение в иерархию не позволит дочерним объектам ни при каких условиях иметь прежние смещение, поворот и скейл в глобальном пространстве (точнее для этого недостаточно смещения, поворота и скейла, нужна, например, еще и трансформация сдвигом).
Допустим, есть такая иерархия, где A - корневой объект и для всех объектов имеются их локальные сдвиг (T), поворот (R) и масштаб (S):
A <- B <- D <- E
Нужно между B и его потомком D вставить новый объект С с локальными Tc, Rc, Sc:
A <- B <- C <- D <- E
Требуется модифицировать у объекта D его локальные Td, Rd, Sd так, чтобы мировые координаты D и всех его потомков не изменились.
--
> Как я делаю сейчас: беру обратную глобальную матрицу трансформации объекта к которому будет прикреплен новый объект и умножаю на глобальную матрицу нового объекта.
Я думаю, с таким же успехом, но проще и быстрее, можно взять обратную локальную матрицу трансформации нового объекта C и домножить её на локальную матрицу трансформации D. Ну или наоборот, зависит от реализации. Смысл в том, чтобы новая матрица для D сначала отменяла трансформации, сделанные появившимся C, а потом к результату применяла старые трансформации D.
Должна получиться новая локальная матрица трансформации для D. Из неё можно достать новые локальные Td, Rd, Sd.
--
Можно обойтись и без матриц, смысл тот же: новые трансформации D должны сначала отменять трансформации C и к результату применять старые трансформации D. Проблема только не запутаться в порядке преобразований. Попозже поэкспериментирую.
BingoBongo
> Я так понимаю, проблема в том, что может существовать новый объект с такими
> смещением, поворотом и скейлом, что его введение в иерархию не позволит
> дочерним объектам ни при каких условиях иметь прежние смещение, поворот и скейл
> в глобальном пространстве (точнее для этого недостаточно смещения, поворота и
> скейла, нужна, например, еще и трансформация сдвигом).
Всё равно может не получиться. Если новая трансформация схлопывает объёмный объект в плоский, в отрезок или в точку, то достать из них обратно объёмный объект уже не получится никак.
mr.DIMAS
> Можно немного поподробнее, пожалуйста. Что здесь R' ?
Второй поворот.
}:+()___ [Smile]
А почему нельзя в TRS разложить? Можно пример? Что-то не могу себе представить.
alorken
> А почему нельзя в TRS разложить? Можно пример? Что-то не могу себе представить.
Ну вот попробуй разложить в RS (\(\alpha\) — произвольный параметр), перенос я выкинул для простоты, с ним все ясно:
\(\left(\begin{array}1+\alpha&\alpha&\alpha\\\alpha&1+\alpha&\alpha\\\alpha&\alpha&1+\alpha\end{array}\right)\)
mr.DIMAS
Тебе точно нужно анизотропное растяжение? Задача была бы гораздо проще, если бы масштаб задавался одним скаляром.
alorken
> А почему нельзя в TRS разложить? Можно пример? Что-то не могу себе представить.
Я дам тебе более наглядный пример:
Delfigamer
> Тебе точно нужно анизотропное растяжение?
Ага, у меня масштаб может анимирован быть через редактор и он не равномерный - в разных ситуациях нужен разный масштаб по разным осям.
В общем-то эту задачу я решаю как раз для редактора, чтобы можно было делать attach/detach узлов сцены с сохранением положения в глобальных координатах.
mr.DIMAS
> В общем-то эту задачу я решаю как раз для редактора, чтобы можно было делать
> attach/detach узлов сцены с сохранением положения в глобальных координатах.
То, как ты её решил - и есть приемлимое решение. Писал редактор, проходил через те же грабли.
Тема в архиве.