• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            芳草春暉

            偶爾記錄自己思緒的地方...

             

            Gamebryo使用經(jīng)驗(yàn)談(1)

            Gamebryo的材質(zhì)系統(tǒng)

            一個(gè)模型(有一大堆頂點(diǎn)跟索引數(shù)據(jù)組成)描畫的方式,跟材質(zhì)有很大的關(guān)系。
            Gamebryo提供了一個(gè)很強(qiáng)大的材質(zhì)系統(tǒng)。

            首先gamebryo使用了一個(gè)自定義的Pipeline,這個(gè)也是在之前的文章中介紹過的。其實(shí)這個(gè)Pipeline就是大家最常用的一些Shader。GB幫我們總結(jié)出來(lái)了,并做成了一個(gè)標(biāo)準(zhǔn)的材質(zhì)。這在GB里叫StandardMaterial。

            標(biāo)準(zhǔn)材質(zhì)跟Pipeline是相對(duì)應(yīng)的。但是標(biāo)準(zhǔn)材質(zhì)的實(shí)現(xiàn)是非常困難的,可以查閱NiStandartMaterial,大約有5000多行代碼。GB會(huì)首先查找一下Shader文件夾下的那些Shader。
            這些Shader的文件名是由一對(duì)數(shù)字+字母組成的。這些文件都是不重復(fù)的,因?yàn)镚B內(nèi)部通過Hash碼得出這些值。如果在Shader文件夾下沒有,那么GB會(huì)把當(dāng)前的渲染方式記錄到這個(gè)Shader中去,作為緩存。

            當(dāng)然你也可以構(gòu)建自己的Material系統(tǒng),比如GB的NiCommonMaterial里也給出了一些構(gòu)建自己材質(zhì)系統(tǒng)的例子,不過這是非常復(fù)雜,基本思想都是需要維護(hù)一個(gè)Shader樹。

            不過自己寫Shader是非常方便的,你可以用RenderMonkey或者ShaderFX,把做好的*.fx文件放到Shader文件夾中,MAX再次打開的時(shí)候就會(huì)找到這些Shader。讓美工使用起來(lái)非常的方便。

            關(guān)于優(yōu)化的問題總結(jié)

            引擎本身做的很好,不會(huì)對(duì)速度產(chǎn)生太大影響。但是使用者往往會(huì)由于開發(fā)經(jīng)驗(yàn)過低等等因素,導(dǎo)致游戲運(yùn)行速度太慢。這里有些是因?yàn)閷?duì)Gamebryo系統(tǒng)的不熟悉造成。

            美術(shù)上:美術(shù)如果不熟悉Art文檔,不熟悉圖形技術(shù)的話,用任何引擎都是白搭。其實(shí)大部分的浪費(fèi)都是美術(shù)造成的。下面先說(shuō)說(shuō)美術(shù)的優(yōu)化
            1.注意Mesh的顆粒度,什么意思呢。就是主要不要有太多小物件。三角面很少的Mesh,如果材質(zhì)相同的話,完全可以合并起來(lái)。


            1.關(guān)于Gamebryo中的update與update select。這是avobject里重要的兩個(gè)函數(shù),也是Gamebryo中更新場(chǎng)景圖最重要的函數(shù)之一。update select是做了優(yōu)化的,也就是說(shuō),如果變換矩陣沒有做出變換的話,gamebryo不會(huì)更新world信息,這樣會(huì)節(jié)省一定的時(shí)間,所以如果是靜態(tài)物體,請(qǐng)優(yōu)先使用UpdateSelect.
            相反動(dòng)態(tài)物體,比如人物。如果確定他一定不是靜態(tài)的話,請(qǐng)不要使用UpdateSelect,因?yàn)檫@會(huì)多做一次對(duì)變換矩陣是否改變的判斷,這是沒有意義的。

            gamebryo中的管線

            跟開源圖形引擎一樣,商業(yè)引擎的價(jià)值在于幫助你做了很多前人的積累。
            gamebryo就是這樣的引擎,當(dāng)然unreal做的更加牛。這是后話了,關(guān)于unreal的做法我將以后分析。

            先來(lái)說(shuō)說(shuō)gamebryo,跟Ogre不一樣的是,gamebryo有一個(gè)自己所謂的pipeline。
            Ogre很靈活,當(dāng)然靈活的代價(jià)是很多東西需要你自己做,gamebryo也很靈活,不過作為商業(yè)引擎,他同時(shí)幫你做了很多事情。




            Gamebryo中的對(duì)象系統(tǒng)之一:智能指針和引用計(jì)數(shù)

            本文是一系列Gamebryo底層系統(tǒng)的介紹。
            Gamebryo除了是一個(gè)強(qiáng)大的游戲引擎之外,在研究他的源代碼同時(shí),我驚喜的發(fā)現(xiàn)他提供了很多值得我們?cè)趯懘a過程中學(xué)習(xí)和借鑒的東西。
            本文就是來(lái)介紹這些底層系統(tǒng)到底是在穿插在引擎中使用的。
            Gamebryo的底層系統(tǒng)運(yùn)用于他所有的模塊和工具中,他提供了對(duì)象管理,引用計(jì)數(shù),對(duì)象持久化(有點(diǎn)像Java的東西)以及快速的運(yùn)行時(shí)型別轉(zhuǎn)換等功能。



            首先我們來(lái)介紹一下引用計(jì)數(shù)與智能指針。

            在Gamebryo中所有基礎(chǔ)NiRefObject的Object都會(huì)被計(jì)數(shù)的。這就意味著Object存儲(chǔ)著所有引用他的數(shù)目。如果需要長(zhǎng)期的引用一個(gè)對(duì)象的話,需要聲明一個(gè)引用,并在結(jié)束時(shí)釋放掉改引用。當(dāng)引用計(jì)數(shù)等于零的時(shí)候,對(duì)象會(huì)自己釋放掉所申請(qǐng)的內(nèi)存區(qū)。不過這樣看起來(lái)用起來(lái)會(huì)比較煩,好在GB提供了“smart pointers”來(lái)減輕繁雜的工作。

            要注意的是所有繼承NiRefObject的子類都必須通過堆來(lái)分配,不用使用于靜態(tài)類型對(duì)象或者棧上對(duì)象。因?yàn)楫?dāng)引用計(jì)數(shù)為零的時(shí)候,該對(duì)象會(huì)被刪除,而刪除靜態(tài)對(duì)象或者棧上對(duì)象都會(huì)導(dǎo)致內(nèi)存錯(cuò)誤或者崩潰。

            談?wù)勁夸秩?nbsp;

                 隨著顯卡寄存器數(shù)量越來(lái)越多,批量渲染已經(jīng)不是什么稀奇的事情了.

                  其實(shí),根據(jù)我最近研究發(fā)現(xiàn),暴雪早在DX8時(shí)代就做了批量渲染這件事,所以一舉占據(jù)了RTS老大的地位.很湊巧的時(shí)候我現(xiàn)在的項(xiàng)目也是個(gè)RTS類游戲.所以批量渲染就成了一個(gè)亟待解決的問題.

                  Gamebryo是支持MeshInstancing的,就是模型的批量渲染。
                哦,先介紹下DX9支持的幾種Instancing的方式吧,一種叫HardwareInstancing,中文叫硬件批量渲染吧,其實(shí)是DX9提供了SetStreamSourceFreq這個(gè)接口,讓你可以把一個(gè)數(shù)據(jù)源多次使用,比如我們要批量需然一組模型,每個(gè)模型有自己的Translation信息,但是他們的頂點(diǎn)和索引數(shù)據(jù)是共用的。例如,你要批量10個(gè)這樣的模型的話,只要抽取出他們不同的數(shù)據(jù)上傳到一個(gè)數(shù)據(jù)源中,然后頂點(diǎn)和索引數(shù)據(jù)重復(fù)使用十次就可以了。
                另外一種是ShaderInstancing,所謂Shader Instancing,意思就是,把Instancing數(shù)據(jù)傳到vertex shader里去,在渲染的時(shí)候通過一些方法索引到這些Instancing數(shù)據(jù),用來(lái)對(duì)頂點(diǎn)數(shù)據(jù)做不同的描畫。

            Gamebryo幀渲染系統(tǒng)詳解

            如果沒記錯(cuò)的話,我曾經(jīng)寫過一篇關(guān)于Gamebryo幀渲染系統(tǒng)的內(nèi)容。估計(jì)當(dāng)時(shí)剖析的不是太詳細(xì)。那么現(xiàn)在我在這里重新講一下幀渲染系統(tǒng),希望能把他將清楚。由于我手頭沒有代碼,而且又是商業(yè)引擎,所以很多函數(shù)我并不是完整的使用gamebryo中的,能使用偽代碼的地方我盡量使用偽代碼。

            好,首先再次強(qiáng)調(diào)下幀渲染系統(tǒng)是邏輯系統(tǒng),嚴(yán)格上跟渲染沒有任何關(guān)系,就是說(shuō)如果你可以繞開幀渲染系統(tǒng),一樣可以畫出想描畫的東西,只不過GB這樣做的目的是使得渲染層次更加清晰,靈活了。
            OGRE也有類似的概念,在Ogre中也可以定義自己的層,但是由于沒有幀渲染系統(tǒng),所以層次上不如Gamebryo靈活,方便易用。

            RenderFrame 和RenderStep我就不再贅述了,因?yàn)檫@兩個(gè)概念很簡(jiǎn)單,里面也沒有實(shí)質(zhì)性的內(nèi)容。你想怎么理解都可以,前者是后者的超集,Step又是Click的超集。

            詳細(xì)說(shuō)一下RenderClick和RenderView。RenderView可以理解成我們所要描畫的物件。RenderView里有AppendScene這樣的接口,就可以把所有想View的東西都掛接上去。RenderView里還有個(gè)重要的工具叫做Culler,Culler是做什么用的呢?是負(fù)責(zé)裁剪的,這里的裁剪是邏輯上的裁剪,就是精確到幾何體級(jí)別的裁剪。(注意不是三角面級(jí)別的)。Culler是作為Processor被加進(jìn)去的,就是一個(gè)裁剪的過程。Culler提供了一些抽象接口,來(lái)滿足用戶的自定義裁剪。就是說(shuō)你可以根據(jù)你的需要來(lái)在渲染前進(jìn)行裁剪。

            下面說(shuō)到RenderClick,RenderClick精確的字面意思就是一次描畫,這個(gè)類的功能也基本是這樣,知道了要畫的東西,但是要畫到什么上去就需要RenderClick了,每個(gè)RenderClick對(duì)應(yīng)了一個(gè)RenderTarget。就是要描畫的地方。一個(gè)描畫的過程是這樣的,首先找到RenderTarget就是要描畫的地方,因?yàn)槿绻呛笃谔匦В袝r(shí)候會(huì)有多個(gè)RenderTarget。
            知道了要描畫的地方后就開始描畫了,首先從RenderView里找出要描畫的幾何體(這里的幾何體已經(jīng)是被裁剪過后的幾何體了),然后Click里再做一個(gè)處理,這里的處理也是個(gè)Processor,就是意味著用戶可以定義。這里處理的目的基本上是對(duì)物體做一個(gè)排序。這里不會(huì)再對(duì)幾何體進(jìn)行裁剪了,而是進(jìn)行類似Alpha排序等這樣的工作,保證物體被正確的按層次畫出來(lái)。最終得到的RenderObjList就是用來(lái)描畫的了。

            整個(gè)過程其實(shí)還是比較簡(jiǎn)單的,給用戶很多自己選擇的機(jī)會(huì)。是一個(gè)不錯(cuò)的設(shè)計(jì)。

            GameBryo ---- 模板類

            GameBryo提供了一太基本的模板容器類,這些容器在整個(gè)庫(kù)內(nèi)使用。

            Lists

            NiTPointerList對(duì)象可以包含和管理指針,智能指針,以及其他任何大小小于等于指針的元素,該鏈表可以有效的插入和刪除所有元素,以及正向遍歷和反向遍歷所有元素,同樣可以通過給定值查找元素的實(shí)體和所在位置,NiTPointerList的元素的內(nèi)存是從一個(gè)共享內(nèi)存中分配的,從而提高類的執(zhí)行速度和內(nèi)存效率,如果鏈表元素大于指針,程序可以使用NiTObjectList.

            Array

            NiTArray對(duì)象實(shí)現(xiàn)勒幾乎可以包含所有對(duì)象的動(dòng)態(tài)數(shù)組,該數(shù)組可以縮放,并且可以壓縮(通過轉(zhuǎn)移元素來(lái)移除空空間)。內(nèi)置類型(char*, float, int等)使用NiTPrimitiveArray。NiMemObject派生出的類型使用NiTobjectArray。注意NiTArray的元素上限為65535;如果大于該限制,使用NiTLargeArray派生出的類,比如NiTLargePrimitiveArray或NiTLargeObjectArray。

            Map

            NiTPointMap對(duì)象實(shí)現(xiàn)勒哈希表的功能,允許任何類型的鍵值來(lái)影射到指針,智能指針,以及其他任何大小小于等于指針的元素,并能快速的儲(chǔ)存和查找鍵值對(duì),不過不能使用字符串鍵哈希表,而NiTStringPointerMap對(duì)象是專為此設(shè)計(jì)的,NiTPointMap和NiTStringPointerMap的元素內(nèi)存也是從一個(gè)共享內(nèi)存中分配的,從而提高執(zhí)行速度和內(nèi)存效率,如果map元素大于指針,程序可以使用NiTMap和NiTStringMap

            StringMap

            NiTStringMap和NiTStringPointerMap對(duì)象的函數(shù)和NiTMap和NiTPointerMap風(fēng)格類似,但是允許字符串作為鍵,并且通過字符串比較來(lái)進(jìn)行鍵散列

            FixedStringMap

            NiTFixedStringMap對(duì)象函數(shù)和NiTMap對(duì)象風(fēng)格相似,但是允許NiFixedString對(duì)象作為鍵

            Queue

            NiTQueue實(shí)現(xiàn)勒基本所有類型對(duì)象的先進(jìn)先出隊(duì)列,但不提供智能指針,需要注意鏈表可以當(dāng)做隊(duì)列來(lái)使用

            Set

            NiTSet實(shí)現(xiàn)了基本所有類型的無(wú)序集合,也沒提供智能指針,內(nèi)置類型(char*, float, int等)使用NiTPrimitiveSet。NiMemObject派生出的類型使用NiTobjectSet,智能指針則使用NiTObject或者NiTPrimitivePtrSet,這將正確的處理引用計(jì)數(shù)。

            Pool

            NiTPool實(shí)現(xiàn)了小型對(duì)象的池,使得程序能通過一個(gè)池來(lái)分配小型對(duì)象,并能重復(fù)使用,而不是單獨(dú)的去分配和釋放一個(gè)小型對(duì)象



            GameBryo ---- 場(chǎng)景圖的幾何更新

            一個(gè)程序會(huì)在需要的時(shí)候改變一個(gè)節(jié)點(diǎn)的轉(zhuǎn)換,計(jì)算該節(jié)點(diǎn)的時(shí)間轉(zhuǎn)換,以及該節(jié)點(diǎn)子節(jié)點(diǎn)的其他轉(zhuǎn)換將被延遲,直到應(yīng)用程序調(diào)用例行的update。

            update是高效使用深度優(yōu)先來(lái)遍歷子圖計(jì)算世界轉(zhuǎn)換和世界包圍球,從而最大限度的減少節(jié)點(diǎn)的訪問,當(dāng)向下遞歸時(shí),轉(zhuǎn)換被更新,包括所有的自節(jié)點(diǎn),當(dāng)矩陣更新后,世界包圍球通過遞歸調(diào)用返回

            總之,轉(zhuǎn)換在遞歸中被更新,而包圍球在遞歸返回時(shí)得到

            通常大多數(shù)的對(duì)象都不會(huì)移動(dòng)的,所有只更新只限于小部分可以移動(dòng)的對(duì)象。在場(chǎng)景圖的數(shù)據(jù)處理初始化中,當(dāng)應(yīng)用程序使用到場(chǎng)景圖前,至少要對(duì)場(chǎng)景圖的根節(jié)點(diǎn)進(jìn)行一次例行update,這樣保證所有節(jié)點(diǎn)的世界信息及本地信息都是最新的。

            在應(yīng)用程序幀到幀的運(yùn)行中,當(dāng)符合下面任何一條時(shí),應(yīng)用程序必須調(diào)用對(duì)象“O”的update。

            ·O被綁定到父親節(jié)點(diǎn)或者從父親節(jié)點(diǎn)解除綁定

            ·O綁定了一個(gè)新子節(jié)點(diǎn)或者解除了一個(gè)子節(jié)點(diǎn)的綁定

            ·O任何一個(gè)轉(zhuǎn)換被改變

            注意一下,調(diào)用當(dāng)前發(fā)父親節(jié)點(diǎn)或者任何祖先節(jié)點(diǎn)的update可以代替當(dāng)前節(jié)點(diǎn)update的調(diào)用。例如,如果對(duì)象A綁定了子節(jié)點(diǎn)B和C,只需要調(diào)用A的update就夠了。沒有必要調(diào)用三個(gè)對(duì)象的update,應(yīng)用程序會(huì)以批處理的方式更新。

            例如,當(dāng)應(yīng)承需要改變了一個(gè)活動(dòng)角色的所有的關(guān)節(jié)矩陣,他應(yīng)該推遲update直到所有的改變都完成,并且只需要調(diào)用一次角色根節(jié)點(diǎn)的update。

            但是,注意update盡量在場(chǎng)景圖的更下層調(diào)用,如果一個(gè)場(chǎng)景圖每幀只有一個(gè)葉子被改變,那么調(diào)用根節(jié)點(diǎn)的update就太過分了,這將降低性能。


            GameBryo ---- 網(wǎng)格數(shù)據(jù)共享

            為了世界中對(duì)象只需要少量的頂點(diǎn),一棵樹可以用來(lái)代表場(chǎng)景圖,每個(gè)對(duì)象被單獨(dú)表現(xiàn)為樹中的節(jié)點(diǎn)。但是,在絕大多數(shù)場(chǎng)景圖中,會(huì)多次出現(xiàn)一個(gè)需要大量?jī)?nèi)存來(lái)存儲(chǔ)的復(fù)雜對(duì)象,絕大多數(shù)的內(nèi)存是消耗在紋理和頂點(diǎn)數(shù)據(jù)上,比如紋理坐標(biāo)和法線。

            如果一個(gè)應(yīng)用程序需要多份這樣一個(gè)對(duì)象,是有可能通過共享的NiDataStream來(lái)分享模型空間的幾何信息,顏色,紋理和其他顏色。換句話說(shuō),若干網(wǎng)格對(duì)象可能分享NiDataStream對(duì)象,在這種情況下,場(chǎng)景圖是有向非循環(huán)圖,而不是一棵樹。

            在幾何數(shù)據(jù)共享的情況下,葉網(wǎng)格對(duì)象共享NiDataStream對(duì)象的模型空間網(wǎng)格。但是,兩個(gè)模型數(shù)據(jù)的實(shí)例是在世界的不同位置,因?yàn)樗麄兇淼亩鄠€(gè)網(wǎng)格對(duì)象,并且每個(gè)副本自己?jiǎn)为?dú)的轉(zhuǎn)換。

            這些管理是在應(yīng)用程序的內(nèi)部透明處理的——應(yīng)用程序只需要建立兩個(gè)網(wǎng)格對(duì)象使用同一個(gè)NiDataStream對(duì)象。網(wǎng)格對(duì)象甚至要比一套最小的網(wǎng)格數(shù)據(jù)小的多,因?yàn)榫W(wǎng)格對(duì)象不像數(shù)據(jù)流,不存在每個(gè)頂點(diǎn)的數(shù)據(jù)

            下面的圖象是一個(gè)典型的情況:

             

             

             

                                                        (兩個(gè)網(wǎng)格對(duì)象使用同一個(gè)NiDataStream)

            兩個(gè)葉網(wǎng)格對(duì)象分享一個(gè)輪胎NiDataStream對(duì)象的頂點(diǎn)位置和法線。一個(gè)網(wǎng)格對(duì)象對(duì)應(yīng)到自行車的前輪,另一個(gè)對(duì)應(yīng)到自行車的后輪。NiDataStream對(duì)象自身存儲(chǔ)的網(wǎng)格頂點(diǎn)的位置和法線被共享,兩個(gè)網(wǎng)格對(duì)象都保存表現(xiàn)自己網(wǎng)格的轉(zhuǎn)換。

            注意以下,Gamebryo不為任何類型的NiAVObject提供多父親的功能。綁定一個(gè)已經(jīng)擁有父節(jié)點(diǎn)的對(duì)象C,會(huì)導(dǎo)致C自動(dòng)脫離原來(lái)的父節(jié)點(diǎn)


            GameBryo ---- Working with Properties

            Gamebryo通過一套相互獨(dú)立的渲染性質(zhì)為每個(gè)能渲染的葉子對(duì)象定義了渲染屬性,每一個(gè)渲染屬性都為能渲染的對(duì)象定義了某一方面的渲染狀態(tài),并且都是NiProperty的子類。對(duì)個(gè)可渲染的對(duì)象可以共享渲染屬性。針對(duì)一個(gè)對(duì)象的完整渲染狀態(tài)是所有屬性的完整組合。當(dāng)屬性狀態(tài)對(duì)象存在與NiRenderObject葉子節(jié)點(diǎn)時(shí),這個(gè)個(gè)體渲染屬性就被綁定在場(chǎng)景圖的任何NiAVObject上。這正式用于每個(gè)可渲染葉子對(duì)象產(chǎn)生屬性狀態(tài)的每個(gè)NiAVObject的屬性。一個(gè)屬性被綁定到一個(gè)NiAVObject將影響所有子數(shù)上的子對(duì)象(包括它自己),除非在子樹中同樣的屬性類型被其他屬性所替代。如果沒有任何屬性被設(shè)置到場(chǎng)景圖的對(duì)象上,該對(duì)象會(huì)通過合適的默認(rèn)屬性來(lái)繪制。每個(gè)屬性類型的默認(rèn)相當(dāng)于為該類型設(shè)置一個(gè)默認(rèn)構(gòu)造,每個(gè)NiAVObject都包含了一個(gè)綁定與它的所有屬性的鏈表,一個(gè)NiAVObject可能沒有任何屬性綁定,也有可能綁定一個(gè)或多個(gè)屬性。所有的方式達(dá)到一個(gè)NiAVObject能綁定的每樣屬性的最大值。注意確保應(yīng)用程序任何時(shí)候都不能給單一的NiAVObject綁定一個(gè)以上已經(jīng)類型的屬性。一個(gè)單一的NiAVObject綁定已經(jīng)類型的一個(gè)以上的屬性會(huì)導(dǎo)致奇怪的視覺效果和未知的問題。

            繪制屬性類型

            NiProperty對(duì)象在Gamebryo中的數(shù)據(jù)層次如下:

            NiObject

                          NiProperty

                                          NiAlphaProperty

                                          NiDitherProperty

                                          NiFogProperty

                                          NiMaterialProperty

                                          NiShadeProperty

                                          NiSpecularProperty

                                          NiStencilProperty

                                          NiTexturingProperty

                                          NiVertwxColorProperty就如上面討論的,屬性設(shè)置從根到葉層次。一個(gè)被綁定到NiAVObject對(duì)象的屬性會(huì)影響該對(duì)象及它的子對(duì)象。除非在更低的子樹中綁定該類型的其他屬性。因此,一個(gè)可渲染葉節(jié)點(diǎn)的當(dāng)前狀態(tài)是由場(chǎng)景圖中它祖先的鏈所決定的

                                          NiWireFramProperty

                                          NiZBufferProperty

            更新屬性到集合物體上

             

            Gamebryo會(huì)讓整個(gè)場(chǎng)景圖保持綁定屬性,綁定在每個(gè)可渲染葉對(duì)象的屬性狀態(tài)是包含所有提供的類型的屬性的數(shù)組,這樣,每個(gè)可渲染的對(duì)象包含一個(gè)直接指向用來(lái)繪制的渲染屬性的指針。這很重要,因?yàn)殇秩局簧婕翱射秩镜娜~對(duì)象,而不是整個(gè)場(chǎng)景圖。于是每個(gè)可渲染對(duì)象的屬性狀態(tài)都是繼承其他可渲染對(duì)象的所有屬性的副本。

            Gamebryo使用一個(gè)系統(tǒng)類似使用NiAVObject::Update函數(shù)來(lái)更新這些屬性狀態(tài)對(duì)象。這個(gè)類似的渲染屬性函數(shù)是NiAVObject::UpdateProperties。當(dāng)出現(xiàn)下面的情況UpdateProperties必須在obejct"O"或任何一個(gè)他的祖先調(diào)用下一次渲染

            ·一個(gè)以O(shè)個(gè)根節(jié)點(diǎn)的樹剛被創(chuàng)建

            ·一個(gè)屬性被綁定到O或從O移除

            ·O被綁定到節(jié)點(diǎn)P或從P上被移除

            注意,當(dāng)只改變了一個(gè)已有屬性,應(yīng)用程序不需要調(diào)用UpdateProperties。

            要實(shí)現(xiàn)最佳性能,這些UpdateProperties的調(diào)用可以以相同的方式進(jìn)行批處理來(lái)執(zhí)行批處理更新,如果應(yīng)用程序?qū)⒃谧訕渖辖壎ɑ蚪獬壎ㄔS多屬性,它必須調(diào)用所有的綁定或解除綁定函數(shù),然后在子樹的根部調(diào)用一次UpdateProperties,通常的,因?yàn)閷傩院妥庸?jié)點(diǎn)的綁定和解綁沒有每一幀這樣頻繁,所以UpdateProperties要比每幀積累屬性快的多,但是對(duì)于程序員。將多出一個(gè)額外的小負(fù)擔(dān)。


            GameBryo ---- SoftParticles

            軟粒子主要是為了解決粒子廣告牌和場(chǎng)景幾何相交時(shí),產(chǎn)生的生硬邊緣,如下圖煙霧與地面相交時(shí)的邊

            為了解決上面的情況,我們需要用到場(chǎng)景的深度信息,如下圖:

            在一般的渲染管線中,點(diǎn)P3就是產(chǎn)生生硬邊的點(diǎn),為了改善這種情況,SoftParticles通過改變粒子的alpha值來(lái)處理粒子后面的場(chǎng)景,這里使用了自定義的shader常量來(lái)決定距離d以便我們調(diào)整alpha值(d為world place中),任何距離原場(chǎng)景深度大于d的粒子相素我們將不處理他的alpha值(對(duì)應(yīng)上圖P1的公式),

            上圖中點(diǎn)P1正好達(dá)到該距離,點(diǎn)P1到P3的alpha混合程度會(huì)遞增,距離d設(shè)置的越小,那效果就越接近于硬粒子的效果,因?yàn)镻1的條件很容易滿足,對(duì)alpha值的修改會(huì)減少,但是如果距離設(shè)置的過大,那P2就很容易滿足,這樣導(dǎo)致Len/d產(chǎn)生的值很小,讓粒子變的很透明,造成的粒子很稀疏,具體的效果要自己手動(dòng)調(diào)節(jié)。

            這種邊緣軟化的方式只是近似的,當(dāng)場(chǎng)景的法線于攝像機(jī)方向錘子時(shí)會(huì)失效,當(dāng)出現(xiàn)這種情況時(shí),隨便粒子與相交面很接近了,但因?yàn)閿z像機(jī)與相交面近乎垂直,而粒子相素的深度檢測(cè)是沿與攝像機(jī)方向的,從而產(chǎn)生一個(gè)很大len值,導(dǎo)致了本來(lái)應(yīng)該成為P3效果的點(diǎn),成為P1。

            DEMO5個(gè)類,SoftParticles,MRT_ColorDepthMaterial,SoftParticlesMaterial,SoftParticlesManager,MRT_ColorBlackMaterial

            SoftParticles::CreateScene()

            負(fù)責(zé)創(chuàng)建場(chǎng)景,從Nif文件中獲取場(chǎng)景,攝像機(jī)及粒子系統(tǒng),設(shè)置alpha排序,剔除,及默認(rèn)材質(zhì)MRT_ColorDepthMaterial, MRT_ColorDepthMaterial繼承于NiStandardMaterial,重載了函數(shù)bool HandleFinalVertexOutputs()和函數(shù)bool HandleFinalPixelOutputs(),這兩個(gè)函數(shù)分別在vertex shader和pixel shader的最后執(zhí)行,通過HandleFinalVertexOutputs函數(shù),為vertex shader的output結(jié)構(gòu)增加成員NiMaterialResource* pkVertOutViewTexCoord = Context.m_spOutputs->AddInputResource("float4", "TexCoord", "World",
            "PosViewPassThrough");作為紋理坐標(biāo)的格式輸出

            NiMaterialNode* pkSplitterNode = GetAttachableNodeFromLibrary(
                    "PositionToDepthNormal");
                kContext.m_spConfigurator->AddNode(pkSplitterNode);
                kContext.m_spConfigurator->AddBinding(pkViewPos,
                    pkSplitterNode->GetInputResourceByVariableName("Input"));
                kContext.m_spConfigurator->AddBinding(
                    pkSplitterNode->GetOutputResourceByVariableName("Output"),
                    pkVertOutViewTexCoord);

            獲得自定義函數(shù)PositionToDepthNormal,將pkViewPos作為傳入?yún)?shù),把新增的pkVertOutViewTexCoord作為輸出參數(shù)

            而HandleFinalPixelOutputs則在輸入結(jié)構(gòu)中增加float4 WorldPosProjected : TEXCOORD6;代碼如下

            NiMaterialNode * pkInputResource;
                pkInputResource = kContext.m_spConfigurator->GetNodeByName("PixelIn");

                NiMaterialResource* pkDepthFromVP = pkInputResource->AddOutputResource(
                    "float4", "TexCoord", "World", "WorldPosProjected");

            然后在輸出結(jié)構(gòu)中增加深度顏色,通過WorldPosProjected來(lái)賦值,CreateScene()還將場(chǎng)景中所有的粒子系統(tǒng)添加進(jìn)SoftParticlesManager,添加完所有的ParticlesSystem后,SoftParticlesManager通過Initialize()函數(shù),創(chuàng)建默認(rèn)的粒子材質(zhì),以及SoftParticlesManager自己的RnderView及click,然后通過InitializeScene()為每個(gè)粒子系統(tǒng)設(shè)置材質(zhì),并添加進(jìn)RnderView,這里要注意執(zhí)行順序

            SoftParticles::CreateFrame()

            該函數(shù)中,通過獲取后備緩沖的屬性,來(lái)創(chuàng)建相同一張texture,用來(lái)渲染深度,不過格式要設(shè)置為NiTexture::FormatPrefs::SINGLE_COLOR_32,表示32位的單通道顏色,用R通道表示,然后新建一個(gè)RenderGroup,要包含原來(lái)的后備緩沖以及先建的位圖緩沖,讓場(chǎng)景同時(shí)渲染到這兩個(gè)緩沖上,并將紋理緩沖作為SoftParticlesManager中創(chuàng)建的click的一個(gè)輸入


            GameBryo ---- MSAA

            MSAA(MultiSampling Anti-Aliasing)

            GB中MSAA實(shí)現(xiàn)的關(guān)鍵代碼基本是直接用的D3D,除了自己的渲染批次系統(tǒng),DX9不能直接對(duì)渲染到紋理啟用MSAA,但是提供了渲染表面surface,可以對(duì)surface啟用MSAA。

            實(shí)現(xiàn)的關(guān)鍵步驟大致如下

            1。NiRenderedTexture::Create創(chuàng)建一個(gè)和背景緩沖一樣大的RenderTexture,NiRenderTargetGroup::Create利用RenderTexture創(chuàng)建RenderTarget,屏幕最終渲染的目標(biāo)就是該RenderTarget,我們需要的也是將MSAA后的數(shù)據(jù)給RenderTexture

            2。通過D3D的CreateRenderTarget按照自定的MSAA級(jí)別來(lái)創(chuàng)建surface,利用surface的buffer創(chuàng)建另外一個(gè)MSAARenderTarget

            3。新建一個(gè)RenderView,GB中用的NiScreenFillingRenderView,就是D3D中四個(gè)頂點(diǎn)組成的矩形,該RenderView綁定一個(gè)baseTexture為步驟1所創(chuàng)建的RenderTexture的NiTexturingProperty,創(chuàng)建RenderClick掛接該RenderView,并設(shè)置一個(gè)CallBackFunc,然后將該click插到mainClick后面,這樣用兩pass來(lái)完成MSAA

            4。主click將畫面渲染到開啟MSAA的MSAARenderTarget,然后進(jìn)入新click的CallBackFunc,獲取MSAARenderTarget的buffer,用D3D的StretchRect復(fù)制數(shù)據(jù)到RenderTexture,這樣新click就會(huì)渲染出進(jìn)行MSAA后的texture

            posted on 2010-04-20 00:04 CrazyDev 閱讀(4090) 評(píng)論(2)  編輯 收藏 引用 所屬分類: 游戲引擎

            評(píng)論

            # re: Gamebryo使用經(jīng)驗(yàn)談(1) 2011-04-12 18:17 yzhg

            樓主經(jīng)驗(yàn)會(huì)誤導(dǎo)別人
            你要是有程序Demo 和詳細(xì)的圖紙?jiān)诔鰜?lái)百話,我就覺的不可笑
            什么叫暴雪用批渲染決定他游戲的地位,這個(gè)是你主觀猜測(cè)的吧,別瞎說(shuō)。  回復(fù)  更多評(píng)論   

            # re: Gamebryo使用經(jīng)驗(yàn)談(1) 2011-04-12 18:20 yzhg

            研究一個(gè)從根上就不是自己的系統(tǒng),真是怪,為什么不塌心的一點(diǎn)一點(diǎn)用c++寫
            呢,我看到國(guó)外有人能用c++ opengl 寫個(gè)rts 不從根上做一輩子都不會(huì)
            更何況rts game,真是說(shuō)笑  回復(fù)  更多評(píng)論   

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(1)

            隨筆檔案

            文章分類

            文章檔案

            C/C++

            CEGUI

            Friend Bog

            Game Industry

            Lua

            OGRE

            Other

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            亚洲精品99久久久久中文字幕| 国产精品久久久久影视不卡| 香蕉久久夜色精品国产小说| 久久精品无码午夜福利理论片| 99蜜桃臀久久久欧美精品网站| 久久精品国产亚洲αv忘忧草| 久久国产AVJUST麻豆| 亚洲а∨天堂久久精品| 中文精品久久久久人妻| 77777亚洲午夜久久多人| 久久AV无码精品人妻糸列| 婷婷五月深深久久精品| 国产成人久久精品激情 | 久久er热视频在这里精品| 久久精品国产亚洲AV无码偷窥| AV色综合久久天堂AV色综合在| 久久久精品午夜免费不卡| 国产精品亚洲综合专区片高清久久久 | 国产农村妇女毛片精品久久| 国产亚州精品女人久久久久久 | 久久婷婷五月综合成人D啪 | 久久精品国产只有精品66| 久久最新免费视频| 婷婷久久香蕉五月综合加勒比| 成人久久久观看免费毛片| 亚洲国产精品成人AV无码久久综合影院 | 久久精品国产亚洲AV电影| 久久精品国内一区二区三区| 久久一区二区三区免费| 色综合久久中文字幕无码| 99国产欧美精品久久久蜜芽| 久久久久国产日韩精品网站| 国产69精品久久久久久人妻精品| 国产精品久久久久久福利漫画| 理论片午午伦夜理片久久| jizzjizz国产精品久久| 久久久久亚洲国产| 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲 | 亚洲AV乱码久久精品蜜桃| 国产成人无码精品久久久久免费 | 久久精品国产亚洲AV电影|