Z-бои после глубокой подготовки на GTX 980
Я реализую глубинный подготовительный в OpenGL. На Intel HD Graphics 5500 этот код работает нормально, а на Nvidia GeForce GTX 980 - нет (на рисунке ниже показан результат z-боя). Я использую следующий код для генерации изображения. (Все, что не имеет отношения к проблеме, опущено.)
// ----------------------------------------------------------------------------
// Depth Prepass
// ----------------------------------------------------------------------------
glEnable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glUseProgam(program1); // The problem turned out to be here!
renderModel(...);
// ----------------------------------------------------------------------------
// Scene Rendering
// ----------------------------------------------------------------------------
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_FALSE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glUseProgam(program2); // The problem turned out to be here!
renderModel(...);
Похоже, что glDepthFunc не изменился на GL_LEQUAL
, Тем не менее, когда я перехожу через вызовы GL в RenderDoc, glDepthFunc
установлен правильно.
Похоже ли это на ошибку драйвера или у вас есть предложения, что я могу делать не так? Когда это ошибка драйвера, как я могу реализовать предварительный анализ глубины?
2 ответа
При использовании другой программы шейдера для предварительной подготовки глубины необходимо четко убедиться, что эта программа генерирует те же значения глубины (хотя и для одной и той же геометрии), что и программа для основного прохода. Это делается с помощью invariant
классификатор на gl_Position
,
Разница объясняется GLSL-спецификацией 4.4:
В этом разделе под дисперсией понимается возможность получения разных значений из одного и того же выражения в разных программах. Например, скажем, два вершинных шейдера в разных программах, каждый из которых устанавливает gl_Position с одним и тем же выражением в обоих шейдерах, а входные значения в это выражение одинаковы при запуске обоих шейдеров. Возможно, из-за независимой компиляции двух шейдеров, значения, присвоенные gl_Position, не совсем одинаковы при запуске двух шейдеров. В этом примере это может вызвать проблемы с выравниванием геометрии в многопроходном алгоритме.
В этом случае классификатор используется следующим образом:
invariant gl_Position;
Эта линия гарантирует, что gl_Position
вычисляется по точному выражению, которое было дано в шейдере без какой-либо оптимизации, так как это изменит операции и, следовательно, вполне вероятно, изменит результат каким-то незначительным образом.
В моем конкретном случае источником проблемы было назначение. Вершинный шейдер программы для основного прохода содержал следующие строки:
fWorldPosition = ModelMatrix*vPosition; // World position to the fragment shader
gl_Position = ProjectionMatrix*ViewMatrix*fWorldPosition;
Вершинный шейдер программы для препасса вычисляется gl_Position
в одном выражении:
gl_Position = ProjectionMatrix*ViewMatrix*ModelMatrix*vPosition;
Изменив это на:
vec4 worldPosition = ModelMatrix*vPosition;
gl_Position = ProjectionMatrix*ViewMatrix*worldPosition;
Я решил проблему.
Некоторые из версий Sponza огромны. Я помню, что исправил эти проблемы с одним из двух решений:
Буфер глубиной 24 бита.
Второй подход уступает плиточным архитектурам, которые используют ранний тест глубины для удаления скрытой поверхности. На мобильных платформах снижение производительности может быть довольно заметным.