きかいや。

機械といいつつだいたいプログラミングのはなし

(すぐできる高速化?)ヘボPCでもOculusがしたい

HPASimを

OculusDK2 SDK0.4.4 Unity4.6.1f'(Pro)
で75FPSを出すために設定でできることをやったことのメモです。
75FPSでない悲しいPCで頑張るための忘備録。(いいパソコンを買え。)

経緯:
頭を回すと視界が妙にブレ、FPSが足りていないことが原因と判明。

(回転運動の予測演算がずれて制御的に振動している?)

 

-----クオリティ設定-------
・Disable Shadows 影を切る

(影は残したいけど…というときは、その下の項目を画像のように弄るとクオリティは落ちるが影は残る)

・Anti Ailiasing アンチエイリアスなし

先ずこのふたつが大きく効きます。

あと、異方性テクスチャとやらも切ってみた

f:id:machinemaker:20150304211654p:plain

f:id:machinemaker:20150304211915p:plain

 

---------------オブジェクトの設定

水面オブジェクト(Daylight Water)の設定

・Refractive(屈折の再現)にはしない

・Refrective(反射とかを描画する)テクスチャサイズを256->64へ

割と効く。水面の反射だけは残したかった。(水面に近いものがあるとチラつくので、調整する)

f:id:machinemaker:20150304212630p:plain

 

・OVRManager(CameraRigについてるスクリプト)の設定

f:id:machinemaker:20150304210743p:plain

Native Texture Scaleを下げる。めちゃめちゃ効く。最後の手段。
樽型変形の際に使うテクスチャサイズを下げる。代わりに表示は荒くなる。
が、ある程度荒いほうがかえってモデルの荒が気にならなくなったりする。。。


PCはASUS U24A
CPU IntelCorei5-3230M 2.6GHz

Memory 8GB

VideoCard:Intel4000HD(OnBoard)

---------------

そのほか

この辺をまず読もう。

izmさんとこ。いい話だ。

Unity+OculusRiftコンテンツのパフォーマンスチューニング - izm_11's blog

引用:

  • Occlusion Cullingと固定物のstatic化はしている
  • 毎フレームDebug.Logを呼ぶような恐ろしい無駄は削除済み

 :というあたりはすぐにできるので、まずやる。


フレームセンシスさんとこ


Unity+Oculus Rift開発メモ(DK2、SDK 0.4.4対応) - フレームシンセシス 技術ブログ

:樽型shaderのテクスチャサイズの話はここ読んで知りました。

MFT2014でHPASim(OculusRift対応版)を出した話

この記事はOculus Rift Advent Calendar 2014 の7日目の記事になります。

Maker Faire Tokyo 2014 | Maker Faire Tokyo 2014 | Make: Japan

に、「はかるひと」という出展内の一企画として、人力飛行機シミュレータ HPASimを出展してきました。(はかるひと、というのは慣性センサをロケットや人力飛行機や鳥にくっつけて、飛びもののセンサ計測を趣味や仕事でやっているひとたちの集まりです。)

今回はこのレポートというか、ここに至るまでの忘備録です。何を考えてこんなものを作っているか、という話になります。Oculusのカレンダーですが、人力飛行機の話や筐体側を作るうえでの話、体験会での注意点的なものが多くなっています。適宜飛ばして読んでいただければ。

 

1.HPASimって何?なんで作ったの?(人力飛行機の話)

人力飛行機シミュレータ(Human Powered Airplane Simulator)といいます。
人力飛行機はペダルをこぐ力でプロペラを回し、空を飛ぶというものです。傍から見ると漕ぐのが大変そうなのはわかるのですが、その操縦性が難しいことはあまり知られていないと思います。慣性が大きく応答が悪いため、飛行機の動きを予測して早めに舵を切らないといけないのです。たとえるなら、ハンドルを切ってから2秒後にやっと曲がり始める車みたいなモノです。(パイロットは筋肉だけ鍛えればいいというものではない)

 昔コレの設計と製作をしていたのですが、その操縦性の悪さにもかかわらず、操縦練習できるシミュレータがこれといって公開されていませんでした(滑空機のシミュレータはいくつかあったのですが、プロペラ機のモノがない。あっても研究室のものだったり、あそこが持っているらしいという話くらい)。パイロットはラジコン飛行機を飛ばしたり、グライダーに乗せてもらったり、市販のフライトシミュのパラメータをいじったりしてそれっぽい動きの飛行機をつくり練習をした後、最後は実機で操作を体得するという流れでした。人力飛行機は出来上がったら荷重試験や重心調整をしたのち、自家用飛行機の滑走路などを使ってテストフライトを行っています)。FlightGear,MSFS,RealFlightのような一般機のフライトシミュの特性を書き換えるのは割と面倒で、真面目に合わせようと思うと飛行機の運動特性を自前で計算してやることになり、この計算が面倒です。スタートボタンを押したらすぐ飛べて練習できる、そんなシミュレータがあればなぁ、という思いからDXライブラリでシミュレータを作りました。そしてOculusRiftを知り、コレを使えばとてもいい練習用のシミュレータになるだろう、と考えて作りました。

あと、アレって基本的にパイロットの専用機なので、作ってるほかの人は乗れないんですよ。せっかく作ったら自分も乗ってみたくなるじゃないですか、アレ。(本音)

f:id:machinemaker:20141207200652j:plain

( こんな筐体に乗ってペダルをこぐと、画面内の飛行機が飛びます)


流れとしては
DXライブラリ+MMDモデルで作成、twitterで公開 -> MFT2013で展示 -> OculusRift(DK1)購入 -> Unityで作り直す ->Oculus Rift(DK1)対応 -> Ocufes(秋葉原大好き祭り)展示 -> ペダル連動するよう筐体作成 -> 裏オキュフェス2で発表 -> OculusRift(DK2)購入->mbed祭り2014@夏の東銀座【一般参加枠】 - mbed祭り | Doorkeeperで飛び入り発表 -> ポジショントラッキング対応、筐体作り直し -> MFT2014で展示

と変遷をたどっています。

 

2.設計コンセプト
設計コンセプトは以下のようにしています。

  • 没入感を高め、また視界を忠実に再現するため、パイロットのアバターを表示する( ポジショントラッキング対応とアバターのIK対応
  • 操縦系/操縦方法を人力飛行機のものに合わせることで、実機への乗り換えをシームレスに行う。
  • デモンストレーションで持ち運び可能なように設計する。(解体・組立・輸送)
  • 特殊な工作具を使用しないでも作れる(というか使えない)

 

3.機器構成

MFTやOcufesでは、体験してもらってハイ次のひとー、という形になってしまったので、あまり技術面の話をじっくりできませんでしたので、ここに。(mbed祭りや裏Ocufesではその辺の話もしていたので、特色が出ますね。)

  • 筐体構成
    フレーム:棚を作るためのL字アングルで構成
    椅子:座椅子を分解してフレームを取り出し、金具でフレームに固定。園芸用のアルミの台を上において、下にクッションゴムを敷き詰めて荷重を床に逃がしています。(MFT2014はビッグサイトで行われ、防火法のため装飾の布類に防炎証明が必要でした。展示物は法律上別扱いとも聞いたのですが、筐体はできるだけ金属や塩ビなど燃えないもの、自己消化性をもつもので構成しました)

    操縦:
    ペダル入力…ペダルをこぐとプロペラが回ります。ペダルにはコレ

    Amazon.co.jp | ながら エクササイズ フィットネス 足 こぎ ペダル ローラー | スポーツ&アウトドア 通販

    を使っています。右ペダルにフォトインタラプタと回転盤、左ペダルに磁石とホールセンサがついています。回路の項で後述。
    尾翼・補助翼(ラダー・エレベータ・エルロン):飛行機の水平尾翼垂直尾翼主翼についている補助翼を操作することで機体のロール・ピッチ・ヨーを制御できます。ここはジョイパッドですが、操縦桿にしたいですね。

  • 回路
    マイコン:mbedマイコンのコレ


    mbed NXP LPC1768 + Starborad orange 【きばん本舗SHOP】

    を使用しています。今回はシリアル通信とセンサのOn/OFFしか見ていないので、ここまで高級なマイコンとボードを使うこともないのですが、扱いやすさや今後の拡張性からコレを使用しています。あと、実機も最近はフライバイワイヤの機体はサーボで尾翼やエルロンを動かし、エンコーダで足元の回転数を見ていたりするので、その基板をそのまま使えるというのが理想的です。車でもそうですが、シミュレータは操縦桿やペダルなどをその操縦系と同じものを使うのが理想だ、という考えが根底にあります。(あとArduinoやH8ではなくmbed推しなのは、AVRは遅い、H8はレジスタのセットアップが面倒という研究室時代にうえつけられた悪夢イメージと、開発環境のインストールが不要でmbedのクラウド開発環境にソースもコンパイラも置いてあるというのが非常に便利なためです。あとCではなくC++で書けるのと、レジスタ周りをみなくても簡単に使えるので良い。ほかの人が作ったクラスやコードのインポートがボタン一発で終わって、ボタンを押せば実行ファイルがダウンロードできて、USBでD&Dで書き込まれるの、楽すぎます。あと、mbedクラスタtwitterにいるので、割と人に聞きやすいです。mbed派増えないかなぁ、Oculusクラスタ。)

    センサ:

     

    f:id:machinemaker:20141207210051j:plain


    ホールセンサ…回転位置のリセット(キャリブレーション)用です。左のペダルに磁石(画像にある、ペダルのパイプについてる黒いやつ)がついており、磁石の通過を検知すると回転の絶対値をリセットします。これがあることで、お客さんはキャリブレーション用の動作なく、知らないうちにリアルの脚の回転とVRの脚の回転が一致します。(今見たら、ディスコンになってる…)

    f:id:machinemaker:20141207205333j:plain

    f:id:machinemaker:20141207211600j:plain


    フォトインタラプタ…画像の黒いやつです。光がさえぎられてのを検出し、回転角度に変換します。空間分解能は2°です。VRでは時間・空間的分解能が低いとアニメーションががくがくして、思いのほか体験の質が低下します。鋏とカッタで作れる中でできるだ歯(スリット)を増やそうとしてこのような直径300mmの大円盤になっています。また、分解能が高ければ人力飛行機的には脈動も見ることができるので、漕ぎ方自体の練習にもなるのではないかな、とも。
    (90パルス2逓倍で分解能2°、A層、Z層のみのロータリエンコーダとなっているので、逆回転させても正転しているように認識しますが、自転車を逆さに漕ぐこともあまりないこと、A層に対して1/4周期ずらしたB層用の回転盤をうまく固定できないし壊れたら直せないだろうということから、このようになっています。ホットメルトで固定してあったのですが、展示中数回この円盤は外れました。最後はガムテ固定でどうにかしました)
  • ソフト
    Untiy4.5.4+Oculus SDK 0.4.2で開発しました。PCがASUS


    ノートパソコン - U24A - ASUS
    で、グラフィックオンボードチップ(Intel4000HD)の、DK2には心もとないスペックです。そのためエフェクトの類を極力きり、DirectモードでFPS75を維持しています。Oculus Riftの体験の質を上げているのは何よりも、人の動きに対する画面の追従速度で、立体視や解像度などおまけに過ぎません。なので、最近のデスクトップPCなら問題なく動くはずです。
    Oculus Riftの体験の質を上げているのは何よりも、人の動きに対する画面の追従速度で、立体視や解像度などおまけに過ぎません。大事なことなので二回書きました。これだけ覚えておけばOKです。

4.これまで展示をしてきて感じたことなど

  • A.筐体と回路は頑丈に、きれいに作ろう
    mbed祭りに参加するまで、ブレッドボード上で回路を組んでいたのですが、mbed祭りでは輸送中に壊れました。また体験会中にDK2の配線が絡みまくりました。ペダルもフレームなしでおいていただけだったので、ガタンガタンと前後左右にズレて漕ぎづらそうでした。この時MFTへの参加が決まっていたころだったので、「このままだとあの規模の体験会だと確実に壊れるぞ」と感じて基板、筐体ともにちゃんと作りました。またフレームの角でけがをしないよう、各所養生やゴムで保護などをしています。
  • 無線と有線
    裏オキュフェスまでは、mbedとPCはbluetooth接続だったのですが、春のVR/AR祭りに出そうとした際、PCとの相性(デモ用PCがほかの人のだった)、会場の電波の込み具合(ワイヤレスLANだらけだったらしい)からか、接続できず封印されていたということがあったので、MFTでは有線にしています。電波が込み合う会場の場合、無線で通信しているものはこの辺リスクになります。
  • 運び込むことを考えよう
    デモ用に作っているため、自分で輸送できることが大切です。そのため車に運び込めるサイズに抑えること、分解組立が可能なようにしています。大きいですが、できるだけ軽く作ったので一人で持ち上げることもできます。ビッグサイトに運ぶ際は、コレをもって階段を上っていたので、周りの人に心配されたり奇異の目で見られたりしました…
    あと、平地移動用にキャスターが付け外しできるようにしています。
  • ゲーブルが引っかからないようにしよう

    f:id:machinemaker:20141207212341j:plain

    f:id:machinemaker:20141207212332j:plain
    Oculus Rift DK2はケーブルお化けです。ワイヤーが絡んだり、人がひっかけたりして大参事になります。あと今回のモノは人の脚で動かす非電動器具とはいえ回転モノな ので、巻き込みに気を付けなければなりません(本当は回転部を露出しないようにフルカバーしたかったところです。巻き込みそうな服装でないかは一応チェッ クしてました)。なので、ケーブル類はスパイラルケーブルでまとめ、フレームにケーブルタイやテープなどで固定しています。センサ系のワイヤーはコレで固定しています。USBハブを使ってPCと接続 するようにすると、ハブのケーブルだけを扱えばいいのでセットアップが楽です。

  • 展開性
    組みあがり状態で車に積めるので、現地ではUSBハブを二個PCとつなぎ、カメラの脚立を置くだけでセットアップ完了です。運び込める時間が決まっているので、展開・撤収が速いと楽です。
  • 説明書をタイトルで表示
    説明書をタイトル画面で表示していました。が、一人5分とかの体験だと、そもそも操作を複雑にしないことが肝心だろうなぁ…。説明だけで1分かかったりするので。展示会によっては「漕ぐだけ」のような形でもありじゃないかなと思っています。
  • 難易度調整
    本物のパラメータに比べ、思いっきり操縦をしやすくしています。1月のocufesでは5割程度のクリアだったのですが、7-8割くらいの人はクリアできるようでした。1月のocufesで展示するまえ、昔人力飛行機を一緒に作っていた人たち(パイロット、非パイロット)に使ってもらったところ、パイロットには「本物より操作しやすい」と言われたものの、それ以外の人たちはほとんどすぐに墜落しました。なので、体験会にもっていくたびに機体パラメータを甘めに書き換えていっています(具体的には、尾翼の位置を本物よりだいぶ後ろにあるように計算させている。また、上反角を実際よりかなり大きくしている)。やはり展示会によっては「漕ぐだけ」のような形でもありじゃないかなと思っています。難易度を選択できるようにしておくべきかな。
  • 制限時間など
    制限時間制、リトライN回まで、みたいにしてあらかじめ説明すると、買い移転率良く回せると思います。
  • キャリブレーション
    カメラの位置のリセット機能を必ずつけましょう。最新版でのやり方はこちらで紹介されています。SDK0.4.2でもCameraConrollerの中にRecenterPose()があるので、それを呼ぶとカメラの位置姿勢がリセットされます。

4.今後

まずは操縦桿が付けたいですね。それから、滑走路を走っているときの振動をフィードバックして離陸時にフッと振動が消える感じを出したり、ペダルの負荷をシミュレーションと連動させてやりたいです。ものが大きいので、展示機会が限られるのですが、そのうちまた何かに出したいと思います。
シミュレータソフトのアップロードは準備中なので、ちょっと待っていていただければ…SDKのアップデートが激しすぎてついていけない!

FinalIKを使って頭位置にキャラクターの姿勢を追従させる。[OculusRiftDK2]

というわけでその忘備録です。

アセット購入から実装まで実質期間:2日。

感想:ちょう楽。おススメアセット

 

[目的]

この記事の内容、要点は以下のとおり。

フライトシミュレータ、レースゲーム、ロボ操縦もの、コタツでミカン食べるなど、着座姿勢を基本とする場合に特に有用です。
コンポーネントの適用
①キャラクターは着座姿勢を保つ

②ペダルの回転に合わせて、キャラクターの足を動かす

③手は操縦桿に固定

④OculusDK2のポジトラに合わせて、キャラクターの頭位置を追従させる。

出来上がるとこんな感じ。 


FinalIK - YouTube

 

[背景]

人力飛行機シミュレータ(HPASim)は没入感を得られるよう、
キャラクターを画面に表示しています。DK1では首(頭)のボーンにOculusRiftの回転角を反映してやれば、自分とキャラクターの動きを合わせることができましたが、DK2のポジショントラッキングでは自由度が増えたせいで位置合わせが煩雑になりました。せっかくのポジショントラッキング、自分が動いたらキャラクターも追従してほしいものです。

で、最近Unity-OculusクラスタFinalIKというアセット(有料)を知りました。(だいたい1万円)。 (@izmさんのめかしむ 1 2)。やりたいことが近かったので、先人がいる安心感と、簡単にできたというコメントを聞いて購入。

 

[手法]

 今回動かしたいのはpilot(学ラン君)です。MMD4Mecanimでインポート。verは忘れましたが、最新版をお勧めします。(僕の使ったのは古いverなので、モデルの物理演算をさせると問題が出るらしい。キャラの物理演算しないので気にせずやりました。)
パイロット周りのオブジェクトをまとめて飛行機に乗せるため、
親 sag2(人力飛行機モデル)-pilotParent-pilot という構成です。

 

 ⓪おもむろにFullBodyBipedコンポーネントをpilotにぶち込む
するとあら不思議。人型モデルのボーン構造を認識してくれるため、ボーン周り設定をほとんど設定なしに使えます。謎の技術だ…

あ、bipedとは二足歩行のことです。

f:id:machinemaker:20141028203404p:plain

f:id:machinemaker:20141028204759p:plain

 

Final IKでは手や腰など、コレの部位をこの位置に固定したい/動かしたいんだ、というときに、その位置にターゲットのオブジェクトを配置します。ターゲットを動かさなければ手や腰はそこに固定され、ターゲットを動かすと人モデルの関節がイイ感じに動いてくれて、手や腰がターゲットにひっついて動きます。

①着座させる
まずは座らせます。
(1)ターゲット作成
空のオブジェクト IKTargetTorso を作り、飛行機の子にして座席あたりに置きます。f:id:machinemaker:20141028210606p:plain

(2)BodyEffectorのターゲット指定とIK設定
body effector タブのtarget に、先ほど作ったIKTargetTorsoを指定します。
[重要!]:この時Maintain Head Rotを1にします。コレをしないと、頭の回転がおかしくなります。

余談ですが手や足なんかのことをend effectorといいます。
これでもう、腰が座席に行くようになりました。

f:id:machinemaker:20141102004041p:plain


②足をペダルに追従させる

(1)ターゲット作成

足(Foot)のターゲットをIKTargetFootL,Rをペダルの子として配置します。
だいたいペダルの上に足関節が来るように。

f:id:machinemaker:20141028215507p:plain

 

(2)IKの設定
以下のように設定。設定はデフォルトまんまでOKでした。

f:id:machinemaker:20141028222055p:plain


ここまで終えると、座った学ラン君がペダルの位置に足がついてくるようになっています。


このペダル設定、3分くらいで終わりました。

ペダルのモーションをアニメーションでやってた時は、モーション作成3時間、プログラム数日とか苦労したので、あっけなさ過ぎてびっくりします。


③手を操縦桿に合わせる
(1)ターゲット作成

①の時と同じように、飛行機の子として左右の操縦桿あたりにIKTargertHandL,Rを置きます。

f:id:machinemaker:20141028211520p:plain


(2)ターゲット設定

f:id:machinemaker:20141028223438p:plain

 


④頭位置をカメラに追従させる

 今回のキモです。イロイロなインチキ工夫をやっています。そのうえ3割くらいなぜうまく動いてるのかちゃんと理解してないです。そのうちまとめなおします。
実はFinalIKのFullBodyBipedコンポーネントは、頭へのIKを直接設定することができません。代わりに、肩のIKを使ってうまいこと頭位の位置を指定します。このへんはizmさんからヒントを得てます。(ほぼ答え)


鉄騎コンのあれを作ってる時に得られたOculusRift DK2 memo - izm_11's blog


考え方:
Oculusのカメラコントローラは本来人間の目の位置に来るべき。

目の位置から肩の位置を算出する。

⓪カメラコントローラから目の位置姿勢を取得。
①目の位置姿勢からA:頭の姿勢、B:肩の位置を逆算する。

②肩のIKターゲットにBを代入し、キャラの肩までの動きをIKで算出

③キャラの頭の絶対姿勢にAを代入

 

(1)ターゲット配置
人間の左右の目の中心あたりにEyeCenter(Oculusの位置姿勢)を置きます(右眼の前あたりのほうが良いのかも…)。その子にIKTargetHead(ダミーの頭IKターゲット)を置き、更にその子にIKTargetSholderL,Rを配置します。

EyeCenter-IKTargetHead-iKTargetShoulderL,R

という感じです。
そして、肩のIKのターゲットにShoulderL,Rを指定します。(名前に統一感がなくなってますね、直す気力が…)

f:id:machinemaker:20141102002909p:plain

f:id:machinemaker:20141028223438p:plain

こうすることで、目の位置にOculusの位置姿勢を入れると頭の位置姿勢が出ます。

 

※この方式はちょっと欠点があって、頭のヨーイングをすべて体幹のヨーイングとして表現してしまう。(首だけで横に回さない。体幹を回す。ピッチとロールはオフセットをつけるとなんかうまくごまかせる)
しかし意外と違和感がない。違和感が出る姿勢は、首を真横に向けた状態で肩を見る姿勢になるので、通常まずできないかやらない動きだからだろうなぁ。操縦桿で手の位置を固定しているのも大きいかも。見えないところはバレない。 

 

(1.5)インチキを始める

OVRCameraControllerのCameraRightの子にREyeTargetIKを配置。
CameraRightより0,2ほど後ろに配置してオフセットをつける(頭の中が見えるの回避調整)

f:id:machinemaker:20141102001722p:plain


逆に前側ににオフセットすると、頭の後ろから見ている3rdParsonViewっぽくなってこれはこれで面白い。

 

(2)スクリプト

IKTargetEyeの位置・姿勢をEyeCenterのtransformへ渡す。

以下のスクリプトをpilot(キャラクタ)にアタッチする

 

 

using UnityEngine;
using System.Collections;
//using RootMotion.FinalIK;

public class PilotBehaviourScript : MonoBehaviour {
private GameObject player_;
private GameObject head_; //pilot head
public GameObject eye_=null;
public GameObject rEye = null;
private GameObject headTarget;
private GameObject headTargetParent;
private GameObject camera_=null; //camera object

// Use this for initialization
void Start () {
//get Player Component
player_ = gameObject;
headTarget = GameObject.Find("IKTargetHead").gameObject;
rEye = GameObject.Find("IKTargetEyeR").gameObject;
//get head component
head_ = GameObject.Find("20.joint_Head").gameObject;
eye_ = GameObject.Find("eyeCenter").gameObject;

Debug.Log (head_.name);

// Get main camera
camera_ = GameObject.Find("OVRCameraController").transform.FindChild("CameraRight").gameObject;

Debug.Log (camera_.name);

}


// Update is called once per frame
void LateUpdate () {
Debug.Log("Pilot::Update");
Quaternion headRot = camera_.transform.rotation;
head_.transform.rotation = headRot;

eye_.transform.position = rEye.transform.position;
eye_.transform.rotation = headRot;

}

 

だいたいこんな感じです。

両眼の中心位置の取り方をちゃんと把握してないので、ひどい感じですね。最後のほうそのうち修正したい。
突っ込みお願いします。

 

[備考]
検証環境

Unity4.5,4.f1

Oculus Rift SDK 0.4.2

UnityのDebug.Logをビルドしたアプリケーションで実行させない

開発中、ついつい変数をDebug.Logで表示したり
Debug.Log("Init now");

みたいに状態確認に使います。

ただし、このDebug.Log,結構重くてUpdateなどの中で呼ぶのは

お勧めできません。時間は測ってないけど、C言語のprintfデバッグやってた時より格段に重いから相当。

あと、ユーザにこういうログを見せたくなかったりとか。


なんて話をしてたら

 

 

とのご指摘が。

検証したところ、

 

というわけで、Update内でデバッグ用にLog出しててフレーム落ちが気になるとか、

AppleStoreに出す時にログを出力するはねられる?とかの対策に使えるみたいです。

ブログ移行テスト

ソースコードとか表示したいのではてなへ移行しました

旧ブログは
http://machinemaker.blog.fc2.com/

です。