深入研究虚幻4反射系统实现原理(三)
前面兩篇文章介紹了虛幻引擎中對(duì)于反射的支持(如果沒(méi)讀過(guò)前兩篇文章,推薦你仔細(xì)看下,否則你可能不知道我在講什么),不過(guò)還差一點(diǎn)內(nèi)容,就是這些信息是如何 加入到運(yùn)行時(shí)的,講完這些那么這個(gè)系列也就算是基本結(jié)束了,下面進(jìn)入正文。
信息注冊(cè)
虛幻引擎使用一系列靜態(tài)變量來(lái)注冊(cè)需要生成反射信息的函數(shù),這個(gè)我們前面的文章已經(jīng)比較詳細(xì)的講過(guò)。至于用生成的C++的代碼所帶來(lái)的好處,我前面翻譯的文章中也講過(guò)。下面我把它貼到這里。
用生成的C++代碼來(lái)存儲(chǔ)反射數(shù)據(jù)的一個(gè)最大好處就是,它可以保證跟二進(jìn)制做到同步。你永遠(yuǎn)也不會(huì)加載陳舊或者過(guò)時(shí)的反射數(shù)據(jù),因?yàn)樗歉娴钠渌a同時(shí)編譯的,并且它會(huì)在程序啟動(dòng)的時(shí)候使用C++表達(dá)式來(lái)計(jì)算成員偏移等,而不是通過(guò)針對(duì)特定平臺(tái)/編譯器/優(yōu)化的組合中進(jìn)行逆向工程。UHT作為一個(gè)單獨(dú)的不使用任何生成頭文件的程序來(lái)構(gòu)建,因此它也避免了雞生蛋、蛋生雞的問(wèn)題,這個(gè)在虛幻3的腳本編譯器中一直被詬病。
UCLASS
對(duì)于類的反射支持,虛幻4分為兩步來(lái)做的。
IMPLEMENT_CLASS() 這個(gè)宏用于在程序啟動(dòng)時(shí)注冊(cè)這個(gè)類,包括生成UClass類以及注冊(cè)C++原生函數(shù)等操作。
static FCompiledInDefer 創(chuàng)建一個(gè)靜態(tài)變量,用于向DeferredCompiledInRegistration這個(gè)靜態(tài)數(shù)組中添加注冊(cè)函數(shù),來(lái)初始化默認(rèn)的反射屬性。包括函數(shù)、成員變量、元數(shù)據(jù)等。
USTRUCT
對(duì)于結(jié)構(gòu)體的支持,虛幻4引擎也是分為兩步來(lái)做的。
static FCompiledInDeferStruct 存儲(chǔ)一個(gè)用于構(gòu)建結(jié)構(gòu)體的一個(gè)單例函數(shù),用于在程序啟動(dòng)的時(shí)候調(diào)用,讀者可以自行查看代碼就知道這個(gè)過(guò)程了。
還會(huì)創(chuàng)建一個(gè)靜態(tài)對(duì)象,這個(gè)對(duì)象在構(gòu)造函數(shù)中會(huì)調(diào)用UScriptStruct::DeferCppStructOps,它用來(lái)向這個(gè)DeferredCppStructOps map 中注冊(cè)一個(gè)動(dòng)態(tài)管理結(jié)構(gòu)體構(gòu)造、析構(gòu)的一個(gè)類。
UENUM
枚舉比較簡(jiǎn)單,只有一步。
static FCompiledInDeferEnum 創(chuàng)建一個(gè)靜態(tài)變量,用于在程序啟動(dòng)時(shí)存儲(chǔ)一個(gè)創(chuàng)建枚舉反射對(duì)象的一個(gè)單例函數(shù)。
啟動(dòng)過(guò)程分析
上面我們講解了這個(gè)注冊(cè)信息的過(guò)程,而它們的執(zhí)行是伴隨著當(dāng)前模塊的加載而執(zhí)行的,我們都知道靜態(tài)變量的初始化是先于Main函數(shù)執(zhí)行的。下面我們簡(jiǎn)單畫(huà)了一下虛幻編輯器的啟動(dòng)流程,這樣我們就可以準(zhǔn)確地看到整個(gè)注冊(cè)反射信息的過(guò)程了。
可以看到void ProcessNewlyLoadedUObjects()這個(gè)函數(shù)就是我們主要關(guān)注的函數(shù),我們前面講到的注冊(cè)的信息,包括類、結(jié)構(gòu)體以及枚舉類型的反射信息都會(huì)在這里進(jìn)行注冊(cè),它的代碼如下所示:
void ProcessNewlyLoadedUObjects()
{
DECLARE_SCOPE_CYCLE_COUNTER(TEXT("ProcessNewlyLoadedUObjects"), STAT_ProcessNewlyLoadedUObjects, STATGROUP_ObjectVerbose);
#if WITH_HOT_RELOAD
UClassGenerateCDODuplicatesForHotReload();
#endif
UClassRegisterAllCompiledInClasses();
while( AnyNewlyLoadedUObjects() )
{
UObjectProcessRegistrants();
UObjectLoadAllCompiledInStructs();
UObjectLoadAllCompiledInDefaultProperties();
}
#if WITH_HOT_RELOAD
UClassReplaceHotReloadClasses();
#endif
}
下面我們對(duì)上面代碼做一個(gè)簡(jiǎn)單的解釋,讀者也可以自行翻閱代碼來(lái)仔細(xì)查看它是怎么實(shí)現(xiàn)的。
代碼中WITH_HOT_RELOAD這個(gè)宏是用來(lái)處理C++代碼熱加載使用的。
UClassRegisterAllCompiledInClasses()用來(lái)注冊(cè)所有要加載的類,這里面的所有類就是通過(guò)前面IMPLEMENT_CLASS()宏添加進(jìn)來(lái)的。
UObjectProcessRegistrants()用于處理自動(dòng)注冊(cè)的對(duì)象,并把它們添加到ObjectArray中去,用于后期的檢索。
UObjectLoadAllCompiledInStructs()用于注冊(cè)結(jié)構(gòu)體和枚舉的反射信息。數(shù)組里面的數(shù)組是通過(guò)FCompiledInDeferStruct和FCompiledInDeferEnum創(chuàng)建的靜態(tài)對(duì)象注冊(cè)進(jìn)去的。
UObjectLoadAllCompiledInDefaultProperties()用于注冊(cè)類的反射信息并且創(chuàng)建一個(gè)默認(rèn)對(duì)象(CDO)。
總結(jié)
到此為此,這個(gè)系列的3篇文章通過(guò)代表示例的方式向讀者展示了虛幻中反射系統(tǒng)的實(shí)現(xiàn)方式,原理其實(shí)很簡(jiǎn)單,網(wǎng)上也有一些如何用C++支持反射類的方法,虛幻實(shí)現(xiàn)的是其中一種,因?yàn)橛辛薝HT的幫助,所以好多臟活、累活都不用我們來(lái)做了,比如最笨的方法是我們自己實(shí)現(xiàn)一些宏用來(lái)注冊(cè)各種反射信息,但這樣效率還是比較低。而有的實(shí)現(xiàn)方式會(huì)從編譯器產(chǎn)生的調(diào)試信息入手,比如vs生成的pdb文件,或者clang生成的文件等,這樣做也可以,但是它有一個(gè)比較大的問(wèn)題就是跨平臺(tái)的支持不是特別友好。所以虛幻4中這一套UHT工具總體上來(lái)說(shuō)還是很不錯(cuò)的,如果后面有時(shí)間,希望給大家?guī)?lái)對(duì)UHT工具的分析。對(duì)了,如果你有什么想對(duì)虛幻4引擎比較想了解的,也歡迎在下面留言,我也會(huì)挑大家比較感興趣的模塊來(lái)先做分析。接下來(lái),我可能會(huì)主要把精力放在虛幻中藍(lán)圖的實(shí)現(xiàn)原理和基于物理的渲染具體實(shí)現(xiàn)上。敬請(qǐng)期待!
總結(jié)
以上是生活随笔為你收集整理的深入研究虚幻4反射系统实现原理(三)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 网站301重定向 解决方法
- 下一篇: css 清除浮动float 嗒嘀嗒滴