GLSL шейдер: порядок окклюзии и выбраковка
У меня есть GLSL-шейдер, который рисует трехмерную кривую с учетом набора кривых Безье (трехмерные координаты точек). Само рисование выполняется так, как я хочу, за исключением того, что окклюзия не работает должным образом, т. Е. При определенных точках обзора кривая, которая должна находиться в самом переднем крае, кажется, все еще закрыта, и наоборот: часть кривой, которая предполагается быть окклюдированным все еще видно.
Чтобы проиллюстрировать, вот несколько примеров скриншотов:
1 - Цветная кривая ближе к камере, поэтому она отображается правильно.
2 - Предполагается, что цветная кривая находится за серой кривой, но она отображается сверху.
Я новичок в GLSL и, возможно, не знаю правильного термина для этого вида эффекта, но я предполагаю, что это выборка окклюзии (обновление: это фактически указывает на проблему с буфером глубины, путаница в терминологии!). Мой вопрос: как мне бороться с окклюзиями при использовании шейдеров GLSL? Нужно ли обрабатывать их внутри шейдерной программы или где-то еще?
Что касается моего кода, он немного длинный (плюс я использую библиотеку обертки OpenGL), но основные шаги:
- В вершинном шейдере я вычисляю
gl_Position = ModelViewProjectionMatrix * Vertex;
и передайте информацию о цвете в геометрический шейдер. - В геометрическом шейдере я беру 4 контрольные точки (
lines_adjacency
) и их соответствующие цвета, и получим треугольную полосу, которая следует кривой Безье (я использую некоторую базовую интерполяцию цветов между сегментами Безье). - Фрагмент шейдера также прост:
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
на стороне процессора, чтобы иметь значение глубины, прежде чем он будет передан в шейдер.
Пока вы используете матрицу ортографической проекции, визуализация не должна быть затронута (помимо правильного порядка прорисовки).