Как добавить бесчисленные источники света в фреймбуфере - PullRequest
0 голосов
/ 30 ноября 2018

Следуя обучающему уроку (https://learnopengl.com/Advanced-Lighting/Deferred-Shading), автор оставляет фиксированное количество света (32 источника света), как показано в GLSL:

 #version 330 core
out vec4 FragColor;

in vec2 TexCoords;

uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedoSpec;

struct Light {
    vec3 Position;
    color;
};
const int NR_LIGHTS = 32;
uniform Light lights [NR_LIGHTS];
uniform vec3 viewPos;

void main ()
{
    // retrieve data from G-buffer
    vec3 FragPos = texture (gPosition, TexCoords) .rgb;
    vec3 Normal = texture (gNormal, TexCoords) .rgb;
    vec3 Albedo = texture (gAlbedoSpec, TexCoords) .rgb;
    float Specular = texture (gAlbedoSpec, TexCoords) .a;

    // then calculate lighting as usual
    vec3 lighting = Albedo * 0.1; // hard-coded ambient component
    vec3 viewDir = normalize (viewPos - FragPos);
    for (int i = 0; i <NR_LIGHTS; ++ i)
    {
        // diffuse
        vec3 lightDir = normalize (lights [i] .Position - FragPos);
        vec3 diffuse = max (dot (Normal, lightDir), 0.0) * Albedo * lights [i] .Color;
        lighting + = diffuse;
    }

    FragColor = vec4 (lighting, 1.0);
}

И когда речь идет о применении источников света:

glBindFramebuffer (GL_FRAMEBUFFER, 0);

        // 2. lighting pass: calculate lighting by iterating over screen filled quad pixel-by-pixel using the gbuffer's content.

        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        shaderLightingPass.use ();
        glActiveTexture (GL_TEXTURE0);
        glBindTexture (GL_TEXTURE_2D, gPosition);
        glActiveTexture (GL_TEXTURE1);
        glBindTexture (GL_TEXTURE_2D, gNormal);
        glActiveTexture (GL_TEXTURE2);
        glBindTexture (GL_TEXTURE_2D, gAlbedoSpec);
        // send light relevant uniforms
        for (unsigned int i = 0; i <lightPositions.size (); i ++)
        {
            shaderLightingPass.setVec3 ("lights [" + std :: to_string (i) + "] .Position", lightPositions [i]);
            shaderLightingPass.setVec3 ("lights [" + std :: to_string (i) + "] .Color", lightColors [i]);
            // update attenuation parameters and calculate radius
            const float constant = 1.0; // note that we do not send this to the shader, we assume it is always 1.0 (in our case)
            const float linear = 0.7;
            const float quadratic = 1.8;
            shaderLightingPass.setFloat ("lights [" + std :: to_string (i) + "] .Linear", linear);
            shaderLightingPass.setFloat ("lights [" + std :: to_string (i) + "] .Quadratic", quadratic);
        }
        shaderLightingPass.setVec3 ("viewPos", camera.Position);
        // finally render quad
        renderQuad ();

но я бы хотел добавить столько источников света, сколько я хочу, потому что в моем проекте будет множество источников света (лазерное оружие, костер, взрыв), поэтому я внес некоторые изменения:

GLSL:

uniform Light light;
uniform vec3 viewPos;

void main()
{             
    // retrieve data from gbuffer
    vec3 FragPos = texture(gPosition, TexCoords).rgb;
    vec3 Normal = texture(gNormal, TexCoords).rgb;
    vec3 Diffuse = texture(gAlbedoSpec, TexCoords).rgb;
    float Specular = texture(gAlbedoSpec, TexCoords).a;

    // then calculate lighting as usual
    vec3 lighting  = Diffuse * 0.1; // hard-coded ambient component
    vec3 viewDir  = normalize(viewPos - FragPos);

        // diffuse
        vec3 lightDir = normalize(light.Position - FragPos);
        vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * light.Color;
        // specular
        vec3 halfwayDir = normalize(lightDir + viewDir);  
        float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0);
        vec3 specular = light.Color * spec * Specular;
        // attenuation
        float distance = length(light.Position - FragPos);
        float attenuation = 1.0 / (1.0 + light.Linear * distance + light.Quadratic * distance * distance);
        diffuse *= attenuation;
        specular *= attenuation;
        lighting += diffuse + specular;        

    FragColor = vec4(lighting, 1.0);
}

А затем я передал значения одно за другим и отрисовал квад:

for (unsigned int i = 0; i < lightPositions.size(); i++)
        {
            shaderLightingPass.use();
            shaderLightingPass.setInt("gPosition", 0);
            shaderLightingPass.setInt("gNormal", 1);
            shaderLightingPass.setInt("gAlbedoSpec", 2);
            shaderLightingPass.setVec3("light.Position", lightPositions[i]);
            shaderLightingPass.setVec3("light.Color", lightColors[i]);

            const float constant = 1.0; // note that we don't send this to the shader, we assume it is always 1.0 (in our case)
            const float linear = 0.7;
            const float quadratic = 0.08;
            shaderLightingPass.setFloat("light.Linear", linear);
            shaderLightingPass.setFloat("light.Quadratic", quadratic);
            shaderLightingPass.setVec3("viewPos", camera.Position);

            renderQuad();

            glUseProgram(-1);

        }

, а также добавил новый шейдер для визуализации кадрового буфера на экране.:

screenShader.use();
renderQuad();

но мой код отображает только первый источник света: Результат Может кто-нибудь сказать мне, что я делаю неправильно и как добавить источники света в конечный результат?

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Проблема заключается в том, что фиксированный термин «окружающий» повторяется для количества источников света, которые перекрывают сцену.

Шейдер содержит:

vec3 lighting  = Diffuse * 0.1; // hard-coded ambient component

Это эффективно повторно добавляетАльбедо каждый раз, когда свет перекрывается.

Старый код имел следующую сумму:

vec3 lighting = Diffuse * 0.1;
foreach (Light l : lights)
    lighting += Diffuse * (l's diffuse lighting)

Но теперь с аддитивным смешиванием у вас есть:

foreach (Light l : lights)
    lighting += Diffuse * 0.1;
    lighting += Diffuse * (l's diffuse lighting)

Таким образом, вы получилисверхяркое окружение в https://i.ibb.co/gMBtM6c/With-Blend.png

Чтобы исправить это, вам нужно разделить термин (Diffuse * 0.1) в отдельный шейдер.У вас будет 1 вызов draw для применения ambient, а затем n вызовов draw для n источников света.

Тогда алгоритм на стороне C ++ будет выглядеть так: Убедитесь, что у вас есть аддитивное смешение.

  1. Очистить экран
  2. Установить шейдер Ambient, Draw Quad.
  3. Установите шейдер Light, сделайте вашу петлю освещения и нарисуйте n Quads для n источников света.

РЕДАКТИРОВАТЬ: Кроме того, похоже, что вы не читаете правильную текстуру Альбедо на основе ваших скриншотов.Похоже, вы читаете буфер положения на основе цветов, которые вы получаете.

0 голосов
/ 01 декабря 2018

Пожалуйста, включите код, как показано ниже

void renderDeferredPass(int i)
{
glUseProgram(ps[Passes::Deferred]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_fbo);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
//mat4 model = glm::scale(mat4(1.0f), vec3(3.1f, 3.1f, 3.1f));
   model = glm::translate(mat4(1.0f), vec3(-150.0f, -600.0f, -800.0f+camera));
   model = glm::rotate(model, 30.0f, vec3(0.0f, 1.0f, 0.0f));

    mat4 view = glm::lookAt(glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 0.0, -5.0), glm::vec3(0.0, 1.0, 0.0));

    glUniformMatrix4fv(modelLocation, 1, GL_FALSE, &model[0][0]);
    glUniformMatrix4fv(viewLocation, 1, GL_FALSE, &view[0][0]);
    glUniformMatrix4fv(projLocation, 1, GL_FALSE, &projection[0][0]);
    glUniform1i(textureLocation, 0);

    quad->Render();

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glUseProgram(0);
    glDepthMask(GL_FALSE);
    glDisable(GL_DEPTH_TEST);
   } 

И

 void renderLightPass()
{
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_BLEND);
    glBlendEquation(GL_FUNC_ADD);
    glBlendFunc(GL_ONE, GL_ONE);

    glUseProgram(ps[Passes::LightPass]);
    glBindVertexArray(quadVAO);
    bindUbo();

    for (unsigned int i = 0; i < NUM_GBUFFER_TEXTURES; i++) 
     {
           glActiveTexture(GL_TEXTURE1 + i);
           glBindTexture(GL_TEXTURE_2D, 
           g_textures[POSITION_TEXTURE + i]);
      }


    glUniform1i(mapLocations[POSITION_TEXTURE], 1);
    glUniform1i(mapLocations[DIFFUSE_TEXTURE], 2);
    glUniform1i(mapLocations[NORMAL_TEXTURE], 3);
    glUniform1i(mapLocations[TEXCOORD_TEXTURE], 4);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);

    glUseProgram(0);
    glBindVertexArray(0);

    glEnable(GL_DEPTH_TEST);
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

   } 

И ваша функция рисования должна выглядеть следующим образом:

void display()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glGenerateMipmap(GL_TEXTURE_2D);
    glEnable(GL_MULTISAMPLE);

    //for (int i = 0; i < quad->m_Entries.size(); i++)
        {
          renderDeferredPass(0);
          renderLightPass();
        }

    glutSwapBuffers();
    glutPostRedisplay();
    } 

Для полной реализации см. Ниже

https://github.com/PixelClear/Deferred-renderer

У меня есть код выше, где мы храним информацию о светах в SSBO, так что эта демонстрация имеет 32 источника света, но может быть легко распространена на многие.

...