GLSL шейдер: порядок окклюзии и выбраковка

У меня есть GLSL-шейдер, который рисует трехмерную кривую с учетом набора кривых Безье (трехмерные координаты точек). Само рисование выполняется так, как я хочу, за исключением того, что окклюзия не работает должным образом, т. Е. При определенных точках обзора кривая, которая должна находиться в самом переднем крае, кажется, все еще закрыта, и наоборот: часть кривой, которая предполагается быть окклюдированным все еще видно.

Чтобы проиллюстрировать, вот несколько примеров скриншотов:

1 - Цветная кривая ближе к камере, поэтому она отображается правильно. правильный рендер

2 - Предполагается, что цветная кривая находится за серой кривой, но она отображается сверху. неправильный рендер

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

Что касается моего кода, он немного длинный (плюс я использую библиотеку обертки OpenGL), но основные шаги:

  1. В вершинном шейдере я вычисляю gl_Position = ModelViewProjectionMatrix * Vertex; и передайте информацию о цвете в геометрический шейдер.
  2. В геометрическом шейдере я беру 4 контрольные точки (lines_adjacency) и их соответствующие цвета, и получим треугольную полосу, которая следует кривой Безье (я использую некоторую базовую интерполяцию цветов между сегментами Безье).
  3. Фрагмент шейдера также прост: gl_FragColor = VertexIn.mColor;,

Что касается настроек OpenGL, я включаю GL_DEPTH_TEST, но, похоже, нет ничего из того, что мне нужно. Также, если я добавлю на сцену любую другую не-шейдерную геометрию (например, quad), кривые всегда отображаются поверх нее, независимо от точки обзора.

Любые идеи и советы о том, как решить и почему это происходит, приветствуются.

Обновление решения

Итак, первоначальная проблема, как я узнал, заключалась не в нахождении алгоритма отбраковки, а в том, что я неправильно обрабатываю вычисление z-значений (см. Принятый ответ). Я также узнал, что при правильной настройке буфера глубины OpenGL самостоятельно обрабатывает окклюзии, поэтому мне не нужно заново изобретать колесо.

Я искал в своей программе GLSL и обнаружил, что я в основном устанавливаю z-значения в нули в своем геометрическом шейдере при переводе координат вершины в экранные координаты (vec2( vertex.xy / vertex.w ) * Viewport;). Я исправил это, рассчитав z-значения (vertex.z/vertex.w) по отдельности и присваивает им излучаемые баллы (gl_Position = vec4( screenCoords[i], zValues[i], 1.0 );). Это решило мою проблему.

Что касается настроек буфера глубины, мне не нужно было явно указывать их, поскольку используемая библиотека настраивает их по умолчанию правильно, как мне нужно.

1 ответ

Решение

Если вы не используете буфер глубины, то последний отображаемый объект всегда будет сверху.

Вы должны включить его с glEnable(GL_DEPTH_TEST), установите функцию по своему вкусу (glDepthFunc(GL_LEQUAL)) и убедитесь, что вы очищаете его каждый кадр со всем остальным (glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)).

Затем убедитесь, что ваш вершинный шейдер правильно устанавливает значение Z конечной вершины. Похоже, что самый простой способ установить часть модели ModelViewProjectionMatrix на стороне процессора, чтобы иметь значение глубины, прежде чем он будет передан в шейдер.

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

Другие вопросы по тегам