【问题标题】:Shadow Mapping in OpenGLOpenGL 中的阴影映射
【发布时间】:2015-02-23 08:02:41
【问题描述】:

我无法在我的应用程序中使用阴影映射。我尝试渲染一辆四轮摩托车并在它下面的地板上查看它的影子。 这是我的一些代码。 纹理创建:

    // Create a depth texture
    glGenTextures(1, &depth_texture);
    glBindTexture(GL_TEXTURE_2D, depth_texture);
    // Allocate storage for the texture data
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32 ,1600, 900, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    // Set the default filtering modes
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // Set up wrapping modes
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glBindTexture(GL_TEXTURE_2D, 0);
    // Create FBO to render depth into
    glGenFramebuffers(1, &depth_fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
    // Attach the depth texture to it
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    depth_texture, 0);
    // Disable color rendering as there are no color attachments
    glDrawBuffer(GL_NONE);
    //check fbo status
    GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if(result != GL_FRAMEBUFFER_COMPLETE)
        throw std::runtime_error("shadow mapping framebuffer error");
    //bind default framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

渲染到深度纹理:

progShadow.Use();
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);

glClear(GL_DEPTH_BUFFER_BIT);

glm::mat4 shadowProjection = glm::frustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 100.0f);
glm::mat4 shadowView = glm::lookAt(light.position, glm::vec3(0,0,0), glm::vec3(0,1,0));
glm::mat4 shadowModel(1);
if(g_rotate)
    shadowModel = glm::rotate((float)clock() / (float)CLOCKS_PER_SEC, glm::vec3(0,1,0));
glm::mat4 shadowMVP = shadowProjection * shadowView * shadowModel;
progShadow.SetUniform("MVPMatrix", shadowMVP);
quadBike.Draw();

我还使用“测试”着色器程序来渲染我的深度纹理。这是它的样子。

所以我想我到现在都很好。 现在我可以正常渲染场景了。

glBindTexture(GL_TEXTURE_2D, depth_texture);
prog.Use();//main program
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 shadowBias = glm::mat4(0.5, 0.0, 0.0, 0.0,
                                 0.0, 0.5, 0.0, 0.0,
                                 0.0, 0.0, 0.5, 0.0,
                                 0.5, 0.5, 0.5, 1.0);
glm::mat4 ShadowBiasMVP = shadowBias * shadowMVP;
prog.SetUniform("ShadowBiasMVP", ShadowBiasMVP);

//draw quadBike and floor
...

我的顶点着色器的相关部分:

#version 430

...

out vec4 shadowCoord;

void main()
{
    gl_Position = ProjectionMatrix * CameraMatrix * ModelMatrix * vec4(vertex, 1.0);
    shadowCoord = ShadowBiasMVP * vec4(vertex, 1.0);
    ...
}

片段着色器的相关部分:

#version 430

...

uniform sampler2D shadowMap;
in vec4 shadowCoord;

void main()
{
    ...

    float visibility = 1.0;
    if ( texture(shadowMap, shadowCoord.xy).z <  shadowCoord.z)
        visibility = 0.0;

    ...
}

现在的问题是我得到了一个完全黑暗的场景,就好像它被阴影覆盖了一样。只有当灯光真正靠近四轮摩托车时,它才会正常渲染。 (深度纹理在右侧可见,因为它是用不同的程序渲染的。我用它来测试)

我做错了什么?

【问题讨论】:

  • 偏置矩阵的目的是重新缩放(x 0.5)和偏移(+ 0.5)你的xy(纹理坐标)和z(深度)从剪辑空间([-w,w])。要完成偏置矩阵应该进行的转换,您需要除以 w(现在您的数学仅在 shadowCoord.w1.0 时才有效,如果您不是这种情况正在使用透视投影)。

标签: c++ opengl shader shadow shadow-mapping


【解决方案1】:
  1. 您应该在第一个组件处读取灰度深度纹理。

    texture(shadowMap, shadowCoord.xy).r

    texture(shadowMap, shadowCoord.xy).x

  2. 阴影坐标应该在插值后去均匀化(除以 w)。

    -> 在片段着色器中:shadowPos = shadowPos/shadowPos.w;

  3. 如果不使用多边形偏移等其他技术,则需要从阴影深度值中减去偏差以防止自身阴影。

这是一个在片段着色器中计算阴影的示例函数。注意:它是延迟渲染器的一部分,这就是为什么在片段着色器中进行矩阵乘法的原因。

float calculateShadow(vec3 position){
    vec4 shadowPos = depthBiasMV * vec4(position,1);
    shadowPos = shadowPos/shadowPos.w;


     float bias =  0.0012;
     float visibility = 1.0f;
     if ((shadowPos.x < 0 || shadowPos.x > 1 || shadowPos.y < 0 || shadowPos.y > 1 || shadowPos.z < 0 || shadowPos.z > 1)){
       visibility = 1.0f;
     }else{
        float shadowDepth = texture(depthTex, shadowPos.xy).r;
        if(shadowDepth<shadowPos.z-bias)
            visibility = 0.0f;
     }
     return visibility;

}

【讨论】:

  • 使用您发布的功能,我在地板上得到了一个非常大的阴影。 link
  • 仍然坚持这个 :(。任何人都可以发布一个链接到一个广泛解释这个主题的好指南吗?使用 this 教程并没有解决我的问题。
  • 问题是基本的阴影映射实际上非常简单,所以你可能在某个地方犯了一个愚蠢的错误。但也许阅读其他教程会有所帮助。 ogldev.atspace.co.uk/www/tutorial23/tutorial23.html
  • 我让它工作了。问题出在我的顶点着色器中。 “shadowCoord”应该被声明为shadowCoord = ShadowBiasMVP * ModelMatrix * vec4(vertex, 1.0);。现在我正在调试程序并测试不同的值。你能回答下一个问题吗?如果我错了,请纠正我:在片段着色器中,shadowPos.z 是光源到表面的距离,那么如果我将其替换为:vec3 surfacePos = vec3(ModelMatrix * vec4(fragVert, 1)); float surfaceToLight = length(surfacePos - light.position);//the new value 有什么区别,为什么会得到不同(和错误)的结果?
  • 是的,shadowPos.z 是光源到片段的距离是正确的,但这个距离不在世界空间中。由于阴影贴图(由光源渲染的纹理)位于“阴影空间”中,因此您也需要将顶点转换为阴影空间。只有当两个位置(shadow-map 和 shadowPos)都在 shadow-space 中时,距离比较才有意义。
猜你喜欢
  • 2021-09-07
  • 1970-01-01
  • 2015-02-04
  • 2013-08-23
  • 2013-06-30
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 2016-12-22
相关资源
最近更新 更多