投影すること

最終更新日12 Feb 2017 00:57

3次元のものを2次元に投影するってどういうことだろう?
3Dコンピュータグラフィックスの基本です。
projection射影ともいう
射影とは

物体に光を当ててその影を映すこと、またその影のこと

である
コンピュータのモニターは2次元の平面である。
なので、OpenGLによってレンダリングされる3Dの情景は
コンピュータースクリーンに投影されて最終的に2次元の絵にならなければならないのである。
もっと言えば、画面の幅×高さ個のピクセルの2次元配列にならないといけないのである。
カメラ=原点の状態であるカメラ座標系からクリップ座標系に変換する。
OpenGLの投影行列では
カメラ座標系クリップ座標系正規化デバイス座標までの変換をいっきにやってくれる。

カメラと比較

nearクリッピング面は、投影される面になる。つまり、焦点となる

用語の定義

用語 意味 座標系
ビュー平面 投影面。あなたが見てる画面のこと ウィンドウとも呼ばれる
VRP ビューリファレンス点 View Reference Point VRCの原点
VPN View Plane Normalビュー平面垂線。ビュー平面の法線のこと
VUP View Up Vector 表示ベクトル
VRC View Reference Coordinate 3次元ビューリファレンス座標
CW ウィンドウの中心
DOP Direction Of Projection 投影方向
PRP 投影の基準点 VRC座標系
透視投影 平行投影
投影中心 PRP(投影基準点)→CW(ウィンドウ中心) DOP

参考にした書籍

glProjectベタ書きバージョン

How to do picking in modern OpenGL without gluUnProject?

    /*!
    @param  _local_posオブジェクトの中心が原点な座標系
    */
    template <typename T>
    vec3<T> project(const vec3<T> _local_pos,const mat4<T>& _modelmatrix,const mat4<T>& _projmatrix,T _near,T _far,const vec2<int>& _winsize){
            vec4<T> view_pos;//視点が原点な座標系
            vec4<T> clip_pos;//クリップ座標での位置
            vec3<T> normalized_device_pos;
            view_pos=_modelmatrix*_local_pos;//ローカル座標→カメラ座標
            clip_pos=_projmatrix*view_pos;//カメラ座標→クリップ座標
            //クリップ座標→wで割って正規化デバイス座標になる//正規化デバイス座標はX座標が -1.0f から1.0f,Y座標が-1.0f から 1.0f ,Z軸が0.0f から 1.0f 
            if( clip_pos.w==0.0){//視界の外にある。本来なら、ビューフラスタムテストで除外されているはず。
                return vec3<T>(0.0,0.0,0.0);//見えてないから0
            }
            normalized_device_pos.x =clip_pos.x/ clip_pos.w;
            normalized_device_pos.y =clip_pos.y/ clip_pos.w;
            normalized_device_pos.z =clip_pos.z/ clip_pos.w;
            cout<<"w="<<clip_pos.w<<" near:"<<_near<<","<<_far<<endl;
            //正規化デバイス座標→デバイス座標へ
            vec3<T> device_pos;
            device_pos.x=(normalized_device_pos.x+1.0)*(T)_winsize.x*0.5;
            device_pos.y=(normalized_device_pos.y+1.0)*(T)_winsize.y*0.5;
            device_pos.z=(normalized_device_pos.z*(_far-_near)+(_near+_far))*0.5;
            //0.5をかけたのは、正規化デバイス座標の長さが2.0だから。
            return device_pos;//引き算する=距離・サイズ
 
        }

unproject

    /*!
    @param _device_pos デバイス座標
    @param _objZ 求めたいオブジェクト座標のz平面をどこにするかの指定
    */
    template <typename T>    
    vec3<T> unproject(T _deviceX,T _deviceY,T _objZ,const mat4<T>& _modelView,const mat4<T>& _proj,vec2<int>& _winsize,T _near,T _far){
        //デバイス座標→正規化デバイス座標
        vec4<T> normalized_device_pos;
        normalized_device_pos.x=_deviceX*2.0/(T)_winsize.x-1.0;
        normalized_device_pos.y=_deviceY*2.0/(T)_winsize.x-1.0;
        normalized_device_pos.z=(0.0-(_near+_far)*0.5)/(_far-_near);//deviceZ=0とみなした値
        //正規化デバイス座標→クリップ座標
        //wの値 投影行列の三列目は常に[0,0,-1,0]なので、結局モデルビューの3行目にマイナスかけたものになる
        T w=_modelView.m[3]*x+_modelView.m[7]*y+_modelView.m[11]*_objZ+_modelView[15];
        vec4<T> clip_pos;//クリップ座標での位置
        clip_pos.x=normalized_device_pos.x*w;
        clip_pos.y=normalized_device_pos.y*w;
        clip_pos.z=normalized_device_pos.z*w;
        clip_pos.w=w;
        vec4<T> view_pos;//視点が原点な座標系
        view_pos=_proj.inv()*clip_pos;
        vec4<T> obj_pos=_modelView.inv()*view_pos;
    }

viewing-pipeline


files

サポートサイト Wikidot.com viewing-pipeline