我的阴影贴图实现有啥问题?

Posted

技术标签:

【中文标题】我的阴影贴图实现有啥问题?【英文标题】:What is wrong with my shadow map implementation?我的阴影贴图实现有什么问题? 【发布时间】:2013-06-05 05:19:23 【问题描述】:

我正在尝试在我的游戏中实现阴影映射。您在下面看到的着色器会为游戏地图正确绘制阴影,但在地图上四处走动的所有模型都是全黑的。

截图如下:

我怀疑问题出在世界位置的计算上。 gl_Vertex 不会以任何方式进行转换。因为地图是使用绝对世界坐标生成的,所以使用光照矩阵的变换会产生一个正确的相对位置,可用于执行阴影映射。

但是,我的 3D 模型都非常接近原点。因此,如果使用光照矩阵对它们的坐标进行简单转换,它们很可能永远不会被点亮。

我想知道是否会出现这种情况,如果是,我该如何解决。

这是我的顶点着色器:

#version 120
uniform mat4x4 LightMatrixValue;

varying vec4 shadowMapPosition;
varying vec3 worldPos;

void main(void)

    vec4 modelPos = gl_Vertex;
    worldPos=modelPos.xyz/modelPos.w;

    vec4 lightPos = LightMatrixValue*modelPos;

    shadowMapPosition = 0.5 * (lightPos.xyzw +lightPos.wwww);
    gl_Position = ftransform();

片段着色器: 变化 vec4 shadowMapPosition; 不同的 vec3 worldPos;

uniform sampler2D depthMap;
uniform vec4 LightPosition;

void main(void)

    vec4 textureColour = gl_Color;
    vec3 realShadowMapPosition = shadowMapPosition.xyz/shadowMapPosition.w;
    float depthSm = texture2D(depthMap, realShadowMapPosition.xy).r;

    if (depthSm < realShadowMapPosition.z-0.0001)
           
        textureColour = vec4(0, 0, 0, 1);
    
    gl_FragColor= textureColour;

【问题讨论】:

首先,截图没有说明什么——第二——为什么这么复杂?只需在第一遍中从光线的角度渲染场景 - 由于深度测试,阴影中的表面位置将被更接近光线的位置覆盖!在第二遍中,从眼睛的角度渲染场景,同时将顶点转换为光照 pov,以执行阴影贴图检查! @dinony 在我看来好像就是这样做的。有LightMatrixValue*modelPos 用于在光线pov 中进行转换。以及相应的查找。但是如果不知道阴影贴图是如何创建的,就很难猜出哪里出了问题。 0.5 * (lightPos.xyzw +lightPos.wwww) 可能是问题所在。还有纹理查找中的realShadowMapPosition.xy @dinony:正如 t.niese 指出的那样,我确实已经这样做了。据我所知,问题在于计算阴影距离本身。地图上投射了正确的阴影,因为像素已被其前面的单位遮挡。这些单位不会,因为它们没有以某种方式进行变换,以提供它们相对于灯光位置的位置。 @t.niese:我使用额外的渲染通道创建阴影贴图,该通道仅存储从灯光的角度来看的像素深度。如果你愿意,我可以添加代码。 阴影贴图的创建方式(着色代码)始终很重要,因为这会影响到固定的z 值。你为什么要这样做0.5 * (lightPos.xyzw +lightPos.wwww)(你对此有什么期望)lightPos 这是从光源位置的原点到顶点的vector(假设LightMatrixValueShadow shader) 中使用的矩阵相同。因此,通过这种计算(取决于w),您可以将点移向光源或其他方向。 【参考方案1】:

我写在这里是因为它不适合上面,我希望它能解决你的问题。

一方面,为了呈现您的模型,使用模型矩阵来定位元素,另一方面,您拥有 viewprojection 矩阵来转换您的模型进入屏幕空间。

为了创建你的阴影贴图(最简单的方法,我猜是你选择的那个)你从光源的视图渲染场景,所以你应用 viewprojection 光源矩阵,它将xyz 值映射到屏幕空间。 xy 值用于图像中的位置,z 用于深度缓冲区测试和您在颜色缓冲区中写入的颜色(稍后用作阴影贴图)。

对于最终渲染,您将这个阴影贴图和 viewprojection 矩阵加载到您的着色器中。对于场景中的显示,您将相机的 viewproject 矩阵应用到顶点,对于阴影贴图查找,您应用 viewprojection 光到顶点的矩阵(就像你对阴影贴图的渲染所做的那样)。当您将灯光 viewprojection 矩阵应用到顶点时,您将拥有与阴影贴图通道中相同的映射,现在您只需转换您的 x 和 @ 987654328@ 坐标到纹理坐标并查找存储的z 值,然后将其与计算得到的值进行比较。

将模型的世界位置转换为屏幕空间(从灯光的角度来看)

这部分通常在顶点或几何着色器中完成:

shadowMapPosition = matLightViewProjection * modelWoldPos;

这通常在片段着色器中完成:

shadowMapPosition = shadowMapPosition / shadowMapPosition.w ;

// Add an offset to prevent self-shadowing and moiré pattern
shadowMapPosition.z += 0.0005;

//lookup the stored z value
float distanceFromLight = texture2D(depthMap,shadowMapPosition.xz).z;

现在只需将distanceFromLightshadowMapPosition.z 进行比较,看看对象是否在阴影中。

因此,在您的第二遍中,您将再次执行阴影映射的步骤,只是您不绘制您计算的数据,而是将其与您在之前的遍中计算的数据进行比较。

【讨论】:

不幸的是,这并没有解决我的问题。然而,它确实摆脱了一个水平条,这是我用来将模型坐标“转换”到屏幕空间的丑陋黑客的结果。此外,您的方法比我的方法漂亮得多。我认为这足以考虑回答我的问题:)

以上是关于我的阴影贴图实现有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章

级联阴影贴图无法按预期工作

使用立方体贴图(OpenGL/GLSL)的点光源是不是可以实现软阴影?

Shadow Map阴影贴图技术之探

如何在 OpenGL 中使用立方体贴图数组来渲染带有阴影贴图的多个点光源?

静态贴图阴影参数被忽略

OpenGL 阴影贴图移动版不起作用