Дрожание эффекта параллакса в libGDX

В основном я использую этот класс ParallaxCamera для создания эффекта в моей игре, но при движении слои "покачиваются". Это особенно заметно, когда камера движется медленно.

Я исправил временной шаг и использую интерполированное сглаживание. Я использую увеличенный пиксель-арт. Камера сосредоточена на игроке, обновляется после движения. Отключение эффекта делает перемещение камеры плавным.

Какие, я думаю, проблемы могут быть:

  • слои движутся с разной скоростью, что означает, что они перемещаются в разное время

  • округление для отображения заставляет слои принимать немного разные положения в каждом кадре при перемещении камеры

Спасибо за любую помощь


person Arunex    schedule 23.01.2020    source источник
comment
В вашей игре пиксель-арт с низким разрешением? Используете ли вы ближайшую фильтрацию текстур?   -  person Tenfour04    schedule 24.01.2020
comment
да, у меня есть 384x216 с ближайшим, и я масштабирую его. при масштабировании он правильно использует дополнительное разрешение для анимации, однако слои просто не двигаются вместе   -  person Arunex    schedule 28.01.2020


Ответы (1)


Я использовал эту стратегию для пиксельной графики с низким разрешением. Я рисую в небольшой FrameBuffer с разрешением 1:1, а затем рисую его на экране. Это должно позаботиться о дрожании.

Если ваша сцена также имеет такое же разрешение, вам придется использовать небольшой хак, чтобы обеспечить правильную обработку ввода. Тот, который я использовал для использования StretchViewport, но я вручную вычисляю ширину и высоту мира, чтобы не растягивать мир, поэтому я в основном делаю те же вычисления, что и ExtendViewport за кулисами. Вы также должны округлить до целого числа ширину и высоту. Вы должны сделать это в resize и применить ширину и высоту, используя viewport.setWorldWidth() и setWorldHeight(). Таким образом, в этом случае не имеет значения, какой размер мира вы задаете конструктору, поскольку он будет изменен в update().

Когда вы вызываете update в окне просмотра в resize, вам нужно делать это в контексте FrameBuffer, в который вы рисуете. В противном случае это испортит размеры буфера кадров экрана.

public void resize(int width, int height) {

    int worldWidth = Math.round((float)WORLD_HEIGHT / (float)height * (float)width);
    viewport.setWorldWidth(worldWidth);
    viewport.setWorldHeight(worldHeight);
    frameBuffer.begin();
    viewport.update(width, height, true); // the actual screen dimensions
    frameBuffer.end();

}

Вы можете посмотреть примеры использования FrameBuffer в LibGDX. Вы должны делать все отрисовки в игре между frameBuffer.begin() и end(), а затем отрисовывать цветовой буфер frameBuffer на экран следующим образом:

stage.act();
frameBuffer.begin();
//Draw game
stage.draw();
frameBuffer.end();
spriteBatch.setProjectionMatrix(spriteBatch.getProjectionMatrix().idt());
spriteBatch.begin();
spriteBatch.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2);
spriteBatch.end();

В моем случае я делаю более сложный расчет ширины и высоты мира, чтобы они представляли собой целочисленный множитель фактических размеров экрана. Это предотвращает разный размер больших пикселей на экране, что может плохо выглядеть. Кроме того, вы можете изменить фильтрацию текстуры FrameBuffer на линейную и использовать масштабирующий шейдер при ее рисовании.

person Tenfour04    schedule 28.01.2020
comment
фреймбуфер мало что сделал, но я думаю, это не повредит. Я снял небольшое видео, где это хорошо видно (облако, гора, лес или передний план) youtube.com/ watch?v=eA3eMqwhNZM нет проблем с масштабированием при помощи screenviewport, фактически я могу использовать любое разрешение. игра замедляется x28 для видео. если я присмотрюсь, то увижу это даже в таких играх, как террария, но множество крошечных движений усугубляют это. заставляет меня думать, что виновата природа параллакса, возможно, он становится все менее и менее плохим, чем выше масштабирование (например, на дисплее 4k). вы используете сцену только для пользовательского интерфейса, верно? Спасибо за помощь - person Arunex; 30.01.2020
comment
FrameBuffer сделал бы этот тип дрожания невозможным, потому что пиксели не могли перемещаться на незначительное расстояние. В вашем видео я вижу, что вы не используете FrameBuffer с масштабом пиксельной графики 1: 1, потому что пиксели разных слоев могут частично перекрывать друг друга. - person Tenfour04; 30.01.2020
comment
хорошо, если бы мои слои перемещались только в точных пикселях, это было бы еще более нервно, не так ли? или какова цель фреймбуфера здесь? Я использовал ваш код, только с screenviewport, потому что это дало мне идеальное масштабирование для любого разрешения. - person Arunex; 30.01.2020
comment
Он будет двигаться более блочно, а не нервно. Это ничем не будет отличаться от настоящей ретро-игры, в которой никогда не было пикселей, частично перекрывающих друг друга. Блочный эффект не вызывает тошноты, как дрожь. Я делаю это таким образом, чтобы добиться аутентичного ретро-вида. Эта стратегия не сработает, если это не тот внешний вид, который вам нужен. - person Tenfour04; 30.01.2020
comment
Я не пошел на этот взгляд раньше. Я думаю, что решением может быть пользовательский шейдер, в котором вы делаете текстуры линейными, а затем в шейдере применяете функцию к координатам текстуры перед их использованием, чтобы они выполняли в основном ближайшую фильтрацию, за исключением узкой области на краях текселей. Это должно было бы придать ему небольшую плавность на самых краях ваших пикселей. Вы бы сделали эту гладкую область шириной с результирующий экранный пиксель. Я не делал ничего из этого раньше ... это просто идея. - person Tenfour04; 30.01.2020
comment
ну это очень шатко для меня. Игры Unity, такие как Hollow Knight, имеют очень хороший параллакс, поэтому должно быть что-то - person Arunex; 31.01.2020
comment
Hollow Knight имеет спрайты высокого разрешения с линейной фильтрацией. Дрожание является результатом округления до ближайшего фильтра. Вот почему я предлагаю шейдерному решению использовать линейную фильтрацию, сохраняя внешний вид с низким разрешением. Но в качестве примера того, что я сделал в ответе выше, посмотрите на Shovel Knight. Это также есть в Unity, и они используют ту же настройку перспективной камеры, что и Hollow Knight, но они должны выполнять рендеринг в небольшой буфер кадра, как в моем примере выше, потому что пиксели никогда частично не перекрывают друг друга. - person Tenfour04; 31.01.2020
comment
э-э, может быть, мне следует придерживаться игр с видом сверху, а затем XD или лучше рисовать .. лопата-рыцарь не пересекается? что ты имеешь в виду? мне не кажется, что он движется целыми пикселями... разве лопатный рыцарь не работает лучше, потому что это только ось X, есть несколько слоев и персонаж движется с постоянной скоростью? у меня не сработал буфер кадров, что именно я должен увидеть? точно так же, как и без масштабирования, кроме большего размера, верно? или я что-то пропустил здесь? и вау, установил фильтр на линейный и весь джиттер пропал... - person Arunex; 31.01.2020