Использование 'discard' в фрагментном шейдере GLSL 4.1 с мультисэмплингом
Я пытаюсь выполнить глубинный пилинг с включенной мультисэмплингом, и у меня возникают проблемы с некорректными данными, которые попадают в мои прозрачные слои. Я использую следующее, чтобы проверить, является ли образец (первоначально фрагмент) действительным для этого прохода:
float depth = texelFetch(depthMinima, ivec2(gl_FragCoord.xy), gl_SampleID).r;
if (gl_FragCoord.z <= depth)
{
discard;
}
куда depthMinima
определяется как
uniform sampler2DMS depthMinima;
Я включил GL_SAMPLE_SHADING
что, если я правильно понимаю, должно привести к тому, что фрагментный шейдер вызывается для каждого образца. Если это не так, могу ли я добиться этого?
В результате первый или два слоя выглядят правильно, но под этим (и я делаю 8 слоев) я начинаю получать нежелательные значения - в основном, простой синий, иногда значения из предыдущих слоев.
Это прекрасно работает для буферов с одной выборкой, но не для буферов с несколькими выборками. Ключевое слово discard все еще отбрасывает весь фрагмент?
1 ответ
Я включил GL_SAMPLE_SHADING, что, если я правильно понимаю, должно привести к тому, что фрагментный шейдер вызывается для каждого образца отдельно.
Недостаточно только включить GL_SAMPLE_SHADING
, Вам также необходимо установить:
glMinSampleShading(1.0f)
Значение 1.0 указывает, что каждая выборка в кадровом буфере должна быть независимо затенена. Значение 0,0 эффективно позволяет GL игнорировать затенение частоты дискретизации. Любое значение от 0,0 до 1,0 позволяет GL затенять только подмножество всех выборок в каждом покрытом фрагменте. Какие образцы заштрихованы и алгоритм, используемый для выбора этого подмножества фрагментов, зависит от реализации.
Другими словами 1.0
говорит ему затенять все образцы. 0.5
говорит ему затенять как минимум половину образцов.
// Check the current value
GLfloat value;
glGetFloatv(GL_MIN_SAMPLE_SHADING_VALUE, &value);
Если либо GL_MULTISAMPLE
или же GL_SAMPLE_SHADING
отключен, тогда затенение образца не имеет никакого эффекта.
Для каждого фрагмента будет несколько вызовов фрагментированных шейдеров, для которых каждый образец является подмножеством фрагмента. Другими словами. Затенение образца определяет минимальное количество выборок для обработки для каждого фрагмента.
Если GL_MIN_SAMPLE_SHADING_VALUE
установлен в 1.0
затем будет выдан вызов фрагментного шейдера для каждого образца (в примитиве). Если установлено 0.5
тогда будет шейдерный вызов для каждого второго сэмпла.
max(ceil(MIN_SAMPLE_SHADING_VALUE * SAMPLES), 1)
Каждый оценивается в месте их отбора (gl_SamplePosition
). С gl_SampleID
являющийся индексом образца, который в настоящее время обрабатывается.
Следует ли отбрасывать работу для каждого образца или все еще работать только для каждого фрагмента?
С или без затенения образца discard
все еще только завершить единственный вызов шейдера.
Ресурсы:
Я столкнулся с аналогичной проблемой при использовании depth_peeling в буфере с несколькими сэмплами.
Некоторые артефакты появляются из-за ошибки depth_test при использовании текстуры multi_sample depth из предыдущего пилинга и текущей глубины фрагмента.
vec4 previous_peel_depth_tex = texelFetch(previous_peel_depth, coord, 0);
третий аргумент - это образец, который вы хотите использовать для сравнения, который даст значение, отличное от центра фрагмента. Как сказал автор, вы можете использовать gl_SampleID
vec4 previous_peel_depth_tex = texelFetch(previous_peel_depth, ivec2(gl_FragCoord.xy), gl_SampleID);
Это решило мою проблему, но с огромным падением производительности, если у вас есть 4 образца, вы запустите свой фрагментный шейдер 4 раза, если у 4 есть пилинг, это означает вызовы 4x4. Вам не нужно устанавливать флаги opengl, если хотя быglEnable(GL_MULTISAMPLE);
на
Любое статическое использование [gl_SampleID] во фрагментном шейдере вызывает оценку всего шейдера для каждого образца.
Я решил использовать другой подход и добавить предвзятость при сравнении глубины.
float previous_linearized = linearize_depth(previous_peel_depth_tex.r, near, far);
float current_linearized = linearize_depth(gl_FragCoord.z, near, far);
float bias_meter = 0.05;
bool belong_to_previous_peel = delta_depth < bias_meter;
Это решает мою проблему, но некоторые артефакты все еще могут появляться, и вам нужно отрегулировать смещение в единицах eye_space (метр, см, ...)