使用紋理數(shù)據(jù)的最佳做法
紋理數(shù)據(jù)通常是您的應(yīng)用程序用于渲染框架的數(shù)據(jù)的最大部分;紋理提供向用戶呈現(xiàn)優(yōu)質(zhì)圖像所需的細(xì)節(jié)。要從應(yīng)用程序中獲得最佳性能坊谁,請(qǐng)仔細(xì)管理應(yīng)用程序的紋理爱榕∑妫總結(jié)指導(dǎo)方針:
- 在您的應(yīng)用程序初始化時(shí)創(chuàng)建紋理臊诊,并且不要在渲染循環(huán)中更改它們鸽粉。
- 減少紋理使用的內(nèi)存量。
- 將較小的紋理組合成更大的紋理圖集抓艳。
- 使用mipmap可以減少獲取紋理數(shù)據(jù)所需的帶寬触机。
- 在單次傳遞中使用multitexturing來執(zhí)行紋理化操作。
初始化期間加載紋理
創(chuàng)建和加載紋理是一項(xiàng)昂貴的操作玷或。為了獲得最佳效果儡首,請(qǐng)避免在應(yīng)用運(yùn)行時(shí)創(chuàng)建新紋理。而是在初始化期間創(chuàng)建并加載紋理數(shù)據(jù)偏友。
創(chuàng)建紋理后蔬胯,避免更改它,除非在幀的開頭或結(jié)尾位他。目前氛濒,所有iOS設(shè)備都使用基于瓦片的延遲渲染器,調(diào)用glTexSubImage和glCopyTexSubImage功能特別昂貴鹅髓。有關(guān)詳細(xì)信息舞竿,請(qǐng)參閱基于平鋪的延遲渲染。
使用GLKit框架加載紋理數(shù)據(jù)
加載紋理數(shù)據(jù)是一個(gè)重要的基本操作窿冯。使用GLKit框架骗奖,GLKTextureLoader類可以輕松創(chuàng)建和加載新紋理。 GLKTextureLoader類可以從各種來源加載紋理數(shù)據(jù)醒串,包括文件执桌,URL,內(nèi)存中的表示和CGImages厦凤。不管輸入源如何鼻吮,GLKTextureLoader類從數(shù)據(jù)創(chuàng)建并加載新的紋理,并將紋理信息作為GLKTextureInfo對(duì)象返回较鼓∽的荆可以訪問GLKTextureInfo對(duì)象的屬性來執(zhí)行各種任務(wù),包括將紋理綁定到上下文并使其可以進(jìn)行繪制博烂。
注意:GLKTextureInfo對(duì)象不擁有它描述的OpenGL ES紋理對(duì)象香椎。完成使用后,您必須調(diào)用glDeleteTextures函數(shù)來處理紋理對(duì)象
清單9-1顯示了從文件加載新紋理并綁定并啟用紋理以供將來使用的典型策略
GLKTextureInfo *spriteTexture;
NSError *theError;
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Sprite" ofType:@"png"]; // 1
spriteTexture = [GLKTextureLoader textureWithContentsOfFile:filePath options:nil error:&theError]; // 2
glBindTexture(spriteTexture.target, spriteTexture.name); // 3
這是代碼所做的禽篱,對(duì)應(yīng)于列表中的編號(hào)步驟:
- 創(chuàng)建包含紋理數(shù)據(jù)的圖像路徑畜伐。該路徑作為參數(shù)傳遞給GLKTextureLoader類方法textureWithContentsOfFile:
- 從圖像文件加載新的紋理,并將紋理信息存儲(chǔ)在GLKTextureInfo對(duì)象中躺率。有各種紋理加載選項(xiàng)可用玛界。有關(guān)更多信息万矾,請(qǐng)參閱GLKTextureLoader類參考。
- 將紋理綁定到上下文慎框,使用GLKTextureInfo對(duì)象的相應(yīng)屬性作為參數(shù)
GLKTextureLoader類也可以以最常見的圖像格式加載cubemap紋理良狈。而且,如果您的應(yīng)用程序在運(yùn)行時(shí)需要加載和創(chuàng)建新的紋理笨枯,GLKTextureLoader類還提供異步紋理加載的方法薪丁。有關(guān)更多信息,請(qǐng)參閱GLKTextureLoader類參考馅精。
減少紋理內(nèi)存使用
降低iOS應(yīng)用程序使用的內(nèi)存量始終是調(diào)整應(yīng)用程序的重要部分严嗜。也就是說,OpenGL ES應(yīng)用程序也受到可用于加載紋理的內(nèi)存總量的限制洲敢。在可能的情況下漫玄,您的應(yīng)用程序應(yīng)始終嘗試減少用于保存紋理數(shù)據(jù)的內(nèi)存量。降低紋理使用的內(nèi)存幾乎總是以圖像質(zhì)量為代價(jià)沦疾,因此您必須將應(yīng)用程序?qū)ζ浼y理的任何更改與最終渲染幀的質(zhì)量水平進(jìn)行平衡称近。為了獲得最佳效果,請(qǐng)嘗試下面描述的技術(shù)哮塞,并選擇在可接受的質(zhì)量水平下提供最佳內(nèi)存節(jié)省的技術(shù)刨秆。
壓縮紋理
紋理壓縮通常提供最佳的內(nèi)存節(jié)省和質(zhì)量平衡。適用于iOS的OpenGL ES支持多種壓縮紋理格式忆畅。
所有iOS設(shè)備都通過實(shí)現(xiàn)GL_IMG_texture_compression_pvrtc擴(kuò)展來支持PowerVR紋理壓縮(PVRTC)格式衡未。 PVRTC壓縮有兩個(gè)級(jí)別,每像素4位家凯,每像素2位缓醋,分別比未壓縮的32位紋理格式提供8:1和16:1壓縮率。壓縮的PVRTC紋理仍然提供了一個(gè)體面的質(zhì)量水平绊诲,特別是在4位級(jí)別送粱。有關(guān)將紋理壓縮為PVRTC格式的更多信息,請(qǐng)參閱使用紋理工具壓縮紋理掂之。
OpenGL ES 3.0還支持ETC2和EAC壓縮紋理格式;但是抗俄,建議在iOS設(shè)備上使用PVRTC紋理。
使用較低精度的顏色格式
如果您的應(yīng)用程序無法使用壓縮紋理世舰,請(qǐng)考慮使用較低精度的像素格式动雹。 RGB565,RGBA5551或RGBA4444格式的紋理使用RGBA8888格式紋理的一半存儲(chǔ)器跟压。只有當(dāng)您的應(yīng)用程序需要該級(jí)別的質(zhì)量時(shí)胰蝠,才能使用RGBA8888。
使用適當(dāng)尺寸的紋理
基于iOS的設(shè)備顯示的圖像非常小。您的應(yīng)用程序不需要提供大的紋理來將可接受的圖像呈現(xiàn)給屏幕茸塞。將紋理的兩個(gè)維度減半將該紋理所需的內(nèi)存量減少到原始紋理的四分之一躲庄。
縮小紋理之前,先嘗試壓縮紋理或使用較低精度的顏色格式翔横。使用PVRTC格式壓縮的紋理通常提供比縮小紋理更高的圖像質(zhì)量读跷,并且它也使用較少的內(nèi)存!
將紋理組合到紋理圖集中
綁定到紋理需要時(shí)間才能處理OpenGL ES禾唁。減少對(duì)OpenGL ES狀態(tài)所做更改次數(shù)的應(yīng)用程序性能更好。對(duì)于紋理无切,避免綁定到新紋理的一種方法是將多個(gè)較小的紋理組合成單個(gè)大的紋理荡短,稱為紋理圖集。當(dāng)您使用紋理圖集時(shí)哆键,您可以綁定單個(gè)紋理掘托,然后使用該紋理進(jìn)行多個(gè)繪圖調(diào)用,甚至將多個(gè)繪圖調(diào)用合并到單個(gè)繪圖調(diào)用中籍嘹。修改頂點(diǎn)數(shù)據(jù)中提供的紋理坐標(biāo)以從圖集中選擇較小部分的紋理闪盔。
紋理圖集有一些限制:
- 如果您使用GL_REPEAT紋理包裝參數(shù),則不能使用紋理圖集辱士。
- 過濾可能有時(shí)將紋素移除到預(yù)期范圍之外泪掀。要在紋理圖集中使用這些紋理,您必須在構(gòu)成紋理圖集的紋理之間放置填充颂碘。
- 由于紋理圖集仍然是紋理异赫,它受到OpenGL ES實(shí)現(xiàn)的最大紋理大小以及其他紋理屬性的約束。
Xcode可以從圖像集合自動(dòng)為您構(gòu)建紋理地圖集头岔。有關(guān)創(chuàng)建紋理圖集的詳細(xì)信息塔拳,請(qǐng)參閱Xcode幫助。此功能主要面向使用Sprite Kit框架的開發(fā)人員峡竣,但任何應(yīng)用程序都可以使用它生成的紋理圖集文件靠抑。對(duì)于項(xiàng)目中的每個(gè).atlas文件夾,Xcode在應(yīng)用程序包中創(chuàng)建一個(gè).atlasc文件夾适掰,其中包含一個(gè)或多個(gè)已編譯的圖集和屬性列表(.plist)文件颂碧。屬性列表文件描述構(gòu)成圖集的各個(gè)圖像及其在圖集圖像中的位置 - 您可以使用此信息來計(jì)算在OpenGL ES繪圖中使用的適當(dāng)紋理坐標(biāo)
使用Mipmap來減少內(nèi)存帶寬使用
您的應(yīng)用程序應(yīng)該為所有紋理提供mipmap,除了用于繪制2D未縮放圖像的紋理攻谁。雖然mipmap可以使用額外的內(nèi)存稚伍,但它們可以防止紋理偽影,并提高圖像質(zhì)量戚宦。更重要的是个曙,當(dāng)較小的mipmap被采樣時(shí),從紋理存儲(chǔ)器中取出較少的紋素,這降低了圖形硬件所需的存儲(chǔ)器帶寬垦搬,從而提高了性能呼寸。
GL_LINEAR_MIPMAP_LINEAR過濾器模式在紋理化時(shí)提供最佳質(zhì)量,但需要從內(nèi)存中提取額外的紋素猴贰。通過指定GL_LINEAR_MIPMAP_NEAREST過濾器模式对雪,您的應(yīng)用程序可以交換一些圖像質(zhì)量以獲得更好的性能。
將mip地圖與紋理圖集相結(jié)合時(shí)米绕,請(qǐng)使用OpenGL ES 3.0中的TEXTURE_MAX_LEVEL參數(shù)來控制紋理的過濾方式瑟捣。 (此功能也可通過APPLE_texture_max_level擴(kuò)展名在OpenGL ES 1.1和2.0中使用。)
使用多重?cái)U(kuò)展而不是多次通過
許多應(yīng)用程序執(zhí)行多次通過以繪制模型栅干,改變每次通過圖形管道的配置迈套。這不僅需要額外的時(shí)間來重新配置圖形流水線,而且還需要為每次通過重新處理頂點(diǎn)信息碱鳞,并在稍后的傳遞中從幀緩沖區(qū)讀回像素?cái)?shù)據(jù)桑李。
iOS上的所有OpenGL ES實(shí)現(xiàn)至少支持兩個(gè)紋理單元,大多數(shù)設(shè)備至少支持八個(gè)窿给。您的應(yīng)用程序應(yīng)該使用這些紋理單元在每次通過中在算法中執(zhí)行盡可能多的步驟贵白。您可以通過調(diào)用glGetIntegerv函數(shù),將GL_MAX_TEXTURE_UNITS作為參數(shù)傳回應(yīng)用程序的紋理單元數(shù)崩泡。
如果您的應(yīng)用需要多次傳遞來渲染單個(gè)對(duì)象:
確保每個(gè)通行證的位置數(shù)據(jù)保持不變禁荒。
在第二和后期階段,通過使用GL_EQUAL作為參數(shù)調(diào)用glDepthFunc函數(shù)來測(cè)試模型表面上的像素