カメラに関する情報を取得する

最終更新日12 Mar 2018 01:20

カメラの方向を取得する

注視点-カメラ位置のベクトルのこと
どの座標でやるかによって何通りかやり方がある。
ワールド座標の場合

vec3 viewVec = normalize(worldPosition-worldCameraPosition);

worldCameraPositionはlookAt関数の注視点として渡す値。
ビュー座標で計算する場合、
ビュー座標というのはカメラが原点となる座標なので、
ビュー座標におけるオブジェクト座標自体がカメラ方向ベクトルになる。
頂点シェーダで計算してフラグメントシェーダに渡す
out vec3 vViewDirection;
vec4 viewCoord = uModelViewMatrix * vec4(iPosition, 1.0);
vViewDirection = normalize(viewCoord.xyz);

フラグメントシェーダのgl_FragCoordから逆算する場合
gl_FragCoordはウィンドウ座標なので逆算するには以下の情報が必要

  • ウィンドウのサイズ
  • near,farの値
  • などなど。。。

かなり面倒くさい。だったら頂点シェーダからフラグメントシェーダに渡るときに
自動的に補完してくれる機能を使った方がいい

モデルビュー行列からビューベクトルを取得する方法 (オブジェクト位置(0,0,0)限定)

過去にこのページではモデルビュー行列を駆使してカメラベクトルを取得する方法をひたすら連ねていましたが、
あとから自分で見返してもわかりにくいので、
以下に述べる方法はあまりよくないと思います。
なんらかのメモリを節約したいとか特別なライブラリを使っている、
他の人のソースコードを解析してるとかの理由で
モデルビュー行列しか得られる情報がない場合は以下の方法が有用かもしれません。

glm::vec3 viewVec(-viewMatrix[2],-viewMatrix[6],-viewMatrix[10]);

ベクトルの長さ1という正規化された状態でとれる
これは注視点-カメラ位置の正規化と全く同じ結果になります。
how to convert modelview matrix to gluLookAt parameters?
しかしこれはオブジェクト位置が(0,0,0)の場合の時のビューベクトル限定なので、
これを使ってレイトレーシングはできません。

ローカル座標におけるカメラ位置を取得する

理論的に正しい方法

モデルビュー行列の逆行列に(0,0,0,1)を掛け算する

理論的に正しいが、計算コストが最もかかる。
もっと簡単にやるには、次の方法が有効

モデルビューの逆行列の3列目にマイナス1をかける

モデルビュー行列の逆行列に(0,0,0,1)を掛け算して求める方法と常に同じ結果になる。
w=1の時だけ有効らしい。
つまり、

modelviewInv[12],modelviewInv[13],modelviewInv[14]

ということ

カメラ位置の取得の仕方final
modelview

3列目説

モデルビューの3列目(つまり平行移動成分)にマイナスをかけたもの(スケール行列がかかってないときだけ有効である

モデルビュー行列の逆行列に(0,0,0,1)を掛け算して求める方法(実装の仕方)

現在のモデルビュー行列の取得

display関数にて

glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);

ここでいうローカル座標とは、物体の中心が原点になるような座標の事。
カメラ座標の原点(0,0,0,1)にモデルビューの逆行列を掛け算する(1)
\begin{pmatrix} 0&4&8&12\\ 1&5&9&13\\ 2&6&10&14\\ 3&7&11&15\\ \end{pmatrix} \begin{pmatrix} 0\\ 0\\ 0\\ 1.0\\ \end{pmatrix}
  1. ワールド座標での頂点=modelMatrix*ローカル座標の頂点
  2. ワールド座標での頂点と、カメラの初期位置(0,0,-6)との距離を計算

これを最適化すると、結局求めたい結果は

(2)
\begin{pmatrix} 12\\ 13\\ 14\\ 15\\ \end{pmatrix}

逆行列成分の(12,13,14,15)なのだということがわかる。
逆行列を得る

サンプルコード

mModelView=glm::mat4();//loadidentity
    glm::vec3 lookat(0.0f,0.0f,0.0f);
    glm::vec3 upper(0.0f,1.0f,0.0f);
    mModelView=glm::lookAt(glm::vec3(0.0,0.0,mZoom),lookat,upper);
    mModelView=mModelView*rotation;
    mModelViewProj=mProj*mModelView;
    mInvModelView=glm::inverse(mModelView);
    camera=mInvModelView*glm::vec4(0.0,0.0,0.0,1.0);
    printf("(%f,%f,%f)\n",camera.x,camera.y,camera.z);

QuickSortRenderingCheckより

[quicksort]のページにあるQuickSortRenderingCheckというプログラムから抜粋。

CMatrix modelCmatrix(modelMatrix);
    modelCmatrix.transpose();
    modelCmatrix.invert();
        CVector vecView(0,0,0,1);
        vecView=modelCmatrix*vecView;        
        vecView.getv(camera);
        Vec3 cameraVec=Vec3((float)camera[0],(float)camera[1],(float)camera[2]);
        for(int i=0;i<blockNum*blockNum*blockNum;i++){
            blockSorting[i][1]=    debugBlock[(int)blockSorting[i][0]].setDistanceFromCamera(cameraVec);    
        //前フレームで並びかえた結果を使って、だいぶちらつきが減った!!
        }//printf("distance=%.3f\n",debugBlock[63].distanceFromCamera);
//centerVecが必要
float Block::setDistanceFromCamera(Vec3 camera){
    Vec3 distanceVec=camera-(this->blockCenterPoint);//this->blockCenterPoint.print();
 
    this->distanceFromCamera=distanceVec.length();//100倍しないとほとんど差がでないから
    if(this->distanceFromCamera==0.0f)printf("中心点を設定してください。視点からの距離が計算できません\n");
    //printf("%.3f\n",this->distanceFromCamera);
 
    return this->distanceFromCamera;
}

関連事項

違う角度から見た図を載せる…..取得したカメラ位置があってるかどうか視覚的に確認する。
Extracting camera position from a ModelView Matrix


matrix modelview-matrix


ファイル

サポートサイト Wikidot.com matrixmodelview-matrix