2015-02-08 68 views
1

我想使用OpenGL实现延期着色,我渲染位置和法线到纹理。当我仅使用1个光源而没有混合所有东西时效果很好,但是在我开启混合后,其他光源可以发挥作用,我获得透明度。有没有人有同样的问题和解决方案?OpenGL不需要的透明度与延迟着色

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

#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/

+0

你在哪里启用混合,什么时候再禁用它?这是完全不清楚你在这里做什么。 – derhass 2015-02-08 14:25:26

+0

在几何通过完成后启用混合。并在光通过结束后禁用它。 – user3696459 2015-02-08 17:46:53

回答

1

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

解决方案

大多数引擎渲染的第二次没有后备缓冲区,但另一个FBO,主要是因为后期处理。但是这允许在两个renderpathes中使用相同的深度缓冲区。在第一阶段中,深度读取和写入按照您已经完成的方式执行。在第二遍中,深度写入被禁用,但深度测试仍然完成(使用GL_LESS_OR_EQUAL)。这会丢弃最顶层的所有碎片。有时可能需要将第二条路径上的物体稍微靠近摄像头以防止出现z战斗问题。

如果你不能使用第二个fbo,你可以做两件事:复制第一遍的深度缓冲区到默认的深度缓冲区(通常可怕的表现),或者你可以在你的片段着色器中进行深度测试。

+0

你是对的,我调整了窗口的大小,看到这个[链接](http://s9.postimg.org/qmxe0kmq7/ex1.png) – user3696459 2015-02-08 21:45:09