Взвешенные смешанные заказы, независимые вопросы прозрачности - PullRequest
0 голосов
/ 12 июня 2018

Я реализую метод OIT из этой статьи , и я просто не могу получить правильные результаты, основываясь на его эталонном изображении .Когда я пытаюсь воспроизвести его ссылку (ну, не ТОЧНО ), получается следующее:

enter image description here

Issue

Таким образом, результат раскрытия выглядит хорошо, но его накопление является неправильным.Для начала, нет проверки глубины.Синие и красные квадраты должны быть позади или перед желтым квадратом.Также нет никакого альфа-смешения с черным фоном из-за трех средних квадратов, все из которых имеют альфа-значения 0,75.

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

Из того, что я могу сказать с большей частью кода OpenGL, является то, что порядок выполнения имеет решающее значение, и я при отладке (продолжался в течение трех дней), я получаю разные результаты при перемещении чего-то вродеgl.DepthMask(false) или gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) вверх на одну строку.

Код

func (o *OpenGL) draw() {   
    gl.ClearColor(clearColor.R, clearColor.G, clearColor.B, clearColor.A)
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)


    // DRAW OPAQUE FIRST (although the issue isn't really here, I just put it in incase)
    gl.BindFramebuffer(gl.FRAMEBUFFER, o.opaqueFBO)
    gl.DrawBuffer(gl.COLOR_ATTACHMENT0)
    gl.Enable(gl.DEPTH_TEST)
    gl.DepthMask(true)
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.Disable(gl.BLEND)
    gl.UseProgram(o.opaqueShader)

    // Set uniforms
    // Draw opaque objects

    gl.UseProgram(0)

    // THEN TRANSPARENT
    gl.BindFramebuffer(gl.FRAMEBUFFER, o.transparentFBO)
    gl.DrawBuffers(2, &[]uint32{gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1}[0])
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.ClearBufferfv(gl.COLOR, 0, &[]float32{0, 0, 0, 1}[0])
    gl.ClearBufferfv(gl.COLOR, 1, &[]float32{1, 1, 1, 1}[0])
    gl.Enable(gl.DEPTH_TEST)
    gl.DepthMask(false)
    gl.Enable(gl.BLEND)
    gl.BlendFunci(0, gl.ONE, gl.ONE)
    gl.BlendFunci(1, gl.ZERO, gl.ONE_MINUS_SRC_ALPHA)

    gl.UseProgram(o.transparentShader)

    // Set uniforms
    // Draw opaque objects

    gl.UseProgram(0)

    // COMPOSITE PASS

    gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
    gl.Disable(gl.DEPTH_TEST)
    gl.Disable(gl.BLEND)

    gl.UseProgram(o.compositeShader)

    gl.ActiveTexture(gl.TEXTURE0)
    gl.BindTexture(gl.TEXTURE_2D, o.transparentTex0)
    gl.Uniform1i(uniformLocation(o.compositeShader, "ColorTex0\x00"), int32(0))

    gl.ActiveTexture(gl.TEXTURE1)
    gl.BindTexture(gl.TEXTURE_2D, o.transparentTex1)
    gl.Uniform1i(uniformLocation(o.compositeShader, "ColorTex1\x00"), int32(1))

    gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, gl.PtrOffset(0))
    gl.BindVertexArray(0)
    gl.UseProgram(0)


    // RENDER A SPECIFIC TEXTURE FROM A FRAMEBUFFER. FOR TESTING THIS DRAWS OVER WHAT HAS ALREADY BEEN DRAWN.

    // A.
    // o.renderFramebuffer(o.transparentFBO, o.transparentTex0)

    // B.
    // o.renderFramebuffer(o.transparentFBO, o.transparentTex1)
}


func (o *OpenGL) renderFramebuffer(fbo uint32, tid uint32) {
    // FBO DEBUGGER
    gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
    gl.UseProgram(o.framebufferShader)

    gl.ActiveTexture(gl.TEXTURE0)
    gl.BindTexture(gl.TEXTURE_2D, tid)
    gl.Uniform1i(uniformLocation(o.framebufferShader, "Texture\x00"), int32(0))

    // draw fullscreen quad

    gl.UseProgram(0)
    o.window.SwapBuffers()
}

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

Шейдеры

Вот фрагментный шейдер из o.transparentShader

#version 450 core
layout(location=0) in vec2 vTexCoord;

uniform vec4 uColor;

layout(location=0, index=0) out vec4 oFragData0;
layout(location=0, index=1) out vec4 oFragData1;

float w(float z, float a) {
    return a * max(
        pow(10.0, -2.0),
        min(
            3.0 * pow(10.0, 3.0),
            10.0 /
            (
                pow(10.0, -5.0) + 
                pow(abs(z) / 5.0, 2.0) +
                pow(abs(z) / 200.0, 6.0)
            )
        )
    );
}
void main() {
    vec4 Ci = uColor;

    float ai = Ci.a;
    float zi = gl_FragCoord.z;

    float wresult = w(zi, ai);
    oFragData0 = vec4(Ci.rgb * wresult, ai);
    oFragData1.r = ai * wresult;
}

И фрагментный шейдер из o.compositeShader

#version 450 core
layout(location=0) out vec4 outColor;

uniform sampler2D ColorTex0;
uniform sampler2D ColorTex1;

out vec4 oFragColor;

void main() {
    vec4 accum = texelFetch(ColorTex0, ivec2(gl_FragCoord.xy), 0);
    float r = accum.a;
    accum.a = texelFetch(ColorTex1, ivec2(gl_FragCoord.xy), 0).r;
    vec4 transparentColor = vec4(accum.rgb / clamp(accum.a, 1e-4, 5e4), r);
    oFragColor = transparentColor * (1.0 - r);
}

Заключительная записка

Я убрал все проверки ошибок, чтобы вопрос оставался минимальным.Я могу подтвердить, что нет ошибок с шейдерами, вложениями кадрового буфера или gl.GetError() во время выполнения моих тестовых выходных данных.

Я также удалил большую часть кода, относящегося к рисованию непрозрачных объектов, так как эта проблемао прозрачных объектах.

Обновление № 1 (тестирование без кадровых буферов)

В качестве отчаяния я удалил весь код, связанный с FBO, и натолкнулся на некоторые интересные результаты, касающиесясмешивание ...

DEPTH_TEST включен |BLEND отключен |DEPTH_MASK false enter image description here DEPTH_TEST отключен |BLEND включен |DEPTH_MASK false enter image description here DEPTH_TEST включен |BLEND включен |DEPTH_MASK false enter image description here

Как бы нелепо это ни звучало, на самом деле похоже, что можно проводить смешивание и тестирование глубины по отдельности, но при объединении это просто немногои то и другое сдается ... Может ли это быть как-то связано с функциями смешивания?

Обновление № 2 (почти идеальные результаты, основанные на справочнике NVidia)

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

enter image description here

Я получил это, настроивЗначения BlendFunc и изучение нескольких сложных уроков о том, когда использовать какую из этих пар:

  • texture против texelFetch
  • GL_TEXTURE_2D против GL_TEXTURE_RECT
  • RGBA16F против RGBA
  • ONE_MINUS_SRC_ALPHA против ONE_MINUS_SRC_COLOR

Я настоятельно рекомендую полностью понять различия, прежде чем пытаться MRT, Framebuffers или OIT.Каждая ссылка использовала различную комбинацию этих значений.

Обновление № 3 (окончательное)

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

enter image description here

Я собираюсь оставить этот вопрос на некоторое время, прежде чем яОтправьте ответ, потому что я все еще немного скептичен и хочу провести больше тестов (или, возможно, услышать от вас, ребята?).

...