KLabGames Tech Blog

KLabは、多くのスマートフォン向けゲームを開発・提供しています。 スマートフォン向けゲームの開発と運用は、Webソーシャルゲームと比べて格段に複雑で、またコンシューマゲーム開発とも異なったノウハウが求められる領域もあります。 このブログでは、KLabのゲーム開発・運用の中で培われた様々な技術や挑戦とそのノウハウについて、広く紹介していきます。

※この記事ではgitのタグ「v2.74」からブランチを生成してコードリーディングしています。

CPUなのか?GPUなのか?

前々から疑問に思っていた事がありました。Blenderの画面に表示されている3Dモデル、GPUでレンダリングされているのでしょうか?それともCPUでソフトウェアレンダリングされているのでしょうか?

DCCツールはゲームと違い、モデルの頂点が頻繁に編集されるのでメインメモリからGPUメモリへのデータ転送コストが毎回発生するはずなのでこのような疑問を持ちました。当然マシン環境やDCCツールの機能によってもどちらが適切なのかは変わってるくるはずですが、Blenderはどのような実装になっているのでしょう?

レンダリング部分のコードを突き止める

この疑問の答えを出すためにレンダリング部分のコードを探し出してみましょう。

OpenGLのドローコールが呼ばれていればGPUでレンダリングされていると見ていいでしょうし、CPUでピクセルの配列の色を決定しているようなコードが見つかればソフトウェアレンダリングが使われているということになります。

最終的に該当部分をコメントアウトしてみて、3Dモデルが消えればそこが答えだと証明できるはずです。

part1ではBlenderを立ち上げて何も触らない状態、要するにObjectモードでViewport ShadingはSolidの状態でのレンダリングについて調べてみます。

試しにそれっぽいキーワードでプロジェクト全体を検索してみる

レンダリング部分のコードを見つけ出したいので、手始めに「render」や「draw」でソースコード全体を検索してみます。
  draw -> 21478 results in 773 files
  render -> 15695 results in 802 files
・・・。まあ、わかってはいましたけど大量に引っかかりますよね・・・。これを1つ1つ見ていくのは人間には無理でしょう。

Viewport ShadingがSolidの状態なので「solid」ではどうか?
  solid -> 1484 results in 206 files
これもやっぱり数が多い。

Objectモードなので、「objectmode」ならどうか?
  objectmode -> 42 results in 12 files
おお!これくらいなら1つ1つ見ていく事も可能ですね!

手がかりになりそうなenum値が見つかる

するとこんなenum値が見つかります。

typedef enum ObjectMode {
    OB_MODE_OBJECT        = 0,
    OB_MODE_EDIT          = 1 << 0,
    OB_MODE_SCULPT        = 1 << 1,
    OB_MODE_VERTEX_PAINT  = 1 << 2,
    OB_MODE_WEIGHT_PAINT  = 1 << 3,
    OB_MODE_TEXTURE_PAINT = 1 << 4,
    OB_MODE_PARTICLE_EDIT = 1 << 5,
    OB_MODE_POSE          = 1 << 6,
} ObjectMode;  

Blenderを使っている方ならお気付きかと思いますが、
Mode
モード選択といかにも関係ありそうなenum値ですね。

このenum値の中でObjectモードを指し示しているであろう「OB_MODE_OBJECT」で検索してみましょう。
 OB_MODE_OBJECT -> 32 results in 14 files

いかにも怪しいファイルが

この14個のファイルの中にdrawobject.cといういかにも怪しいファイルがあるのでこれを見てみる事にします。

drawobject.cの中にはdraw_〜〜〜と名前のついた関数がたくさん存在します。この関数の中に該当するものがありそうです。

レンダリング命令の周りのコードにOB_MODE_OBJECTの記述があるかは不明ですが、draw_object()とdraw_mesh_fancy()内にのみOB_MODE_OBJECTが書かれているのでとりあえず追ってみます。

この2つの関数の先頭にブレイクポイントを張って実行してみると、2つとも引っかかるようです。

ここでわかるのは、  draw_object() -> draw_mesh_object() -> draw_mesh_fancy() という構造で各関数が呼ばれている事です。

draw_object()でdraw_mesh_object()を呼んでいる場所のswitch文は

        switch (ob->type) {
            case OB_MESH:
                empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);

となっており、OB_MESHの定義に飛んでみるとオブジェクトのタイプ(??)がいくつか定義されているのでこれは狙っているオブジェクトのレンダリング部分につながっているかもしれません。

試しにこのempty_object = draw_mesh_object(...の行をコメントアウトして実行してみましょう。するとデフォルトで表示されているはずのキューブが丸ごと消えます!
default
↓↓↓
draw_mesh_object
このコメントアウトを取り消して行を復活させ、今度はdraw_mesh_object()でdraw_mesh_fancy()を呼んでいる場所をコメントアウトしましょう。すると同じくキューブが丸ごと消えます。

オブジェクト選択時のオレンジ色のアウトラインも一緒に消えてしまうので、アウトラインのレンダリングもdraw_mesh_fancy()に含まれていると言えます。

ゴールは近い!!

確認の意味も含めて、アウトラインを残してオブジェクトの面のみを消してみたいですね。

面の色の塗り方はViewport Shadingの設定によって変わります。ですので全体検索では大量に引っかかってしまった「solid」で今度はdraw_mesh_fancy()の中を検索してみます。するとヒットするのは9カ所。これくらいであれば1つ1つ追っていくのは簡単ですね。

9カ所全て見ていくと、drawFacesSolid()といういかにもそれっぽい関数が4カ所で呼ばれているのがわかります。drawFacesSolid()の呼ばれている箇所を上から順に見ていくと、
 1番目:enum値OB_MODE_TEXTURE_PAINTを使ってオブジェクトのモードを判断しているif文内にあるので該当しなさそう
  (2番目〜4番目はOB_SOLIDが条件に使われているif文内にあるので怪しい)
 2番目:if (draw_flags & DRAW_MODIFIERS_PREVIEW)という条件なので違いそう
 3番目:if文の条件を見るとスカルプトに関連していそうなので除外
 4番目:if文的に2番目ではないかつ3番目ではないのでこれが正解のはず。
よって4番目をコメントアウト。
goal
オレンジのアウトラインを残し、面のみが消えました!!
さて、コメントアウトをもとにもどします。

drawFacesSolidは関数ポインタになっているので、実際に呼ばれる関数を追ってみます。

4番目のところにブレイクポイントを張り、Step into。

するとcdderivedmesh.cの中の

static void cdDM_drawFacesSolid(DerivedMesh *dm,
                                float (*partial_redraw_planes)[4],
                                bool UNUSED(fast), DMSetMaterial setMaterial)

にたどり着きます。

この中でOpenGLの命令であるglDrawArrays()が呼ばれているので、Objectモードに関してはソフトウェアレンダリングではなく、GPUを使ってレンダリングを行っている事がわかって当初の疑問が解消され・・・

いや、待てよ

ObjectモードについてはGPUレンダリングが行われているのがわかりました。

でも最初に書いた「モデルの頂点が頻繁に編集されるのでメインメモリからGPUメモリへのデータ転送コストが毎回発生する」のは主にEditモードでした。

というわけで、part2につづきます。


@fmystB

プログラマのfmystBです。

普段3D関連のプログラミングをする事が多いのですが、様々な局面でちょっとしたテスト用のモデルが欲しくなる事があります。でもわざわざアーティストに頼むほどでもない・・・。そんなときBlenderが使えると便利でして、日頃とてもお世話になっています。

毎日のように仕事でBlenderに触れているうちに、内部の仕組みを知りたくなって来たのでコードリーディングにチャレンジしようと思います。

宝が星の数ほど

Blenderには数多くの3DCG技術が集約されているので、コードを読んで楽しい場所はたくさんあるはずです。

Modifiersや物理シミュレーション部分のコードには特に興味があります。

オブジェクトの形状を便利に編集できるModifiers機能には高度な幾何学が使われていると思いますし、物理シミュレーションにはプリレンダリングの技術が使われているのでリアルタイムレンダリングとは違ったアルゴリズムを知る事が出来るでしょう。

他にも、マシン環境によっては有効となるCUDAオプションのコードを追いかけてみるのもGPGPUプログラマにとっては面白そうですし、Pythonハッカーな人はスクリプト機能の部分に興味があるかと思います。

全てを知ろうとするな

このようにプログラマにとって刺激的な内容にあふれたBlenderですが、 BlenderWikiのDev:ContentsNew Developer Info にこんな注意書きがあります。

「Don't choose a project that spans across many files and areas of Blender, since you may get bogged down trying to understand everything at once.」

Blenderは規模が大きいだけに、一度に全てを知ろうとすれば泥沼にはまるようですね。興味がある部分に絞って理解を深めていくのが長続きするポイントのようです。

ですのでこの連載でも気の趣くままに、面白そうな部分だけピックアップして紹介していきます。

準備

環境としてはMacのXcodeを使い、ソースを読むだけではなくブレイクポイントを張りながら実行する事で動作を確認していきます。(後の記事でも触れるつもりですが、Blenderはいたる所で関数ポインタを使っているのでステップ実行せずに読み進めるのはキツいです><)

ソースコードの管理はGitが使われており、ダウンロードからXcodeプロジェクトの生成まではこちらに書かれている通りです。

コマンドラインのみでビルドする方法も書かれていますが、今回はXcodeでビルドしてBlenderを起動する事が目的なのでそこまでの設定が出来れば大丈夫です。

また、ここで書かれている事の他に、Blenderは頻繁に更新されてしまうのでコードリーディング用のブランチをtagから作成しておくと便利です。この記事を書いている時点では2.74が最新安定板なので、「v2.74」というtagからブランチを作成してしばらくそこでコードリーディングを進めていきます。


@fmystB

KLabGames Tech Blogとは

KLabGames Tech Blogは、KLabの新しい技術ブログです。 これまでの、「若手エンジニアのブログ」と、 「データ分析グループのブログ」を整理して、 KLabのゲーム開発の技術を紹介するブログとして新しく作られました。

KLabでは、多くのスマートフォン向けモバイルオンラインゲームを開発・提供しています。 モバイルオンラインゲームの開発と運用は、Webソーシャルゲームと比べて格段に複雑で、 またコンシューマゲーム開発とも異なったノウハウが求められる領域もあります。 このブログでは特に、「DSAS開発者の部屋」だけではカバーしきれない、 KLabのゲーム開発・運用の中で培われた様々な技術や挑戦とそのノウハウについて、 幅広く紹介していきたいと思います。

誰が書くの?

社内のエンジニアが誰でも記事を書けるような仕組みを構築しました。 今後、KLabの様々な技術領域を専門とするエンジニアが、 モバイルオンラインゲーム開発で得た技術や経験を紹介していきます。 また、ゲーム開発ではエンジニア職以外でも技術的な課題を扱いますので、 ゆくゆくはゲーム開発に関わる全職種が記事を書くような体制を目指します。 ご期待ください。

どんな内容を扱うの?

KLabの技術ブログといえば 「DSAS開発者の部屋」 をご存じの方も多いかと思いますが、 こちらはインフラおよびR&D関連の記事が中心です。 それに対し、「KLabGames Tech Blog」では、 現在KLabのビジネスの中心となっているモバイルオンラインゲーム事業の技術側面のアウトプットを、 積極的に行っていきたいと考えています。

では、モバイルオンラインゲームを支えている技術とはどのようなものでしょうか。 例えば、

  • Unityや自社ゲームエンジンPlaygroundを活用したゲーム開発の実際
  • PHPやPythonで構成するサーバーサイドの技術
  • シェーダーなどの3DCGの技術
  • Jenkinsやパイプライン、Unityエディタ拡張などの自動化やツールの話題
  • AIやゲームロジック・アルゴリズムなどの話題
  • ゲームのバックグラウンドで頑張っているデータ分析の話題
  • 同期対戦などの、ネットワークの話題

他にも様々な話題があると思います。 これらの幅広い技術領域を、広く深く紹介していきます。

最後に

KLabは、「世界と自分をワクワクさせろ」というビジョンを持っています。 私たちは、ゲームを通してユーザーさんにワクワクを届けるだけでなく、 このブログを通してゲーム開発者の皆さんにも、 KLabらしい技術的な『ワクワク』をお伝えしていきたいと考えています。

よろしくお願いいたします。

↑このページのトップヘ