openGL 2D Parallax Scrolling Texture Слезы / Швы - PullRequest
0 голосов
/ 08 мая 2018

Я реализую 2-мерную параллаксную прокрутку в openGL, используя один квад и текстурный атлас.

Я использую следующее (смещение 1,0 / количество слоев, поэтому 0,2):

atlas

Работает почти идеально, но при определенных смещениях швы в точках петли видны. (См. Слезу в средней стене, которая показывает замок и океан позади него.)

seam

Мой алгоритм: Для каждого фрагмента рассчитайте положение в текстуре со смещением * i; Если цвет прозрачный, перейдите к смещению * (i + 1) и т. Д. Остановитесь, когда нажмите сплошной цвет. Опять же, смещение составляет 1,0 / (количество слоев) или 0,2 здесь.

На изображении выше, похоже, что мой алгоритм выбирает пространство слева или справа от правильного положения текстуры, поэтому он получает прозрачный цвет, что неверно.

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

Есть ли способ выполнить расчеты, чтобы гарантировать, что участки текстуры цикличны? - Может быть, использовать фрактал и пол каким-то необычным образом? (Я нашел это обсуждение, но не смог понять его полностью, потому что ни ОП, ни принятый ответ не объяснили значение многих переменных: смещения параллакса с текстурным атласом? В нем используются фрактал и пол, но этот метод может быть несовместим. Трудно сказать.)

В этом случае ниже приведены соответствующие выдержки из моего кода вершинного и фрагментного шейдера (с удалением ненужных частей - с использованием precision highp float):

// vertex shader
void main(void) 
{
   gl_Position = u_matrix * vec4(a_position, 1.0);
   v_uv = vec2(a_uv.x * u_offset_layers_x, a_uv.y);
   v_position_cam = u_position_cam; // set the camera position to an out variable
}

// fragment shader
void main(void)
{
   vec4 texel;
   // each successive layer scrolls more slowly
   float rate = 0.65;
   // iterate through each layer and sample until the alpha is not 0
   // since I get tears every so often, I might have rounding errors that end up sampling part of a previous or successive texture by mistake
   for (int i = 0; i < u_count_layers; ++i) {
      // I use multiplications and divisions by 1000.0 in an attempt to reduce the error, but I don't think it works at all

      // the camera position offsets the parallax layer
      float sample_coord = v_uv.x + ((v_position_cam.x * 1000.0 * rate) / 1000.0);

      // the y offset seems fine
      float off_y = (-v_position_cam.y * rate * rate * rate);
      off_y = max(off_y, 0.0);

      // offset by i layers, add that offset to (the sampled coordinate * offset per layer) % offset per layer 
      texel = vec4(texture(tex0, vec2(
         (float(i) * u_offset_layers_x) + mod(sample_coord * 1000.0, u_offset_layers_x * 1000.0) / 1000.0,
         v_uv.y + off_y))
      );

      // if the alpha is not 0, then don't sample the layers behind it (a texel has an alpha of 0.0 or 1.0)
      if (texel.a != 0.0) {
         break;
      }

      // reduce the scroll speed for the next layer
      rate *= rate;
   }

   // output the color
   color = vec4(texel.rgb, texel.a);
}

** Я добавлю, что я мог бы легко использовать GL_REPEAT на 5 отдельных текстурах, сопоставленных с 5 квадратами (или перевязать униформу и заново визуализировать один и тот же квад), но я хочу, чтобы шейдер работал с одной текстурой и одним квадом для создания шейдерных эффектов и текстурные переходы наиболее легко достижимы при рендеринге в один квад. Кроме того, сокращение количества комплектов униформы - это хорошо. Кроме того, я заинтересован в разработке этой проблемы и использую этот метод для решения этой задачи. Я чувствую, что я близко, но я не могу найти документацию / решения проблемы сшивания / смещения. Отключение GL_REPEAT и использование GL_CLAMP_TO_EDGE, похоже, не сработало, но, по общему признанию, GL_REPEAT не требуется, если я использую такой атлас.

Заранее благодарю за помощь.

РЕДАКТИРОВАТЬ: Если подход с одной текстурой не работает, было бы ужасно связать 5-10 повторяющихся текстур сразу и использовать аналогичный алгоритм, но полагаться на GL_REPEAT вместо мода? Я думаю, что это, вероятно, приведет к худшей производительности, но я могу ошибаться. В будущем я хотел бы перейти между двумя многослойными фонами, используя плавный шаг. Вот почему я предпочитаю подход с одним квадром. Кроме того, если я получу эту работу, тогда у меня будет больше слоев.

РЕДАКТИРОВАТЬ 2: Я заметил, что на этом скриншоте отсутствует одна вертикальная черная линия на «кирпичной кладке», поэтому я думаю, что здесь происходит то, что выборка / интерполяция иногда дает сбой на уровне идеального пикселя, что имеет смысл , Есть ли способ обойти это?

1 Ответ

0 голосов
/ 08 мая 2018

Я бы сказал, что вы слишком умны, пытаясь сделать это в фрагментном шейдере. Было бы намного проще просто вычислить правильные положения для каждого слоя параллакса на основе положения «камеры». Если вам нужно обернуться вокруг, вы также визуализируете второй квад для этого слоя. Таким образом, вы можете предотвратить взлом, гарантируя, что позиции вершин для общих вершин идентичны.

Поскольку вы используете текстурный атлас, вам даже не придется менять текстуры между различными слоями.

...