深い深い訳がある

物理シミュレーション目次

 

 今回は、物理シミュレーションじゃなく、移動ロボットの障害物回避シミュレーションやるっす。

 色々事情があるんだよ。

 

 扱うのは、センサベースドナビゲーション。

 こいつは、移動ロボットが走行中にまわりの障害物の情報(位置や形状など)を 外界センサ(ビジョンや超音波センサなど)で獲得し,それに基づいて 目的地までの経路をリアルタイムで探し出すってやつです。

 

 

 このためのアルゴリズムにはLumelskyとかSankaranarayananとか色々あって、それぞれに長所短所があるみたい。

 で、実物だと、超音波センサなんかで距離測定して、目的地方向に障害物がないか調べて、障害物があったら回避だ〜って話なんだけど、シミュレーションじゃ超音波センサないわけですよ。

 どうしようかって話なんだけど、正統派なら、ロボットから目的地に向けての視線を飛ばして、各障害物との交差判定ってことになります。

 なんだけど、これって結構めんどくさいわけで…

 障害物を構成する形状平面と直線の交差判定を、延々繰り返すことになるわけで、障害物が多いと、色々工夫(障害物を視点からの距離でソートしたりとか)しないと処理がムッチャ遅くなるんですな。

 

 

 ま、そういう正統派もありなんですが、せっかくWebGL使ってるわけだし、ここはひとつ、実際にロボットから目的地への視線で画像を作り出して、その際に副産物で出来上がる深度バッファ利用しちゃおうかなと考えるわけです。

 

深度バッファ

 てのは、知らない人は、なんすか、それ?って話なんだけど、3DCGを描くときに、物体の前後関係を知るために利用されるバッファのことです。

 具体的には「WebGLでいきますぜい」で描いた立方体と球体の図なら

 

 

 次のような、深度バッファが自動的に副産物として作成されてます。

 実際には、深度は0.0〜1.0で表されるんだけど、これをグレー階調で表現するとこうなるわけです。白くなるほど視線からの距離がある。

 

 なんでまた自動的に副産物として深度バッファなんてものが作られるかというと、現在の3DCG描画処理の主流が、物体の形状表面を2D画面に描く時に

 

 1)すでに自分より手前にある形状表面によって画面が描かれていたら、そこには自分の形状表面を描かない。

 2)描く描かないは、画素単位で判定する。

 

 

というルールのもとに行われるようになってるからです。

 これで、どの形状表面を先に描こうが、前後関係が正しくなるわけなんですな。

 注意)厳密には形状表面を細かな三角形平面に分けて、その三角形単位で行う

 

 Zバッファ法といって、「iPhoneアプリ開発、その(98) 」で、もうちょっと詳しく説明してます。興味がある人はよんでみてね。

 

 で、このルールを実践するには、1つの形状表面を描くたびに、画素単位でその画素に描かれた形状表面の視点からの深度を記録しないと、次の形状表面を描くときに評価できないわけですよ。そのために深度バッファが必要になる。

 600x600の2D画面に表示するなら、600x600個の深度を記憶するバッファが必要になります。

 

 現在のコンピュータは3D画像は基本、描画専用の装置が担当することになってて、コンピュータの中央処理装置(CPU:Central Processing Unit)にちなんで、グラフィックの処理装置(GPU:Graphics Processing Unit)て呼ばれてるんですが、こいつが行う3DCG描画処理には、いくつかある描画方法のうちから、この深度バッファを使う方法が採用されているんですな。

 

 ちなみに「WebGLでいきますぜい」のサンプル:cube-600.htmlの以下の部分

 

        cube = new THREE.Mesh(

            new THREE.CubeGeometry(50,50,50),

            new THREE.MeshLambertMaterial({color: 0xffffff}));

 

 こいつを

 

        cube = new THREE.Mesh(

            new THREE.CubeGeometry(50,50,50),

            new THREE.MeshDepthMaterial());

 

と書き換えると、立方体だけ深度バッファをグレー階調化した描画になります。

 このさいに、カメラ側の設定もちょっといじらないと、綺麗なグレーのグラデーションじゃなく、真っ白になる。

 綺麗なグレーのグラデーションにしたいなら

 

        camera = new THREE.PerspectiveCamera( 45 , 

                frame.clientWidth / frame.clientHeight , 1 , 10000 );

 

 

        camera = new THREE.PerspectiveCamera( 45 , 

                frame.clientWidth / frame.clientHeight , 50 , 100 );

 

に変更だ!

 こうしないと、70〜90くらいの深度にある立方体の表面が

 

 1(最近)〜10000(最遠)

 

の範囲の中で、0.0〜1.0の間に正規化されるので

 

 (70〜90 -1) / (10000 - 1)

 

で、0.007〜0.009くらいの範囲になって、ほとんど変化しなくなっちゃうんですな。

 これを

 

 50(最近)〜100(最遠)

 

とするのが、上の修正。

 

 (70〜90 -50) / (100 - 50)

 

で、0.4〜0.8くらいの範囲になって綺麗にグラデーションになる。

 

 で、表示的には、こんなお手軽な方法で深度バッファを表示できるんだけど、私がやりたいのは、この深度バッファの深度情報を取り出すことなわけでして、そのためにやったのが…

 以下次回

 

AD