引擎技术研究之实时阴影技术

阴影和纹理映射一样,通常是在渲染器中附加算法来实现,并被粘贴到场景中。在场景中每个光源产生的贴图称为阴影贴图(shadermap)。在渲染的过程中对该贴图进行存取,以找出某个像素是否位于阴影中。

阴影贴图的生成原理如下图所示:

引擎技术研究之实时阴影技术

把光源模拟成有特定方向的发光点,其发出的光线与长方体相交与A点,若射穿长方体则与地面相交于B点,我们记录光线首次与物体相交的点的信息,并保存光源到该点的距离,称为该点在灯光空间的深度Depth。如此被长方体遮盖住的部分地面里的点则没有相交信息,则保存为同一光源线上首次与光源相交的点的信息为该点的Depth,如图,A点和B点保存的都是A点到光源的距离。如此场景中每个点均有Depth。我们可比较点与光源的实际距离P和点的Depth:若P>Depth,则P点在某一物体的阴影中,由此可计算场景中物体的每个点是否在阴影中来生成阴影贴图,最后在渲染时将阴影贴图贴在场景中。

具体实现如下:

1:定义一监听器m_pShadowRenderer和相应的渲染目标m_pShadowTarget(具体步骤可参考“引擎技术之渲染到目标“)

Execute函数的实现:

先获取光源的位置lightPos和方向lightPos

计算lightlookat=lightPos+lightDir;

定义光源的顶方向up(0,1,0);执行:

D3DXMatrixLookAtLH( &lightview, &lightPos, &lightlookat,&up);

获取视图矩阵。接着根据 shader文件获取相应的baseshader变量。

设置shader里的视图矩阵变量: baseShader->SetMatrix("LightView",&lightview);

baseShader->CommitChanges();

渲染场景中的物体:

执行IDirect3DDevice9接口的BeginScene(),若返回真,遍历场景中的物体。设置相应的

shader里的技术后再渲染,渲染后再设置回才场景默认的shader技术,最后执行

IDirect3DDevice9接口的EndScene()函数。

2: Shader的实现

实现阴影效果要用到两个技术: techScene techShadowMap

techShadowMap用于渲染到阴影贴图shadermap,而techScene作最终的渲染。

techShadowMap VS 中主要进行三个变换矩阵的操作,并保存变换后顶点与光源的距离

PS 中主要计算 depth= IN.depth.z/IN.depth.w;return float4(depth,1,1,1);

techScene中除了一般的矩阵变换后,还需要进行特殊设置:

VS:

//计算shadow相关的属性

float4 lightworldPos = mul( inPosition, World );

lightworldPos = mul( lightworldPos, LightView );

lightworldPos = mul( lightworldPos, Projection );

//float w=lightworldPos.w;

//计算本点在灯光空间的深度

OUT.depth = lightworldPos;

//计算本点在shadowmap里的纹理坐标

OUT.vShadowTexcoord.x = ( lightworldPos.x * 0.5 + lightworldPos.w * 0.5 );

OUT.vShadowTexcoord.y = ( lightworldPos.w * 0.5 - lightworldPos.y * 0.5 );

OUT.vShadowTexcoord.z = lightworldPos.z/lightworldPos.w;

OUT.vShadowTexcoord.w = lightworldPos.w;

PS:

float shadowvalue=1.0f;

float4 smcolor=tex2Dproj(ShadowSampler,IN.vShadowTexcoord/IN.vShadowTexcoord.w);

float smDepth=smcolor.r;

float realDepth=IN.depth.z/IN.depth.w;

if(realDepth*0.9997f>smDepth)//比较该点对于光源的实际距离和其在灯光空间的深度

{ shadowvalue=0; }//设置该点在阴影区域内

IN.vShadowTexcoord/=IN.vShadowTexcoord.w;

if( IN.vShadowTexcoord.x<0 || IN.vShadowTexcoord.x>1

|| IN.vShadowTexcoord.y<0 || IN.vShadowTexcoord.y>1)

{ shadowvalue=1; }

float diff=(shadowvalue*IN.diff+ambient)/(1+ambient);

color.rgb=color.rgb*diff;

效果图如下:

引擎技术研究之实时阴影技术