http://www.cnblogs.com/cxrs/archive/2009/10/17/1585038.html

1、什么是Shadow Maping?
      Shadow Mapping是由Lance Williams于1978年在一篇名为"Casting curved shadows on curved surfaces"的文章中提出的,这篇文章是ShadowMap技术之根源。其实原理很简单,如果光源和目标点之间的连线没有任何物体阻挡的话,则目标点没有在阴影中;如果有物体遮挡,则目标点处在阴影中。而ShadowMap,就是一张记录了每个象素处用于比较遮挡关系信息的Texture. 
      产生这个ShadowTexture的方法很简单,以SpotLight为例,把3D Camera放到光源的位置,把DepthTest打开,渲染场景,在PixShader中把每个象素的深度信息或者光源和此象素的距离信息写到RenderTarget上,由于DepthTest是打开的,保证了最终写到RenderTarget上的均是物体上未处在阴影中的点的深度值,实质完全可以等效为最终的DepthBuffer。
     得到这个ShowMap之后,如何最终生成阴影呢?在PixShader对每个pixel进行处理时,算出当前象素与灯当的距离Dc,与存在ShdowMap中的引像素的值Dz进行比较,如果Dc > Dz,则在阴影中,反之则被灯光照亮。
2、Shadowmap之HLSL的实现
    在Direct SDk中有ShadowMap的Sample,下面的Shader和Sample里面空全一样,只是加了一些注释便于理解。
    (1)生成ShadowMap的VS和PS

//-----------------------------------------------------------------------------
// Vertex Shader: VertShadow
void VertShadow( float4 Pos : POSITION,
                 float3 Normal : NORMAL,
                 out float4 oPos : POSITION,
                 out float2 Depth : TEXCOORD0 )
{
    //从模型坐标系变换到观察坐标系
    oPos = mul( Pos, g_mWorldView );
   //进行投影变换
   oPos = mul( oPos, g_mProj );
   //把投影坐标系的ZW值赋给Depth,作为PixelShader中的输出,这里的Z还是齐次坐标,这里不直接输出Z/W,我的理解是让Z和W都在Rasterizer中进行线性插
  //值,这样可以增加最终生成的ShadowMap的精度。
    Depth.xy = oPos.zw;
}
//-----------------------------------------------------------------------------
// Pixel Shader: PixShadow
void PixShadow( float2 Depth : TEXCOORD0,
                out float4 Color : COLOR )
{
    // 把 z / w的值作为Color值输出,写到RenderTarget上,此时的RT formate是D3DFMT_R32F
   //把Z/W目的是把齐次坐标Z变换到三维空间的非齐次坐标,范围则是[-1,1]
    Color = Depth.x / Depth.y;
}

(2)用ShadowMap生成Shadow

//-----------------------------------------------------------------------------
// Vertex Shader: VertScene
// Desc: Process vertex for scene
//-----------------------------------------------------------------------------
void VertScene( float4 iPos : POSITION,
                float3 iNormal : NORMAL,
                float2 iTex : TEXCOORD0,
                out float4 oPos : POSITION,
                out float2 Tex : TEXCOORD0,
                out float4 vPos : TEXCOORD1,
                out float3 vNormal : TEXCOORD2,
                out float4 vPosLight : TEXCOORD3 )
{
    vPos = mul( iPos, g_mWorldView );
    oPos = mul( vPos, g_mProj );
    vNormal = mul( iNormal, (float3x3)g_mWorldView );
    Tex = iTex;
    //把当前顶点位置变换到以光源为Camera的投影空间,
    vPosLight = mul( vPos, g_mViewToLightProj );
}

//-----------------------------------------------------------------------------
// Pixel Shader: PixScene
// Desc: Process pixel (do per-pixel lighting) for enabled scene
//-----------------------------------------------------------------------------
float4 PixScene( float2 Tex : TEXCOORD0,
                 float4 vPos : TEXCOORD1,
                 float3 vNormal : TEXCOORD2,
                 float4 vPosLight : TEXCOORD3 ) : COLOR
{
    float4 Diffuse;

// 计算光源到当前象素方向向量并单位化
    float3 vLight = normalize( float3( vPos - g_vLightPos ) );

//  dot( vLight, g_vLightDir )为光源到当前象素方向向量和光的方向向量之间的夹角余旋值,由于是spotlight,因此必须要在spotlight可照射的范围内。因为角 
    //度越小余旋值越大,因此这里是大于
    if( dot( vLight, g_vLightDir ) > g_fCosTheta ) 
    {
        // Pixel is in lit area. Find out if it's
        // in shadow using 2x2 percentage closest filtering

//从投影空间坐标转化为纹理空间坐标,也就是找到投影空间中的点和纹理空间中的点的对应关系
       //除以w,xy坐标便处在(-1,1)的范围内,乘0.5加0.5,则变换到了(0,1)的范围,因texture space的u,v坐标是(0,1)的
        float2 ShadowTexC = 0.5 * vPosLight.xy / vPosLight.w + float2( 0.5, 0.5 );
       //在投影坐标系中,Y轴是向上的,而在纹理空间中Y轴向下,因此要作以下处理
        ShadowTexC.y = 1.0f - ShadowTexC.y;

// 在texel space中对应的象素坐标
        float2 texelpos = SMAP_SIZE * ShadowTexC;
        
        // 取得小数部分         
        float2 lerps = frac( texelpos );

//这里使用的是2x2 percentage closest filtering,因此是采的邻近的四个点,判断它们是否在阴影中,
        float sourcevals[4];
        sourcevals[0] = (tex2D( g_samShadow, ShadowTexC ) + SHADOW_EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;  
        sourcevals[1] = (tex2D( g_samShadow, ShadowTexC + float2(1.0/SMAP_SIZE, 0) ) + SHADOW_EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;  
        sourcevals[2] = (tex2D( g_samShadow, ShadowTexC + float2(0, 1.0/SMAP_SIZE) ) + SHADOW_EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;  
        sourcevals[3] = (tex2D( g_samShadow, ShadowTexC + float2(1.0/SMAP_SIZE, 1.0/SMAP_SIZE) ) + SHADOW_EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;  
        
        // 用lerps 
        float LightAmount = lerp( lerp( sourcevals[0], sourcevals[1], lerps.x ),
                                  lerp( sourcevals[2], sourcevals[3], lerps.x ),
                                  lerps.y );
        // 计算光照,如果完全在阴影中,则LightAmount为0,这里只计算了Diffuse color,没有高光
        Diffuse = ( saturate( dot( -vLight, normalize( vNormal ) ) ) * LightAmount * ( 1 - g_vLightAmbient ) + g_vLightAmbient )
                  * g_vMaterial;
    } else
    {
        Diffuse = g_vLightAmbient * g_vMaterial;
    }

return tex2D( g_samScene, Tex ) * Diffuse;
}

3、ShdowMap的优缺点
    优点:简单,不需要知道场景中Object的Geometry,不需要Stencil Buffer,每个灯光只需多渲染一个Pass。
    缺点:当ShadowMap分辨率不够高时,或灯光与物体隔得很近时,在边缘处会产生Aliasing,锯齿,因此,很多改进shadowMap的算法都围绕着如何消除锯齿作文章。
4、ShadowMap的改进
    关于ShadowMap的改进,又出了很多的paper和技术,比如:Percentage Shadow map,  使用bloom filter对ShadowMap进行模糊处理.以及siggraph 2002 中Marc Stamminger和 George Drettakis提出的Perspective Shadow map.以及Adaptive Shadow Map等等。

Shadow mapping的更多相关文章

  1. Tutorial - Deferred Rendering Shadow Mapping 转

    http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx Tutorial - Deferred ...

  2. OpenGL阴影,Shadow Mapping(附源程序)

    实验平台:Win7,VS2010 先上结果截图(文章最后下载程序,解压后直接运行BIN文件夹下的EXE程序): 本文描述图形学的两个最常用的阴影技术之一,Shadow Mapping方法(另一种是Sh ...

  3. opengl 教程(24) shadow mapping (2)

    原帖地址:http://ogldev.atspace.co.uk/www/tutorial24/tutorial24.html 本篇教程中,我们通过shadowmap来实现阴影渲染. 我们知道shad ...

  4. OpenGL 阴影之Shadow Mapping和Shadow Volumes

    先说下开发环境.VS2013,C++空项目,引用glut,glew.glut包含基本窗口操作,免去我们自己新建win32窗口一些操作.glew使我们能使用最新opengl的API,因winodw本身只 ...

  5. (转)Shadow Mapping

    原文:丢失,十分抱歉,这篇是在笔记上发现的.SmaEngine 阴影和级联部分是模仿UE的结构设计   This tutorial will cover how to implement shadow ...

  6. shadow mapping实现动态shadow实现记录 【转】

    http://blog.csdn.net/iaccepted/article/details/45826539 前段时间一直在弄一个室内场景,首先完成了render,效果还可以.然后给其加上shado ...

  7. OpenGL核心技术之Shadow Mapping改进版

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

  8. OpenGL核心技术之Shadow Mapping

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

  9. Shadow Mapping 的原理与实践(二)

    3) 定义并生成Shadow Map纹理 texture2D Lamp0ShadowMapColor : RENDERCOLORTARGET < float2 ViewPortRatio = { ...

随机推荐

  1. PHP:汉字转拼音类(全拼与首字母)

    [php] <?php class GetPingYing { private $pylist = array( 'a'=>-20319,'ai'=>-20317,'an'=> ...

  2. 引擎设计跟踪(九.14.2h) 开发计划

    以后的开发计划: 完善game runtime code, 跑简单的demo目前只有编辑器的运行流程, 没有游戏/demo流程, 图形的测试主要在编辑器上测试, 现在需要测试android系统的图形, ...

  3. Log4Net 全方位跟踪程序运行

    原文:http://kb.cnblogs.com/page/100968/ 1.Log4Net 简单使用 使用Log4net必须引入log4net.dll 文件,因为log4net 是开源的,所以可以 ...

  4. MyEclipse — Maven+Spring+Struts+Hibernate 整合 [学习笔记-3]

    引入Struts2 在pom.xml中加入jar包 <!-- struts2 --> <dependency> <groupId>org.apache.struts ...

  5. lintcode:两个数组的交

    题目 返回两个数组的交 样例 nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2]. 解题 排序后,两指针找相等元素,注意要去除相同的元素 public class ...

  6. Jlink更新新固件USB连接不上的问题

    采购新买了一个jlink,在调试过程中发现不能使用.拿到手后对jink上电以后,发现灯不亮,到网上查了一下估计是固件损坏的原因,经过一番摸索从新更新了固件,然后可以正常使用了,下面说一下步骤: 新版的 ...

  7. MakeObjectInstance的简单理解

    昨天把MakeObjectInstance的代码详细研究了一下,当然还有众多前辈高手们的帮助,终于大致搞明白了是怎么回事.但是给我顿悟的,不是高手们的帖子,而是来自我自己的一个疑惑,TObjectIn ...

  8. JavaWeb笔记——Jsp的指令、内置对象和动作标签

    JSP三大指令   一个jsp页面中,可以有0~N个指令的定义! 1. page --> 最复杂:<%@page language="java" info=" ...

  9. Spring笔记——Spring框架简介和初次框架配置

    Spring简介 Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Deve ...

  10. iOS 安装使用cocoapods

    一.什么是CocoaPods 1.为什么需要CocoaPods 在进行iOS开发的时候,总免不了使用第三方的开源库,比如SBJson.AFNetworking.Reachability等等.使用这些库 ...