Shadow Map 原理和改进_ronintao的博客
文章推薦指數: 80 %
shadow map是一种常用的实时阴影的生成方法。
通常用来生成平行光(direction light)的阴影。
点光源也可以用,不过要更加复杂一些(称 ...
ShadowMap原理和改进
ronintao
于 2016-07-0711:50:54 发布
42146
收藏
88
分类专栏:
Unity
文章标签:
unity
render
版权声明:本文为博主原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ronintao/article/details/51649664
版权
Unity
专栏收录该内容
4篇文章
3订阅
订阅专栏
参考
1、CommonTechniquestoImproveShadowDepthMaps
2、Tutorial16:Shadowmapping
3、ShadowMapping
4、ShadowMappingAlgorithms
5、ShadowMap阴影贴图技术之探
6、CascadedShadowMaps
写在前面
之前已经很久没有再更新博客,上一篇已经是3年前的记录了,当时还比较菜(现在当然仍然菜),所以写的东西大多不是很好……
这期间其实也学了很多新的东西。
学习中比较痛苦的一点,是经常发现所学的东西要么就只有一个大意的原理讲解,不会特别深入;要么就是只有一个实现的简单方法,不知道所以然(国内的资料很多是这样);能够两者兼顾的通常是比较难啃的英文资料,隔一段时间回去再翻阅,由于语言问题又需要花比较长的时间;另外一个问题就是各个相关知识点比较散落,不方便融汇贯通来看。
因此,又产生了回来重开博客,进行汇总的想法。
另外回来重新翻阅之前的博客,发现多了很多留言,以后慢慢的回复填坑吧……
一、shadowmap原理
shadowmap是一种常用的实时阴影的生成方法。
通常用来生成平行光(directionlight)的阴影。
点光源也可以用,不过要更加复杂一些(称为omnidirectionalshadowmaps,生成的是cubemap,如果我会填坑的话,会在以后讲到)。
说到xxmap,第一反应当然是会生成并利用某种纹理。
没错,shadowmap的核心就是要生成并利用shadowdepthmap。
下面具体来说。
1、阴影算法的任务
shadowmap(以及shadowvolume)等shadow算法,到底是做什么的?这其实是需要解决的第一个问题。
这些阴影算法的核心,实际上就是要针对任意给定的一个物体片段点(fragmentpoint),鉴定出它是否处在阴影之中。
所以阴影算法,归根结底是要给出这样一个函数:
boolShadowAlgorithm(vector3fragmentPoint){
if(IsInShadow(fragmentPoint))
returntrue;
else
returnfalse;
}
各种不同的阴影算法,实际上就是“是否在阴影中”的鉴别方法不同。
2、阴影产生的自然原理
什么样的点是在阴影中的?看看下面这张图
图1、阴影(图中橘黄色的是不透明的物体)
在平行光的照射下,直觉的可以知道,点A、点D在阴影之外,而点B、点C在阴影之中。
直觉判断的依据,就是由于光线的直线传播特性,一旦遇到遮挡,就会产生阴影。
换言之,对于光线来说不可见的点,就是在阴影中的点。
那么上面的判断函数 IsInShadow,就可以进一步写为如下的伪代码:
boolIsInShadow(vector3fragmentPoint){
return!IsVisibleToLight(fragmentPoint,mLight);
} 其中mLight是需要生成阴影的平行光,fragmentPoint是需要进行判断的片段点。
3、基于自然原理的提炼:lightspace的 shadowdepthmap
一提到这种可见性的判定,自然的就会想到depthtest。
我们站在光源的位置,按照光线传播的视角,观察场景,计算场景中的物体距离光源的距离(也就是该视角下的深度),并记录各个位置上的最小值(即距离光源最近的点的位置),从而获得一张shadowdepthmap。
其实,上面的流程和普通的camera获取depthmap的流程是基本一样的,只是要改换到光源位置来观察而已。
4、应用到场景中:利用shadowdepthmap
获取了shadowdepthmap之后,就要利用它来进行鉴别。
根据第2小节的讨论,可以知道,如果某个点,其在光源视角下的depth大于shadowmap中对应位置的depth,则意味着它被某个物体遮挡,因此是在阴影中的;反之则不在阴影之中。
所以,对于世界中的某个点p,我们只要将其转移到lightspace,比较他在lightspace下的depth,就可以判定它是否是在阴影之中了。
二、基本的shadowmap流程
根据第一章的讨论,可以大致梳理出流程,下面逐步来说:
1、在lightspace摆放camera
1)投影方式
camera的投影方式有两种:orthographic和perspective。
那么应该使用哪一种呢?
这就牵涉到shadowmap的原理:以光源的角度观察世界。
由于我们这里使用的是平行光,所以它眼中的世界是没有透视关系的,因此应该使用orthographic。
而如果使用的是点光源,那么就应该使用perspective了。
2)视锥体(frustum)
确定了投影方式为orthographic之后,就要确定它的视锥体。
显然我们需要将view视角下所有物体都包含到视锥体中,但是过大也没有意义,会引起不必要的渲染开销,另外也可以更充分的利用shadowdepthmap。
这里有两种方式(这一小节的图,全部来自于微软的网站):
a.FitToScene
图2、任意指定的视锥体和fittoscene设定下的视锥体
左边是一个任意设定的视锥体,里面的梯形是view视角的frustum,右边是调整shadowfrustum,使他正好包含整个scene的情况。
可以看到,如果按照左边的设置,视锥体中有一部分区域是完全空着的,那么截取出的shadowdepthtexture,对应的这一部分也就完全为空,因而利用率更低。
另一方面,左边的视锥体远近平面距离较远,由于深度取值实际是转换到0~1范围内的,这就意味着有部分值域是利用不上的,那么深度值的精度也被降低了。
那么,如果给定场景的AABB,如何确定灯光的frustum?如果当前lightspace的只需要将该AABB的顶点转移到lightspace,然后取出xmin,xmax,ymin,ymax,zmin,zmax。
由于camera的观察视野由xy分量确定,观察的深度由z确定,因此将camera摆放在x,y的中心点,size取其半径的较大值,然后将zmin设置为near,zmax设置为far即可。
例如下面unity的代码,lightCamera就是我们摆放在灯光处的camera
privatevoidFitToScene(){
List
可以看到在左边的情况下,其表现非常好,只需要包含很少的区域,右边的情况对比fittoscene则有得有失。
值得注意的是,view视角下的阴影,并不一定完全由view视角内包含的物体产生,可以看下面这张图,view视角很小的情况下就会出现问题。
图4、fittoview在viewfrustum很小时的阴影丢失
因此在实际使用中,是使用灯光的无穷远视锥体和viewfrustum以及场景的AABB盒的交集来做的
图5、综合使用scene与viewfrustum来解决阴影丢失
另外这种方法还有个问题在于视锥体的确定和viewfrustum产生了关联。
只要观察视角变动,则截取尺寸就有可能变化,而在fittoscene情况下,则是相对固定的。
这种情况的代码与上面的差别不大,可以看到near和farclipplane仍然取决于scene,而size则完全取决于viewfrustrum
privatevoidFitToView(){
List
所以在实际使用中,可以先获取viewcamera的maxdepth,然后再进行计算(当然可能还有更好的方式)
2、截取 shadowdepthmap
1)texturesize
要将shadowdepthmap保存为多大尺寸的纹理是个非常重要的问题。
尺寸越大,包含的信息越多,当然越精确,但是消耗的内存也越多。
尺寸太小会引发锯齿问题。
这里先不展开讨论,在后面的部分会详细讲到。
2)编码方式
texturesize体现的是位置的精确度,而该像素点上的值,则是其深度值的精度。
如果仅仅利用纹理像素中的一维,则精度显然不够高,而且十分浪费。
所以可以通过编码的方式,将其四位(RGBA模式下)统统利用起来。
例如unity中的 EncodeFloatRGBA
//Encoding/decoding[0..1)floatsinto8bit/channelRGBA.Notethat1.0willnotbeencodedproperly.
inlinefloat4EncodeFloatRGBA(floatv)
{
float4kEncodeMul=float4(1.0,255.0,65025.0,16581375.0);
floatkEncodeBit=1.0/255.0;
float4enc=kEncodeMul*v;
enc=frac(enc);
enc-=enc.yzww*kEncodeBit;
returnenc;
} 在需要取出的时候再进行解码:
inlinefloatDecodeFloatRG(float2enc)
{
float2kDecodeDot=float2(1.0,1/255.0);
returndot(enc,kDecodeDot);
}
这样就提高了深度值的精度。
3、开始渲染阴影
对于一般的物体,那么直接渲染即可,而对于一些透明的物体,或者需要特殊处理的物体,则可以在这一步再做点文章。
比如说对于一些透明的物体,只希望他的边界处产生阴影,则可以只对他的边界处记录Z值。
这里会在以后补全(希望我会填这个坑)
4、对于每个点,转到lightspace,转换矩阵的确定
首先要明确的是转换的目的。
上面截取的depthmap是在lightspace中获得的,那么对于场景中任意的一点,就需要知道他在lightspace中的位置。
那么和viewspace中的mvp转换一样,这里也需要转移到lightspace的mvp矩阵。
在unity中这几个矩阵其实可以直接获取,不过在《Unity3DShaderLab开发实战详解》中的第13章中有出现一个具体的矩阵,但是这个矩阵有一些问题(这是一本充满bug的好书),因此在这里额外讨论一下这个矩阵如何确定。
这里我们分别对m、v、p进行讨论:
1)model矩阵:local->world
显然,lightspace和viewspace所面对的世界是一样的,那么将坐标从local坐标系转换到world坐标系的model矩阵就是相同的。
那么在unity中,在shader中直接使用 _Object2World矩阵就可以了
2)view矩阵:world->view
在unity中可以直接获取这个矩阵,使用 Camera.worldToCameraMatrix 即可。
而在《实战》一书中,使用的是灯光的Transform.worldToLocalMatrix。
乍一想,这两个矩阵的功效应该相同:对lightspace来说,所谓的viewspace,其实不就是灯光看到的世界吗,那不就是灯光本地的世界吗?
然而将这两个矩阵打印出来,会发现在Z轴方向有符号上的差异。
详细的讨论可以参考 unity,相机空间与相机gameObject的局部空间 这篇文章。
其实问题的本质就在于unity中的坐标系是左手坐标系,而cameraview坐标系是右手坐标系。
所以在z轴上发生了方向的反转,这样的反转之后,camera所见的物体z<0,且越远,z越负。
因此,这里需要使用 Camera.worldToCameraMatrix来获取view矩阵,或者使用对角矩阵[1,1,-1,1]左乘 Transform.worldToLocalMatrix。
两者得到的结果是相同的。
3)projection矩阵:view->projection
在unity中可以直接从 Camera.projectionMatrix中获取。
《实战》一书中,在light处放置的是一个perspective的camera,所以其投影矩阵是透视投影,他这里给出的矩阵有比较多的错误。
这里的求法可以参考我之前的博客《【OpenGL】02-OpenGL中的坐标系》 最后的结论:
在unity的官方手册上也有相同的公式,可见链接最下面的范例。
由于实际使用中,camera处在viewspace的原点,因此
Right-Left=WidthAtNearClip;
Top-Bottom=HeightAtNearClip;
Right+Left=0;
Top+Bottom=0; 而在近平面的width和height可以由camera的fov、aspect和near求取出来:
floatfov=c.fieldOfView;
floatn=c.nearClipPlane;
floatf=c.farClipPlane;
floataspect=c.aspect;
floatheightAtNear=2*n*Mathf.Tan(fov/2f*Mathf.Deg2Rad);
floatwidthAtNear=aspect*heightAtNear; 将这个结果带入原矩阵,并定义
floatd=1/Mathf.Tan(fov/2f*Mathf.Deg2Rad); 则得到
这样求出的投影矩阵,和Camera.projectionMatrix是相等的。
但这个矩阵仍然不能直接使用,需要根据GPU情况再进行处理(这里的原理我并不清楚,期待今后可以补完),还需要使用
GL.GetGPUProjectionMatrix(c.projectionMatrix,false) 才能够得到shader中使用的投影矩阵。
4)正投影的投影矩阵
仍然可以使用 Camera.projectionMatrix然后使用 GL.GetGPUProjectionMatrix转换后得到。
具体的 Camera.projectionMatrix矩阵计算方法依旧可以参考我之前的博客 《【OpenGL】02-OpenGL中的坐标系》
5)correction矩阵
注意到《实战》一书中,还有一个correction矩阵,这个矩阵是做什么的?
一个顶点,经过MVP变化之后,其xyz分量的取值范围是[-1,1],现在我们需要使用这个变化过的顶点值来找到shadowdepthmap中对应的点来比较深度,即要作为UV使用,而UV的取值范围是[0,1],所以需要进行一个值域的变换,这就是这个矩阵的作用。
需要注意的是,要使这个矩阵成立,该vector4的w分量必须是1。
在shader中运算的时候必须注意。
5、将上面求得的转换矩阵赋值给shader
在unity中,可以使用下面的代码来达到效果。
Shader.SetGlobalMatrix("LightMV",matrix); 在后面的实践中,有时我们还需要传递数组给shader,这个特性在目前的版本(5.3)中还不支持,从官网的论坛上来看,将在5.4中支持该特性。
6、在物体的shader中进行深度比较,来确定阴影
到了这一步,就只需要简单的比较深度就可以了,当然这里也是可以扩展的改善的,后面的bias里面我们会谈到。
7、基础shadowmap的代码
代码可以参考附例中的" 01BasicShadowMap",可以看到综合的流程。
三、对这个流程的一些思考
除了上一章中对于每个独立步骤的讨论之外,对于流程整体,这里还有一些思考。
1、对静态平行光源,shadowdepthmap可以预生成吗?
如果场景中需要投射阴影的物体是静态的,且不使用fittoview时是可以的。
2、多个光源要怎样处理?
现在针对单个光源,是放在mainpass中执行的,对于多个光源,则每个光源都需要有自己独立的depthmap,以及自己的转换矩阵,在shader中分别处理。
可以写在一个pass中,也可以分散到多个pass(类似于forwardadd,其实感觉forwardadd是最合适的处理位置)。
现在我们已经完成了基础的shadowmap。
但是现在的效果还很难让人满意,所以还需要很多改进。
下面我们针对问题逐个来看。
四、问题一:ShadowAcne&&SelfShadowing
1、现象
在任何改进措施都不采用的情况下,运行 " 01BasicShadowMap",会看到一张惨不忍睹的画面(当然,阴影还是有的)
图6、无改进的shadowmap中的shadowacne
更常见的情况是下图左边这样的锯齿状条纹:
图7、条纹状的shadowacne
这种现象,就被称为 ShadowAcne或者Self-Shadowing
2、原因
ShadowMapping 里的 Shadowacne一节解释的比较清楚,根本原因就是shadowdepthmap的分辨率不够,因此多个pixel会对应map上的同一个点。
图8、shadowacne成因图
图中黄色箭头是照射的光线,黑色长方形是实际物体表面,黄色的波浪线是shadowmap中的对应值的情况。
可以看到,由于map是对场景的离散取样,所以黄色的线段呈阶梯状的波浪变化,相对于实际场景中的情况,就有一部分比实际场景中的深度要大(对应着黑色线段部分),着部分不会产生阴影(注意图画反了);一部分比实际场景中的深度要小(对应着黄色线段部分),这部分会产生阴影,所以就出现了条纹状的阴影。
由于这种情况,是物体的实际深度,与自己的采样深度,相比较不相等(实际深度大于采样深度)导致的,所以可谓是自己(采样的副本)遮挡了自己(实际的物体),所以被称为selfshadowing。
3、对策
解决的方法很简单,其实只有实际深度大于采样深度的时候才有问题,那么我们在计算实际深度的时候,往灯光方向拉一点,让他减小一点就可以了
图9、shadowacne的对策:ShadowBias
这就是shadowbias的原理,具体怎么做,我们后面来看。
五、问题二:PeterPanning
1、现象
图9、peter-panning
这个现象只有在加入了shadowbias的时候才会出现,如上图,会看到影子脱离了物体(像飞起来的小飞侠一样),被称为peter-panning。
2、原因
上面现象中提到了shadowbias,容易知道,其实就是shadowbias加的太多了。
shadow的计算是根据计算中使用的深度与shadowmap的深度对比得到的,如果shadowbias加的太多,就会导致物体计算影子时的深度,与他的实际深度差别太大。
所以影子就和物体产生了分离。
3、对策
解决的方法,当然就是不要使用太大的shadowbias。
六、ShadowBias
前面两节一直在说要加入shadowbias,但是可以看到,加小了没用,会有shadowacne;加多了又会导致peterpanning。
所以要怎么加,是有一定技巧的,最终的目标是要找到一个刚好能够消除shadowacne的bias值。
现在常用的shadowbias的计算方法,是基于物体斜度的,称为slopescalebaseddepthbias。
简单来说就是
公式的具象化可以参考下图:
图10、slopescaledepthbiasdiagram
这样做的原理是,当斜度大的时候,shadowmap上的一个点,所对应的实际物体的一小块面,其深度变化就会更大。
举例来说,一个x方向的斜坡,同样是在x方向上差0.01,如果坡角是45度,那么深度差就是0.01,如果坡角是60度,那么深度差就是0.017.
如果采样点都是在x=0.005处,那么对坡角60的情况,就需要bias至少为0.0085,才可以保证不会产生shadowacne,而45度的情况,bias只要0.005就可以了
图11、slopescaledepthbias示例
对于这个公式,需要做一些说明:
1)坡度如何确定?当然是用顶点的normal,但是需要注意的是,我们是在灯光坐标系下观察物体的,所以normal需要转换到lightspace中。
2)里面的两个参数factorSlope和 constantBias如何确定?NVidia告诉我们:这是一门艺术....所以慢慢调吧。
shadowbias的代码,可以参考范例中"02ShadowMapWithBias"部分。
七、问题三:HardShadow&&SoftShadow
1、现象
现在我们生成的阴影,其边缘是没有过渡的,这样也容易产生锯齿。
(本节的图来自于nvidia的gpugems)
图12、hardshadow和边缘的锯齿
而现实世界中的影子(物理原理我忘记了,希望以后会填坑),边缘会更淡,有一定的渐变效果。
我们现在产生的这种无渐变的影子,就被称为hardshadow,有边缘效应的则称为softshadow。
2、原因
原因是显然的:我们的判断是0-1的,只是检查是否在阴影之中,只有是和不是两种情况,当然会产生hardshadow。
3、对策
常用的解决方案称为shadowfiltering,在下一段,我们会展开来说。
八、ShadowFilter&&PCF(PercentageCloserFiltering)
由于对PCF以外的shadowfilter了解甚少,因此我对于shadowfilter的理解还不够清楚。
其他可查的filter手段包括"Exponentialshadowmapfiltering",“VarianceShadowMaps”(这个很常用,有机会要补完),都是用来解决shadowmap的硬边缘和锯齿问题。
对于PCF,其核心思路就是,如果是影子内部,则他周围的一圈点肯定也在阴影之中,如果是影子边缘,则他周围就会有些点不在阴影里,且越靠边,这些不在阴影中的邻居越多。
所以检测一个点是否是在影子边缘,只要观察他的邻居就可以了。
在实际代码中,输入一个点A,我们在 shadowdepthmap中取出他和他周围点的深度,然后和A的深度做比较(相当于用A的深度来代表他周围那一圈点的深度),然后根据有多少个点在阴影中,确定点A处影子的强度。
原理是十分简单的,根据取点的方法和范围,又分为 2×2PCF,4×4PCF等等;根据每个点对影子强度加成的系数不同,又分为平均采样,泊松采样等等。
代码可以参见范例中的"03ShadowMapWithPCF"
九、问题四:近处锯齿PerspectiveAliasing
1、现象
图13、锯齿
如左图,在场景比较大的情况下容易出现这种情况,在viewcamera的近处,产生了锯齿状的影子。
2、原因
根本原因仍然是shadowmap的分辨率不够(可以看出,这一点是shadowmap方法的软肋)。
在camera的近处,场景中的物体的分辨率比较高,一小段面片,会对应着大量的pixel,而此时的shadowmap精度没有发生变化,所以就会有大量的pixel对应着shadowmap中的同一点,因而产生锯齿情况(当然使用PCF会略有好转)。
MSDN上的这张图很能说明问题:
图14、单张shadowmap时的效果情况图
图中的方块中,颜色越深,表示shadowmap的利用情况越差。
可以看到,在camera近处,shadowmap的利用率低,最终产生了锯齿。
另外一方面,对于较大的场景,如果使用一张shadowmap来记录整个场景的depth,就容易不够用,也容易导致锯齿。
3、对策
解决的方案参见下一段:CSM
十、CSM(CascadedShadowMap)
针对上面的问题,容易想到,既然一张不够,那么我们就多来几张。
这就是CSM的出发点。
那么场景就变成了这样:
图15、多张shadowmap时的效果情况图
同上面的图一样,图中的方块颜色越深,表示shadowmap的利用情况越差。
可以看到在使用多张shadowmap的情况下,效果明显提高了。
CSM本身也是一个很大的话题,其中许多关键点也有多种实现方式,具体可以参考这里。
我这里由于懒的原因,只实现了最基本的CSM。
下面来说明具体流程:
1、首先要将整个场景分割成多块
这里也主要有两种方法:
一种是FitToScene,他的特点是所有区块的近平面都是相同的,变化的是远平面。
见下图左。
另一种是FitToCascade,他是普通的按照viewcamera的深度范围,将场景划分为若干块。
见下图右。
图15、FitToScene&&FitToCascade
显然FitToCascade对map的利用率更高,但是FitToScene也有好处,主要是用来解决闪烁问题(这里我并没有理解透彻,期望以后可以补全)。
2、对每个区块,进行正常的shadowmap截取
这一步和普通的shadowmap并没有什么不同,只是要针对每个区块进行一次,从而会得到多个shadowdepthmap。
每次截取,都需要记录截取时lightcamera的MVP矩阵。
3、在shader中,判断应该使用哪个shadowmap
由于每个区块划分的依据是深度,因此简单的做法是将顶点的深度与划分区块的深度进行比较,就可以知道归属了。
另一种复杂的方法被称为Map-basedcascadeselection。
由于我本人理解有限,这里也不展开讲了。
4、选出shadowmap之后,按照普通的shadowmap方法进行深度比较和filtering
这一步与普通的shadowmap也是相同的。
同样可以使用shadowbias和pcf。
5、在普通的CSM流程之后,还可以进行CSM区块之间的blending等操作来改善效果
这一步可以说是对基本CSM的改进了,我这里的代码没有实现。
总体来说,就是针对两张shadowmap交接处的不匹配现象,通过blending来进行平滑过渡。
以上就是CSM的基本流程,具体的代码可以参考范例的"4CSM"部分。
十一、范例
最后附上范例,地址:http://download.csdn.net/detail/ronintao/9569628。
该范例使用unity5.3.4编写,由于水平所限,仅仅实现了最基本的功能。
ronintao
关注
关注
42
点赞
踩
25
评论
88
收藏
打赏
扫一扫,分享内容
点击复制链接
专栏目录
图形学基础|阴影技术ShadowMap
【黑键】
04-10
2525
实时阴影技术总结
实时渲染中的软阴影技术
ShadowMap原理和改进
以上几个参考文章写的非常好.
我只是做了最第一篇的简单摘录.作为我入门的学习.
阴影的实现
在光线追踪算法中,实现阴影(shadowray)更加符合直觉.
在光栅化算法中,基于ShadowMap的实现更加常见.
阴影的"软硬"
理想中的点光源会造成只有本影区的硬阴影(hardshadows)
但是现实中的光源毕...
shadowmap范例
07-07
shadowmap范例,对应解释文档参考http://blog.csdn.net/ronintao/article/details/51649664
评论 25
您还未登录,请先
登录
后发表或查看评论
ShadowMap_PCF
06-07
ShadowMap_PCF
Unity中ShadowMap动态阴影的实现
MonoBehaviour的博客
03-16
456
具体的实现如下:
1,生成ShadowMap
2,根据ShadowmMap实现阴影的绘制
ShadowMap的生成:
v2fvert(appdatav)
{
v2fo;
o.vertex=mul(unity_ObjectToWorld,v.vertex);
float3normal=normalize(mul(v.normal,unity_WorldToObject));
终于搞定了SHADOWMAP,
coder
03-13
1789
5*5pcf
shadowmap的原理与实现
the_shy33的博客
09-01
821
最近在预研一个pbr模型的时候接触到了阴影渲染的部分,因为之前一直用的是Unity内置的宏去生成阴影,并且需要用到平行光。
对于阴影的制作有各种各样的办法,而shadowmap就是最典型生成阴影的一种方法,在Unity内部也是用shadowmap的变种**CSM(CascadedShadowmap)和SSSM(ScreenSpaceShadowmap)**的两种阴影。
在Unity内部如果目标平台不支持SSSM的话,它会转为CSM的阴影。
下面就简单说一下shadowmap的原理和实现过程。
shadow
shadowMap简单回顾
qq_36091277的博客
05-16
104
编程指南:shadowMap示例连接
编程指南部分代码
获取gl变量
varcanvas=document.getElementById('webgl');
vargl=getWebGLContext(canvas);
获取Plane、Triangle顶点缓冲区,颜色缓冲区,索引缓冲区(数组转的)
vartriangle=initVertexBuffersForTriangle(gl);//三角形
varplane=initVertexBuffersForPlane(gl);
three.js聚光灯SpotLight使用,调整聚光灯颜色、位置、角度、强度、距离、衰减指数、方向、可见性、是否产生阴影属性(vue中使用three.js09)
点燃火柴的博客
09-11
1798
聚光灯SpotLight使用一、聚光灯介绍二、如何使用聚光灯1.创建聚光灯2.聚光灯的属性2.1颜色-color2.2是否可见-visible2.3角度-angle2.4强度-intensity2.5距离-distance2.6光照衰减指数-decay2.7照射面光影衰减百分比-penumbra2.8目标-target2.9是否产生阴影-castShadow2.10位置-position三、demo效果四、demo代码
一、聚光灯介绍
聚光灯是一个沿着特定方向方散发的光源,照射范围在三维空间中构成一个圆锥体
点光源阴影
m0_57980287的博客
06-23
143
文章目录点光源阴影(OmnidirectionalShadowMaps)摊牌原理实现显示立方体深度贴图副作用锯齿
点光源阴影(OmnidirectionalShadowMaps)
摊牌
由点光源产生的阴影,过去的名字是万向阴影贴图(OmnidirectionalShadowMaps)
点光源可以照射的方向是空间中的各个方向,因此他产生的阴影也是在空间中的各个方向
原理
先回顾一下阴影贴图中提到的绘制阴影的原理:首先在光源的视角下渲染场景,得到一张深度贴图,然后在摄像机的视角下再次渲染场景,
版本升级后ShadowMap内存骤增
UWA—简单优化,优化简单!
09-03
242
这是第174篇UWA技术知识分享的推送。
今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。
UWA问答社区:answer.uwa4d.com
UWAQQ群2:793972859(原群已满员)
本期目录:
版本升级后ShadowMap内存骤增
UGUI的Outline的替代方案
xLua对Obj的引用无法释放
坐标系转换
内存
Q:自从升级...
shadowmap中的深入测试
coder
11-06
186
我发现shadowmap,如果正交投影,不论多少,都是同样的,只要在远切面内
如下图
如果是透视投影,
即使在远切面1000.0f内,投射投影,也不是说在1000以内就行,得是在100以内还行,阴影图会出现个小的物体,再小就看不见了,
下图是900的位置
下图是300的位置
下图是100的位置
下图是视点为10的位置
如果想出来效果,就要增加阴影图尺...
用shader创建shadowmap时出现了问题
03-23
如果有一个非常大的场景,场景中的街道上有一个人,这个人站在太阳下。
如果以太阳的视角创建shadowmap,那么人在这张shadowmap最多也就占1像素。
要是把这张shadowmap贴回场景,估计太阳下那个人的阴影可能会极度的不正常,就算提高shadowmap的分辨率也不是一个好的解决方案。
有没有解决这类问题的方法,谢谢!
shadowmapdepthbias
yaorongzhen123的专栏
09-11
364
研究过shadowmapping技术的人应该都知道shadowmap会有一种叫self-shadowing(有的文章也叫shadowacne)的问题,如下图所示:
因为shadowmap的精度有限,当要渲染的fragment在lightspace中距Light很远的时候,就会有多个附近的fragement会sampershadowmap中同一个texel,但是即使这些frag...
OpenGLES学习教程(十六)ShadowMap的理解
HelloCaptain
07-20
747
目前游戏上的阴影一般用ShadowMap实现。
我一直在学习LearnOpenGL上的文章,ShadowMap这一篇,说实话我两年前就开始看了,一直没明白,或者说没有认真花时间去看。
最近在给lives2d堆功能,终于也到了阴影的实现。
LearnOpenGL上ShadowMap教程地址:
http://learnopengl-cn.readthedocs.io/zh/latest/05%2...
全局光照算法:reflectiveshadowmaps
最新发布
JMXIN422的博客
02-26
132
1.技术理解
RSM的全称是reflectiveshadowmaps,受到InstantRadiosity这个离线技术的启发,其思想和ShadowMap的思想近似。
在正式介绍和了解这个技术之前,我需要确定RSM用处何在?我想,《RTR4》中对它的分类很正确——DynamicDiffuseGlobalIllumination,这是一个处理动态全局漫反射的技术:
GI(全局光照):用于二次及以上bounce造成的间接光。
Dynamic(动态):可以实时更新,可作用于动态物体。
Diffuse(
使用shadowmap实现软阴影效果
痞子龙3D编程
07-23
3502
在实时阴影渲染中shadowmap是一种颇具潜力的算法,相比shadowvolume算法具有实现简单、适应范围广的优点,而且shadowmap是基于图像的算法,在实现软阴影上具有先天优势,下面我们就来看看如何用shadowmap实现软阴影效果。
通常的shadowmap算法产生的
LearnOpenGL笔记6.4PointShadows(点光源阴影贴图)
u013617851的博客
01-05
227
我们学习了使用阴影贴图创建动态阴影。
但它主要适用于定向(或聚光)灯,因为阴影仅在光源方向上生成。
因此,它也被称为directionalshadowmapping定向阴影贴图,因为深度(或阴影)贴图仅从光所看到的方向生成。
本章将重点关注的是在所有周围方向上动态阴影的生成。
我们使用的技术非常适合点光源,因为真正的点光源会向各个方向投射阴影。
这种技术被称为点(光)阴影或更早以前称为omnidirectionalshadowmaps全向阴影贴图。
directionalshadowmappi
three中shadow的常用参数
qq_38694034的博客
04-04
1007
当我们投射阴影的时候如果想调节阴影的清晰度:可以将shadow.mapSize设置为更大的值: light.shadow.map.width=light.shadow.map.height=1024 // 还可以选的值128,256,512,2048等当我们投射阴影的时候如果想调节阴影的大小:可以设置shadow.camera的参数:vard=50;light.s...
ShadowMap基本原理
l364244206的专栏
07-23
528
unity的阴影实现方式是采用Shdowmap技术,但是一直不知道其中的原理。
它的原理并不复杂,假设有一个摄像机在灯光的位置,从灯光的位置往物体看,这时候会有一张光源空间的深度信息图,这就是ShadowMap。
凡是物体的深度值大于ShadowMap上的深度值的都是被遮挡的部分,表示处于阴影中。
所需知识点:
1.模型空间到屏幕空间的变换过程http://www.idivecat.co...
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
©️2022CSDN
皮肤主题:大白
设计师:CSDN官方博客
返回首页
ronintao
CSDN认证博客专家
CSDN认证企业博客
码龄14年
暂无认证
27
原创
21万+
周排名
174万+
总排名
23万+
访问
等级
1840
积分
223
粉丝
107
获赞
60
评论
236
收藏
私信
关注
热门文章
Unity中的旋转
52607
ShadowMap原理和改进
42142
Unity中的坐标系
26905
【OpenGL】02-OpenGL中的坐标系
16337
【cocos2D-x学习】9.音乐炫台——音效与特效
9178
分类专栏
cocos2D-x
16篇
C/C++
4篇
Android
OpenGL
3篇
Unity
4篇
C#
1篇
渲染
最新评论
Unity中的坐标系
夏日蛙鸣:
好文章,收益匪浅啊,不愧是大佬~
ShadowMap原理和改进
大A气氛组:
感谢大佬,受益匪浅
ShadowMap原理和改进
william607:
感谢作者,有一些图缺了,可以麻烦再补一下吗
ShadowMap原理和改进
weixin_46269678:
基于斜度的偏移主要是解决极端角度下,比如光线接近平行表面时产生的shadowacne
ShadowMap原理和改进
Qiu.D:
对,我也是,锯齿更加严重了
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
C#中运算符重载的几点注意
凹凸材质:从BumpMap到ReliefMap
Unity中的旋转
2017年1篇
2016年4篇
2014年2篇
2013年23篇
目录
目录
分类专栏
cocos2D-x
16篇
C/C++
4篇
Android
OpenGL
3篇
Unity
4篇
C#
1篇
渲染
目录
打赏作者
ronintao
你的鼓励将是我创作的最大动力
¥2
¥4
¥6
¥10
¥20
输入1-500的整数
余额支付
(余额:--)
扫码支付
扫码支付:¥2
获取中
扫码支付
您的余额不足,请更换扫码支付或充值
打赏作者
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
0
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。
余额充值
延伸文章資訊
- 1阴影映射 - LearnOpenGL-CN
阴影映射(Shadow Mapping)背后的思路非常简单:我们以光的位置为视角进行渲染,我们 ... uniform sampler2D shadowMap; uniform vec3 lig...
- 2Tutorial 16 : Shadow mapping
The basic shadowmap algorithm consists in two passes. First, the scene is rendered from the point...
- 3图形学基础- 阴影- ShadowMap及其延伸 - 知乎专栏
笔者最近在回顾一些图形学基础知识,遂整理在此,此文涉及图形学中的阴影本文着眼于最流行的阴影贴图(Shadow Mapping) 技术,对其难点进行分析, ...
- 4Shadow mapping - Wikipedia
Shadow mapping or shadowing projection is a process by which shadows are added to 3D computer gra...
- 5App - Shadowmap
Shadowmap visualizes solar shadows on an interactive 3D web-based map. For any moment in time, an...