3

我终于让我的 GBuffer 工作了(不是真的),但现在我遇到了一些奇怪的问题,我不知道为什么。

当我在屏幕上绘制法线纹理时,法线总是向我显示(蓝色总是指向相机)。我不知道如何正确解释,所以这里有一些屏幕:

(我认为这就是为什么我的光照通道看起来很奇怪的问题)

以下是我创建 GBuffer 的方法:

glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);

// generate texture object
glGenTextures(GBUFFER_NUM_TEXTURES, textures);
for (unsigned int i = 0; i < 4; i++)
{
    glBindTexture(GL_TEXTURE_2D, textures[i]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

// generate depth texture object
glGenTextures(1, &depthStencilTexture);
glBindTexture(GL_TEXTURE_2D, depthStencilTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT,NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthStencilTexture, 0);

// generate output texture object
glGenTextures(1, &outputTexture);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, outputTexture, 0);

GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
assert(Status == GL_FRAMEBUFFER_COMPLETE);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

这里是几何通道:

glEnable(GL_DEPTH_TEST);
glDepthMask(true);
glCullFace(GL_BACK);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);

GLenum DrawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
glDrawBuffers(GBUFFER_NUM_TEXTURES, DrawBuffers);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();
camera.Render();

geoProgram->Use();

GLfloat mat[16];

glPushMatrix();
glTranslatef(0,0,-20);
glRotatef(rot, 1.0, 0, 0);
glGetFloatv(GL_MODELVIEW_MATRIX,mat);
glUniformMatrix4fv(worldMatrixLocation, 1, GL_FALSE, mat);
glutSolidCube(5);
glPopMatrix();

glPushMatrix();
glTranslatef(0,0,0);
glGetFloatv(GL_MODELVIEW_MATRIX,mat);
glUniformMatrix4fv(worldMatrixLocation, 1, GL_FALSE, mat);
gluSphere(sphere, 3.0, 20, 20);
glPopMatrix();

glDepthMask(false);
glDisable(GL_DEPTH_TEST);

这里是几何通道着色器:

[Vertex]
varying vec3 normal;
varying vec4 position;
uniform mat4 worldMatrix;

void main( void )
{       
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    position = worldMatrix * gl_Vertex;
    normal = (worldMatrix * vec4(gl_Normal, 0.0)).xyz;
    gl_TexCoord[0]=gl_MultiTexCoord0;
}


[Fragment]
varying vec3 normal;
varying vec4 position;

void main( void )
{
    gl_FragData[0] = vec4(0.5, 0.5, 0.5, 1);//gl_Color;
    gl_FragData[1] = position;
    gl_FragData[2] = vec4(normalize(normal),0);
    gl_FragData[3] = vec4(gl_TexCoord[0].st, 0, 0);
}

抱歉,问题/代码片段很长,但我不知道下一步该做什么,我用其他 GBuffer 实现检查了所有内容,但找不到错误。

//编辑:

好吧,看来你是对的,问题不在于 gbuffer,而在于照明通道。我玩过很多,但不能让它工作:(

这是照明通道:

[vs]
void main( void )
{
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

[fs]
uniform sampler2D colorMap;
uniform sampler2D positionMap;
uniform sampler2D normalMap;
uniform sampler2D texcoordMap;

uniform vec2 screenSize;
uniform vec3 pointLightPostion;
uniform vec3 pointLightColor;
uniform float pointLightRadius;


void main( void )
{
    float lightDiffuse = 0.5;
    float lightSpecular = 0.7;
    vec3 lightAttenuation = vec3(1.4, 0.045, 0.00075);

    vec2 TexCoord = gl_FragCoord.xy / screenSize.xy;
    vec3 WorldPos = texture2D(positionMap, TexCoord).xyz;
    vec3 Color = texture(colorMap, TexCoord).xyz;
    vec3 normal = texture(normalMap, TexCoord).xyz;
    normal = normalize(normal);

    vec3 lightVector = WorldPos - pointLightPostion;
    float dist = length(lightVector);
    lightVector = normalize(lightVector);

    float nDotL = max(dot(normal, lightVector), 0.0);
    vec3 halfVector = normalize(lightVector - WorldPos);
    float nDotHV = max(dot(normal, halfVector), 0.0);

    vec3 lightColor = pointLightColor;
    vec3 diffuse =  lightDiffuse * nDotL;
    vec3 specular = lightSpecular * pow(nDotHV, 1.0) * nDotL;
    lightColor += diffuse + specular;

    float attenuation = clamp(1.0 / (lightAttenuation.x + lightAttenuation.y * dist + lightAttenuation.z * dist * dist), 0.0, 1.0);


    gl_FragColor = vec4(vec3(Color * lightColor * attenuation), 1.0);
}

如有必要,我还可以发布 sencil pass 和/或所有其他处理。

4

2 回答 2

5

我知道这有点老了,但我想让你知道经过大量研究后我一切正常!如果有人遇到类似/相同的问题,我只想在这里发布。

实际上位置图是完全错误的(我的照明模型也是,但那是另一个故事:))。正如你已经说过的,我正在使用固定的管道功能(这真的很愚蠢)。实际的失败是我得到了“模型矩阵”

glGetFloatv(GL_MODELVIEW_MATRIX,mat);
glUniformMatrix4fv(worldMatrixLocation, 1, GL_FALSE, mat);

这实际上是固定管道中的模型矩阵 * 视图矩阵。所以我将所有内容都更改为自定义模型计算,瞧,位置图是正确的。(你也可以使用固定函数管道并设置一个具有匹配值的自定义模型矩阵,并将其作为模型矩阵输入到着色器中,但这只是脏)。多亏了你,我走上了正确的道路,并设法了解矩阵计算和着色器等更多!

顺便说一句:gbuffer 现在看起来像这样(纹理位置实际上是不必要的:)): 在此处输入图像描述

于 2013-11-01T06:06:06.790 回答
2

查看您的解决方案,从您在评论中发布的链接中,首先引起我注意的是:在照明通道顶点着色器中,您可以

viewSpace = gl_ModelViewMatrix * gl_Vertex;

然后在片段着色器中你做

vec3 lightPos = pointLightPostion * viewSpace;
vec3 WorldPos = texture2D(positionMap, TexCoord) * viewSpace;
vec3 normal = texture2D(normalMap, TexCoord) * viewSpace;

这完全没有意义。
现在,您正在执行延迟着色,这是现代 openGL (3.2+) 的典型技术,在古代硬件中表现不佳,我认为您使用了本教程中的东西,这也是现代 openGL,所以为什么要这样做你用glPushMatrix和那种旧东西?太糟糕了,我从来没有学过旧的openGL,所以我不确定我是否正确理解了你的代码。
顺便说一句,回到几何通道。在顶点着色器中,你做

position = gl_ModelViewMatrix * gl_Vertex;
normal = (modelMatrix * vec4(gl_Normal,0.0)).xyz;

但是你在视图空间中有位置,在模型空间中有正常位置。(如果您传递给着色器的 modelMatrix 确实是模型矩阵,因为从您的屏幕截图来看,法线似乎在视图空间中)。另外,请注意,如果法线不在视图空间中,而是在模型空间中,则必须对它们进行偏置和缩放normal = 0.5f*(modelMatrix * vec4(gl_Normal,0.0)).xyz +1.0f;。我只是去

position = gl_ModelViewMatrix * gl_Vertex;
normal = (gl_ModelViewMatrix * vec4(gl_Normal,0.0)).xyz;

请记住,重要的是您在同一个空间中同时拥有位置和法线。您可以使用世界空间或视图空间,但请坚持您的选择。在照明通道中,只需执行

vec3 WorldPos = texture2D(positionMap, TexCoord).rgb;
vec3 normal = texture2D(normalMap, TexCoord).rgb;
vec3 lightVector = WorldPos - pointLightPostion;

并确保它pointLightPostion在您决定的同一空间中,通过在您的应用程序中,在 CPU 端对其进行转换,然后将其传递给已经转换的 openGL。

另外,我不明白你为什么这样做

lightColor += diffuse + specular;

而不是

lightColor *= diffuse + specular;

这样一来,您的照明中就会有一个发射组件,其中包含您的灯光颜色以及没有它的漫反射和镜面反射。这似乎不是一个好的选择,尤其是在延迟着色中,您可以轻松地在整个帧上执行环境通道。

希望我有所帮助。太糟糕了,我不使用过剩,我无法构建你的代码。

编辑
要将pointLightPostion(我假设已经在世界空间中)转换为视图空间,只需执行

pointLightPostion = (ViewMatrix * glm::vec4(pointLightPostion,1.0f)).xyz;
于 2013-09-15T08:04:13.953 回答