OpenGLでクリッピング面で切る

opengl-clip.png

全体の手順

  1. glClipPlane(GL_CLIP_PLANE0,equation);
  2. glEnable(GL_CLIP_PLANE0);
  3. 描画(クリッピングされる)

glClipPlane(GLenum plane,GLdouble *equation)

引数

GLenum plane

GL_CLIP_PLANE0,
GL_CLIP_PLANE1,
GL_CLIP_PLANE2,
GL_CLIP_PLANE3,…
みたいな定数を渡す。
あとで

glEnable(GL_CLIP_PLANEi);
...
glDisable(GL_CLIP_PLANEi);

という風に使うのだ。

GLdouble *equatiobn

Ax+By+Cz+D=0
という平面の方程式のパラメータを渡す。
Ax + By + Cz + d≧0
をみたす部分だけを描画するものである。

座標系はどうなる??

どの時点でglEnable(GL_CLIP_PLANEi);をしたかによって決まる

GLSLと併用する場合

普通に
glClipPlane(GL_CLIPPLANE0,eqn);
glEnable(GL_CLIP_PLANE0);
した上で更に、
頂点シェーダでgl_ClipVertexに値を渡してあげる必要がある。

gl_ClipVertex= ModelView*gl_Vertex;

これをしないと、クリップしてくれない。

平面の方程式

float gClipPlane=0.6f;
GLdouble eqn[]={0.0,0.0,1.0,gClipPlane};

みたいな値を渡すけど、どこで

したかによって変わってくる。これも、頂点座標を渡すのと同じと思っていい。
だから、オブジェクトと平行に切ることもできるし、
モデル行列を渡す前にやれば、視点からどのくらいの距離までを切る、みたいなことも出来る。

どの段階でglClipPlane(GL_CLIP_PLANE0,m_Eqn);するのか?

によって、変わってくる。
視点からpushする形にしたいなら、
クリップ面をobjectト alignedにしたいなら、平行移動、回転操作をした直後に

lClipPlane(GL_CLIP_PLANE0,m_ClippingEquation);
    glEnable(GL_CLIP_PLANE0);

する。
view alignedにしたいなら、平行移動回転操作するまえにやる。

クリップ面を描く

使用上の注意
これを書くとき、mBoundingBoxにだけglTranslateしないこと。
するぐらいだったら、mBoundingBoxの頂点位置データを平行移動させる。
じゃないと、クリッピング面がズレズレになっちゃうよ。

void CMeasure::DrawClipPlane(){
    vec3<float> intersection[6];
    float m[16];
    glGetFloatv(GL_MODELVIEW_MATRIX,m);
    bool visible=mBoundingBox.CalcClipPlaneVerts(m,-m_pClipped->getDis(),intersection);
    //mFontColor.glColor();
    if(visible){
        glBegin(GL_LINE_LOOP);
        for(int i = 0; i < 6; ++i) {
            intersection[i].glVertex();
        }
        glEnd();
    }
 
}

bool CalcClipPlaneVerts(double _clipEqn[4],vec3<float> intersection[6]){
            vec3<float> vecView((float)_clipEqn[0],(float)_clipEqn[1],(float)_clipEqn[2]);
 
            float mindist = vecView.innerProduct( corner[0]);
            int nearest_id = 0;//nMaxIdxは、m_pEdgeListのためのインデックス
            for(int i = 1; i < 8; ++i) {
                float dist = vecView.innerProduct(corner[i]);//各頂点との内積を求める
                if ( dist < mindist) {
                    mindist = dist;
                    nearest_id = i;//マウスで箱を動かすとここの値が変わる。初期値では0
                }
 
            }//一番遠い頂点調べるの終わり
 
            mindist += FLT_EPSILON;
 
            int count=0;
            for(int p=0;p<6;p++){
                for(int e=0;e<4;e++){
                    int index=edge_e[p][e];
                    if(index<0){
                        break;//このeは終わり
                    }
                    int vidx1 = edges[edgeList[nearest_id][index]].nV1;
                    //int(nSequence[int(frontIdx * 8 + int(v1[gl_Vertex.x * 4 +e]))]);
                    int vidx2 = edges[edgeList[nearest_id][index]].nV2;
                    //int(nSequence[int(frontIdx * 8 + int(v2[gl_Vertex.x * 4 +e]))]);
                    vec3<float> vecV1 =  corner[vidx1];
                    vec3<float> vecV2 =  corner[vidx2];
                    vec3<float> vecStart = vecV1;//+vecTranslate;
                    vec3<float> vecDir =(vecV2-vecV1).normalize();
                    float denom=vecDir.innerProduct(vecView);//立方体の辺とスライス面が完全に平行なとき0になる。
                    float lambda = (denom!= 0.0) ?  (_clipEqn[3]-vecStart.innerProduct(vecView))/denom : -1.0;
                    //どこで迷子になるのか?
                    if((lambda >= 0.0) && (lambda <= 1.0)) {
                        intersection[p] = vecStart+   vecDir*lambda;
                        count++;
                        break;
                    }//if
                }
            }
            if(count==0){return false;}else{return true;}
 
        }

サポートサイト Wikidot.com