投影された立方体の大きさ

lod-switch-cube.png

立方体の場合、球の場合と違って、見る角度によって投影面積が違う。
とはいえ、大体3つのパターンになる

cube1.png cube2.png cube3.png

効率的な方法

Schmalstiegさん.pdfの考えた効率的な方法は、
立方体に関するカメラの視点を分類し、
その分類を使って、投影された立方体の輪郭にどの投影頂点が含まれているかを決定すること。
それらの頂点を使ってポリゴンの面積計算の方法で面積を計算する。

  1. 視点が立方体の平面のどちら側にあるかを判定
    1. 3つのパターンのうちのどれかがわかる
  2. 比較の結果をLUT(loot up table)のインデックスとして使う。
  3. ルックアップテーブルには、視点から見える輪郭内の頂点の数が入っている
  4. もうひとつのルックアップテーブルを使って実際にどの頂点が輪郭をなしているのかを参照する。
  5. これらの「輪郭をなす頂点」をスクリーンに投影した(たぶん、行列を掛け算するんだろうな)後面積を計算する。

馬鹿正直な方法

オブジェクトが星形だろうがなんだろうが、この方法ならなんでも計算できるよん★

vec2<T> projectedsize(const mat4<T>& _modelmatrix,const mat4<T>& _projmatrix,const vec2<int>& _winsize){
        T max_distance = numeric_limits<T>::min();//カメラから頂点への距離の最大値
 
        vec4<T> local_pos;//オブジェクトの中心が原点な座標系
        vec4<T> view_pos;//視点が原点な座標系
        vec4<T> clip_pos;//クリップ座標での位置
        vec2<T> normalized_device_pos;
        //正規化デバイス座標系のキューブの中で投影された中でも一番右上と左下を求めて最大の大きさを知る
        vec2<T> minNrmDvPos(numeric_limits<T>::max(),numeric_limits<T>::max());
        vec2<T>    maxNrmDvPos(-numeric_limits<T>::max(),-numeric_limits<T>::max());
        for(int i = 0;i  < 8;i++)//
        {
            local_pos.set(corner[i]);
            //_modelmatrix.print("モデルビュー");
            view_pos=_modelmatrix*local_pos;
            // view_pos.print("視点座標");
            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){//視界の外にある。本来なら、ビューフラスタムテストで除外されているはず。
                assert(!"変だ ちゃんとモデルビュー取得した?");//return vec2<T>(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;
            if(normalized_device_pos.x<minNrmDvPos.x){
                minNrmDvPos.x=normalized_device_pos.x;
            }
            if(normalized_device_pos.x>maxNrmDvPos.x){
                maxNrmDvPos.x=normalized_device_pos.x;
            }
            //めんどくさいようだけど、xとyは別々にやらなきゃならない。
            if(normalized_device_pos.y<minNrmDvPos.y){
                minNrmDvPos.y=normalized_device_pos.y;
            }
            if(normalized_device_pos.y>maxNrmDvPos.y){
                maxNrmDvPos.y=normalized_device_pos.y;
            }
 
        }
 
        //0.5をかけたのは、正規化デバイス座標の長さが2.0だから。
        vec2<T> winsize((T)_winsize.x*(T)0.5,(T)_winsize.y*(T)0.5);
        return vec2<T>(vec2<T>(maxNrmDvPos-minNrmDvPos)*winsize);//引き算する=距離・サイズ
 
    }

投影された立方体を表示

    void drawProjectedBoundingBox(const mat4<T>& _modelmatrix,const mat4<T>& _projmatrix,const vec2<int>& _winsize){
        T max_distance = numeric_limits<T>::min();//カメラから頂点への距離の最大値
 
        vec4<T> local_pos;//オブジェクトの中心が原点な座標系
        vec4<T> view_pos;//視点が原点な座標系
        vec4<T> clip_pos;//クリップ座標での位置
        vec2<T> normalized_device_pos;
        //正規化デバイス座標系のキューブの中で投影された中でも一番右上と左下を求めて最大の大きさを知る
        vec2<T> minNrmDvPos(numeric_limits<T>::max(),numeric_limits<T>::max());
        vec2<T>    maxNrmDvPos(-numeric_limits<T>::max(),-numeric_limits<T>::max());
        for(int i = 0;i  < 8;i++)//
        {
            local_pos.set(corner[i]);
            //_modelmatrix.print("モデルビュー");
            view_pos=_modelmatrix*local_pos;
            // view_pos.print("視点座標");
            clip_pos=_projmatrix*view_pos;
            //wで割って正規化デバイス座標になる
            //正規化デバイス座標はX座標が -1.0f から1.0f,Y座標が-1.0f から 1.0f ,Z軸が0.0f から 1.0f 
 
            normalized_device_pos.x =clip_pos.x/ clip_pos.w;
            normalized_device_pos.y =clip_pos.y/ clip_pos.w;
            if(normalized_device_pos.x<minNrmDvPos.x){
                minNrmDvPos.x=normalized_device_pos.x;
            }
            if(normalized_device_pos.x>maxNrmDvPos.x){
                maxNrmDvPos.x=normalized_device_pos.x;
            }
            //めんどくさいようだけど、xとyは別々にやらなきゃならない。
            if(normalized_device_pos.y<minNrmDvPos.y){
                minNrmDvPos.y=normalized_device_pos.y;
            }
            if(normalized_device_pos.y>maxNrmDvPos.y){
                maxNrmDvPos.y=normalized_device_pos.y;
            }
 
        }
        //0.5をかけたのは、正規化デバイス座標の長さが2.0だから。
        vec2<T> winsize((T)_winsize.x*(T)0.5,(T)_winsize.y*(T)0.5);
        vec2<T> minpos=(minNrmDvPos+(T)1.0)*winsize;
        vec2<T> maxpos=(maxNrmDvPos+(T)1.0)*winsize;
 
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        gluOrtho2D(0,_winsize.x,0,_winsize.y);
            glMatrixMode(GL_MODELVIEW);
            glPushMatrix();
            glLoadIdentity();
            glRasterPos2d((minpos.x+maxpos.x)*0.5,maxpos.y+10);
            stringstream message;
            message<<(int)(maxpos.x-minpos.x)<<"pixel";
            glutBitmapString(GLUT_BITMAP_HELVETICA_18,reinterpret_cast<const unsigned char*>(message.str().c_str()));
            message.str("");
            glRasterPos2d(maxpos.x,(minpos.y+maxpos.y)*0.5);
            message<<(int)(maxpos.y-minpos.y)<<"pixel";
            glutBitmapString(GLUT_BITMAP_HELVETICA_18,reinterpret_cast<const unsigned char*>(message.str().c_str()));
 
                glBegin(GL_LINE_LOOP);
                glVertex2f(minpos.x,minpos.y);
                glVertex2f(maxpos.x,minpos.y);
                glVertex2f(maxpos.x,maxpos.y);
                glVertex2f(minpos.x,maxpos.y);
                glEnd();
            glPopMatrix();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
 
        //glRectfv(&minpos.x,&maxpos.x);
    }
Bibliography
1. aabox.pdf….Real-time Bounding Box Area Computation.pdf
2. Real-Time Rendering….のp342

サポートサイト Wikidot.com