real-time 3d programming in scala

20
+ ScalaLWJGLリアルタイム3Dプログラミング @chimerast たけうちひでゆき

Upload: hideyuki-takeuchi

Post on 23-Jun-2015

2.007 views

Category:

Technology


6 download

TRANSCRIPT

Page 1: Real-Time 3D Programming in Scala

+

ScalaとLWJGLで リアルタイム3Dプログラミング

@chimerast たけうちひでゆき

Page 2: Real-Time 3D Programming in Scala

+自己紹介

n たけうちひでゆき n  Twitter: @chimerast n  Blog: http://chimera.st/ n  Scala歴: 1ヶ月ぐらい n  LWJGL歴: 3週間ぐらい

n 永遠のNEET n  普段はWeb/ネットワーク系プログラマの仮面をかぶってます。 n  Seasar Foundationの隅っこの方でS2Wicketを1.4以降作っています。 n  wicket-ja, java-ja

n リアルタイム3Dプログラミングとのつきあい n  大学浪人中に3D横スクロールシューティングゲームを作ったくらい n  DirectX7 Immediate Mode(直接ポリゴン描くモード)でごりごり作ってました

Page 3: Real-Time 3D Programming in Scala

+新しく勉強する言語で ゲームを作ることのすすめ

n とりあえず目標ができる n  動くものができて成果を確認しやすい

n 意外に多種のデータ構造を使うことになる n  あまり複雑な使い方はしないため勉強には最適 n  ファイルの入出力とかも一通り網羅

n パフォーマンスの確認もできる n  やっちゃいけない操作とかがわかる

n 高校数学を役に立たせることができる? n  行列とか複素平面とか三角関数とか n  頭の体操

Page 4: Real-Time 3D Programming in Scala

+今回のお題 Scalaでリアルタイム3Dプログラミング

n 目的 n  リアルタイム3Dアクションゲーム(or シューティング)を作る

n とりあえずの目標 n  ゲームで使うためにMikuMikuDanceの3Dモデルデータ・アニメーションデータを読み込めるようにする

n 今使用しているライブラリ等 n  Scala

n  LWJGL

n  Slick

Page 5: Real-Time 3D Programming in Scala

+MikuMikuDance

n ニコニコ動画で人気の3D動画制作ツール n  http://www.geocities.jp/higuchuu4/

n  キャラクターをおどらせたりことができる

n  DirectXで動作

n 作ろうとしているゲームでファイルフォーマットを流用 n  ソフト自体やツール類が多数フリーで公開

n  スキンメッシュアニメーションに対応している

n  物理演算にも対応している

n  JVMで動かして大丈夫かどうかは不安

http://www.nicovideo.jp/watch/sm9647253

Page 6: Real-Time 3D Programming in Scala

+Scala A Scalable Language

n オブジェクト指向言語+関数型言語 n  といわれているが他にも便利な言語機能が多数ある

n データの変換処理の記述が得意、だと思う n  Javaだと数十行に及ぶようなコードが1行で書けることも

n  3Dファイルフォーマットを読み込むのが非常に楽だった

n  Javaで冗長だったコードが排除できる n  型推論による変数宣言時の型指定

scala> List(3,2,5,1).reduceLeft(math.max) res0: Int = 5

Page 7: Real-Time 3D Programming in Scala

+LWJGL Lightweight Java Game Library

n ゲームを作りに必要なライブラリ類のラッパ+ユーティリティ n  http://www.lwjgl.org/ n  OpenGL

n  3DグラフィックスAPI n  三角形の座標を変換したり画面に描いたりできる

n  OpenAL n  クロスプラットフォーム3DオーディオAPI n  とりあえず音が出せるっぽい

n  OpenCL n  GPGPUと呼ばれるGPUに汎用的な計算をさせる為のAPI

n  ゲームパッドやキー入力イベント管理 n  その他行列演算のクラス等々

Page 8: Real-Time 3D Programming in Scala

+Slick 2D Game Library based on LWJGL

n 簡単にLWJGLを使った2Dゲームを作るためのライブラリ n  http://slick.cokeandcode.com/

n  LWJGL(OpenGL)は単純な2Dゲームを作成するには低レベルすぎる

n 今回はテクスチャの読み込みに使用 n  2Dゲームでなくても使える便利なクラスが多数用意されている

n  フォントの描画

n  各種サウンドデータフォーマットの読み込み

n  SVGとかも読み込めるっぽい

Page 9: Real-Time 3D Programming in Scala

+LWJGLを使った簡単なプログラム デモ・コード解説

n  https://github.com/chimerast/scala-lwjgl-sample n  ビルドにはsbtが必要です

n ただ三角形を描くプログラム n  でも3Dモデルを構成するポリゴンと呼ばれるものはただの三角形の寄せ集め

n  →三角形さえ描ければ3Dモデルが描ける

n  LWJGLはnativeなライブラリがあるためjava.library.pathを正しく設定してやる n  sbtの場合はプロセスをforkする設定をする(詳しくはコードで)

Page 10: Real-Time 3D Programming in Scala

+作っているもののデモ

n  3Dモデルを読み込める

n  スキンメッシュアニメーションができる

n  IKボーンには非対応(足とか)

n  物理演算には非対応

n  シェーダープログラミング

n  トゥーンシェーディング

n  フォンシェーディング

n  境界線描画

n  ポリゴン拡大法(?)

Page 11: Real-Time 3D Programming in Scala

+フレーム制御型 ゲームプログラミングの特徴

n 毎フレーム毎に画面の再描画を行う n  基本的に全部一から書き直す

n  理想は60fps(1秒間に60回描画)

n  つまり約16msの中に全ての演算・描画処理を詰め込む必要

Page 12: Real-Time 3D Programming in Scala

+Java/Scalaでフレーム制御型の ゲームを作ることの障壁

n ガベージコレクション(GC) n  フレーム管理されたゲームを作る上での最大の障壁

n  1秒近く画面の更新が止まる

n  C++と比べると遅い n  JITの最適化度合いによってはC++の速度を上回ることもあるがJITは気まぐれ

n  場合によってはアセンブラ(SIMD命令等)まで繰り出してくるC++製プログラムには絶対勝てない

n  SIMD命令って?→1CPU命令で複数個の浮動小数点の計算

n  普通の浮動小数点演算より10倍~速い

n  特に3Dプログラミングではこれが有用

Page 13: Real-Time 3D Programming in Scala

+障壁に対する対応策

n ガベージコレクション対策 n  毎フレーム毎に途中計算で使うオブジェクトは使い回す

n  行列を保持するArray[Float]とか n  多少初めののロード時間が長くなってもいいので不要な途中計算が発生しないようにする

n  更新でオブジェクトを捨てまくるScalaのimmutable.Listとかは論外 n  コンカレントGCを使う(要調査)

n 遅いことの対策 n  Javaで可能な限り計算しない

n  OpenGLのライブラリもしくはGPUに計算させる n  GPUはSIMD命令に特化された演算器

n  遅いと感じたらプロファイルを行う

Page 14: Real-Time 3D Programming in Scala

+Scalaのプロファイル 配列・コレクションの特性

単位: マイクロ秒 .apply .update .foreach .prepend .append .insert

java.util.ArrayList[AnyRef] 11 19 16 19,746 158 39,317

java.util.LinkedList[AnyRef] 38.622 388,877 43 152 141 320

Array[AnyRef] 1 21 174 - - -

mutable.ArrayBuffer[AnyRef] 11 19 122 19,734 172 40,118

mutable.ListBuffer[AnyRef] 94,595 94,861 367 119 170 95,643

mutable.Queue[AnyRef] 99.916 100,672 497 142 230 -

immutable.List[AnyRef] 94,543 4,718,559 312 175 2,482,455 -

immutable.Vector[AnyRef] 107 517 211 779 662 -

すべてJIT後の値(たぶん)

続・Scalaの配列とコレクションのパフォーマンス http://d.hatena.ne.jp/chimerast/20110304/1299237142 Array[AnyRef].applyはJITで最適化されすぎて(DCE)正しい プロファイル結果でない可能性があります。まあでもそれはそれ。

Page 15: Real-Time 3D Programming in Scala

+MikuMikuDanceのファイル

n  PMDファイル(.pmd) n  3Dモデルの情報

n  VMDファイル(.vmd) n  3Dモデルの動きの情報

n ファイルフォーマットは公開ではなく2ch等で勝手に構造が解析されている n  通りすがりの記憶 - MMDのモデルデータ(PMD)形式 めも

http://bit.ly/fFYlS n  構造体だけ示されており実装は示されてないのでその辺は勘

n 解析結果を使ったクローンがいくつかあるので参考にした n  AS3版(b2ox様): http://www.libspark.org/browser/as3/FLARMMD n  XNA版(wilfrem様): http://sourceforge.jp/projects/mmdx/

Page 16: Real-Time 3D Programming in Scala

+PMDファイルフォーマット

n 3Dモデルのファイルフォーマット in MMD n  頂点情報のリスト(3D空間内の座標) n  面情報のリスト(どの頂点を使って面を構成するか) n  材質情報のリスト(色情報やテクスチャ情報) n  ボーン情報のリスト n  IKボーン情報のリスト n  表情情報のリスト(顔のアニメーションのための頂点情報)

n  これらがバイナリで詰め込まれて入っている

n  Direct3DとOpenGLの違い n  とりあえず座標系が違う

n  OpenGLは右手座標系・DirectXは左手座標系 n  とりあえずz軸の座標をマイナスに反転すればよい

Page 17: Real-Time 3D Programming in Scala

+VMDファイルフォーマット

n ボーンアニメーション用フォーマット n  ボーンや表情の番号や変化の度合いがフレーム毎に入っている

n  他にもいろいろ入っているらしいが解析してない

n  こっちも値がバイナリで入っている

n フレームはキーフレームのみが記録されているため間は補完する n  現在は線形補間。本来はベジェ曲線で補完する

Page 18: Real-Time 3D Programming in Scala

+バイナリファイルの読み込み in Scala

val file = new File(path) using(new RandomAccessFile(file, "r")) { f => val channel = f.getChannel val buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size) buffer.order(ByteOrder.LITTLE_ENDIAN) Some(new PMDModel(file, buffer)) }

class PMDModel(file: File, buffer: ByteBuffer) { val header = new PMDHeader(buffer) val vertices = Array.fill(buffer.getInt) { new PMDVertex(buffer) } val indices = Array.fill(buffer.getInt) { buffer.getShort } val materials = Array.fill(buffer.getInt) { new PMDMaterial(buffer) } val bones = Array.fill(buffer.getShort) { new PMDBone(buffer) } val iks = Array.fill(buffer.getShort) { new PMDIKData(buffer) } val skins = Array.fill(buffer.getShort) { new PMDSkinData(buffer) } val skinIndex = Array.fill(buffer.get) { buffer.getShort } val boneDispName = Array.fill(buffer.get) { buffer.getString(50) } val boneDisp = Array.fill(buffer.getInt) { new PMDBoneDisp(buffer) } }

Page 19: Real-Time 3D Programming in Scala

+今後の予定・目標

n  IKボーンに対応 n  よくわからないけどクローンのコードを見てがんばる

n 物理演算に対応 n  JBullet: http://jbullet.advel.cz/

n ちゃんとゲームを作る n  一緒に作ってくれる3Dモデラーを募集中

n  いなければ自分でがんばる

n  Prologさん=推理大好きっ子みたいなそんなゲーム

Page 20: Real-Time 3D Programming in Scala

+終わり

n ご清聴ありがとうございました