« Shadow Map阴影贴图技术之探ⅠShadow Map Demo1 »

Shadow Map阴影贴图技术之探Ⅱ

这里是ZwqXin关于Shadow Map阴影贴图的OpenGL实现记录的第二辑,在上篇中讲述了大概原理,在本篇我想在此基础上讲讲我所认为和理解的细节关键点,并放出demo。上篇请参考 Shadow Map阴影贴图技术之探Ⅰ。——ZwqXin.com

本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
      原文地址:http://www.zwqxin.com/archives/opengl/shadow-map-2.html

事实上我在这里最想要讲的就是在再弹OpenGL矩阵——到另一个空间去 和 Shadow Map阴影贴图技术之探Ⅰ 中重重地提及但没有展开的两个问题(当然,其实当时是不太了解所以没说下去,但是经过这些天对demo运作效果的调试,我想我应该可以说说了)。其一,怎么变换矩阵到所需的光源视觉下投影空间,怎样转化为可查询的纹理;其二,那些“在相机中可以看到,但是在光源视觉下看不到”的场景,怎么办。

Coordinate spaces

1.  到深度纹理的纹理空间去

先讲讲矩阵变换的问题。Shadow Map中的第一步(PASS 1),我们要把光源所看到的东西映射到一张深度纹理中,这涉及的也就上面这张曾经给我莫大启发的图中的变换。找到光源的视界,我们是回到最初,按照右边那条路一路变下来的,矩阵变换也应该按照这条路子思考。明确我们现在(在PASS 2中)要做的是:寻找这么一个矩阵变换,通过变换可以让物体某个坐标(局部坐标)逐步对应到那幅深度图的某个纹理坐标(即点与点对应,见上篇),这跟我以前说过的顶点坐标在不同空间的转换一样的嘛。因为涉及最终目标——纹理空间下的纹理坐标,所以我们叫此变换为:纹理矩阵变换。OpenGL也专门给了一个外号这类型的变换:GL_TEXTURE。和GL_MODELVIEW,GL_PROJECTION一样,是一个标志,glMatrixMode(GL_TEXTURE)表明接下来的变换是“纹理矩阵变换”。(标志有什么作用?它们作用在于通知OPENGL,这样OPENGL就知道对变换归类,知道顶点坐标和矩阵之间应该“怎么乘”了,也能在编程人员喊“给我把XX变换的矩阵叫来!”的时候,准确给出所需要的。典型的是shader中由opengl提供的gl_ModelViewMatrix,gl_ProjectionMatrix....当然还有gl_TextureMatrix[i]。)

好了,开始变换吧!(以下涉及变换实际顺序与代码操作顺序的倒置,不太清楚的朋友可以参考我写的乱弹OpenGL中的矩阵变换系列呵呵[ZwqxXin自卖广告]。)首先,与以前一样的是从模型空间转到世界空间,没问题!然后,啊,有问题啦!从世界坐标到光源版本的视图空间。问题不是这个转换矩阵怎么求(事实上很简单嘛,单独弄个光源的glLookat再获取此命令生成矩阵),而是上面那个从模型空间转到世界空间的模型变换矩阵怎么求!opengl里它是和视图变换矩阵合在一起的啊!直接求的话实在太委屈了,像往常那样如何?PASS1里不是就实施过一下光源视觉嘛,在那时候获得那个modelview怎么样?那你准备在什么时候去取?代码逻辑跟变换顺序是相反的,于是模型变换的代码会放在最后——而且紧接的就是物体的原始坐标在那儿了,假如物体很多,模型变换错综复杂,那你都搞不清该在哪放置获取矩阵的代码了——很不现实。那么退一步看呢?有没有直接从物体顶点坐标(原始坐标)到光源视觉下该顶点的位置坐标的变换呢?明显没有!

这时候你得好好看图了——路径还有一条:从相机的视图空间,经过世界空间到光源的视图空间!后者前面说了,很容易获得,可前者呢?这可是要求正常的那个视图变换的逆矩阵啊!视图变换矩阵与模型变换矩阵不同,它与后继操作(也就是模型变换)泾渭分明,可在确定“分界线”位置获得。关键是引入求逆!米办法了,去找个OPENGL矩阵类央求个求逆算法回来吧~~(注意是在设定正常相机时候去获得。)右边那些项之间的变换矩阵可轻松获得,于是我们跳到光源版本的屏幕空间吧,它是个平面,Z都被“归”掉了,而X,Y方向范围是[-1,1],缩半后向左上角偏移就有一个[0,1]的纹理坐标啦。等等!我刚才抽的是哪根烟!哪能跳得那么快啊!光源版本的视图空间(Light's Eye Space)到光源版本的屏幕空间(Light's Screen Space)中间的投影过程是有归一,裁减,透视相除等几个主要操作的,而图中的末端只不过是屏幕空间未进行透视相除(各分量除以w并舍弃z,由流水线完成)前的样子而已(所以也叫裁减空间)!(P.S.我只是学BOB大叔口头禅咋,我不是吸烟哦~)这么说可能更明白点:你看书gluPerspective生成的变换矩阵不都是个4*4矩阵么,不可能让坐标变成2*2的,透视相除要在opengl流水线上做。好了,再说下去就超过本篇主题范围了——知道这里的过程的结果是光源版本的裁减空间(Light's Clip Space)就可以了。

但是呢?现在是求“纹理变换矩阵”,很明显要自己做透视相除将上面的结果转化成2*2矩阵啊。当然可以按照某教程那样通过glTexGenfv来直接生成纹理(貌似也可免去求逆了),但是这样shader是处理不到的。因此我们干脆就把上述结果作为gl_TextureMatrix[0]交给shader,让vertex shader做剩下来的工作吧:

  1. vec4 texcoord = gl_TextureMatrix[0] * gl_ModelViewMatrix * gl_Vertex;
  2.  
  3.  shadowTexcoord = texcoord / texcoord.w;
  4.  shadowTexcoord = 0.5 * shadowTexcoord +0.5;

很明显透视相除和偏移后shadowTexcoord还是个 vec4,没有舍弃什么。是这样的,在fragment shader里shadow2DProj获取深度纹理的值,需要的纹理坐标要是个vec4(s,t,p,q)。另外回应一下,上面把gl_TextureMatrix[0] 乘 gl_ModelViewMatrix就能通过前者里那个 相机逆矩阵抵消gl_ModelViewMatrix里那个相机矩阵了,满足图中要求:

  1. texcoord = gl_TextureMatrix[0] * gl_ModelViewMatrix * gl_Vertex
  2. =Light_ProjectionMatrix * Light_ViewMatrix * Camera_ViewInverseMatrix
  3.  * gl_ModelViewMatrix * gl_Vertex
  4. =Light_ProjectionMatrix * Light_ViewMatrix * Camera_ViewInverseMatrix
  5.  * Camera_ViewMatrix * ModelMatrix * gl_Vertex
  6. =Light_ProjectionMatrix * Light_ViewMatrix * ModelMatrix * gl_Vertex

2.当光被视线斩断

我确实把相机视觉下看到的场景的顶点映射到那张光源视觉下“拍到”的深度纹理图上了。但是那部分在相机中可以看到,但是在光源视觉下看不到的场景怎么办?它们无法在深度纹理图上找到它们的对应部分啊!这是个难题,也许有某些技术可以做得好,但我还没有探究到那里。目前我能确认的:一是把光源位置调得远一点,甚至无限远(辅以远近裁减面调节),这样光源处所看到的场景就更大了,出来的深度图信息更丰富,但是这样的话,光源所看到的场景细节就淡了,无疑得出的阴影锯齿加重;二是不要限定光源只看原点——但是看哪里呢?即使与相机焦点一致,也还是会出现这个问题的;三是把深度图范围弄大点,FBO不是可以做到截出比屏幕大的范围到大纹理里吗?但是光源的视野也就那么点了,还得让流水线的屏幕外裁减功能失效,因此我通过增大FBO纹理效果不明显。没辙了,你看我的demo,调整光源位置(靠近目标点,即减小光源视野,用空格视现)阴影消失,或者出来了一些黑黑的东西,(即该部分没有深度比较)就是这个原因。

Shadow Map Demo1
更详细截图,包括成功之前的,看这里:
Shadow Map Demo1 -ZwqXin.com

本DEMO使用了shader,需要下载glew库到指定目录,下载见此:OpenGL常用的库
放上本DEMO:shadowmapdemo1byzwqxin.rar
按键:
    →   ←   ↑   ↓  PageUp  移动光源
   鼠标左键下按不放并移动鼠标:旋转视角;鼠标滚轮移动
   鼠标右键:自动旋转开关
   空格:(默认光源目标点定位于原点)正常模式/射线可见模式/光源目标点定位于与相机焦点一致

P.S.下篇:[Shadow Map阴影贴图技术之探Ⅲ]

本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
      原文地址:http://www.zwqxin.com/archives/opengl/shadow-map-2.html

  • quote 1.aaaa

  • texcoord = gl_TextureMatrix[0] * gl_ModelViewMatrix * gl_Vertex; 这段代码里面gl—TextureMatrix【0】的作用是什么呢?能否详细解释下这段代码?


    本文来源于ZwqXin http://www.zwqxin.com/ , 转载请注明
    原文地址:http://www.zwqxin.com/archives/opengl/shadow-map-2.html


    zwqxin 于 2011-3-20 22:32:17 回复
    (Bia Matrix *)Light proj Matrx * LightView Matrix * CameraViewInverse Matrix
  • 2011-3-20 21:18:40 回复该留言
  • quote 2.誠斯
  • "但是那部分在相机中可以看到,但是在光源视觉下看不到的场景"

    不是在frame shader上去比較光視覺空間的深度與深度紋理而決定陰影嗎?
  • 2015-12-14 23:51:56 回复该留言

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

IE下本页面显示有问题?

→点击地址栏右侧【兼容视图】←

日历

Search

网站分类

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Walle Build 100427

Copyright 2008-2013 ZwqXin. All Rights Reserved. Theme edited from ipati.