VRエンジン作成日記

ひたすらVRエンジンを作っていきます

マウスのクリック位置とオブジェクトの衝突判定処理を追加

マウスのクリック位置とオブジェクトの衝突判定処理を追加した。処理内容としては、カメラからマウスのクリック位置方向へ線をまっすぐ作って、その線とオブジェクトを囲む箱とが衝突するか判定する処理を書いた。次のサイトを参考にさせて頂いた。

その18 直線とAABB

Unityだと、Camera.ScreenPointToRay() でカメラから線を作ることができる。Physics.Raycast() を使うと、線と衝突する、画面上のオブジェクトを取得することができる。それと同様の処理を今回は追加したことになる。今のところ、Raycast() メソッドの名前はUnityに合わせることができていない。

今のところ、AABBと衝突判定する処理になっているので、回転したオブジェクトをクリックした時、何もない空間でもクリックされたと判定してしまうことがある。OBBと衝突判定する処理に変えることで、違和感は減るだろうと考えている。

他には、昨日の最適化で壊れてしまった箇所を修正したりしていた。

・関連するコミット

add hit test mouse · hikipuro/tea.js@d01e526 · GitHub

 

実行速度を最適化した

実行速度を最適化した。JavaScriptでは、C言語だとコンパイラが最適化してくれそうな箇所で最適化が入らなかったりする。最適化の一般的なお話でいうと、次のような項目は効果があると言えそう。

・関数のインライン展開

・複数回参照される項目を変数にキャッシュ

 (getterを見落としやすい)

・新しいオブジェクトを極力作らない

 (何らかの操作を行うメソッド内でnewされる箇所を見落としやすい)

・ループの展開

今のところ、ループの展開以外のものは心当たりがあったので、細かく最適化を入れていった。JavaScriptのコードはタスクマネージャで見てもCPU負荷に揺れがあるので、数値を見て最適化を実感することが難しかった。いくつもの内容を積み上げた結果、0.x%速くなったというようなことを繰り返した。CPU負荷に揺れがあるのは、JITの入るタイミングが不明、GCの動くタイミングが不明という2つが主な原因だと思う。

手書きで最適化する余地が多いのは、JavaScriptが動的な型付け言語だからだと言えそう。コンパイル時に変数の中に何が入っているのか分からない状態では、コンパイラJITの最適化に限界があるんだと思う。

今回、getter/setterの中身が簡単な場合でも、関数呼び出しと同じ負荷がかかってそうだというのを発見した。また、ベンチマーク用の関数を書いて2つの処理負荷を比べようと考えた時に、A → Bの順番で関数を呼び出した場合と、B → Aの順番で関数を呼び出した場合ではA、Bそれぞれの速度が変わってしまうというのも発見した。2つの位置をコピペで入れ替えて再度測ってみて、どちらの場合でもAが速いと言えないと、Aが実際に速いのかどうか分からない。これは盲点になりそうだ。あと、モダンなJavaScript限定のお話だけど、constを使うよりもvarの方がアクセスが速そうだった。これは確信を持ってそうだと言えるわけではないけど、数を積み重ねるとconstは処理が重くなっていく原因になっているように思える。

Webインスペクタの画面でパフォーマンスタブを開くと、メソッド1つ単位で処理負荷が見れるので、何度もリロードしては眺めて処理負荷を確認した。

UnitTestも揃っていない状態で最適化を入れたせいか、いくつか動きがおかしくなってしまったようだ。

・関連するコミット

optimize run speed · hikipuro/tea.js@38593fc · GitHub

 

バンプマッピングを実装してみた

バンプマッピングを実装してみた。考え方については分かっていたものの、具体的にコードで考えるのは難しかった。下の画像の地面の部分と、カプセルのオブジェクトから文字が飛び出しているように見えるところがバンプマッピングの処理。

f:id:hikipuro:20180906202603p:plain

次のサイトを参考にさせて頂いた。画像もお借りして、そのまま使わせて頂いている。画像はリポジトリにはアップロードしていない。バンプマッピング用の画像は、PhotoShopプラグイン等を使って出力できるようだ。

wgld.org

今のところテクスチャの天地が逆になっている時に、飛び出す方向も上下逆になっていたりとか、処理がうまくいっていないところがある。

プログラムを書く前に、次のサイトも読んでおくと考え方が理解しやすいと思う。

news.mynavi.jp

バンプマッピングのこの先の段階としては、視差を考慮したりとか、遮蔽部分を考慮したりとか、工夫でよりリアルに表現する手段があるらしい。西川善司さんの連載を読むと、基本的な発想はどうなっているのかということと、どのゲーム作品で実際に使われているのかが分かる。

・関連するコミット

add bump mapping · hikipuro/tea.js@9103154 · GitHub

 

視錐台カリングを実装してみた

今日は視錐台カリングを実装した。実装したけど、考え方をきちんと理解しているわけではない。次のサイトに書かれている内容を参考にさせて頂いて、なんとなくで書いた。

edom18.hateblo.jp

描画オブジェクトが多い場合は違いが分かりそうだけど、今のところ画面に出しているオブジェクトが少なすぎて、実感できるほどの効果は出ていない。ドローコールの数をカウントしてみたら、確かに描画回数は減っているようだ。オブジェクトの回転を考慮せずにAABBのサイズを計算しているので、回転で大幅に大きさが変わるオブジェクトについては、カリングされてはいけない時にカリングされる可能性がある。これについては後ほど修正したい。

あと、ようやくフォンシェーディングをまともにできたと思う。カメラを動かしても、環境光、拡散光、反射光ともにうまく当たっているように見える。こちらはわりと時間をかけて考えたので、間違えていないと思いたい。

ついでに、フォルダ構成を少し整理した。ファイル数が増えてきたので、目的のファイルが思ったフォルダに入っていなかったみたいなことで時間を費やしてしまうのを減らしたかった。

・関連するコミット

add frustum culling · hikipuro/tea.js@abfa628 · GitHub

 

親子関係にあるオブジェクトの座標2

シャドウマップがうまくいっていないことも気になってるんだけど、そもそもフォンシェーディングも綺麗にできていなかった。さらに考えると、親子関係のオブジェクトの位置関係もUnityと見比べると違う結果になっていた。

親子関係のオブジェクトは、

・親オブジェクトのワールド座標を中心として回転する

・子オブジェクトのローカル座標は親オブジェクトのスケール値でスケーリングされる

という効果もあるようだったので、これを加味して修正した。

あと、親オブジェクトに子オブジェクトを追加する時、子オブジェクトの現在のグローバル座標から、親オブジェクト空間のローカル座標へ座標変換する必要もあるようだったので、この挙動も追加しておいた。まだチェックしていないケースで動きがおかしいかもしれない。やはりUnitTestも書いた方が良さそうだ。手作業と目視だと、どうしてもチェック漏れが出てきてしまう。

・関連するコミット

fix object parent child relation · hikipuro/tea.js@bfa6aa1 · GitHub

 

シャドウマップを実装しようとした

シャドウマップを使って影を描く処理を実装しようとしたけど、難しくて今日中に終えることができなかった。

毎日1個ペースで機能を増やそうと思ってたけど、何日か考える必要がある箇所がこれからもたびたび出てきそうな予感。以前に考えたことがある内容であれば簡単に実装できるけど、今まで考えたことがないことを1から考えるのは難しい。

RenderTextureの追加

今日はRenderTextureを追加した。いつものことながら、今のところ雑に追加したままになっている。

f:id:hikipuro:20180902230825p:plain

地面に敷いた、四角形の領域でRenderTextureを使用している。この機能があると、他のカメラでレンダリングした映像を再度画面に配置して、2次元のテクスチャとして使用することができる。

物体の影を描く時の土台としてもRenderTextureを使用することができる。あらかじめ準備しておくと、今後の作業が進めやすくなる。

Unityと同様に、CameraオブジェクトのtargetTextureプロパティへRenderTextuerオブジェクトをセットすることで、そのカメラの映像がテクスチャに描かれるような仕組みにしている。targetTextureプロパティをnullにすることで、画面に直接描画することができる。

・関連するコミット

add render texture · hikipuro/tea.js@09f91a3 · GitHub