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

自分語りすみません。自己紹介ついでです  
  
#自己紹介
学生の頃ふと図書館においてあった古いゲーム雑誌に  
「ゲーム業界では服装も髪も自由だ。黒髪でリクルートスーツ着ている人より、金髪でラフな服装をしている人のほうが　きっとエンタテイメントな人生をおくってるに違いない。ゲーム業界では独創的な人は大歓迎だ」
といったリクルート記事をみて　一瞬でゲームプログラマに決めました  
学生時代は勉強は出来たけど、集団生活や 授業を聞くことが出来ず常に授業中走り回ってました
大学も3ヶ月で教師と喧嘩して辞めて　東京に出て フリーでビジネスプログラミングをしました
高校時代に ゲームを逆アセンブルして、グラフィックローダや音楽ドライバ等を高速化して
会社に送りつけたりしてたので、すんなり仕事はできました
そこからは お金がほしい時はビジネスプログラム、夢がほしい時はゲームプログラムと
業界を行ったり来たりし、ソーシャルゲームバブルで ゲーム業界がビジネスと同じ金額になってからは
だいたい　ゲーム・エンタメ系で仕事しています
5年前に　チームを組んで仕事を請けはじめ、会社を作ったほうが便利だったので起業
就職経験は結局ゼロです

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

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

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

ところが nVidiaのハードウェアT&Lにより、ジオメトリ演算がGPU上でハードウェアパイプラインになり
Direct3Dも高速化し
自作３Dでは既に速度が絶対勝てなかったけど
互換性のために 自社で３Dエンジンを作る　といわれ
メインプログラマとして　殆どを作った
３DCGの知識もその時に作りながら全部覚えた  
  
#PS2
悪名高いPS2
会社は大手だったけど、ゲーム会社としては知名度がなく、まともなライブラリももらえず
自社でライブラリを作る事になり、ライブラリを作れる人がいないので私が駆り出された
３Dエンジンぐらいなら・・と 気楽に請けたんだけど
DMAの調停から行わなければならない、サウンド鳴らすには命令をDSUに送って・・・
メモリアロケータもなければ　なんにもなく
カーネルから作るとは思ってもみなかった・・

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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