glsl sampler2DShadow和shadow2D澄清

时间:2014-03-15 04:49:50

标签: opengl glsl shadow-mapping

我在哪里的快速背景(以确保我们在同一页上,并且在我缺少/假设有些愚蠢的情况下进行健全检查):

  • 目标:我想使用延迟光照渲染阴影场景 和shadowmaps。
  • 奋斗:找到关于如何使用shadow2D和sampler2DShadow的清晰一致的文档。

这是我目前正在做的事情:

在我最终渲染过程的片段着色器(实际计算最终碎片值的那个)中,我从光的角度来看传递的MVP矩阵,来自所述传递的深度纹理(又名) "阴影贴"),以及几何缓冲区中的位置/法线/颜色纹理。

据我所知,我需要找到当前片段位置对应的阴影贴图的UV。我通过以下方式做到这一点:

//Bring position value at fragment (in world space) to screen space from lights POV
vec4 UVinShadowMap = (lightProjMat * lightViewMat * vec4(texture(pos_tex, UV).xyz,1.0)).xy; 
//Convert screen space to 'texture space' (from -1to1 to 0to1)
UVinShadowMap = (UVinShadowMap+1)/2;

现在,我已经拥有了这种紫外线,我可以获得深刻的感受'来自光明的pov

float depFromLightPOV = texture2D(shadowMap, UVinShadowMap).r;

并将其与当前片段的位置与光线之间的距离进行比较:

float actualDistance = distance(texture2D(pos_tex, UV).xyz, lightPos);

问题来自于这种深度'存储在值0-1中,实际距离在世界坐标中。我已尝试手动进行转换,但无法使其正常工作。在网上搜索,看起来像我应该这样做的方式是使用sampler2DShadow ......


所以这是我的问题:

我需要做哪些更改才能使用shadow2D? shadow2D甚至做了什么?它只是或多或少的自动转换 - 从深度到世界的纹理?我可以使用相同的深度纹理吗?或者我需要以不同的方式渲染深度纹理?我将什么传递给shadow2D?我想检查片段的世界空间位置?或者和以前一样的紫外线?

如果所有这些问题都可以在一个简单的文档页面中得到解答,那么如果有人能够发布这些问题,我会很高兴。但是我发誓我已经找了好几个小时,找不到任何简单说出shadow2D发生了什么的事情!

谢谢!

1 个答案:

答案 0 :(得分:41)

首先,您使用的是什么版本的GLSL?

从GLSL 1.30开始,没有特殊的纹理查找功能(无论如何名称)与sampler2DShadow一起使用。 GLSL 1.30+使用texture (...)的一堆重载,这些重载是根据传递的sampler类型和坐标的尺寸选择的。

其次,如果你使用sampler2DShadow,你需要做两件事:

  1. 必须启用纹理比较,否则您将获得未定义的结果

    • GL_TEXTURE_COMPARE_MODE = GL_COMPARE_REF_TO_TEXTURE​

  2. 您传递给texture (...)的坐标是3D而不是2D。新的第3个坐标是您要比较的深度值。

  3. 最后,您应该了解使用texture (...)时<{1}}返回的内容:

    如果此比较过去,sampler2DShadow将返回 1.0 ,如果失败则会返回 0.0 。如果您在深度纹理上使用texture (...)纹理滤镜,那么GL_LINEAR将使用深度纹理中最近的4个深度值执行4次深度比较,并在之间的某处返回值 1.0 0.0 ,以了解通过/失败的样本数量。

    这是对阴影贴图进行硬件消除锯齿的正确方法。如果您尝试使用常规texture (...)sampler2D并自己实施深度测试,则会获得单个平均深度回归和布尔通过/失败结果,而不是上面针对{{1}所述的行为}。


    至于从世界空间位置获取深度值进行测试,你走在正确的轨道上(虽然你忘了透视师)。

    从世界空间位置生成深度必须做三件事:

    1. 通过(光照)投影和视图矩阵乘以世界空间位置
    2. 将结果坐标除以其GL_LINEAR组件
    3. 将结果(将在[-1,1]范围内)缩放并偏向范围[0,1]
    4. 最后一步假设您使用的是默认深度范围...如果您尚未调用sampler2DShadow,那么这将有效。

      步骤3的最终结果用作 深度值(W)和纹理坐标< / strong>(glDepthRange (...))用于查找深度图。这样就可以将此值 直接 传递给R。回想一下,纹理坐标的前2个分量与始终相同,第3个是要测试的深度值。