使用延迟着色的OpenGL不需要的透明度

时间:2015-02-08 09:04:44

标签: opengl shader transparency blending

我试图使用OpenGL实现延迟着色,我渲染纹理的位置和法线。当我只使用1个光源而不进行混合时,一切运行良好,但在我打开混合后,所以其他光源可以贡献,我得到透明度。有没有人有同样的问题和解决方案?

这是我用于照明的片段着色器:

#version 330 

uniform vec2 ScreenSize;
uniform vec3 AmbientColor;
uniform vec3 DiffuseColor;
uniform vec3 SpecColor;
uniform vec3 LightPosition;
uniform sampler2D PositionMap;
uniform sampler2D NormalMap;

vec2 CalcTexCoord()
{
    return gl_FragCoord.xy / ScreenSize;
}

out vec4 FragColor;

void main()
{
    vec2 PixelPos = CalcTexCoord();
    vec3 WorldPos = texture(PositionMap, PixelPos).xyz;
    vec3 Normal = texture(NormalMap, PixelPos).xyz;

    vec3 LightDir = normalize(LightPosition - WorldPos);

    float Lambertian = max(dot(LightDir, Normal), 0.0);
    float Specular = 0.0;

    if(Lambertian > 0.0)
    {
        vec3 ViewDir = normalize(-WorldPos);

        // this is blinn phong
        vec3 HalfDir = normalize(LightDir + ViewDir);
        float SpecAngle = max(dot(HalfDir, Normal), 0.0);
        Specular = pow(SpecAngle, 16.0);

        vec3 ReflectDir = reflect(-LightDir, Normal);
        SpecAngle = max(dot(ReflectDir, ViewDir), 0.0);
        // note that the exponent is different here
        Specular = pow(SpecAngle, 4.0);
    }

    FragColor = vec4(AmbientColor+Lambertian*DiffuseColor+Specular*SpecColor, 1.0);
}

几何传递:

glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);

glBindFramebuffer(GL_FRAMEBUFFER, Fbo);

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, Camera.Viewport.X, Camera.Viewport.Y);

UpdateInput(Window, &Camera);
UpdateMatrices(&Camera, &RenderState);

Meshes[1].ModelMat = Translate(M4(1.0f), LightPos);

UseShader(&RenderState, &GeometryShader);

for(uint8 i = 0; i < ArrayCount(Meshes); ++i)
{
`RenderMesh(&GeometryShader, &Meshes[i]);
}

glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);

光通:

glBindFramebuffer(GL_READ_FRAMEBUFFER, Fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, Camera.Viewport.X, Camera.Viewport.Y);

// Binding Position and Normal maps.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Targets[0].Id);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Targets[2].Id);

glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);

UseShader(&RenderState, &LightShader);

LoadVec2(&LightShader, "ScreenSize", V2(Camera.Viewport.X, Camera.Viewport.Y));
LoadVec3(&LightShader, "AmbientColor", V3(0.2f, 0.2f, 0.2f));
LoadVec3(&LightShader, "DiffuseColor", V3(0.1f, 0.1f, 0.1f));
LoadVec3(&LightShader, "SpecColor", V3(0.3f, 0.3f, 0.3f));
LoadVec3(&LightShader, "LightPosition", V3(5.0f, 3.0f, 3.0f));
LoadSampler2D(&LightShader, "PositionMap", 0);
LoadSampler2D(&LightShader, "NormalMap", 1);

for(uint8 i = 0; i < ArrayCount(Meshes); ++i)
{
   RenderMesh(&LightShader, &Meshes[i]);
}

LoadVec3(&LightShader, "LightPosition", LightPos);

for(uint8 i = 0; i < ArrayCount(Meshes); ++i)
{
   RenderMesh(&LightShader, &Meshes[i]);
}
glDisable(GL_BLEND);

我申请的混合:

glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);

纹理格式:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, Width, Height, 0, GL_RGBA, GL_FLOAT, Pixels);

深度纹理格式:

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, Width, Height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);

位置和法线贴图: http://postimg.org/image/qctx0smj7/

混合已关闭: http://postimg.org/image/7nqlz3sbr/

正在进行混合: http://postimg.org/image/99h7x2p5t/

1 个答案:

答案 0 :(得分:1)

您必须确保混合到最终fbo的片段是最顶层的片段。否则,您将在重叠区域中添加光。如果你禁用混合,问题仍然是相同的,但你不会看到它,因为最顶层的碎片被覆盖了。 结论:延迟着色的速度优势完全被浪费,因为您在第二遍中绘制了在正常前向渲染中绘制的相同数量的片段。

<强>解决方案

大多数引擎都会将第二次传递渲染到后备缓冲区而不是另一个fbo,主要是因为后处理。但这允许在两个renderpathes中使用相同的deepbuffer。在第一次传递中,深度读取和写入按照您已完成的方式执行。在第二遍中,深度写入被禁用,但深度测试仍然完成(使用GL_LESS_OR_EQUAL)。这会丢弃最顶层后面的所有碎片。有时可能需要将第二个路径中的对象绘制得更靠近相机以防止z-fighting问题。

如果你不能使用第二个fbo,你可以做两件事:将第一遍的深度缓冲区复制到默认的深度缓冲区(一般性能很差),或者你可以在片段着色器中进行深度测试。 / p>