Cocos2d x與OpenGL底層的感想

2021-08-02 23:32:33 字數 2835 閱讀 3570

這篇文章想寫一些工作經常碰到的一些問題,為什麼我做乙個2d遊戲,渲染100多個精靈就會卡。

他們同樣是做2d遊戲,為什麼渲染那麼多東西幀數非常高,一點卡頓的樣子都沒有?

這裡我們排除一些邏輯因素,在相同遊戲邏輯複雜度下。我每幀也沒什麼邏輯運算也還是卡,這裡我們首先排除掉cpu對於遊戲幀數瓶頸的限制。我們來談下,為什麼都是2d遊戲,我渲染那麼少的東西就會卡。其他遊戲2d大作渲染那麼多東西還是很流暢!

opengl是個非常老舊的渲染api,api層非常單薄,僵硬,程式設計師能控制的東西非常少,無非就是資源的生成,控制一些渲染快取的狀態,呼叫draw介面。其實在現在硬體變革好幾代之後api還是那樣子,已經跟不上硬體的速度。而且手機遊戲中為了相容性問題,一般遊戲都是用opengles2.0這個版本,造成對於硬體效能的浪費。

打個比方如果一台手機可以本來的渲染效能可以渲染基準效能是100分,但是影象介面的問題和驅動層優化問題只能發揮到70分,渲染引擎設計問題繼續砍半只能發揮40分,如果程式設計師對於引擎不夠了解只能發揮到30。這樣就造成貌似機器效能在飛速發展,但是有些遊戲的畫面提公升不是很快。

當我們無法改變圖形介面和驅動的時候,我們能否把可以控制的70分給壓榨出來,就是考驗乙個遊戲廠商的實力(大廠商跟硬體公司合作非常密切,而且單一平台上對於優化更好,所以ps4和xbox的遊戲畫面一直比單機好點。很多硬體廠商會為了某個遊戲還會去優化顯示卡驅動,他們示可以拿到80分甚至90分的效能,小公司是沒有那個待遇的)。

其他設計硬體和渲染管線問題以後提。這裡簡單說明單純的渲染api的呼叫,這個也是最好理解的。opengl是狀態機設計模式,每次呼叫乙個api都會去改變渲染管線中某個功能開關。我們每次呼叫乙個api,就會生成乙個指令。這個指令告訴顯示卡怎麼去做,這邊是有效能損失的。(api呼叫opengl渲染是非同步的過程,在緩衝區中會維護乙個渲染命令佇列,在某個時機去傳送給驅動層怎麼做,驅動做的事情以後再說。這個時機可以我們手動去觸發glflush強制傳送,但是我們一般沒有需求不推薦。我們這裡可以理解呼叫openglapi成同步的。)所以盡量的少呼叫opengl api渲染效能就上去了。說了也是白說,我要畫那麼多東西,當然要多調介面了,不調介面我怎麼畫。

這邊就引出乙個問題,我怎麼少呼叫api,但是可以多畫東西呢?批次渲染是最通用也是最簡答的做法!

如果我們把一次渲染比作一群人出遊,在乙個停車場中。大家準備排隊上車。每輛順序出口出去。但是停車場有個奇怪的規定:相鄰穿相同顏色衣服的人可以坐同一輛車出去,如果後面乙個如果穿不同顏色衣服人,那麼就得新配一輛車。假如100個人穿100種顏色的衣服,那麼就得100輛車,如果100穿相同顏色的衣服話只要一輛車。如果排隊順序是a.b.c.d  ab如果都穿紅色站一起一輛車,c綠一輛車,d紅色一輛車。這樣就三輛車。如果調換下abcd順序變成 a.b.d.c,

這樣就變成兩輛車。車越少,那麼全部離開停車場越短,更快到目的地旅行了。批次渲染就是勁量讓穿相同顏色人,塞進同一部車中。更快的出去。

在一般的遊戲引擎中,我們都會有乙個渲染的佇列,每個渲染單元抽樣成乙個渲染命令。每個命令都會去呼叫opengl api。

如果兩個渲染命令一起的畫,我們是否可以把兩個命令合成乙個命令呢?因為opengl是狀態機啊,第乙個命令狀態設定後,第二個命令無需重新去設定渲染狀態。這樣不就少呼叫api 但是畫一樣的多東西!這個就是批次渲染的概念。

我們今天只談下2d遊戲,在2d遊戲每個渲染命令涉及到opengl api其實比較少了,設定shader  繫結texture,drawelements差不多就這三樣,

一般精靈的shader是一樣的,這個我們是可以合併的。這個比較簡單。

texture紋理,每個精靈都有自己的紋理,沒辦法合併啊!其實有辦法,把兩張小圖拼成一張大圖,設定頂點資料的uv座標!搞定這個也可以合併。

drawelement 這裡我們渲染圖元基本都是三角形,如果把三角形的頂點資料放在乙個vbo中。那麼也是可以合併。

cocos2d 最早以前有個型別叫batchnode,這個型別地下繫結精靈如果是同一張紋理的就會生成乙個批次渲染,但是這個不是很好用,如果美術改了資源的,有個子節點不是用大圖裡面紋理會出問題。後面3.x版本,cocos2d-x推出乙個技術叫(auto-batching)、在深度優先的子節點遍歷情況,相鄰節點如果材質相同就自動合併批次。所以貼圖相同的精靈我們是可以合併批次的。

第乙個基準測試,我們上面都不渲染,只是單純控制cocos2d-x不到滿幀,等下好對比。

第二個我們是使用三張分開圖的測試。

void

testscene::drawpartsprite()

;

for (int nindex = 0; nindex < kdrawnodenum; ++nindex)}}

第三個我們使用一張合併圖,其實裡面東西都一樣的。

void

testscene::drawtogethersprite()

;

for (int nindex = 0; nindex < kdrawnodenum; ++nindex)}}

資源就這樣,非常簡單

非常簡單的三個,分開渲染是三張分開的,合併渲染是用乙個合圖。

其實**基本相同。為什麼效能竟然有那麼大的差距。如果除去cpu效能就是基本效能的消耗。在極端的情況下,我們基本可以達到三倍的提公升,三倍其實是個很誇張的資料了。

如果遊戲中,如果遊戲中精靈批次命中稍微高點,即使對於效能提高10%到20% 對於效能的優化也是有好處的,而你所需要做的可能就是選擇好去合併成一張大圖。

COCOS2DX 場景與層

runscene scene 啟動第乙個場景時使用 popscene 與pushscene配合使用,可以回到上乙個場景 poptorootscene 與pushscene配合使用,可以回到根場景 2.場景過渡動畫 由transitionsecene和它的子類展示 3.場景的生命週期函式 ctor建構...

cocos2d x 資源集合

官網 主席子龍山人 archive 2011 08 08 2131019.html kmyhy的專欄 老g的小屋 cocos2d xtouch事件cocos2d 事件冒泡規律 和 ccmenu一直響應事件的解決辦法 swallow touches how to setmultipletouchena...

cocos2d x 開篇介紹

關於cocos2d x這一遊戲引擎,現在受到了手機遊戲開發者的青睞。其實cocos2d一開始是由於cocos2d iphone的成功,然後帶動各類開源專案越來越火。由蘋果獨家的objective c到了流行的c 支援了更多平台。cocos2d x中的 x 是什麼意識呢,其實其中包含著兩層含義 1 代...