333lu.vip.php,软阴影 - GameRes.com

// Projecti=

on matrix for the light<=

/span>D3DXMatrixPerspectiveFovLH(&matPro=

j, D3DXToRadian(30.0f),1.0f=, 1.0f, 1024.0f);

//ऩ=

4;际上作者在例程中使&=

#29992;的是D3DXMatrixOrthoLH( &matProj=

, 45.0f, 45.0f, 1.0f,

//1024.0f )。=

6825;个函数所构造的project矩=

8453;与D3DXMatrixPerspective=

FovLH()构造的=

span>//不同之处在=

20110;:它没有透视效果z=

90;即物体的大小与视点=

和物体的距离没有关=

1995;。显然例//程中模拟的=

26159;平行光源(direction light),而这里=

27169;拟的是聚光灯源(spot light不知翻译得=

23545;不对?)

=

// Concatenate the world matrix with the above// two to g=

et the required matrix<=

/span>matLightViewProj=3D matWorl=

d * matView * matProj;<=

/o:p>

下面是渲染场景=

深度的顶点渲染和像=

2032;渲染的代码:

=

// Shadow generation vertex shader<=

/span>structVSOUTPUT_SHADOW<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>{

=float4 vPosition: POSITION;floatfDepth&nbsp=

;: TEXCOORD0;=

};<=

/o:p>VSOUTPUT_SHA=

DOW VS_Shadow( float4 inPosi=

tion : POSITION ){

=// Output struct<=

/span>VSOUTPUT_SHADOW OUT =3D (VSOUTPUT=

_SHADOW)0;// Output the transforme=

d positionOUT.vPosition =3D mul( inPosition, g_ma=

tLightViewProj );// Output the scene dept=

hOUT.fDepth =3D OUT.vPosition.z;return OUT;}

=

这里我们将顶点=

的位置与变换矩阵相=

0056;,并将变换后的z值作为深=

24230;。在像素渲染中将ę=

45;度值以颜色(color)的=

方式输出。

float4PS_Shadow( VSO=

UTPUT_SHADOW IN ) : COLOR0{

=// Output the scene dept=

hreturnfloat4( IN.fDepth, IN.fDepth, IN.fDepth, 1.0f );<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>}

=

瞧,=

我们完成了阴影映射=

2270;,下面就是以颜色ਬ=

1;式输出的阴影映射图&=

#65292;深蓝色部分表明较=

567;的深度值,浅蓝色部=

;分表明较大的深度值=

12290;

image004.jpg%22

下面=

,我们要把场景的带=

8452;影的部分渲染到并ߎ=

1;立即显示的缓冲中,&=

#20351;我们可以进行模糊=

788;理,然后再将它投射回屏幕。ཛ=

8;先把场景的阴影部分&=

#28210;染到一幅屏幕大小=

340;定点纹理中。

=

// Create the screen-sized buffer map<=

/span>if(FAILED( g_pd3dDevice->CreateTexture( SCREEN_WIDTH,

<=

/o:p>&nbsp=

;SCREEN_HEIGHT, 1, D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,&nbsp=

;&g_pScreenMap, NULL ) ) ){=

MessageBox( g_hWnd, "Unable to create screen map!=

",&nbsp=

;"Error", MB_OK | MB_ICONERROR );return E_FAIL;

=

o:p>}

=// Grab the=

texture's surface<=

/span>g_pScreenMap=

->GetSurfaceLevel( 0, & g_pScreenSurf );

<=

/span>

为了获得投=

24433;纹理坐标(projective texture coordinates),我们需要一=

010;纹理矩阵,作用是把=

;投影空间(projection space=

65289;中的位置变换到纹ĩ=

02;空间(texture space=

65289;中去。

=

// Generate the texture matrix<=

pre>floatfTexOffs =3D 0.5 + (0.5 / (float)SHADOW_MAP_SIZE);D3DXMATRIX <=

span

class=3DGramE>matTexAdj( 0.5f,&=

nbsp;0.0f,0.0f, 0.0f,&nb=

sp;0.0f,-0.5f,0.0f, 0.0f,<=

pre>&nbsp=

;             <=

/span>0.0f,0.0f,1.0f, 0.0f,<=

pre>&nbsp=

;             <=

/span>fTexOffs, fTexOffs, 0.0f, 1.0f );//这个矩阵是把projection space中范围为[-1,1]的x,y坐标值=

转换到纹理空间中=

//[0,1]的范围中去Ӎ=

0;注意y轴的方=

向改变了。那个(0.5 / (float)SHADOW_MAP_SIZE)

//的值有什么作用=

105;还不清楚,原文也没=

;有说明。<=

/span><=

/o:p>matTexture=3D matLigh=

tViewProj * matTexAdj;<=

/o:p>

我们像往常=

37027;样通过深度的比较Ĉ=

69;获得阴影因数,但随=

后并不是像平常那样=

6755;出整个照亮了的场ਾ=

3;,我们只输出阴影因&=

#25968;。下面的顶点渲染=

644;像素渲染完成这个工=

;作。

=

// Shadow mapping vertex shader<=

/span>structVSOUTPUT_UNLIT{

=float4 vPosition: POSITION;float4 vTexCoord: TEXCOORD0;floatfDepth&nbsp=

;: TEXCOORD1;<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>};<=

/o:p>VSOUTPUT_UNL=

IT VS_Unlit( float4 inPosit=

ion : POSITION ){

=// Output struct<=

/span>VSOUTPUT_UNLIT OUT =3D (VSOUTPUT_=

UNLIT)0;<=

/pre>// Output the transforme=

d positionOUT.vPosition =3D mul( inPosition, g_ma=

tWorldViewProj );<=

/o:p>// Output the projective=

texture coordinatesOUT.vTexCoord =3D mul( inPosition, g_ma=

tTexture );<=

/o:p>// Output the scene dept=

hOUT.fDepth =3D mul( inPosition, g_matLightViewProj ).z;<=

/o:p>return OUT;}

=

我们采用percentage closer filtering (PCF)来平滑锯齿边缘Ӎ=

0;为了完成“PCF”,&=

#25105;们简单的对周围8个纹理点=

36827;行采样,并取得它Ê=

04;深度比较的平均值。=

=

// Shadow mapping pixel shader//=

span>注意这里采ஷ=

2;的是tex2Dproj()函数以&=

#21450;转换到纹理空间的=

521;量(x,y,z,w)对纹理进//行采样。这与d3d9sdk中shadowmapË=

63;子用tex2D()及向量(x,y)进行采样不同Ӎ=

0;具体//区别及原因很ê=

81;易从程序中看出,我=

就不再啰嗦了。<=

/span>float4PS_Unlit( VSOU=

TPUT_UNLIT IN ) : COLOR0{

=// G=

enerate the 9 texture co-ordinates for a 3x3 PCF kernelfloat4 vTexCoords[9];=// Texel sizefloat fTexelSize =3D =

1.0f / 1024.0f;<=

/pre>// G=

enerate the tecture co-ordinates for the specified depth-map size// 4 3 5=// 1 0 2=// 7 6 8<=

/span>VTexCoords[0] =3D IN.vTexCoord;vTexCoords[1] =3D IN.vTexCoord + float4( -fTexelSize, 0.0f, 0.0f, 0.0f );vTexCoords[2] =3D IN.vTexCoord + float4(fTexelSiz=

e, 0.0f, 0.0f, 0.0f );vTexCoords[3] =3D IN.vTexCoord + float4( 0.0f, -fTexelSize, 0.0f, 0.0f );vTexCoords[6] =3D IN.vTexCoord + float4( 0.0f,fTexelSize, 0.0f, 0.0f );vTexCoords[4] =3D IN.vTexCoord + float4( -fTexelSize, -fTexelSize, 0.0f, 0.0f );vTexCoords[5] =3D IN.vTexCoord + float4(fTexelSiz=

e, -fTexelSize, 0.0f, 0.0f );vTexCoords[7] =3D IN.vTexCoord + float4( -fTexelSize,fTexelSize, 0.0f, 0.0f );vTexCoords[8] =3D IN.vTexCoord + float4(fTexelSiz=

e,fTexelSize, 0.0f, 0.0f );// Sample each of them c=

hecking whether the pixel under test is shadowed or not

<=

/o:p>float fShadowTerms[9]=

;float fShadowTerm =3D=

0.0f;for( int i =3D 0; i < 9; i++ )<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>{float A =3D tex2Dproj( ShadowSampler, vTexCoords[i] ).r;float B =3D (IN.fDept=

h - 0.1f);<=

/o:p>// Texel is shadowed<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>fShadowTerms[i] =3D A < B ? 0.0f: 1.0f;fShadowTerm&nbs=

p;+=3D fShadowTerms[i];}// Get the averagefShadowTerm /=3D 9.0f;return fShadowTerm;}

=

屏幕缓冲完=

25104;了,我们还需要进Ŝ=

92;模糊工作。

image006.jpg%22

我们采用seperable

gaussian filter模糊=

屏幕缓冲。但我们也=

1487;以用Poisson filter。这=

次的render targets是<=

span

lang=3DEN-US>A8R8G8B8的纹理和相关的=

表面。我们需要两个render targets,一=

个进行水平阶段,一=

0010;进行垂直阶段。

=

// Create the blur maps<=

pre>for(int i =3D 0; i < 2; i++=

){

=if( FAILED( g_pd3dDev=

ice->CreateTexture( SCREEN_WIDTH,&nbsp=

;            &n=

bsp;SCREEN_HEIGHT, 1, D3DUSAGE_RENDERTARGET=

,&nbsp=

;            &n=

bsp;D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,&nbsp=

;            &n=

bsp;&g_pBlurMap[i], NULL ) ) ){MessageBox( g_hWnd, "Unable to create blur map!&q=

uot;,&nbsp=

;"Error",=

MB_OK | MB_ICONERROR );return E_FAIL;

=

o:p>}// Grab the texture's su=

rfaceg_pBlurMap[i]->GetSurfaceLevel( 0, & g_pBlurSurf[i] );

=}

=

我们用下面=

30340;代码生成15个高斯偏移量(Gaussian offsets=

65289;及他们的权重(corresponding weights)。

floatGetGaussian=

Distribution( float x, float =

y, float rho ){

=float g =3D 1.0f / sqrt( 2.0f * 3.141592654f * rho * rho );return g * exp( -(x *=

x + y * y) / (2 * rho * rho) );}

=<=

/o:p>voidGetGaussianOffsets( bool bHorizontal,&nbsp=

;            &n=

bsp;D3DXVECTOR2 vViewportTexelSize,=

pre>&nbsp=

;            &n=

bsp;D3DXVECTOR2* vSampleOffsets,&nbsp=

;            &n=

bsp;float* fSampleWeights=

){

=// Get the center texel offset and weightfSampleWeights[0] =3D 1.0f * GetGaussianDistribution( 0, 0, 2.0f );<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>vSampleOffsets[0] =3D D3DXVECTOR2( 0.0f, 0.0f );// Get the offsets and w=

eights for the remaining tapsif( bHorizontal ){for( int i =3D 1; i < 15; i +=3D 2 )=

{vSampleOffsets[i + 0] =3D D3DXVECTOR2( i * vViewportTe=

xelSize.x, 0.0f );<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>vSampleOffsets[i + 1] =3D D3DXVECTOR2( -i * vViewportT=

exelSize.x, 0.0f );<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>fSampleWeights[i + 0] =3D 2.0f * GetGaussianDistribution( float(i + 0), 0.0f, 3.0f );fSampleWeights[i + 1] =3D 2.0f * GetGaussianDistribution( float(i + 1), 0.0f, 3.0f );}}else{for( int i =3D 1; i < 15; i +=3D 2 )=

{vSampleOffsets[i + 0] =3D D3DXVECTOR2( 0.0f, i * vViewportTexelSize.y );vSampleOffsets[i + 1] =3D D3DXVECTOR2( 0.0f, -i * vViewportTexelSize.y );fSampleWeights[i + 0] =3D 2.0f * GetGaussianDistribution( 0.0f, float=(i + 0), 3.0f );<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>fSampleWeights[i + 1] =3D 2.0f * GetGaussianDistribution( 0.0f, float=(i + 1), 3.0f );<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>}}

}

为了模糊=

屏幕缓冲,我们将模=

1946;映射图(blur map)作为render target,使=

用下面的顶点渲染和=

0687;素渲染代码渲染一ߑ=

0;与屏幕等大的方块。<=

/span>

// 作者在程序ߑ=

3;预先定义的屏幕大小&=

#26159;1024 * 768,而随后定È=

41;的与屏幕等大的方块=

为:

/=

/<=

/span>pVertices[0].p =3D D3DXVECTOR4( 0.0f, 0.0f,

0.0f, 1.0f );

//pVertices[1].p =3D

D3DXVECTOR4( 0.0f, 768 /

2, 0.0f, 1.0f );

//pVertices[2].p =3D

D3DXVECTOR4( 1024 / 2, 0.0f,

0.0f, 1.0f );

//pVertices[3].p =3D

D3DXVECTOR4( 1024 / 2, 768 / 2, 0.0f,

1.0f );

=

span>

//这种方法与d3dsdk中HDRLight中获得rend=

er

target的width and height然后再构造的//方法不×=

16;:<=

/p>

// svQuad[0].p =3D D3DXVECTOR4(-0.5f, -0.5f,

0.5f, 1.0f);

// svQuad[1].p =3D D3DXVECTOR4(Width-0.5f, -0.5f,

0.5f, 1.0f);

// svQuad[2].p =3D D3DXVECTOR4(-0.5f, Height-0.5f, 0.5f,

1.0f);

// svQuad[3].p =3D D3DXVECTOR4(Width-0.5f,fHeight-0.5f, 0.5f,

1.0f);

// 而一般定义的Ĺ=

83;口大小往往与从render target获得的width

and height不相同。=

o:p>

//而É=

08;者的fvf都是D3DFVF_XYZRHW。这两种方法有什么=

区别我一直没想通。

&=

nbsp;

=

// Gaussian filter vertex shader<=

/span>structVSOUTPUT_BLUR{

=float4 vPosition: POSITION;float2 vTexCoord: TEXCOORD0;};<=

/o:p>VSOUTPUT_BLU=

R VS_Blur( float4 inPositi=

on : POSITION, float2 inTexCoord : TEXCOORD0 ){

=// Output struct<=

/span>VSOUTPUT_BLUR OUT =3D (VSOUTPUT_B=

LUR)0;// Output the position=

span>OUT.vPosition =3D inPosition;// Output the texture co=

ordinatesOUT.vTexCoord =3D inTexCoord;return OUT;}

=// Horizont=

al blur pixel shader<=

/span>float4PS_BlurH( VSOUTPUT_BLUR IN ): COLOR0{

=// A=

ccumulated colorfloat4 vAccum =3D float4( 0.0f, 0.0f, 0.0f, 0.0f );// Sample the taps (g_vS=

ampleOffsets holds the texel offsets// and g_fSampleWeights holds the=

texel weights)<=

pre>for(int i =3D 0; i < 15; i++ )<=

span

lang=3DEN-US style=3D'font-family:"Courier New";color:#333333'>{vAccum +=3D tex2D( ScreenSampler, IN.vTexCoord + g_vSa=

mpleOffsets[i] ) * g_fSampleWeights[i];}return vAccum;

=

o:p>}

=<=

/o:p>// Vertical=

blur pixel shader<=

/span>float4PS_BlurV( VSOUTPUT_BLUR IN ): COLOR0{

=// A=

ccumulated colorfloat4 vAccum =3D float4( 0.0f, 0.0f, 0.0f, 0.0f );// Sample the taps (g_vS=

ampleOffsets holds the texel offsets and// g_fSampleWeights holds the texel weights)<=

pre>for( int i =3D 0; i < 15; i++ )=

{vAccum +=3D tex2D( BlurHSampler, IN.vTexCoord + g_vSam=

pleOffsets[i] ) * g_fSampleWeights[i];}return vAccum;

=

o:p>}

=

这里,模=

糊映射图已经完成了=

5292;为了增加阴影的模౺=

6;程度,增加了纹理上&=

#28857;的采样距离。最后=

968;步自然是将模糊后的=

;纹理图投射回屏幕空໾=

8;使其显示在屏幕上。<=

span

lang=3DEN-US>

image008.jpg%22

After first Gaussian pass

image010.jpg%22

After second Gaussian pass=

span>

为了=

将模糊后的纹理投射=

1040;屏幕上,我们像平६=

0;那样渲染场景,但投&=

#24433;模糊后的纹理时要=

351;用屏幕空间的坐标。=

;我们使用裁剪空间的=

22352;标和一些数学方法Ĉ=

69;产生屏幕空间的坐标=

。下面的顶点渲染和=

0687;素渲染将完成这个ॣ=

7;作:

structVSOUTPUT_SC=

ENE{

=float4 vPosition: POSITIO=

N;float2 vTexCoord: TEXCOOR=

D0;float4 vProjCoord: TEXCOORD1;float4 vScreenCoord: TEXCOORD2;

<=

/span>float3 vNormal: TEXCOORD3;float3 vLightVec: TEXCOOR=

D4;float3 vEyeVec: TEXCOORD5;};// Scene ve=

rtex shader<=

/span>VSOUTPUT_SCE=

NE VS_Scene( float4 inPosit=

ion : POSITION,&nbsp=

;            &n=

bsp;float3 inNormal : NORMAL,&nbsp=

;            &n=

bsp;float2 inTexCoord : T=

EXCOORD0 ){

=VSOUTPUT_SCENE OUT =3D (VSOUTPUT_=

SCENE)0;// Output the transforme=

d positionOUT.vPosition =3D mul( inPosition, g_ma=

tWorldViewProj );<=

/o:p>// Output the texture co=

ordinatesOUT.vTexCoord =3D inTexCoord;<=

/o:p>// Output the projective=

texture coordinates (we use this// to project the spot texture do=

wn onto the scene)//这个是用来ߝ=

5;生light map的纹理坐标௚=

0;。最终效果图中地面&=

#19978;光照效果就是用//这个坐标配ࡧ=

2;上一幅这样的light map实现的。=image012.jpg%22<=

/span>OUT.vProjCoord =3D mul( inPosition, g_ma=

tTexture );<=

/o:p>// Output the screen-spa=

ce texture coordinates//这个就=

是将裁剪空=

间的坐标转换到屏幕=

1354;间的坐标,方法和将裁剪空间的坐标$=

716;换//纹理空=

间的坐标的方法很相=

0284;。=OUT.vScreenCoord.x =3D ( OUT.vPosition.x * 0.5 + OUT.vPosition.w * 0.5 );OUT.vScreenCoord.y =3D ( OUT.vPosition.w * 0.5 - OUT.vPosition.y * 0.5 );OUT.vScreenCoord.z =3D OUT.vPosit=

ion.w;OUT.vScreenCoord.w =3D OUT.vPosit=

ion.w;<=

/o:p>// Get the world space v=

ertex positionfloat4 vWorldPos =3D mul( inPosition, g_matWorld );<=

/o:p>// Output the world spac=

e normalOUT.vNormal =3D mul( inNormal, g_matW=

orldIT );<=

/o:p>// Move the light vector=

into tangent spaceOUT.vLightVec =3D g_vLightPos.xyz=

- vWorldPos.xyz;<=

/o:p>// Move the eye vector i=

nto tangent spaceOUT.vEyeVec =3D g_vEyePos.xyz - v=

WorldPos.xyz;return OUT;}

=float4PS_Scene( VSOUTPUT_SCENE IN ) : COLOR0<=

/pre>{

=// N=

ormalize the normal, light and eye vectors

<=

/span>IN.vNormal=3D normalize( IN.vNormal=

);IN.vLightVec =3D normalize( IN.vLightV=

ec );IN.vEyeVec=3D normalize( IN.vEyeVec=

);// Sample the color and =

normal mapsfloat4 vColor=3D tex2D( ColorSampler, IN.vTexCoord );

<=

/span>// Compute the ambient, =

diffuse and specular lighting terms

float ambient=3D 0.0f;float diffuse=3D max( dot( IN.vN=

ormal, IN.vLightVec ), 0 );float specular =3D pow(max(dot( 2 * dot( I=

N.vNormal, IN.vLightVec ) * IN.vNormal&nbsp=

;            &n=

bsp;- I=

N.vLightVec, IN.vEyeVec ), 0 ), 8 );if( diffuse =3D=3D 0 =

) specular =3D 0;// Grab the shadow term<=

/span>float fShadowTerm =3D=

tex2Dproj( BlurVSampler, IN.vScreenCoord );

=// Grab the spot termfloat fSpotTerm =3D <=

span

class=3Dcodekeyword>tex2Dproj( SpotSampler, IN.vProjCoord );// Compute the final col=

orreturn (ambient * vCo=

lor) +&nbsp=

;(diffuse * vColor * g_vLightColor * fShadowTerm * fSpot=

Term) +&nbsp=

;(specular * vColor * g_vLightColor.a * fShadowTerm * fS=

potTerm);}

=

终于完成了。看=

上去不错。该技术的=

0248;点一是解决了锯齿໾=

2;题,二是在多光源,&=

#20302;内存下实现了软阴=

433;。另外该技术与阴影=

;生成方法无关,可以=

24456;容易的在shadow volumes技术=

中采用这项技术。缺=

8857;是由于进行了模糊ࣦ=

8;理而需要一些填充率&=

#12290;

下面是不同阶段=

的效果比较图:

image014.jpg%22

谢谢你阅读这篇=

文章,如有疑问欢迎=

6469;信(这=

是原作者的信箱)

(汗,好多东西=

心里明白,但翻译出=

6469;就是不满意。各位ව=

1;是看不明白就找出原&=

#25991;研究吧。)

Hardware Shadow Mapping=

. Cass

Everitt, Ashu Rege and Cem Cebenoyan.

Hardware-accelerated

Rendering of Antialiased Shadows with Shadow Maps. Stefan Brabec and

Hans-Peter Seidel.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值