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

  • Вспоминательское :)

    - А ты кто такой, откуда приехал? - С того берега моря. Оседлал хромую блоху и приехал. - Море что, лужа? - Может и лужа, только ту лужу орел не…

  • Игровое )

    Китайский смартфон, если подумать, суть стратежка на выживание. Два ресурса: заряд аккумулятора и объем интернета. И месяц выживай :)

  • Времястремительное )

    - Я старый си-плюс-плюсник и не знаю слов джаваскрипт...

Comments for this post were disabled by the author