基于Shadow map的实时阴影效果实现

原创 2007年10月12日 17:05:00

有光则有影,即时渲染的阴影可以使场景看上去更加真实。

下图显示了实时阴影系统在一个3D项目中的应用:

 

算法描述: 

ShadowMap是一种基于阴影图的阴影生成方法,阴影图是一张2D贴图。阴影图中的每个像素都记录了从光源到遮挡物(遮挡物就是阴影生成物体)的每个“可见”像素的距离。这里的“可见”像素是指,以光源为观察点,光的方向为观察方向,设置观察矩阵并渲染所有遮挡物,最终出现在渲染表面上的像素。使用ShadowMap渲染阴影主要分两个过程:生成阴影图和使用阴影图渲染。下面的代码取自生成阴影图的PS代码

float distance=distance(lightpos,input.PWorld);
distance*=distancescale;            
distance-=depthbais;               
return distance;                 

 
     distance是HLSL的内置函数用于计算两点距离,这里获得了光源到当前像素的距离。
     disancescaler用于对距离值进行缩放,这个值可以通过应用程序设置,使用它就可以对阴影进行即时可见的调整。
     depthbais同样用于阴影图调整。
     返回距离值,实际上此时的渲染目标已经被设置成阴影图,阴影图的设置方法和上节的立方体环境贴图类似,不过这里只需要将遮挡物渲染一次。
下图显示了一个场景和其使用到的阴影图。
 
需要在阴影图中保存从光源到“可见”点的距离是因为:利用这个距离就可以直接判
断一个像素是否在阴影中。如果一个世界空间的“点”到光源的距离大于阴影图中对
应像素的值,那么这个点肯定已经被另一个离光源更近的点遮挡住了,所以它肯定在
阴影中。基于这个原理就可以很容易的编写渲染阴影的代码了。
下面的代码取自渲染阴影的PS代码
 
float CurrentPixelDistance=distance(lightpos,input.PWorld)*distancescale+depthbais;①
Shadow = (CurrentPixelDistance > tex2Dproj(shadowmap,input.ShadowMapCord))②
Shadow*=ShadowDensity;③
Return Shadow;
  
     这里获得当前像素到光源的距离。
     首先对阴影图采样,再用当前像素的值和采样所得的值进行比较。大于则当前像素在阴影中,Shadow=1;否则Shadow=0;
     这里ShadowDensity同样由应用程序调整,用于设置阴影浓度。
该PS返回了阴影值,该数值越大表示阴影越浓。但是直接将其输出是不行的,因为这里只有阴影,而场景必须将场景本身的颜色和阴影“混合”输出。这里的解决方案是AlphaBlend,简单的说就是首先按照指定的方式渲染场景,这里可以使用前面说的任何渲染方式;接着渲染阴影,在渲染阴影的时候启用AlphaBlend,这样前后两次渲染的结果就可以通过AlphaBlend“混合”在一起了。
另外,由于阴影图是一种基于贴图采样的技术。渲染效果和阴影图的分辨率有着极大的关系,当提高分辨率无法满足渲染效果的需要时,有必要采用一些图象处理的方法。例如,对阴影图进行多次采样使得阴影的边缘更加平滑。下面的Shader使用2x2PCF(Percentage Closer Filter)方法对阴影图进行过滤。
 
float ShadowDepth=tex2Dproj(shadowmap,input.ShadowMapCord);①
float ShadowDepth1=tex2Dproj(shadowmap,input.ShadowMapCord+float4(-SampleOffset,0,0,0));
float ShadowDepth2=tex2Dproj(shadowmap,input.ShadowMapCord+float4(0,-SampleOffset,0,0));
float ShadowDepth3=tex2Dproj(shadowmap,input.ShadowMapCord+float4(-SampleOffset,0,0,0));
float Shadow = (CurrentPixelDistance > ShadowDepth);②
float Shadow1=CurrentPixelDistance> ShadowDepth1;
float Shadow2=CurrentPixelDistance> ShadowDepth2;
float Shadow3=CurrentPixelDistance> ShadowDepth3;
……………………………………….
finalshadow=(Shadow+Shadow1+Shadow2+Shadow3)/4;③
 
 
     这四行代码对阴影图执行了4次采样,每次采样以Sample Offset为偏移量,获得阴影图中对应像素周围4个像素所保存的光源距离。
     这四行代码用每一个距离值和当前像素距离值比较得到4个阴影值。
     平均四个阴影值,得到最终的阴影值。
很显然,当一个像素处于阴影边缘的时候,4次采样中可能会有部分结果为0,部分为1。平均以后就可以得到一个
0,1之间的值,这个值将会表现在阴影的浓度上,这样就可以形成平滑的阴影边缘。但是,提升效果的代价也是明
显的,使用多次采样会明显的降低速度。由于PS2.0最多可用64条指令,编写3x3PCF刚好够用,效果更好,但也
更慢。
下图对各种采样方式做了一个比较。从左到右逐渐提高了PCF(百分比渐进过滤)的采样次数:

 

结论,本文给出了一个ShadowMap的实现方式。需要注意的是,文中所提到的PCF实现方式并不是最佳的,因为现在的很多图形硬件已经从硬件上支持多次采样的PCF技术,这种技术能够获得更好的执行效率并且能够免除ps指令条数的限制。

 

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)

UnityEffects(2)之(2)ProjectorShadow(手游上的实时阴影方案) 上一篇说到了在unity5.x中实现shadowMap的方法(UnityEffects(1)之shado...
  • aceyan0718
  • aceyan0718
  • 2016年08月22日 19:36
  • 6751

[OpenGL] shadow mapping(实时阴影映射)

source:原文地址,提供了源代码下载        1978年,Lance Williams在其发表的论文《Casting curved shadows on curved surfac...
  • ZJU_fish1996
  • ZJU_fish1996
  • 2016年07月17日 18:33
  • 5047

css3 shadow实现的各种漂亮阴影效果

css3 shadow按钮阴影效果Demo代码,很多漂亮的纯CSS3实现图片的各种阴影效果代码,而且按钮的背景色处理的也挺个性,看上去很舒服,阴影的各类也挺多,下阴影、弧线阴影、立体阴影等,相信有一款...
  • life66881
  • life66881
  • 2015年06月08日 14:48
  • 1840

基于Shadow Map的阴影实现

0、简介 Shadow Mapping是一种基于图像空间的阴影实现方法,其优点是实现简单,适应于大型动态场景;缺点是由于shadow map的分辨率有限,使得阴影边缘容易出现锯齿(Aliasing);...
  • u011988946
  • u011988946
  • 2013年09月16日 21:39
  • 3897

基于CPU实现的Shadow Map(阴影图)技术--(Cg语言实现)

Shadow Map是一种基于深度图(depth map)的阴影生成方法,由Lance Williams于1978年在文章“Casting curved shadows on curved surfa...
  • UtilXK
  • UtilXK
  • 2015年12月28日 14:01
  • 489

Shader实现的阴影效果(Shadow)

  • 2011年01月23日 14:48
  • 3.25MB
  • 下载

阴影锥(shadow volume)原理与展望---真实的游戏效果的实现

shadow volume 这个术语几乎是随着 DOOM3 的发布而成为FPS 玩家和图形学爱好者谈论的对象的。虽然这个游戏还没有上市,但是凭借 John Carmack 的传奇经历以及 DOOM3发...
  • zhw_giser
  • zhw_giser
  • 2014年01月13日 13:28
  • 1168

css3 shadow实现的各种漂亮阴影效果

css3 shadow按钮阴影效果Demo代码,很多漂亮的纯CSS3实现图片的各种阴影效果代码,而且按钮的背景色处理的也挺个性,看上去很舒服,阴影的各类也挺多,下阴影、弧线阴影、立体阴影等,相信有一款...
  • life66881
  • life66881
  • 2015年06月08日 14:48
  • 1840

CSS实现跨浏览器的box-shadow盒阴影效果

一、前言 我之前曾写过一篇关于实现跨浏览器实现box-shadow效果的文章——“CSS实现跨浏览器兼容性的盒阴影效果”,本文虽然题目类似,但是核心部分是有差异的。前面的文章虽然实现IE下的盒阴...
  • Solo_two
  • Solo_two
  • 2016年05月25日 17:48
  • 278

OpenGLES demo - 15. 阴影贴图 Shadow Map 之点光源

  • 2014年08月07日 20:52
  • 170KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于Shadow map的实时阴影效果实现
举报原因:
原因补充:

(最多只允许输入30个字)