Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Межпланетье - заметки на полях

Мысли, возникающие в процессе работы над проектом "Межпланетье".
Оценить эту запись

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

Запись от Korchy размещена 21.05.2012 в 14:40

Как реализовано движение объекта:
Есть алгоритм, вычисляющий положение объекта в зависимости от параметров и времени. Т.е. в любой момент времени, а точнее - каждую итерацию игрового цикла, положение объекта пересчитывается. Результата возвращается в глобальной системе координат (мировая система).
Соответственно, каждую итерацию игрового цикла происходит вызов процедуры перемещения объекта из координат предыдущей итерации в координаты итерации текущей.
Т.к. скорости движения отдельных объектов невелики, блоками происходит "пустой" вызов процедуры перемещения (когда координаты объекта в предыдущей итерации цикла равны координатам объекта в текущей итерации). Не оптимально, но разговор сейчас не об этом.
А о том, что в принципе перемещение из точки в туже самую точку не должно вызывать фактического перемещения. Процедура перемещения генерирует единичную матрицу, единичная матрица, умноженная на матрицу трансформации объекта, матрицу трансформации не меняет. Но...
На практике такой подход вызывает периодическое, заметное глазом, дрожание объекта. Т.е. фактически происходит перемещение там, где его не должно быть.
Причина же заключается в том самом твипсе (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 все равно округлит точные значения так, как пожелает.
Всего комментариев 4

Комментарии

Старый 21.05.2012 20:52 Aquahawk вне форума
Aquahawk
 
Аватар для Aquahawk
нецелые координаты это ресемплинг(вроде это так называлось) картинки, т.е. вместо пикселей картинки рендерер пытается сделать так, чтобы картинка с нецелыми координатами на мониторе выглядела похоже, по факту происходит сильное падение резкости. Обычно я например отказываюсь от нецелых координат вообще, либо лучше всего руками сделать субпиксельное сглаживание. Принцип хорошо показан тут
Старый 21.05.2012 21:58 Korchy вне форума
Korchy
 
Аватар для Korchy
Для простого примера ваш способ годится. Но для сложного, где объект может двигаться в любом направлении, а плюс еще может быть повернут вокруг центра - это не прокатит.
Целые координаты это примерно как на калькуляторе считать 2+2. Можно и корни брать, но не будем, потому как ограничим себя только сложением
Проблема же, с которой я столкнулся, заключается в погрешности округления матриц трансформации до твипса. Мне совершенно не понятно, зачем округление было закачивать напрямую в матрицы. Округление можно было бы делать один раз, собственно при рендере, но мы имеем его уже в матрицах. Хотя возможно проблема бы не решилась и использованием неокругленных значений т.к. организация хранения чисел с плавающей точкой уже подразумевает наличие некоей погрешности.
Старый 22.05.2012 15:24 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Ну да, можно считать это косяком Adobe. Вместо того чтобы ввести округление толко на этапе рендера (то есть сделать всем объектам скрытое свойство renderMatrix), они сохраняют данные в общедоступные свойства.
Но.
Если бы они все таки ввели 2 вида матриц (для рендера и для ActionScript), то отображаемое на экране не всегда совпадало бы с моделью данных. Кроме того, пришлось бы хранить в 2 раза больше данных на каждый объект.
Старый 22.05.2012 19:01 Korchy вне форума
Korchy
 
Аватар для Korchy
Идеальный вариант наверное был бы - рендерить с точностью Number, а Number хранить без погрешностей.
 

 


Часовой пояс GMT +4, время: 09:20.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.