获得延迟渲染光通过的世界位置

时间:2014-01-05 22:43:42

标签: java opengl glsl lighting deferred-rendering

我最近开始为我正在开发的引擎构建某种延迟渲染管道,但我仍然坚持从深度重建世界位置。我已经看了很多例子,其中解释说你需要世界位置纹理或深度纹理然后用于正确的光线距离和方向计算。

我的问题是,所谓的位置纹理可能是世界位置似乎并没有给我正确的数据。因此,我试图找到获得世界位置的替代方法,有些人建议我应该使用深度纹理而不是什么呢?

为了更清楚地说明这张图片显示了我当前存储的纹理:

Deferred rendering textures 位置(左上),正常(右上),漫反射(左下)和深(右下)。

对于光通道,我试图使用一种方法,如果在第一遍中使用它可以正常工作。当我使用完全相同的变量尝试相同的光通过方法时,它会停止工作。

这是我的Geometry Vertex Shader:

#version 150

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;

in vec4 in_Position;
in vec3 in_Normal;
in vec2 in_TextureCoord;

out vec3 pass_Normals;
out vec4 pass_Position;
out vec2 pass_TextureCoord;
out vec4 pass_Diffuse;

void main(void) {

        pass_Position = viewMatrix * modelMatrix * in_Position;
    pass_Normals = (viewMatrix * modelMatrix * vec4(in_Normal, 0.0)).xyz;
    pass_Diffuse = vec4(1,1,1,1);
    gl_Position = projectionMatrix * pass_Position;

}

几何片段着色器:

#version 150 core

uniform sampler2D texture_diffuse;

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;

in vec4 pass_Position;
in vec3 pass_Normals;
in vec2 pass_TextureCoord;
in vec4 pass_Diffuse;

out vec4 out_Diffuse;
out vec4 out_Position;
out vec4 out_Normals;

void main(void) {
    out_Position = pass_Position;
    out_Normals = vec4(pass_Normals, 1.0);
    out_Diffuse = pass_Diffuse;
}

Light Vertex Shader:

#version 150

in vec4 in_Position;
in vec2 in_TextureCoord;

out vec2 pass_TextureCoord;

void main( void )
{
    gl_Position = in_Position;
    pass_TextureCoord = in_TextureCoord;

}

Light Fragment Shader:

#version 150 core

uniform sampler2D texture_Diffuse;
uniform sampler2D texture_Normals; 
uniform sampler2D texture_Position;
uniform vec3 cameraPosition;
uniform mat4 viewMatrix;

in vec2 pass_TextureCoord;

out vec4 frag_Color;

void main( void )
{
    frag_Color = vec4(1,1,1,1);
    vec4 image = texture(texture_Diffuse,pass_TextureCoord);
    vec3 position = texture( texture_Position, pass_TextureCoord).rgb;
    vec3 normal = texture( texture_Normals, pass_TextureCoord).rgb;
    frag_Color = image;


    vec3 LightPosition_worldspace = vec3(0,2,0);

    vec3 vertexPosition_cameraspace = position;
    vec3 EyeDirection_cameraspace = vec3(0,0,0) - vertexPosition_cameraspace;

    vec3 LightPosition_cameraspace = ( viewMatrix * vec4(LightPosition_worldspace,1)).xyz;
    vec3 LightDirection_cameraspace = LightPosition_cameraspace + EyeDirection_cameraspace;

    vec3 n = normal;
    vec3 l = normalize( LightDirection_cameraspace );

    float cosTheta = max( dot( n,l ), 0);

    float distance = distance(LightPosition_cameraspace, vertexPosition_cameraspace);

    frag_Color = vec4((vec3(10,10,10) * cosTheta)/(distance*distance)), 1);
    }

最后,这是当前的结果: Unexpected result

所以我的问题是,如果有人请说明结果或我应该怎样做才能得到正确的结果。我也很欣赏该地区的良好资源。

1 个答案:

答案 0 :(得分:4)

是的,使用深度缓冲区重建位置是最好的选择。这将显着降低内存带宽/存储要求。现代硬件偏向于进行着色器计算而不是内存提取(这并非总是如此),并且重建每片段位置所需的指令总是比从具有足够精度的纹理中获取位置更快地完成。现在,您只需要了解硬件深度缓冲区存储的内容(了解深度范围和透视分布的工作原理),您就可以了。

我没有看到任何尝试从您的问题列出的代码中的深度缓冲区重建世界/视图空间位置。您只是从存储视图空间中位置的缓冲区中进行采样。由于您未在此示例中执行重建,因此问题与对视图空间位置进行采样有关...您是否可以更新问题以包含G-Buffer纹理的内部格式。特别是,您使用的是可以表示负值的格式(这是表达位置所必需的,否则负值会被限制为0)。

最后一点,您的位置也是查看空间,而不是世界空间,训练有素的眼睛可以立即通过您所处位置的颜色来判断缓冲区在左下角是黑色的。如果要调试位置/法线,则应将采样颜色偏置/缩放到可见范围内:

([-1.0, 1.0] -> [0.0, 1.0])  // Vec = Vec * 0.5 + 0.5

如果要更有效地存储普通G缓冲区(例如,在8位定点纹理而不是浮点格式中),输出某些缓冲区时可能需要执行此操作。