Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Вопрос про glPolygonOffset и Z-Fighting (решено, надо 2 прохода, во втором отключить запись в depth buffer и сместить far plane)

Вопрос про glPolygonOffset и Z-Fighting (решено, надо 2 прохода, во втором отключить запись в depth buffer и сместить far plane)

Страницы: 1 2 3 Следующая »
Роман ШуваловУчастникwww8 мая 20181:53#0
Никогда не оказывался в ситуации, где мог бы начаться Z-Fighting и посему не имел дел с методами борьбы с ним. И вот настал момент, когда пришлось столкнуться с проблемой.

Еще давно, изучая OpenGL, я чё-то слышал про glPolygonOffset и тогда еще подумал, что в случае чего проблему быстро решу. А сейчас вместо решения получил фиг. У меня нет возможности включать-отключать оффсет между наслаивающимися друг на друга объектами. Мне надо сделать так, чтобы Depth Test проверял значения со смещением. Объяснить можно примерно так: в glDepthFunc по умолчанию GL_LESS, а мне, грубо говоря, надо чтоб было GL_LESS с разницей не менее N единиц глубины. Есть такое? Если нет, как обойти?

P.S.: Проблемные полигоны реально лежат в одной плоскости, т.е. дело не в точности. Z-Fighting виден всегда и он абсолютно законный. Задача - показать (скрыть) только тот объект, который по порядку отрисовывался первым (последним).

Правка: 8 мая 2018 2:52

MrShoorУчастникwww8 мая 20182:36#1
Роман Шувалов
Давай скрин чтоль с файтингом. Может тебе вообще reverse depth поможет.
foxesПостоялецwww8 мая 20182:47#2
C Z-Fighting есть много всяких решений. Некоторые можно просто придумать по ходу решения задачи. Использование glPolygonOffset это уж совсем простой пример. Чаще все это шейдерами допиливается.
На вскидку можно банальным масштабирование пределов Near/Far чего то добиться. Проблема в том что глубина прежде всего имеет от части свойство плавающей точки. То есть ближние объекты с шагом по Z = 1 будут выглядеть идеально, а дальние с тем же шагом склеятся и поплывут.
Прежде всего надо понимать с какими масштабами имеем дело.

Правка: 8 мая 2018 2:50

Роман ШуваловУчастникwww8 мая 20182:50#3
Скрин примерно как вот тут (картинка из интернета), только с текстурами.

Изображение

> Может тебе вообще reverse depth поможет.
А это еще зачем? Оно повышает точность, а у меня не в точности дело, объекты реально находятся в одной плоскости и реально проникают друг в друга, повышенная точность только это подтвердит. Задача - показать (либо скрыть) объект, нарисованный первым (или последним). Аналитически вручную искать пересекающиеся объекты слишком накладно. Depth Test разумеется отключать нельзя.

foxes
Прошу прощения, что не уточнил. Плоскости в действительности совпадают, т.е. z-fighting есть абсолютно всегда и он законный.

Правка: 8 мая 2018 2:53

foxesПостоялецwww8 мая 20182:53#4
Роман Шувалов
> объекты реально находятся в одной плоскости и реально проникают друг в друга
ну тут пожалуй можно и смещением обойтись. Один отрисовываешь с нулевым смещением, другой к примеру со значением 10, для теста можно так попробовать. То есть для каждого drawcall свой glPolygonOffset вызываешь.
foxes
> т.е. z-fighting есть абсолютно всегда и он законный.
Если треугольники будут ровно друг на друге лежать, с одинаковыми вершинами, то они ровно перетрут друг друга.

Правка: 8 мая 2018 3:04

MrShoorУчастникwww8 мая 20182:56#5
Роман Шувалов
> Скрин примерно как вот тут (картинка из интернета), только с текстурами.
Ну что такое z-fighting я то знаю. Чужой скрин можно было и не приводить.

> А это еще зачем? Оно повышает точность, а у меня не в точности дело
Уверен что не в точности? Если очень близко подлететь (на расстояние near plane) оно продолжает файтится?

> Аналитически вручную искать пересекающиеся объекты слишком накладно.
А как именно у тебя образуются такие объекты, лежащие в одной плоскости?

Роман ШуваловУчастникwww8 мая 20183:23#6
foxes
> Один отрисовываешь с нулевым смещением, другой к примеру со значением 10
Объектов много, порядка 10.000 штук. Рисуются они пачками, по несколько сотен за один DrawCall.

> Если треугольники будут ровно друг на друге лежать, с одинаковыми вершинами, то они ровно перетрут друг друга.
Да, перетрут, но нет ли способа наподобие того, что я описал в нулевом посте - минимальная разница для GL_LESS или типа того.

MrShoor
> Уверен что не в точности? Если очень близко подлететь (на расстояние near plane) оно продолжает файтится?
Да, я же написал, полигоны действительно лежат в одной плоскости (не в близкорасоложенных соседних, а именно в одной).

> А как именно у тебя образуются такие объекты, лежащие в одной плоскости?
Если вкратце, то это процедурно генерируемая геометрия. При генерировании я ничего не знаю о соседних объектах и поэтому могу попасть плоскостью ровно в кого-то из них. Генерирование идёт по заданным направлениям и опорным точкам, потому такое попадание - не редкость.

Если средств визуально избавиться от вот такого Z-файтинга нет, значит придётся анализировать геометрию и выявлять пересекающиеся плоскости. Это будет мягко говоря сложновато и долго :/

foxesПостоялецwww8 мая 20183:37#7
Роман Шувалов
> Генерирование идёт по заданным направлениям и опорным точкам, потому такое
> попадание - не редкость.
Ну ты можешь генерировать их в одной плоскости то есть как бы 2D - тогда это один вопрос, но если у тебя полностью 3D расстановка тут можно выбрать другой способ генерации.

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

+ Показать

Правка: 8 мая 2018 3:44

MrShoorУчастникwww8 мая 20183:39#8
Роман Шувалов
> Если средств визуально избавиться от вот такого Z-файтинга нет, значит придётся
> анализировать геометрию и выявлять пересекающиеся плоскости. Это будет мягко
> говоря сложновато и долго :/
На самом деле определить, что они лежат в одной плоскости с некоторой погрешностью не так уж и сложно.
Простейший вариант. Заводишь множество уже "занятых плоскостей".
std::unordered_set<ivec4> planes_set;
Здесь ivec4 - округленное уравнение плоскости Ax + By + Cz + D = 0. Округленное до tolerance * 0.5;
Далее пишем проверочку, что такая плоскость уже есть в множестве:
bool ContainsPlane(vec4 plane) {
  plane = plane / (vec4(normal_tolerance, normal_tolerance, normal_tolerance, offset_tolerance) * 2.0);
  for (int a = 0; a < 2; a++)
    for (int b = 0; b < 2; b++)
      for (int c = 0; c < 2; c++)
        for (int d = 0; d < 2; d++)
        {
          ivec4 i_plane ( a? floor(plane.x) : ceil(plane.x), b? floor(plane.y) : ceil(plane.y), c? floor(plane.z) : ceil(plane.z), d? floor(plane.w) : ceil(plane.w) );
          if ( planes_set.find(i_plane) != planes_set.end() ) return true;
        }
  return false;
}

И при генерировании геометрии мы просто проверяем, если плоскость уже есть в множестве, то чуть-чуть её смещаем, пока не найдем свободное место. Нашли? Сгенерировали плоскость и добавили плоскость в множество:
bool InsertPlane(vec4 plane) {
  ivec4 i_plane = round( plane / (vec4(normal_tolerance, normal_tolerance, normal_tolerance, offset_tolerance) * 2.0) );
  planes_set.insert(i_plane);
}

Правка: 8 мая 2018 3:39

Роман ШуваловУчастникwww8 мая 20184:11#9
Так, товарищи, мы немного отвлеклись, с анализом генерируемых плоскостей я буду разбираться только если нет никаких способов визуально победить Z-Fighting. Их точно нет? Может, есть?
MrShoorУчастникwww8 мая 20184:26#10
Роман Шувалов
> с анализом генерируемых плоскостей я буду разбираться только если нет никаких
> способов визуально победить Z-Fighting. Их точно нет? Может, есть?
Чтобы победить z-fighting через polygon offset - нужно знать какой полигон на сколько сдвигать в момент рендеринга => нужно анализировать сгенерированные данные.
Роман ШуваловУчастникwww8 мая 20184:55#11
Значит полигон-оффсетом задача не решается. Другие решения?
MrShoorУчастникwww8 мая 20185:04#12
Роман Шувалов
> Значит полигон-оффсетом задача не решается. Другие решения?
При генерировании. Не допускать появления одинаковых плоскостей.
clcПостоялецwww8 мая 20185:38#13
можно в стенсил отрисовывать первые объекты и запрещать рисовать "конфликтующие"
DelfigamerПостоялецwww8 мая 20185:52#14
glPolygonOffset - он для случаев, когда один полигон реально должен быть нарисован поверх другого на той же плоскости. Главный пример - отрисовка декалей поверх геометрии.

Роман Шувалов
> Объяснить можно примерно так: в glDepthFunc по умолчанию GL_LESS, а мне, грубо
> говоря, надо чтоб было GL_LESS с разницей не менее N единиц глубины. Есть
> такое? Если нет, как обойти?
Будет очень смешно, если с GL_LEQUAL всё внезапно заработает.

Страницы: 1 2 3 Следующая »

/ Форум / Программирование игр / Графика

2001—2018 © GameDev.ru — Разработка игр