Разрыв координат текстуры с мипмапами создает швы

9

Я только начал изучать openGL и получаю этот артефакт при текстурировании сферы с помощью мипмапов. В основном, когда фрагмент выбирает край моей текстуры, он обнаруживает разрыв (скажем, от 1 до 0) и выбирает наименьшее mipmap, которое создает этот уродливый шов:

уродливый шов http://cdn.imghack.se/images/6bbe0ad0173cac003cd5dddc94bd43c7.png

Поэтому я попытался вручную переопределить градиенты, используя textureGrad:

//fragVert is the original vertex from the vertex shader
vec2 ll = vec2((atan(fragVert.y, fragVert.x) / 3.1415926 + 1.0) * 0.5, (asin(fragVert.z) / 3.1415926 + 0.5));
vec2 ll2 = ll;
if (ll.x < 0.01 || ll.x > 0.99)
    ll2.x = .5;
vec4 surfaceColor = textureGrad(material.tex, ll, dFdx(ll2), dFdy(ll2));

Теперь я получаю два шва вместо одного. Как я могу избавиться от них? И почему код выше генерирует 2 шва?

2 eams http://cdn.imghack.se/images/44a38ef13cc2cdd801967c9223fdd2d3.png

Вы не можете сказать по двум изображениям, но 2 шва находятся по обе стороны от оригинального шва.

omikun
источник
2
Является ли ваша сфера сеткой или вы трассируете ее аналитически в шейдере или что-то подобное? Если это сетка, люди обычно решают эту проблему путем дублирования вершин вдоль шва, чтобы у вершин на одной стороне было u = 0, а на другой стороне было u = 1.
Натан Рид
Что касается того, почему ваш код генерирует два шва, я ожидаю, что это потому, что он создает две несплошности - одна, где u скачет с 0,01 до 0,5, а другая - где u скачет с 0,99 до 0,5. Это та же проблема, что и при переходе от 0 к 1 - не такой большой, как прыжок, но все же большой прыжок.
Натан Рид
У меня есть сетка для сферы. Это декаэдр, поэтому вершины не совпадают со швом. Самое смешное в этих двух швах - первоначальный шов исчез. Кроме того, я получаю те же 2 шва, даже если я зажимаю его до 0,01 или 0,99.
omikun
Можете ли вы опубликовать скриншот дела с двумя швами? И как вы генерируете UV (можете ли вы опубликовать соответствующую часть вашего кода)? Я предполагаю, что вы генерируете их процедурно в шейдере, а не просто интерполируете их из вершин, иначе ваша сетка додекаэдра не будет работать вообще.
Натан Рид
Я обновил вопрос с изображением 2 швов, они по обе стороны от оригинального шва, но оригинального шва там нет. Я думаю, что УФ интерполируются от вершин, не уверен. Код сейчас в вопросе.
omikun

Ответы:

4

Основываясь на опубликованном вами коде шейдера, вы не интерполируете UV-координаты из вершин - скорее всего, вы интерполируете трехмерную позицию (fragVert ), а затем вычисляете UV-координаты путем преобразования в сферические координаты.

Ваш анализ верен в том, что наименьшее значение mipmap выбирается при наличии разрыва, поскольку выбор mipmap основан на производных, которые оцениваются численно по UV, используемым в соседних пикселях. Когда один пиксель имеет u = 0, а другой - u = 1, вы получите очень большую производную. Ваша попытка исправить имеет ту же проблему в том, что большие производные встречаются вокруг u = 0,01 и u = 0,99, поэтому два шва появляются по обе стороны от того места, где был первоначальный шов.

Относительно простой подход к решению проблемы состоит в том, чтобы решить, какой уровень MIP использовать самостоятельно, и вызвать textureLodего напрямую. Если планета всегда будет находиться достаточно близко к камере, вы можете просто жестко закодировать уровень мипа в 0 (или, если уж на то пошло, вообще не включать уровни мипа в текстуру). В противном случае это может быть основано на log2 расстояния точки от камеры, масштабируемого некоторыми подходящими факторами. Обратите внимание, что это эффективно отключит анизотропную фильтрацию.

Более «правильный» подход заключается в расчете некоторых более качественных производных. Вместо использования dFdxи dFdyна ультрафиолетовых лучах, которые имеют разрывы из-за atan2, вы можете применить dFdxи dFdyк fragVert(который будет непрерывным на всем протяжении сферы), затем использовать некоторое исчисление (правило цепочки), чтобы найти формулу для получения производных УФ с позиции производных. Это будет более сложным и медленным, но имеет то преимущество, что анизотропная фильтрация должна работать.

Наконец, поскольку вы новичок в OpenGL, я просто отмечу, что, хотя вычисление UV по сферическим координатам является совершенно правильным способом текстурирования сферы, это не «обычный» способ, который выбирает большинство людей. Чаще всего строят сферическую сетку, в которой для каждой вершины заданы значения UV и просто передаются из вершинного шейдера в пиксельный шейдер (линейно интерполируемый по каждому треугольнику). Вершины располагаются вдоль шва, таким образом , что есть две копии каждой вершины, в точно таких же положениях, но половина с u = 0 соединена с треугольниками на одной стороне, а другая половина с u = 1 соединена с треугольники на другой стороне. Это устраняет любой видимый шов и не требует никаких хитростей в пиксельном шейдере.

Натан Рид
источник