Korchy (korchy) wrote,
Korchy
korchy

О дрожании, или при чем здесь twips

Как реализовано движение объекта:
Есть алгоритм, вычисляющий положение объекта в зависимости от параметров и времени. Т.е. в любой момент времени, а точнее - каждую итерацию игрового цикла, положение объекта пересчитывается. Результата возвращается в глобальной системе координат (мировая система).
Соответственно, каждую итерацию игрового цикла происходит вызов процедуры перемещения объекта из координат предыдущей итерации в координаты итерации текущей.
Т.к. скорости движения отдельных объектов невелики, блоками происходит "пустой" вызов процедуры перемещения (когда координаты объекта в предыдущей итерации цикла равны координатам объекта в текущей итерации). Не оптимально, но разговор сейчас не об этом.
А о том, что в принципе перемещение из точки в туже самую точку не должно вызывать фактического перемещения. Процедура перемещения генерирует единичную матрицу, единичная матрица, умноженная на матрицу трансформации объекта, матрицу трансформации не меняет. Но...
На практике такой подход вызывает периодическое, заметное глазом, дрожание объекта. Т.е. фактически происходит перемещение там, где его не должно быть.
Причина же заключается в том самом твипсе (twips).
Что такое твипс? Это единица, на которую графическая система может фактически сдвинуть пиксель на экране. Для Adobe Flash Player величина твипса равна 1/20 пикселя или 0.05.
В тоже время величина смещения пикселя в матрице трансформации задается переменной типа Number (число с плавающей точкой удвоенной точности) с интервалами значений 1,79e+308 - 5e-324 (на практике это выглядит как 206.93289340754893).
Что получается в результате?
Класс Matrix оперирует через Number, перемещения же должны задаваться кратными 0.05. В итоге transform.matrix и transform.concatenatedMatrix при записи в них данных округляют Number до 0.05. Причем, по моим наблюдениям, округляют всегда вниз (например число 0.728 округляется как 0.7 а не 0.75 как должно бы быть).
Что получается на практике:
Имея на входе координаты нового положения объекта в глобальном пространстве и исходные координаты объекта в локальном пространстве, в любом случае нужно производить приведение систем, чтобы получить правильную матрицу трансформации. Соответственно в любом случае будут вызваны GlobalToLocal или LocalToGlobal т.е. на результат приведения обязательно повлияет concatanatedMatrix объекта.
Пусть координаты объекта в локальной системе x1,y1. Имея новые координаты X0,Y0 в глобальной системе, конкатенейтед-матрица в это время M, после преобразования получаем X1,Y1 в локальной системе. Получаем матрицу преобразования, умножаем ее на матрицу трансформации (теперь конкатенейтед-матрица объекта стала M1). На следующей итерации снова подаем на вход X0,Y0. Преобразовав их с помощью матрицы M1, мы должны получить координаты X2,Y2 равные x1,y1, если бы все считалось точно, но не получаем. Погрешность округления tx,ty в concatenatedMatrix дает нам X2,Y2 чуть чуть сдвинутыми. Что заставляет вновь пересчитать матрицу преобразования, умножить ее на матрицу трансформации и чуть-чуть подвинуть объект на экране. По моим наблюдениям погрешность, возникающая в tx,ty в concatenatedMatrix достигает 0.2-0.4. На следующей итерации матрица преобразования отталкиваясь все от тех же X0,Y0 пытается скомпенсировать сдвиг предыдущей итерации. В результате на экране имеем явное дрожание.
Как с этим бороться?
Вариант самый простой - понизить точность и хранить координаты объектов в целых числах. Размер погрешности матриц трансформации такое понижение точности компенсирует. Дрожание пропадает, но за это расплачиваемся более дерганым движением быстрых объектов.
Другой, тоже простой, вариант - в каждом объекте хранить не только его локальные координаты но и координаты в глобальной области с округлением до 0.05 и при вызове процедуры перемещения проводить проверку на равенство входящих и имеющихся глобальных координат. Минус - избыточность хранения ненужных данных, ведь имея локальные координаты объекта и матрицу трансформации всегда можно получить его глобальные координаты.
Ну и третий вариант - переписать всю математику, классы Point,Matrix и их методы на работу с неокругленными Number. Хотя возможно все равно это не даст нужного результата т.к. при применении точной матрицы к матрице трансформации Flash все равно округлит точные значения так, как пожелает.
Tags: actionscript 3.0, progr, интерпланети
Subscribe

  • Сервер B3D Interplanety в discord

    Сервер B3D Interplanety в Discord. Для обсуждения вопросов по Blender, его API, разработки скриптов и аддонов. Вопросы, не относящиеся…

  • Аддон Blender "Select-UP" v. 1.2.0.

    Обновление аддона "Select-UP" до версии 1.2.0. Добавлено выделение в зависимости от парентинга объектов Читать дальше:…

  • Оператор для скрытия объекта во всех сценах

    Для того, чтобы скрыть объект в окне 3D Viewport только для текущей сцены мы все пользуемся оператором object.hide_view_set, вызов которого…

Comments for this post were disabled by the author