完整版延迟渲染的一些思考.docx
《完整版延迟渲染的一些思考.docx》由会员分享,可在线阅读,更多相关《完整版延迟渲染的一些思考.docx(14页珍藏版)》请在冰豆网上搜索。
完整版延迟渲染的一些思考
延迟渲染的一些思考
最近一直在准备开题,打算做延迟渲染(DeferredShading)相关的实现。
DeferredShading是目前实现多动态光源实时渲染的最主流的技术了。
其实DeferredShading后面还有DeferredLighting和InferredLighting这两种更先进一点的改进技术,可师兄师姐们的经验告诉我,开题不能开太难了。
如果开题太难了,最后实现的时候实现不出来,那就是给自己找麻烦了。
其实DeferredShading技术在国外已经提出近20年了,在游戏中实际应用也有近10年了,近几年出的几个好的游戏引擎中几乎都用到了它。
在国外,DS应该说是相当成熟了,可国内运用这种技术的引擎好像还没有听说过。
我想并不是国内没有人会这种技术,网上很多博客都提到DS了,也有人自己实现了DS效果。
只是这种技术对硬件的要求比较高,国内的游戏要照顾大多数的玩家。
国外的玩家有可能因为想玩某个很酷的新游戏而升级硬件,国内几乎没有哪一款游戏有这种魅力。
我想这也是为什么国内的游戏技术水平与国外的相差的不止一个级别的原因之一。
国内有些研究过DS的朋友在网上公布了他们的研究结果,不过好像并没有想像中那么好。
他们的实现中要么就没有考虑阴影(比如燕良的博客中的他实现的源代码和效果图,我还没有认真研究他的源码,不过从他的效果图中看不到有阴影的迹象。
因为这个问题,我纠结了很长时间,DS算法说起来是比较简单,空间换时间。
可为什么大部分相关文章在谈到DS的优点的时候,都说可以实现多动态光源,去很少提到阴影的具体实现方法,好像阴影是理所当然的事。
《GPU精粹2》中有一篇文章《S.T.A.L.K.E.R.中的延期着色(DeferredShadinginS.T.A.L.K.E.R.)》,其中介绍的阴影也是用shadowmap来实现的。
《GPU精粹3》中有一篇专门的介绍延迟渲染的,《TabulaRasa中的延迟着色技术》,其实网上就有这篇文章的翻译:
(“天堂里的死神”童鞋很给力,《GPU精粹3》的中文版是10年6月才出版的,他09年就翻译了这篇文章。
) ,在TabulaRasa中,阴影也是用shadowmap实现的。
他还有一篇相关的博客《“杀戮地带2”中的延迟渲染》2》中也是用的shadowmap来实现的。
这么多的经典游戏中都是用的shadowmap,看来shadowmap是比较好的选择了。
不过也有文章提到用DS实现阴影体渲染的,最后将会附上原文,但没有使用多个光源,如果真的有多个动态光源,估计计数量也够呛。
好了,开题的事就基本定下来了,题目就定为“多光源动态光照的实时渲染”之类的吧,反正是基于延迟渲染的,即使实现了延迟渲染之后,想进一步做DeferredLighting和InferredLighting,也在题目范围之内。
也算了了一大心事了,开题报告就好说了。
此事告一段落,等导师让我们准备开题答辩时,再写开题报告吧。
从此可以全心地准备找实习了,腾讯5月8来来汉笔试,期待中。
希望能去游戏开发岗位实习。
这是《OpenGLShadingLanguage(2ndEdition)》第13章的一节,讲的是用延迟渲染实现阴影体。
(最近比较忙,时间有限,我只把这篇文章中基本关键部分翻译出来了的,水平有限,仅供参考。
)
13.3.DeferredShadingforVolumeShadows
WithcontributionsbyHughMalanandMikeWeiblen
Oneofthedisadvantagesofshadowmappingasdiscussedintheprevioussectionisthattheperformancedependsonthenumberoflightsinthescenethatarecapableofcastingshadows.Withshadowmapping,arenderingpassmustbeperformedforeachoftheselightsources.Theseshadowmapsareutilizedinafinalrenderingpass.Alltheserenderingpassescanreduceperformance,particularlyifagreatmanypolygonsaretoberendered.
Itispossibletodohigher-performanceshadowgenerationwitharenderingtechniquethatispartofageneralclassoftechniquesknownasDEFERREDSHADING.Withdeferredshading,theideaistofirstquicklydeterminethesurfacesthatwillbevisibleinthefinalsceneandapplycomplexandtime-consumingshadereffectsonlytothepixelsthatmakeupthosevisiblesurfaces.Inthissense,theshadingoperationsaredeferreduntilitcanbeestablishedjustwhichpixelscontributetothefinalimage.Averysimpleandfastshadercanrenderthesceneintoanoffscreenbufferwithdepthbufferingenabled.Duringthisinitialpass,theshaderstoreswhateverinformationisneededtoperformthenecessaryrenderingoperationsinsubsequentpasses.Subsequentrenderingoperationsareappliedonlytopixelsthataredeterminedtobevisibleinthehigh-performanceinitialpass.Thistechniqueensuresthatnohardwarecyclesarewastedperformingshadingcalculationsonpixelsthatwillultimatelybehidden.
Torendersoftshadowswiththistechnique,weneedtomaketwopasses.Inthefirstpass,wedotwothings:
1.Weuseashadertorenderthegeometryofthescenewithoutshadowsorlightingintotheframebuffer. 用一个着色器把场景中除了阴影和光照之外的几何形状信息到渲染到帧缓存中。
2. Weusethesameshadertostoreanormalizedcameradepthvalueforeachpixelinaseparatebuffer.(Thisseparatebufferisaccessedasatextureinthesecondpassfortheshadowcomputations.) 用同一个着色器把每个像素点的规一化照相机深度值存到一个单独的缓存中。
(在阴影计算的第二个Pass中,这个单独缓存将会当作一张纹理。
)
Inthesecondpass,theshadowsarecompositedwiththeexistingcontentsoftheframebuffer.Todothiscompositingoperation,werendertheshadowvolume(i.e.,theregioninwhichthelightsourceisoccluded)foreachshadowcastingobject.Inthecaseofasphere,computingtheshadowvolumeisrelativelyeasy.Thesphere'sshadowisintheshapeofatruncatedcone,wheretheapexoftheconeisatthelightsource.Oneendofthetruncatedconeisatthecenterofthesphere(seeFigure13.2).(Itissomewhatmorecomplextocomputetheshadowvolumeforanobjectdefinedbypolygons,butthesameprincipleapplies.)
Figure13.2.Theshadowvolumeforasphere
Wecompositeshadowswiththeexistinggeometrybyrenderingthepolygonsthatdefinetheshadowvolume.Thisallowsoursecondpassshadertobeappliedonlytoregionsoftheimagethatmightbeinshadow. 通过渲染定义阴影体的多边形,我们把阴影与现有的几何信息合成。
这可以让我们执行第二个pass的着色器仅仅只对图像上那些可能处在阴影中的区域进行渲染。
Todrawashadow,weusethetexturemapshowninFigure13.3.Thistexturemapexpresseshowmuchavisiblesurfacepointisinshadowrelativetoashadow-castingobject(i.e.,howmuchitsvalueisattenuated)basedonafunctionoftwovalues:
1)thesquareddistancefromthevisiblesurfacepointtothecentralaxisoftheshadowvolume,and2)thedistancefromthevisiblesurfacepointtothecenteroftheshadow-castingobject.Thefirstvalueisusedasthescoordinateforaccessingtheshadowtexture,andthesecondvalueisusedasthetcoordinate.Thenetresultisthatshadowsarerelativelysharpwhentheshadow-castingobjectisveryclosetothefragmentbeingtestedandtheedgesbecomesofterasthedistanceincreases.
Figure13.3.Atexturemapusedtogeneratesoftshadows
Inthesecondpassofthealgorithm,wedothefollowing:
在算法的第二个pass中,我们做如下的操作:
1. Drawthepolygonsthatdefinetheshadowvolume.Onlythefragmentsthatcouldpossiblybeinshadowareaccessedduringthisrenderingoperation. 画定义阴影体的多边形。
在这次渲染操作中,只有那些可能处在阴影中的像素受影响。
2. Foreachfragmentrendered,对每一个渲染的像素,
a. Lookupthecameradepthvalueforthefragmentascomputedinthefirstpass. 查询些像素在第一个pass中计算出的照相机深度值。
b. Calculatethecoordinatesofthevisiblesurfacepointinthelocalspaceoftheshadowvolume.Inthisspace,thezaxisistheaxisoftheshadowvolumeandtheoriginisatthecenteroftheshadow-castingobject.Thexcomponentofthiscoordinatecorrespondstothedistancefromthecenteroftheshadow-castingobjectandisuseddirectlyasthesecondcoordinatefortheshadowtexturelookup. 在阴影体的局部空间内,计算可见面的点的坐标。
在此空间中,Z轴是阴影体的轴线,原点在被投影物体的中心。
些坐标的X分量对应着该点到被投影物体的中心的的距离,它可以直接用作查找阴影纹理时的第二个坐标。
c. Computethesquareddistancebetweenthevisiblesurfacepointandthezaxisoftheshadowvolume.Thisvaluebecomesthefirstcoordinateforthetexturelookup. 计算可见面上点到阴影体的Z轴的距离的平方。
这个值将会作为查找阴影纹理时的第一个坐标。
d. Accesstheshadowtexturebyusingthecomputedindexvaluestoretrievethelightattenuationfactorandstorethisintheoutputfragment'salphavalue.Thered,green,andbluecomponentsoftheoutputfragmentcolorareeachsetto0. 用前面计算出的索引值从阴影纹理中读取光照衰减因子,并把它存在输出像素的alpha值中。
把输出像素的R,G,B分量分别设为0。
e. Computeforthefragmentthelightattenuationfactorthatwillproperlydarkentheexistingframebuffervalue.Forthecomputation,enablefixedfunctionalityblending,settheblendmodesourcefunctiontoGL_SRC_ALPHA,andsettheblenddestinationfunctiontoGL_ONE. 计算像素的光照衰减因子,它可能使现有的帧缓存中的值变暗。
计算时,打开固定功能混合,设置混合模式源函数为GL_SRC_ALPHA,设置混合目标函数为GL_ONE。
Becausetheshadow(secondpass)shaderiseffectivelya2Dcompositingoperation,thetexelitreadsfromthedepthtexturemustexactlymatchthepixelintheframebufferitaffects.Sothetexturecoordinateandotherquantitiesmustbebilinearlyinterpolatedwithoutperspectivecorrection.Weinterpolatebyensuringthatwisconstantacrossthepolygondividingx,y,andzbywandthensettingwto1.0doesthejob.Anotherissueisthatwhentheviewerisinsidetheshadowvolume,allfacesareculled. Wehandlethisspecialcasebydrawingascreen-sizedquadrilateralsincetheshadowvolumewouldcovertheentirescene.
13.3.1.ShadersforFirstPass
TheshadersforthefirstpassofthevolumeshadowalgorithmareshowninListings13.8and13.9.Inthevertexshader,toaccomplishthestandardrenderingofthegeometry(whichinthisspecificcaseisalltexturemapped),wejustcall ftransform andpassalongthetexturecoordinate.Theotherlinesofcodecomputethenormalizedvalueforthedepthfromthevertextothecameraplane.Thecomputedvalue,CameraDepth,isstoredinavaryingvariablesothatitcanbeinterpolatedandmadeavailabletothefragmentshader.
Torenderintotwobuffersbyusingafragmentshader,theapplicationmustcallglDrawBuffersandpassitapointertoanarraycontainingsymbolicconstantsthatdefinethetwobufferstobewritten.Inthiscase,wemightpassthesymbolicconstantGL_BACK_LEFTasthefirstvalueinthearrayandGL_AUX0asthesecondvalue.Thismeansthatgl_FragData[0]willbeusedtoupdatethevalueinthesoon-to-be-visibleframebuffer(assumingwearedouble-buffering)andthevalueforgl_FragData[1]willbeusedtoupdatethevalueinauxiliarybuffernumber0.Thus,thefragmentshaderforthefirstpassofouralgorithmcontainsjusttwolinesofcode(Listing13.9).
Listing13.8.Vertexshaderforfirstpassofsoftvolumeshadowalgorithm
uniformvec3 CameraPos;
uniformvec3 CameraDir;
uniformfloatDepthNear;
uniformfloatDepthFar;
varyingfloatCameraDepth; //normalizedcameradepth
varyingvec2TexCoord;
voidmain()
{
//offset=vectortovertexfromcamera'sposition
vec3offset=(gl_Vertex.xyz/gl_Vertex.w)-CameraPos;
//z=distancefromvertextocameraplane
floatz=-dot(offset,CameraDir);
//Depthfromvertextocamera,mappe