draw call を減らした話
「何をもたついているんだ?」
「もういっぱいなんだ..」
「何がいっぱいなんだよ?」
「絵だよ png が... Sprite がいっぱいで...」
「こういう時は頭を冷やそう。一つずつ確固撃破するから大変なんだ。まとめてパッっとやっちゃえばいいんだよ。」
プログラマの吉田です。
季節の変わり目ですがみなさま体調はいかがでしょうか?
今回はまじょのおしごとで draw call を減らしているお話をします。
スマホアプリでは GPU というハードウェアを使用して画面を描画しています。 GPU は描画をする時に draw call というものを発行します。 グラフィックの処理というの重たい処理なのでこの draw call をいかに減らすかによってゲームが速度的に快適に動くかどうかが決まります。
cocos2d-x で draw call を減らすために
- SpriteSheet を使ってシーン毎に画像をまとめる
- 可変ではない Text は 画像に差し替える
- 独自のレンダリングを行う UIText などの Node の global Z order を変える
- bitmap フォントを使う
を行いました。するとホーム画面で 119 発行していた draw call が 3 にまで減りました。 多少処理を止めている部分があるのでもう少し増えるとは思いますが劇的な改善過ぎて僕達も驚きました。
具体的にはバトルの画面で「可変ではない Text を画像に差し替える」例をご紹介します。
Xcode の debug ナビゲーターでは「実機デバッグを行っている場合」に「FPS」の解析が出来ます。
上のように1、2、3とクリックすると
このように GPU が何をやっているのかを解析できます。 ここでは draw call が 60回行われています。 これの glDrawElements で何を描画しているのかを検証します。 上のスクリーンショットだとまず背景や各パーツを1度に描画しています。 その次の glDrawElements に移ると下のようになっていました。
このスクリーンショットでは敵魔法陣の「Next↑」という Text を描画していました。
cocos2d-x の ver 3.0 以降 では画像の描画は同一の Texture に Pack している限りなるべく同時に描画するように renderer が改善されました。 しかしながら画像と画像の間に Text などがあると順番に描画してしまうため余分に draw call がかかります。
この 「Next↑」というのは特に変更することは無いので imagemagick を使い 画像にしてしまって差し替えてみます。
$ convert -font ~/project/oke-ya/zeron-ui/WitchProject/cocosstudio/fonts/APJapanesefontT.ttf -pointsize 32 -background none -fill "#FF8844" label:"Next↑" next.png
というコマンドで next.png を生成し cocosstudio の CSI で pack します。
そしてさきほど Text だった ものを画像と差し替えます。
そして再度 Xcode で解析をすると下のように一度に描画してくれるパーツが増えました。
そして draw call が 57 になりました。 これでバトルの時の動きがもっさりしていたというのも改善出来ました。
ゲーム開発者からすると知ってて当然という内容だとは思います。 しかしながらどのような事でもやり始めたころは初心者です。初心者は様々なところに躓くものです。躓いた結果残念なバージョンをリリースしてしまった事に対しては非常に申し訳ありませんでした。しかしながらこのように日々改善するよう努力をしております。またこのようにそのノウハウを公開することで今後ゲームを開発しようという方の助けになれたならば幸いです。cocos2d-x のレンダリングについては cocos2d-x ユーザーしかうれしくありませんが、 Xcode で GPU のレンダリングのデバッグが出来るというのは全ての iOS 開発者が知っていたら便利な事です。
このようにスマホゲーム開発のノウハウもいろいろ貯まってきました。ですので今後もっと良いものが作れると思います。具体的にどうという明言は避けておきますが、今後にもご期待ください。