随深度立方体贴图全向阴影映射(Omnidirectional shadow mapping with

2019-06-24 22:04发布

我与全向点光源工作。 我已经在使用一个立方体贴图作为6帧缓冲区颜色attachement,以及编码在其每一像素的光 - 片段距离实现阴影映射。

现在我想,如果可能的话,要改变我的实现是这样的:

  • 1)附加一个深度立方体贴图到我的帧缓冲区的深度缓冲器,而不是颜色。
  • 2)只渲染深度,在此通过不写颜色
  • 3)在主通,读从立方体贴图的深度,将其转换为距离,并且检查当前片段是否被光或不封闭。

从立方体贴图转换回深度值到一定距离时,我的问题就来了。 我用的是光到片段矢量(在世界空间)的立方体贴图来迎接我的深度值。 在这一点上,我不知道是哪六个面的被使用,也没有什么2D纹理坐标匹配的深度值我读。 然后,我怎么可以在深度值转换为距离?

这里是我的代码来说明片段:

深度纹理:

glGenTextures(1, &TextureHandle);
glBindTexture(GL_TEXTURE_CUBE_MAP, TextureHandle);
for (int i = 0; i < 6; ++i)
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT,
              Width, Height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

帧缓冲区建设:

for (int i = 0; i < 6; ++i)
{
    glGenFramebuffers(1, &FBO->FrameBufferID);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO->FrameBufferID);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
            GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, TextureHandle, 0);
    glDrawBuffer(GL_NONE);
}

这件作品的片段着色器,我试图写来实现我的代码:

float ComputeShadowFactor(samplerCubeShadow ShadowCubeMap, vec3 VertToLightWS)
{   
    float ShadowVec = texture(ShadowCubeMap, vec4(VertToLightWS, 1.0));
    ShadowVec = DepthValueToDistance(ShadowVec);
    if (ShadowVec * ShadowVec > dot(VertToLightWS, VertToLightWS))
        return 1.0;

    return 0.0;
}

该DepthValueToDistance功能是我的实际问题。

Answer 1:

因此,解决方案是在光 - 片段矢量转换为深度值,而不是转换从立方体贴图读入的距离的深度。

下面是修改shader代码:

float VectorToDepthValue(vec3 Vec)
{
    vec3 AbsVec = abs(Vec);
    float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));

    const float f = 2048.0;
    const float n = 1.0;
    float NormZComp = (f+n) / (f-n) - (2*f*n)/(f-n)/LocalZcomp;
    return (NormZComp + 1.0) * 0.5;
}

float ComputeShadowFactor(samplerCubeShadow ShadowCubeMap, vec3 VertToLightWS)
{   
    float ShadowVec = texture(ShadowCubeMap, vec4(VertToLightWS, 1.0));
    if (ShadowVec + 0.0001 > VectorToDepthValue(VertToLightWS))
        return 1.0;

    return 0.0;
}

释上VectorToDepthValue(vec3 Vec)

LocalZComp对应于什么是给定的Z分量Vec成立方体贴图的匹配圆台。 它实际上是最大的组成部分Vec (例如,如果Vec.y是最大的组成部分,我们将看到无论是在Y +或立方体贴图的Y-面)。

如果你看看这个维基百科的文章 ,你就会明白数学刚过(我一直是在认识一个正式的形式),它只是转换LocalZComp (在[-1..1]之间)为标准化Z,然后它映射到其实际范围为深度缓冲器值[0..1]。 (假设你没有改变它)。 nf是用于生成立方体贴图的平截头体的近和远的值。

ComputeShadowFactor然后只从与从计算出的深度值的立方体贴图比较的深度值,片段-光载体(命名为VertToLightWS这里),也如果片段添加一个小的深度偏差(这是在问题丢失),并返回1没有被光遮挡。



Answer 2:

我想补充的关于推导更多的细节。

V是光-片段方向矢量。

正如Benlitz已经说过,在相应的立方体侧平截头体/“眼空间”的Z值可通过取V“S三个分量的绝对值的最大值来计算。

Z = max(abs(V.x),abs(V.y),abs(V.z))

然后,准确地说,我们应该因为在OpenGL,负Z轴指向到屏幕/视锥体否定ž。

现在,我们希望得到的是-Z的深度缓冲“兼容”的价值。

纵观OpenGL的投影矩阵...

http://www.songho.ca/opengl/files/gl_projectionmatrix_eq16.png

http://i.stack.imgur.com/mN7ke.png (备份链路)

......我们看到的是,对于任何均匀的向量与矩阵相乘,所得到的z值完全独立于矢量的x和y分量。

因此,我们可以简单地乘以这个矩阵与向量齐(0,0,-Z,1),我们得到了向量(分量):

x = 0
y = 0
z = (-Z * -(f+n) / (f-n)) + (-2*f*n / (f-n))
w = Z

然后,我们需要做透视分割,所以我们用w(Z),这给了我们划分Z:

z' = (f+n) / (f-n) - 2*f*n / (Z* (f-n))

此Z”是在OpenGL的归一化设备坐标(NDC)范围[-1,1]和需要转换成的一个深度缓冲器兼容范围[0,1]:

z_depth_buffer_compatible = (z' + 1.0) * 0.5

其它说明:

  • 它可能是有意义的上传(F + N),(FN)和(f * N)作为着色制服节省计算的结果。

  • V需要在世界空间,因为阴影立方体地图通常是轴在世界空间从而“ 最大(ABS(Vx的),ABS(VY),ABS(1/2))”对准-Part只能如果V是世界空间方向矢量。



文章来源: Omnidirectional shadow mapping with depth cubemap