立方体shadowmapping算法如何工作?
我在网上搜索,但我找不到合适的描述。 我想在OpenGL ES 2.0中执行以下操作:
在一个简单的场景中,点光源会四处移动,并且我想渲染穿孔阴影。 为此,我必须使用多维数据集shadowmap。
我了解基本算法,即:
1.)从光线的POV渲染6倍的场景。 将深度值存储在立方体贴图适当的面中。 (如果光看着+ X,那么立方体面+ X,如果看-X然后看立方体面-X等等)
2.)从相机的POV渲染场景并使用存储在立方体贴图中的深度值进行比较:
如果深度<与光线的距离,则片段处于阴影中...
我有一些问题,也有一些想法。 我只想得到一些关于我的想法的确认或更正。
我的问题:
我如何从cubemap中获取? 我知道我必须为此使用vec3,但我如何计算这个fetcher矢量? 我只有一个想法:使用vertexPosition - lightPosition向量,但我不确定这是否好。 :(
另一个问题是:距光线的距离:它在世界坐标中,所以它只是一个浮点值...深度值在[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,矩阵);
等等...
这不起作用。 好吧,但是我对它进行了动画处理,并且看到假影随着光源一起移动:光源向上移动,影子也移动了,影子也移动了下来,影子也在...
(光源在(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,matrix);
-X:LookAt(eyeX,eyeY,eyeZ,eyeX -1,eyeY,eyeZ,0,-1,0,matrix);
+ Y:LookAt(eyeX,eyeY,eyeZ,eyeX,eyeY + 1,eyeZ,0,0,-1,matrix);
-Y:LookAt(eyeX,eyeY,eyeZ,eyeX,eyeY-1,eyeZ,0,0,1,matrix);
+ 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通过,而不是顶点的预测深度。 这样,您就可以在深度比较中使用顶点与灯光的距离,而无需将任何东西投影到光照空间中。 这样你就不需要跟踪6个不同的矩阵,并选择正确的用于每个顶点或片段。
编辑:看来你不能写入到ES中的gl_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,并且因此应该抵消透视分割步骤,这将导致非线性深度值(当然,它也抵消从[-1,1]到[0,1]的转换) )。
编辑:根据你的新问题:首先,我希望你的灯光位于(eyeX,eyeY,eyeZ),因为阴影贴图生成的相机必须位于灯的位置,当然。 如果(eyeX,eyeY,eyeZ)实际上是(普通)场景摄像机的位置,那么这当然是错误的,您应该使用(lightX,lightY,lightZ)来代替。
接下来,您当然应该使用正好90度的FoV(视场)作为光线的视图,所以应该以某种方式生成投影矩阵:
glFrustum(-near, near, -near, near, near, far);
或这个:
gluPerspective(90, 1, near, far);
链接地址: http://www.djcxy.com/p/37165.html