GBA dev - аффинные спрайтные паузы каждые 90 градусов, BG без изменений
РЕДАКТИРОВАТЬ: я разобрал программу до ее основ: https://github.com/aidan-aidan/temp/blob/master/source/vpp.c
Я разместил этот вопрос на форумах gba-dev, но они кажутся довольно мертвыми, и я не получил ответа через много дней.
Вот видео, показывающее проблему: http://youtu.be/8gweFiSobwc (в отличие от кода выше, вы можете запустить ROM, если хотите его увидеть)
Как вы можете видеть, на ротацию BG это не влияет, хотя они используют одну и ту же LUT и имеют одинаковые типы данных в своих структурах друг с другом.
Я несколько раз переделывал LUT безрезультатно, и эта проблема появилась только после переключения на 2048 делений круга, а не на 256.
Глядя на просмотрщик памяти в VBA, я вижу, что pb ведет себя не так, как pa. pa колеблется от 0x0100 до 0, как и следовало ожидать (то же самое, что и от 1 до 0), но pb колеблется от 0 до 0x0096, когда пистолет направлен вправо от центральной линии, но скачет до 0xFFFF, как только он уходит влево от центральной линии, Единственное, что я могу понять, это то, что он идет в отрицательном направлении (что имеет смысл, поскольку косинус этого угла должен привести к отрицательному числу), но я не совсем понимаю, какое из них дополняет, поэтому я не уверен 0 "градусов" - горизонтальный справа для пистолета. 512 будет девяносто градусов.
Я включил все, что я могу придумать, любая помощь приветствуется.
Спасибо!
1 ответ
Насколько я могу судить, программа технически работает правильно. Вместо этого ваши визуальные артефакты проистекают из ограниченной 8-битной точности с фиксированной точкой в аффинном преобразовании, используемом аппаратными средствами.
По сути, разница между 0 и 1 в таблицах синусов делает довольно большой и видимый скачок поворота для прямых углов в вашем прямоугольном спрайте, в то время как углы 0°/90°/180°/270° не являются особенными для фона круглой земли.
Тангенс для (со) синусоидальной функции в 0 высокий, поэтому, если вы посмотрите на свои таблицы, есть только одна точка, где они точно равны 0. Если вращение не падает точно по этому индексу, результат выглядит заметно искаженным,
Однако вы можете попытаться обмануть, поиграв с округлением, чтобы получить больше последовательных нулей. В настоящий момент ваш генератор таблиц масштабируется на 256 и округляется до ближайшего целого числа:
sine[i] = floor(sin(i * M_PI / 1024.0) * 256.0 + 0.5);
As an alternative we may skew the table a little by rounding towards zero, as is the default in C, and increasing the scale to insure that the table still reaches 256 for at more than one entry.
int value = sin(i * M_PI / 1024.0) * 257.0;
if(value < -256) value = -256;
if(value > +256) value = +256;
sine[i] = value;
The table may be then flattened even further by increasing the scaling factor even further.
The problem is also that for small sprites near right angles there is nowhere for the rotation to go.
Picture a 64x1 straight line sprite pointing vertically at nearly an almost straight angle, with only the minimum 1/256th fractional step from the sine table. Keep in mind that the rotation is always centered so you get one jagged horizontal step precisely at the center.
For each of the 32 pixels from the center outwards you then add up another 1/256th fraction to the texture coordinate. However all of these together only make for 1/8th of a pixel in total and so no more horizontal steps are taken. In fact for this sprite shape you will see no visible change until the rotation angle reaches a full 8/256th fraction.
On the other hand your large earth object is sufficiently big to always show multiple visible integer "steps." This means that an increased rotation angle will always at least shift the position of the non-centered step, even if it insufficient to add up to another full pixel along entire side. The result is a smoother overall effect due to the continual animation.