0

按照 learnopengl 教程 ( https://learnopengl.com/Advanced-Lighting/Deferred-Shading ),作者保留了 GLSL 所示的固定光量(32 盏灯):

 #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();

但我的代码只呈现第一盏灯: 结果 谁能告诉我我做错了什么以及如何在最终结果中添加灯光?

4

2 回答 2

0

请包括如下代码

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 个灯,但可以轻松扩展到很多。

于 2018-12-01T01:03:54.380 回答
0

问题是由于与场景重叠的灯光数量重复了固定的“环境”术语。

着色器包含:

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 个绘制调用来应用环境,然后有 n 个绘制调用用于 n 个灯光。

C++ 端的算法看起来像:确保你仍然有加法混合。

  1. 清屏
  2. 设置环境着色器,绘制四边形。
  3. 设置灯光着色器,进行照明循环并为 n 个灯绘制 n 个四边形。

编辑:此外,根据您的屏幕截图,您似乎没有阅读正确的 Albedo 纹理。看起来您正在根据获得的颜色读取位置缓冲区。

于 2018-12-04T07:28:25.767 回答