【问题标题】:Render depth to texture将深度渲染到纹理
【发布时间】:2014-12-21 06:40:52
【问题描述】:

我无法正确渲染深度。没有抛出错误,glCheckFramebufferStatus 表示它也已完成。

下面是代码,屏幕总是显示为白色。深度值不是1,而是非常非常接近:

编辑:

所以我尝试将深度片段着色器内部的深度线性化,然后将其直接绘制到屏幕上以确保值正确。他们是正确的。但是,即使我将线性化深度发送到我的全屏四边形着色器(下面的第二个),屏幕仍然是全白的。

public void initFramebuffers() {
    glBindFramebuffer(GL_FRAMEBUFFER, depthShader.fbo);
    depthShader.initTexture(width, height, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthShader.tex, 0);
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);
}

public void initTexture(int width, int height, int format, int internalFormat) {
    tex = glGenTextures();
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_FLOAT, (ByteBuffer)null);
}

深度着色器:

#version 400

in vec3 pos;
in float radius;

uniform mat4 mView;
uniform mat4 projection;
uniform vec2 screenSize;
uniform vec3 lightPos;

out float depth;

float linearizeDepth(float depth) {
    float n = 0.01;
    float f = 100;
    return (2.0 * n) / (f + n - depth * (f - n));
}    

void main() {
    //calculate normal
    vec3 normal;
    normal.xy = gl_PointCoord * 2.0 - 1.0;
    float r2 = dot(normal.xy, normal.xy);
    
    if (r2 > 1.0) {
        discard;
    }
    
    normal.z = sqrt(1.0 - r2);

    //calculate depth
    vec4 pixelPos = vec4(pos + normal * radius, 1.0);
    vec4 clipSpacePos = projection * pixelPos;
    
    depth = clipSpacePos.z / clipSpacePos.w * 0.5f + 0.5f;
    depth = linearizeDepth(depth);
}

深度读取的着色器。 linearizeDepth 中的值是我的远近距离:

#version 400

in vec2 coord;

uniform sampler2D depthMap;
uniform vec2 screenSize;
uniform mat4 projection;

out vec4 color;

float linearizeDepth(float depth) {
    float n = 0.01;
    float f = 100;
    return (2.0 * n) / (f + n - depth * (f - n));
}    

void main() {
    float curDepth = texture2D(depthMap, coord).x;
    //float d = linearizeDepth(curDepth);

    color = vec4(d, d, d, 1.0f);
}

绘制一切的代码:

//--------------------Particle Depth-----------------------
{
    glUseProgram(depthShader.program);
    glBindFramebuffer(GL_FRAMEBUFFER, depthShader.fbo);

    depthShader.particleDepthVAO(points);
    
    //Sets uniforms
    RenderUtility.addMatrix(depthShader, mView, "mView");
    RenderUtility.addMatrix(depthShader, projection, "projection");
    RenderUtility.addVector2(depthShader, screenSize, "screenSize");
    RenderUtility.addVector3(depthShader, lightPosition, "lightPos");
            
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindVertexArray(depthShader.vao);

    glDrawArrays(GL_POINTS, 0, points.size());  
}

    //Draw full screen
{
    glUseProgram(blurShader.program);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
                
    blurShader.blurDepthVAO();
                
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, depthShader.tex);
    glUniform1i(blurShader.depthMap, 0);
    
    //Sets uniforms 
    RenderUtility.addMatrix(blurShader, mView, "mView");
    RenderUtility.addMatrix(blurShader, projection, "projection");
    RenderUtility.addVector2(blurShader, screenSize, "screenSize");
                
    //glEnable(GL_DEPTH_TEST);
                
    glBindVertexArray(blurShader.vao);
                
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glViewport(0, 0, width, height);
}

【问题讨论】:

  • 请不要以使答案无效的方式编辑问题。
  • 那不是目的。目的是反映在我看到您的答案之前我的代码的当前状态。让它保持这种状态只是我的一个错误,我忽略了更新它。
  • 可能有点晚了,但是恕我直言,在线性化深度值时仍然存在错误。如果它对您有用,您可能不会完全是一个错误,但是还有另一种线性化深度的方法(对我有用)。看到这个问题:stackoverflow.com/questions/6652253/… 在这个公式中,另一个 f 乘以 linDepth() 函数的返回值。

标签: java opengl glsl lwjgl framebuffer


【解决方案1】:

问题最终是我的顶点着色器的输出变量名与片段着色器的输入变量名 (doh) 不匹配。上面发布的代码是 100% 正确的,以防将来有人看到。

【讨论】:

    【解决方案2】:

    发布的代码存在一些问题。

    渲染目标的使用不一致

    在FBO的设置中,只有深度附件,没有颜色附件。颜色绘制缓冲区也被明确禁用:

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthShader.tex, 0);
    glDrawBuffer(GL_NONE);
    

    但是,片段着色器会写入颜色输出:

    out float depth;
    ...
        depth = clipSpacePos.z / clipSpacePos.w * 0.5f + 0.5f;
        depth = linearizeDepth(depth);
    

    要写入帧缓冲区的深度附件,您必须设置预定义的gl_FragDepth 变量的值。仅仅因为 out 变量被命名为depth 并不意味着它实际上被用作深度输出。如果您想使用颜色输出,您必须创建一个常规纹理,并将其附加到GL_COLOR_ATTACHMENT0。这实际上看起来更容易。

    linearizeDepth() 计算

    float linearizeDepth(float depth) {
        float n = 0.01;
        float f = 100;
        return (2.0 * n) / (f + n - depth * (f - n));
    }
    
    depth = clipSpacePos.z / clipSpacePos.w * 0.5f + 0.5f;
    depth = linearizeDepth(depth);
    

    clipSpacePos 的处理方式看起来像 linarizeDepth() 的参数将介于 0.0 和 1.0 之间。函数内部对这些极值的计算是:

    0.0 --> (2.0 * n) / (f + n)
    1.0 --> 1.0
    

    这对于 1.0 来说看起来不错,但对于 0.0 来说是有问题的。我相信做准备步骤实际上会更正确:

    depth = clipSpacePos.z / clipSpacePos.w;
    

    这会将 -1.0 和 1.0 之间的参数传递给函数,然后生成:

    -1.0 --> n / f
    1.0  --> 1.0
    

    实际上,将整个事物缩放以产生 0.0 和 1.0 之间的结果对我来说更有意义,但至少这个版本具有直观意义,产生与远平面的相对距离。

    计算过于复杂

    上面的内容对我来说似乎是不必要的复杂。您正在应用投影矩阵,从结果中获取深度,然后有效地反转投影矩阵应用的深度计算。

    首先不应用投影矩阵并简单地取原始距离似乎要简单得多。如果你想要一个相对距离,你仍然可以除以远距离。至少只要你使用标准的投影矩阵,我相信下面的等价于上面的修正计算:

    vec4 pixelPos = vec4(pos + normal * radius, 1.0);
    float f = 100.0;  // far plane
    depth = -pixelPos.z / f;
    

    出现减号是因为最常用的眼睛坐标系假定您正在向下看负 z 轴。

    如果您希望结果介于 0.0 和 1.0 之间,也可以将其更改为:

    float n = 0.01;   // near plane
    float f = 100.0;  // far plane
    depth = (-pixelPos.z - n) / (f - n);
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多