Opengl es 立方体阴影映射算法是如何工作的?

Opengl es 立方体阴影映射算法是如何工作的?,opengl-es,3d,opengl-es-2.0,shadow,Opengl Es,3d,Opengl Es 2.0,Shadow,我在网上搜索过,但找不到合适的描述。我想在OpenGL ES 2.0中执行以下操作: 在一个简单的场景中,一个点光源会四处移动,我想渲染perfragment阴影。为此,我必须使用立方体阴影贴图 我了解基本算法,即: 1.)从灯光的POV渲染场景的6倍。将深度值存储在立方体贴图的相应面中。(如果光线看+X,则立方体面+X,如果看-X,则立方体面-X,依此类推) 2.)从摄影机的POV渲染场景,并使用存储在cubemap中的深度值进行比较: 如果深度

我在网上搜索过,但找不到合适的描述。我想在OpenGL ES 2.0中执行以下操作:

在一个简单的场景中,一个点光源会四处移动,我想渲染perfragment阴影。为此,我必须使用立方体阴影贴图

我了解基本算法,即:

1.)从灯光的POV渲染场景的6倍。将深度值存储在立方体贴图的相应面中。(如果光线看+X,则立方体面+X,如果看-X,则立方体面-X,依此类推)

2.)从摄影机的POV渲染场景,并使用存储在cubemap中的深度值进行比较:

如果深度<与光的距离,则碎片处于阴影中

我有一些问题,也有一些想法我只想得到一些关于我想法的确认或更正。

我的问题:

我怎么从立方体地图上取?我知道我必须使用一个vec3,但是我如何计算这个获取向量呢?我只有一个想法:使用垂直光位置向量,但我不确定这是否好(

另一个问题是: 离光的距离:它在世界坐标中,所以它只是一个浮点值。。。 深度值在[0.0,1.0]范围内

如何在[0.0,1.0]范围内创建距离? 我的想法是将所有6个灯光的视图矩阵和灯光的投影矩阵也传递给顶点着色器。我计算顶点的位置2次:一次用于摄影机的MVP(正常),一次用于灯光的MVP(用于阴影计算,使用适当的视图矩阵)通过这种方式,我将再次获得碎片在光POV中的位置,并且由于w分割,它的z值可以在偏移后用作[0.0,1.0]中与光的距离,因此我可以将其与从立方体阴影贴图中获取的深度值进行比较……对吗

请帮帮我,先谢谢你

编辑:

好了,阴影立方体映射开始工作了。但是,有一些错误我正在尝试修复

起初,阴影是“愚蠢的”。不是它们应该在的地方,或者完全“愚蠢”形状的阴影被渲染

设置为:相机进入(0,4.9,0),注视(0,0,0),向上(0,1,0)。 灯光视图:

+X:LookAt(eyeX,eyeY,eyeZ,eyeX+1,eyeY,eyeZ,0,1,0,矩阵);//自己的实现与gluLookAt相同

-X:LookAt(eyeX,eyeY,eyeZ,eyeX-1,eyeY,eyeZ,0,1,0,矩阵)

+Y:LookAt(eyeX,eyeY,eyeZ,eyeX,eyeY+1,eyeZ,-1,0,0,矩阵)

等等

这不起作用。好的,但我设置了动画,看到假阴影随着光源移动:光源向上移动,阴影也向上移动,ls向下移动,阴影也

(光源位于(0,0,0)并沿Y轴移动,长方体离开光源。)

因此,为了进行测试,我在片段着色器中执行了以下操作:

vec3 fetcher=v_posWorld.xyz-u_light_pos

fetcher.y*=-1.0

这个想法的产生是因为我认为问题可能在于在纹理上渲染时,渲染的图像会被颠倒。这个测试有效,但当然只适用于-X和+X面

因此,我注释掉了“fetcher.y*=-1.0;”行,并更改了灯光的视图:

+X:LookAt(eyeX,eyeY,eyeZ,eyeX+1,eyeY,eyeZ,0,-1,0,矩阵)

-X:LookAt(eyeX,eyeY,eyeZ,eyeX-1,eyeY,eyeZ,0,-1,0,矩阵)

+Y:LookAt(eyeX,eyeY,eyeZ,eyeX,eyeY+1,eyeZ,0,0,-1,矩阵)

-Y:LookAt(eyeX,eyeY,eyeZ,eyeX,eyeY-1,eyeZ,0,0,1,矩阵)

+Z:LookAt(eyeX,eyeY,eyeZ,eyeX,eyeY,eyeZ+1,0,-1,0,矩阵)

-Z:LookAt(eyeX,eyeY,eyeZ,eyeX,eyeY,eyeZ-1,0,-1,0,矩阵)

它可以工作!几乎可以,因为+Y和-Y的视图设置没有像我预期的那样工作:(在玩了一点之后,我将相机的位置更改为(0,-4.9,0),一切工作都变得糟糕:阴影再次“愚蠢”

我在这里完全迷路了。我不知道我的算法哪里失败了。可能是因为,对于纹理渲染,我应该使用左手规则视图(我的意思是在生成灯光的视图矩阵时)

不管怎样,我一直在工作,但也许我不太懂立方体地图(

(很抱歉编辑了这么长时间)

  • 使用假设的“灯光到顶点”向量确实应该是用作纹理坐标的正确向量

  • 也可以将线性深度存储到深度纹理中,只需写入顶点到光源的距离(除以已知的最大灯光影响距离,将其转换为[0,1])进入
    gl_FragDepth
    在前6个过程中,i读取顶点的投影深度。这样,您可以在深度比较中使用顶点到灯光的距离,而无需将任何东西投影到灯光空间。这样,您不需要跟踪6个不同的矩阵,并为每个顶点或场景选择正确的矩阵碎片

  • 编辑:似乎您无法在ES中写入
    gl\u FragDepth
    ,这使得渲染自己的深度有点复杂。仅渲染到普通纹理是不行的,因为每个通道的8位精度在实践中太小了

    但您应该能够在顶点着色器中线性化深度,只需将顶点到光的距离存储在顶点的z分量(转换为[-1,1])乘以其w分量,然后再除以w,并通过光栅化器转换为[0,1],以获得片段的深度:

    uniform mat4 lightModelView;
    uniform mat4 lightProjection;
    unfiorm float maxLightDistance;
    
    attribute vec4 vertex;
    
    void main()
    {
        vec4 lightSpaceVertex = lightModelView * vertex;
        float lightDistance = length(lightSpaceVertex.xyz) / maxLightDistance;
    
        gl_Position = lightProjection * lightSpaceVertex;
        gl_Position.z = (2.0*lightDistance-1.0) * gl_Position.w;
    }
    
    它可以通过相应地更改灯光的投影矩阵来进行优化,但是如果我没有完全错误的话,这段代码(结合简单的穿透碎片着色器)应该将线性灯光到顶点的距离存储到深度缓冲区中。它只是将顶点的z乘以它的w
    glFrustum(-near, near, -near, near, near, far);
    
    gluPerspective(90, 1, near, far);