2015/09/30

Unityでレイトレ

こんにちは.@rootxです.

Unityをアセット管理として用いたレイトレプログラムを書いてみましょう.

Unity5でレイトレーシング

はじめに

なぜUnityで行うか?

先日から少しだけUnityを操作しているのですが,最近のゲームエンジンらしく物理ベースマテリアルに対応している上に,いろんなローダやアセットがたくさんあって,自分で書くよりこれでいいじゃん,と思ったところが始まりです.
ベタのレンダラを書いたことのある人はお分かりかと思いますが,最初に絵を出力するまでに,レンダリング以外の処理を書くのがすごく大変です.例えば,ファイルの読み込みや,画像として保存する,テクスチャに対応する,などなどです.ちょっとプレビューしたいと思ったり,それにGUIを付けたいと思っても,なんだかよくわからないことを,たくさんたくさん調べて書く必要があります.

そこで,

本論の目的は,初学者(私も含め)向けにレンダラの本質(と思われるところ)に焦点を
また,高速化や多くのテクニックの必要性を体験してもらうことです.

なお他のアプローチとしては,任意のフレームをobj等に出力して,自作あるいは既存のレンダラでレンダリングする,という方法もあります.

開発環境

os x 10.10
Unity 5.2.0f3
UnityScript (C#)

開発指針

レイキャスト,古典的レイトレ,パストレの流れを追う.
マテリアルはstandard shaderの設定を使う.
テクスチャ対応.
高速化手段はあまり考えない.
MMDモデルのレンダリングくらいまで.

ここから

準備(適当に)

新規プロジェクトを作成.
適当なオブジェクトの配置.
カメラの設定.
スクリプトを作成.
カメラに,作成したスクリプトをアタッチ.

とりあえず,こんな感じにしてみました.
Unity inital scene

絵を出す(モノクロから)

レイトレーシングの基本的な考え方は,視点(カメラ)からたくさんの視線(レイ)を飛ばして,当たったオブジェクトの位置に基づいていろいろ計算して,色を決定します.

Unityでは便利なAPIがたくさん用意されているのでそれを使って,色の決定の部分を書いていく,という感じで進めます.

レンダリング結果を保持するキャンバスを用意して画面に表示する

レンダリング結果は,テクスチャに描画します.

最初にテクスチャを用意します.今回は,スクリーンサイズと同じサイズのテクスチャをStart()で確保し,レンダリングのためのRendering()を呼びだします,


全画素について処理を行うため,横方向(width)と縦方向(height)の2重ループとなります.
レイトレースを行うには,各ピクセルにおいて,カメラから発するその画素位置を向いたレイを生成し,その結果に応じて色を計算します.

この時点では,まず単純な背景色(黒)をテクスチャへ書き込み,そして画面への表示を行うだけの処理にします.
UnityのColorは不透明度を持っているので,黒の場合は (0.0f, 0.0f, 0.0f, 1.0f)とします.
また,数値で場合は必ずfloat精度として記述してください.うっかり new Color(0.0, 0.0, 0.0 1.0)のように記述すると,コンパイルに失敗してUnityがエラーとなってしまいます.
すべてのピクセルに色を設定したら,テクスチャのApply()で反映することを忘れないようにしてください.
描画した内容を画面に表示するために,OnGUI()コールバックを用意して,テクスチャを画面を覆うような領域に描画します.


https://gist.github.com/cslroot/c66ebadf2ad3651bcab3
この状態で実行すると,真っ黒になると思います.
背景色として指定したbackgroundColorの値をいろいろ変えて,指定した色になることを確認してみましょう.
ここまでできれば,各ピクセルの色をどのように決定するか,という部分に集中して取り組むことができるでしょう.

レイを飛ばして,当たったところを表示する

Unityでは,Physics.Raycast()という大変便利な関数が用意されています.このAPIは,任意の位置(座標)と指定の方向(ベクトル)を指定することで,その半直線の交差情報を取得することができます.
交差情報は,単純に当たった/当たっていないだけではなく,どの物体(シーン内のGameObject)にあたったか,その位置,法線,uv座標なども取得することが可能です.

注意:当たったかどうか,はCollider(コライダ)と呼ばれるコンポーネントで判定されます.Colliderがアタッチされていない要素には当たり判定がないため,Raycast()では無視されてしまいます.

これを使うには,各ピクセルに対しするレイの位置と方向を算出する必要がありますが,Unityにはその計算を自動的に行なってくれるAPIが用意されています:

mainCamera.ScreenPointToRay(Vector3(w, h, 0));



それではまず,当たった場合に白,当たらない場合に黒で表示するように改造してみます.
https://gist.github.com/cslroot/4eb475710a11f87f174e


オブジェクトの色を表示する

物体が表示されましたが,陰影もなく色もない状態です.
そこで,当たった点の情報を利用して物体色を反映させたいと思います,
現時点では2つの物体(CubeとSphere)に材質情報がありませんので,まずはマテリアルを用意します.

Unity上の操作
プロジェクトビューから,新規のマテリアルを作成します(Create > Material).
それぞれの物体に別々のマテリアルを持たせるので2つ作成しておきましょう(MatCube, MatSphere).
それらのマテリアルを選択して,Albedoの色を指定します.とりあえず赤と青にしておきます.
マテリアルを,Hierarchy内のCubeとSphereにそれぞれドラッグ&ドロップしてアタッチします.

ここまでの操作で,Unity上の物体に色が反映されたと思います.



ScriptからAlbedoカラーの取得
色を取得するには,レイと交差した物体のマテリアルを参照する必要があります.
これは,Raycast()のout引数であるRaycastHit構造体から,collider経由で取得します.

https://gist.github.com/cslroot/ce44b752bedce904c6ac

テクスチャマッピングを有効にする

マテリアルが取得できればテクスチャも簡単に習得できます.
テクスチャが設定されている場合は,Material.mainTextureプロパティでアクセスできます.
また,レイと交差した箇所のテクスチャ座標は,RaycastHit.textureCoordに格納されています.


https://gist.github.com/cslroot/ddcff7c39476e19da582

テクスチャを使うときに重要な点が1つあります.
スクリプトからテクスチャの値を取得する場合は,テクスチャの設定で「Read/Write Enble」を変更しなければなりません.これをしない場合,実行時にエラーが発生します.
テクスチャを選択「Texture Type > Advanced」にして「Read/Write Enable」をONにしてください.


今回はこのへんでー.

参考文献





 でわでわ.


2015/09/13

Unityの画面を動画にする

こんにちは.@rootxです.

前回の続きで,Unityで遊んでいます.
今回は,Unity画面を連番キャプチャして

きっと他の開発者の方が作られていると思いますが,Unityスクリプトの勉強として作成しています.

まずは連番出力
かるく調べた感じですと,3つの方法がありそうです:

  1. 「Application.CaptureScreenShot」というそのまんまなAPIを使う方法
  2. RenderTextureを使う方法
  3. Texture2DのReadPixelsを使う方法



今回は任意のサイズで保存したかったので,3番目の方法を採用します.
ちなみに,1番目の方法は遅い,とのこと.

とりあえずザクッと書いてみました.


連番画像を動画にする

ffmpegで簡単に作成できます.

30と書いた箇所は,指定したFrameRate(出力時のフレームレート)と同じにしてください.


参考文献

http://blog.almostlogical.com/2009/12/11/render-to-texture-unity3d/
http://answers.unity3d.com/questions/22954/how-to-save-a-picture-take-screenshot-from-a-camer.html


 でわでわ.

2015/09/12

はじめてのUnityプロジェクト:MMDを動かす

こんにちは.@rootxです.

はじめに

とあるところで「主婦ゆに」(サイン入り)を手に入れました!
Unityにはあまり興味がなかったのですが,せっかくなので触ってみようと思います.

とりあえずはお手本通りに,MMDモデル(PMD, VMD)を読み込み,踊ってもらおうと思います.

なお,Unity5のインストール,アカウント作成を完了したところからスタートとします.

環境

MacBook (Retina, 12-inch, Early 2015)
OS X 10.10  Yosemite
Unity 5.2.0f3





プロジェクトの作成

Newで新規プロジェクトを作成
3Dを選択
アセットはあとから追加できるので,Asset Packagesは特に変更なし
Create Project

とりあえずシーンを保存する
シーンは,ゲーム開発でいう"レベル"に相当.
Save Scene
Asset直下はいろいろなアセットが増えていくのでScenesフォルダを作ってそこに保存.

MMDファイルの読込み

MMD4Mecanim.unitypackageをダブルクリックしてインポート.

各種MMDファイル(pmd, vmd)をアセットに追加(Projectタブにドラッグ&ドロップ)
〜〜.pmdファイルの対応する箇所に,〜〜.MMD4Mecanimが生成されているので選択
Inspectorウィンドウに利用条件が出てくるので確認し,チェックONで右下の「同意する」を押す
Inspectorをロックしておく
モーション(*.vmdファイル)をVMD欄にドラッグ&ドロップする.
Processボタンを押す
#変換処理が完了するまで暫く待つ.
pmdと同フォルダにfbxファイルができているので,それをHierarchy(またはScene)にドラッグ&ドロップ.

動かす

空のAnimator Controllerを追加(Create > Animator Controller)
作成したAnimator Controllerをシーンに配置したMMDモデルのinspectorのAnimator > Controllerにドラッグ&ドロップで設定
作成したAnimator ControllerをダブルクリックしてAnimatorウィンドウを開く
プロジェクト内のモデルデータを(三角形を押して)展開し,読込み時に指定した*.vmdファイルをAnimatorウィンドウにドラッグ&ドロップする

ここまでで,再生を押すと踊るよ.
でも残念な感じのカメラなので調整しましょう.

カメラを自動追従に変更する

既存のMainCameraは削除.
メニューの Assets > Import Package > Cameras をインポート
ProjectウィンドウのAssetからHandheldCamera(Standard Assets > Cameras > Prefab)をシーンに追加
カメラの向きがいまいちなので,適当に位置合わせ 
  Position > X: 0 / Y: 0.5 / Z: 2.0
  Rotation > X: -10 / Y: 180 / Z: 0
デフォルトのクリッピングを 変更 Clipping Planes > Near: 0.1 / Far: 100
FOVも気に入らないので変更 Field of view: 50
追従するように設定 Hand Held Cam (Script) > Target: 適当なジョイント(67.joint_Neck)
再生して確認
→ あまりにも激しく動いて良いそうなので,カメラの追従速度を調整する
  Following Speed: 0.5
  FOV: 35
  Position: Y: 1
  Rotation: 355



でわでわ.