いわゆるRayCast的なことを自前でやってみるテスト。
気づいたことや分かったことを徒然とまとめていきます。
実際に作ってみたjsdo.itのデモはこちら
手順
- 手順はまず、マウス座標をビューポートの逆変換をする(これは-1〜1の間に収まるようにするだけ。ただし、Y座標の扱いに注意)
- 次に、ProjectionMatrixの逆行列を生成する
- さらにViewMatrixの逆行列を生成する
- 求めた行列を使ってプロジェクションを適用する関数を通して変換する(逆射影変換も結局は射影変換ってこと?)
// スクリーン上のマウス位置3D空間内の座標系に変換(ビューポート行列の逆を行う)
mouseX = (mouseX/SCREEN_WIDTH) * 2 - 1;
mouseY = -(mouseY/SCREEN_HEIGHT) * 2 + 1;
とりあえず、Three.jsの中を覗いて見たものをメモ。
↓まずはProjector.js内で行われているunprojectVector
の処理。
Projector.js
this.unprojectVector = function ( vector, camera ) {
camera.projectionMatrixInverse.getInverse( camera.projectionMatrix );
_viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, camera.projectionMatrixInverse );
return vector.applyProjection( _viewProjectionMatrix );
};
getInverseメソッドで、カメラのprojectionMatrix
の逆行列をprojectioMatrixInverseに保存。
この逆行列とカメラ位置をかけたものを_viewProjectionMatrix
に保存
これらを用いて、渡されたvector
にapplyProjection
を適用している。
最終的に出来た部分
//プロジェクション変換マトリクスの生成
var projMatrix = mat4.perspective(60, w / h, 1, 100, mat4());
//ビュー座標変換マトリクスの生成
var viewMatrix = mat4.lookAt(vec3(0, 0, z), vec3(0, 0, 0), vec3(0, 1, 0));
//モデル変換マトリクスを生成
var modelMatrix = mat4();
//最終的に使用されるMVP合算マトリクスを生成
var mvpMatrix = mat4();
//...中略
//他で取得したマウスの位置を元に3次ベクトルを生成(この時点でmouse.x, mouse.yともに-1〜1の間になるよう補正済)
var pos = vec3(mouse.x, mouse.y, 0);
//プロジェクションの逆行列を生成
var invProjMatrix = mat4.inverse(projMatrix);
//ビューの逆行列を生成
var invViewMatrix = mat4.inverse(viewMatrix);
//上記の計算結果用
var res = mat4();
//生成した逆行列を掛ける
mat4.multiply(invViewMatrix, invProjMatrix, res);
//できあがった行列をマウス座標に適用する
pos = vec3.applyProjection(pos, res);