LoginSignup
352
262

More than 5 years have passed since last update.

過去に開発した、高難易度案件の技術概要

Posted at

自分語りすみません。自己紹介ついでです

自己紹介

学生の頃ふと図書館においてあった古いゲーム雑誌に

「ゲーム業界では服装も髪も自由だ。黒髪でリクルートスーツ着ている人より、金髪でラフな服装をしている人のほうが きっとエンタテイメントな人生をおくってるに違いない。ゲーム業界では独創的な人は大歓迎だ」
といったリクルート記事をみて 一瞬でゲームプログラマに決めました

学生時代は勉強は出来たけど、集団生活や 授業を聞くことが出来ず常に授業中走り回ってました
大学も3ヶ月で教師と喧嘩して辞めて 東京に出て フリーでビジネスプログラミングをしました
高校時代に ゲームを逆アセンブルして、グラフィックローダや音楽ドライバ等を高速化して
会社に送りつけたりしてたので、すんなり仕事はできました
そこからは お金がほしい時はビジネスプログラム、夢がほしい時はゲームプログラムと
業界を行ったり来たりし、ソーシャルゲームバブルで ゲーム業界がビジネスと同じ金額になってからは
だいたい ゲーム・エンタメ系で仕事しています
5年前に チームを組んで仕事を請けはじめ、会社を作ったほうが便利だったので起業
就職経験は結局ゼロです

今は 社員1名と外注が6名ぐらいで仕事まわしています

最初のゲームの仕事

ネット掲示板で、コンシュマー会社がDirectXやCOM、通信、Linuxの経験がなく
色々と回答していたら 採用したいと言われ、バイトでならOKと入った
大手ゲーム会社の R&Dで、ゲームセンター(アーケード基盤)と 家庭PC(DirectX)をインターネットでつなぎ
対戦ゲームを行う 研究開発
当時ゲーム会社ではノウハウがなかった ネットワーク、DBの知識が ビジネスで鍛えた私にマッチした
それに比べ趣味でDirectXを触っていたのが役に立った
しかし その会社の副社長のデザイナーが酒乱で酒を飲んだら暴れて迷惑かけるので
酒の席について口論となり 辞めた
私はお酒を1滴も飲めない体だけど、お酒は迷惑かけないように みんなが楽しくなるように飲んでください

PCと特殊ハードを使った独自3Dエンジンゲーム メイン

特殊ハードをつかった アーケード端末
なぜ DirectXを使わずに独自3Dエンジンなのか・・・というと
元々はDirectDraw(2D)とDirect3D のコンポーネントが別れていて
Direct3Dが出た当初はパフォーマンスが悪く、3D部分は自分でアセンブラ入れて自作して
DirectDrawで描画するのが速かったのと
Direct3Dはデバイスごとに使用できる機能が異なりビデオカード対応が面倒だし動かないマシンも多く
それなら 自分で3D作ったほうが、DirectDrawの互換性だけ保てばいいので楽だったから

ところが nVidiaのハードウェアT&Lにより、ジオメトリ演算がGPU上でハードウェアパイプラインになり
Direct3Dも高速化し
自作3Dでは既に速度が絶対勝てなかったけど
互換性のために 自社で3Dエンジンを作る といわれ
メインプログラマとして 殆どを作った
3DCGの知識もその時に作りながら全部覚えた

PS2

悪名高いPS2
会社は大手だったけど、ゲーム会社としては知名度がなく、まともなライブラリももらえず
自社でライブラリを作る事になり、ライブラリを作れる人がいないので私が駆り出された
3Dエンジンぐらいなら・・と 気楽に請けたんだけど
DMAの調停から行わなければならない、サウンド鳴らすには命令をDSUに送って・・・
メモリアロケータもなければ なんにもなく
カーネルから作るとは思ってもみなかった・・

そして、VU0とVU1である
当時はまだ プログラマブルシェーダがなかったので画期的で
今で言う 頂点シェーダのようなものである。
しかし アセンブラで記述する必要があり、しかも SIMDとMIPSの2コアあり
それらがレジスタを共有して並列で動くので 並列アセンブラ!!
という 謎な技術でびっくりした

後にも先にも あんな変態なハードウェアは出てこないと思う。。。
ほんと びっくりしたけど ゲームエンジンと タイトル2本作り上げた

DirectX11のアバターレンダリングサーバ

レンダリングサーバを作るだけなら簡単だが、パフォーマンス要求が恐ろしかった
元々2Dレンダリングで秒間50だったのを 秒間100は必要と言われる
しょっぱなの目標から絶望的だったが、結果的に 秒間800オーバーの数字を叩き出した
2GPUの案件

Deferredコンテキスト

まず、当時出たばかりのDirectX11を利用した理由は Deferredコンテキストのためである
(ライティングを遅らせる Deferred レンダリングとは全く違うもの)
通常は 1つのレンダリングコンテキストが終了してから次のレンダリング命令をGPUに送るのだが
その部分を非同期にし、レンダリング処理中にテクスチャ転送したり、次のレンダリングのための設定を送ったり出来る
技術的には はじめての機能で多少むずかしかった

MultiThread Socket

マルチスレッドによるSocketにしたのは
非同期も試したが、1接続の処理が重く、20接続以上に増やしても GPUがボトルネックになりさばけない
また、CPUのコンテキストスイッチコストもあるため、同じコアにスレッドを固定するほうが速く
けっか マルチスレッド型にした

コンカレントリスト

アバターのアイテム数が何十万とあり、全部がGPUメモリには乗らないので
よく使われるアイテムはGPUに、そうでないものはメインメモリに、あまり使われないものはHDDに
と 3段階のキャッシュシステムを作った
そして メモリ効率のため、それらはすべてのスレッドからアクセス出来るようにした
そのため、スレッドセーフなコンテナが必要であった
その時の候補として IntelTBB、Silk などがあった
結局 IntelTBBを使ったが、Silk++ のほうが速くなったかもしれない

64ビットアセンブラ

最近のC++コンパイラは人間がアセンブラ書くより速く最適化する
まー 実際は熟練者がアセンブラ書けばコンパイラに勝てるのだが、コンパイラで十分である
ただし、SIMDが使える大量データの処理においては 未だに人間が書けば大きくパフォーマンスアップ
出来る場所が多い
ので その部分をアセンブラにした

CUDA

減色処理やデータの変換、Jpeg化などは SIMDアセンブラ使うより GPGPUのほうが速い
DirectComputeやOpenCLを使ってみたが、CUDAでかくのが最も速かったのでCUDAにした
ただし、システム自体がGPUがボトルネックになっているので、スレッドのうちのいくつかはCPUで処理するようにしたり。。

アニメパース

3DCGだと中心からずれると歪む。
例えば二人横に並んでいると 2D絵では二人が並んでまっすぐ前に向くが
3Dだと中心に向かって少し斜めに見える(リアルでは正しい)
ところが アニメに慣れていると それでは違和感を感じるため
透視変換行列を二人かえることで 正面を向くようにしたり
勇者ポーズ等で極端に手前のものが大きくなるよう ジオメトリを変更する機能をいれた

OIT

知っての通り半透明は重ねる順番で色が変わる
そのため、半透明の順番を制御するためのアルゴリズムが必要だが
ちゃんと処理すると非常に重い・・・
が、一応対応した

ジオメトリシェーダ、マルチレンダーターゲット

レンダリングエンジンでは アニメーションをコマ送りでレンダリングし動画にしている
同じモデルを数コマレンダリングするので、レンダーターゲットを変え ジオメトリシェーダで異なるボーンを適用させることで
複数コマを1回のレンダリングパスで処理可能である

ドライバの不具合

秒間200程度なら普通に動くが、それを超えるとブルースクリーンになり落ちる
明らかにドライバに不具合があるので メーカーに相談し、しばらくしたらドライバの不具合が改善した

サーバでの工夫

上記本気で対応して 秒間800を超えて、企画的にはそれ以上高速化不要だったが
最も簡単に高速化できるサーバの問題を見過ごすわけにはいかず
アバターの生成において ハッシュを使いリバースプロキシを頑張った
ハッシュもMemcachedを使い、複数のサーバからも高速アクセス可能に

また、レンダリングエンジン内部のキャッシュヒットを高めるため、サーバが複数たっていたら
アバターのベースごとに、優先するレンダリングサーバを自動的に分散させるシステムも作った
ただし 上記のキャッシュとあわせて、爆速すぎて 10台可動必要な予定が 1台の可動で十分だったため
永遠に分散されることはなかった

上記レンダリングエンジンのスマホ化

時はスマホ。上記レンダリングにつかったモデルをつかってゲームエンジン作成をした

C++ JNI

AndroidはJava、iPhoneはObjective-Cであるが
Javaで作ると遅いし、2つのエンジンをメンテしたくないので
C++でエンジンをつくり、JNIなどを使い AndroidやiPhoneから呼び出す事にした
結果は大成功だと思う
フロント側の要望で 例外入れてほしいとか言われたが、当時のNDKは例外非対応
だったが、無理やり exceptionやrttiライブラリを組み込み 例外に成功

ボーン数とウェイト

モデルは255本ボーン4ウェイトだった
頂点ウェイトをモデルロード時に2ウェイトに削る処理は簡単に出来る
が、スマホのGLES2.0では uniformレジスタが128本であり 2ウェイトでもせいぜい30ボーンしか扱えない
グラフィック的にボーンの数をそこまで減らすことが不可能なたえ しかたなく
CPU上でスキンメッシュをすることにした
高速化のために全部アセンブラ(NEON)で書いた
コマ数が比較的少なかったため、一度にコマ数ぶん スキンメッシュ適用後の頂点データを保存しそこからレンダリングできた
ただ、それだと カメラを動かした時に スキンメッシュ処理を待っていると1秒ラグるので
1コマずつマルチスレッドでなる早で計算し
1コマ目が計算終えたらはじめて 新しいモーションでレンダリングして・・
と 遅延がなるべく見えないように 工夫をした

右手左手座標問題

DirectXでは左手座標、OpenGLでは右手座標のため
DirectXのモデルをそのまま使う必要があったため、扱いに苦労した

機種問題

Galaxyシリーズ、Aquosシリーズは ハードや実装が特殊で
対応していない命令があったり、FrameBufferを読めなかったり
その機種だけ遅かったり 色々対応に苦労して
OSのコードまで読むことになった

C++のMMOサーバ

スマホゲームでのMMO的なゲームのリアルタイムサーバ開発
本来は簡単だったが 私がこだわりすぎて 苦労してしまった ごめんなさい

要件

要件は1サーバあたり1000人もさばけば十分
会社の実績的に1サーバ500ぐらいさばけるのでそこから改良してくれ
C++が最も速いのでC++で

会社の実績コードをみて

マルチスレッドじゃC10K問題で壁が見える。ここは非同期にすべきだ
メッセージ関連でMutex使ってスレッド間で同期をとっているがこれは明らかなボトルネック
これもシングルスレッド非同期にして 同期を防げば早くなる

あなたの資産は使わず 1からBoost.Asioで非同期で作ります

Boost.Asio

まず お客さんに対して、資産をつかわず 非同期で作り直す説明をするための
非同期はすごいぞ 資料を作るのが大変だった
経営者としてバカなことに、それでも もらうギャラは同じなの。
ただ 技術者として、もっと良い技術を知っていて 使わない事はできなかった

ただ 私自身 非同期プログラミングもやったことなく、当然Boost.Asioなんて知らず
STLだってまともに使ったことなかったので
結果的に 泣きそうなほど苦しんだ2週間がある

そのあたりは Qiita記事や SlideShareにいろいろかいてある・・

今現在

C++のサーバいこうは ゲーム作ったり、サーバレスでのゲームサーバや、VirtualYoutuberのシステム開発
あるいは 仮想通貨の取引所の開発
と 色々な仕事をしているが
まだ 苦しむようなものには あたってない

352
262
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
352
262