テクスチャースライシング

本物のページはこちら→texture-slicing

関連ページ

List of pages tagged with slice:

slice64.png

カメラの座標を取得する

前提条件

ここであつかうバウンディングボックスとなる立方体はx,y,zすべての方向において同じサイズの立方体とする。

基本的な考え方

path.png

現在最も手前の頂点から、常に3つの独立した経路が存在している。
この場合、現在最も手前の頂点は6になる。
ここでいう、独立した経路の意味は、始点と終点以外、そこの頂点も共有していない、という意味である。

  • 経路….視点から見て一番手前の頂点と一番奥の頂点を結ぶ。
intersects.png

交点は最大で6つできる

  • P0….緑の経路上に出来る交点
  • P1…緑の経路上に出来る交点
  • P2 ….ピンクの経路上に出来る交点
  • P3 ….ピンクの経路上に出来る交点
  • P4 …青の経路上に出来る交点
  • P5 …青の経路上に出来る交点

うち、破線上に出来る交点は出来たりできなかったりする、
もし出来なかったら他の実線上の交点と一緒の位置にされて見えなくする、という形で実装すればいい。

overlay.pngこんなかんじ。P5とP6が重なっている

頂点シェーダで使う変数名の説明

  • vecTranslate….1立方体につき1個。
  • vecVertices[8]….立方体の座標を示す、位置。ずっと同じままだからconstant。
  • frontIdx….立方体で、現在一番手前に来ている頂点番号。毎フレーム変化する。求め方は視点に一番近い立方体の頂点を求める参考。
  • vecView…視線ベクトル。描く断面はこの視線ベクトルに対して垂直になる
  • nSequence…今どの頂点が手前かを示すfrontIdxに応じた、頂点インデックスの組み合わせを示す入れる。

シェーダ

cube_new.png
こういう場合
.cpp側のコード
glUseProgram(m_SliceProgram);
    glUniform1f(m_Map[1]["threshold"],m_threshold);    
    glUniform3fv(m_Map[1]["u_translate"],m_threshold,&_tra.x);    
    //頂点配列有効 レイキャスティング+ブロック化による不自然なクリッピング面問題を解決するための部分
    glBegin(GL_POLYGON);//x座標は各交点,y座標はスライスの位置が立方体の中心からどれくらいの距離かを示す
        glVertex2f(0.0,_zoom);//P0
        glVertex2f(1.0,_zoom);//P1
        glVertex2f(2.0,_zoom);//P2
        glVertex2f(3.0,_zoom);//P3
        glVertex2f(4.0,_zoom);//P4
        glVertex2f(5.0,_zoom);//P5
    glEnd();
    glUseProgram(0);
//uniform int    frontIdx;
varying vec3 v_cam_local;//オブジェクト中心から見た時のカメラの座標・位置
varying vec3 uvw;//0.0-1.0に正規化された3Dテクスチャ座標
int nSequence[64] = 
{0,1,2,3,4,5,6,7,              
1,4,5,0,3,7,2,6,
2,5,6,0,1,7,3,4,
3,0,6,4,1,2,7,5,
4,3,7,1,0,6,5,2,
5,7,2,1,4,6,0,3,
6,2,7,3,0,5,4,1,
7,6,4,5,2,3,1,0};
 
vec3 vecVertices[8]= 
{ {1.0,1.0,1.0},
{1.0,1.0,0.0},
{1.0,0.0,1.0},
{ 0.0,1.0,1.0},
{0.0,1.0,0.0},
{1.0,0.0,0.0},
{0.0,0.0,1.0},
{0.0,0.0,0.0}};
//横軸はe=0=red,1=blue,2=green
int v1[24] = {0,0,1,4, 1,0,1,4, 0,0,2,5, 2,0,2,5, 0,0,3,6, 3,0,3,6};
int v2[24] = {0,1,4,7, 5,1,4,7, 0,2,5,7, 6,2,5,7, 0,3,6,7, 4,3,6,7};
 
void main(){
    vec3 vecTranslate=vec3(-0.5,-0.5,-0.5);
    v_cam_local=vec4(gl_ModelViewMatrixInverse*vec4(0.0,0.0,0.0,1.0)).xyz;
    int frontIdx;
    if(v_cam_local.x >= 0 && v_cam_local.y >= 0 && v_cam_local.z >= 0)
        frontIdx = 0;
    else if(v_cam_local.x >= 0 && v_cam_local.y >= 0 &&  v_cam_local.z  < 0)
        frontIdx = 1;
    else if(v_cam_local.x >= 0 && v_cam_local.y < 0 &&  v_cam_local.z  >= 0)
        frontIdx = 2;
    else if(v_cam_local.x < 0 && v_cam_local.y >= 0 &&  v_cam_local.z  >= 0)
        frontIdx = 3;
    else if(v_cam_local.x < 0 && v_cam_local.y >= 0 &&  v_cam_local.z  < 0)
        frontIdx = 4;
    else if(v_cam_local.x >= 0 && v_cam_local.y < 0 &&  v_cam_local.z < 0)
        frontIdx = 5;
    else if(v_cam_local.x < 0 && v_cam_local.y < 0 &&  v_cam_local.z  >= 0)
        frontIdx = 6;
    else 
        frontIdx = 7;
    vec3 vecView=normalize(v_cam_local);
    v_cam_local+=0.5;
 
    float dPlane = gl_Vertex.y;
    vec3 Position=vec3(0.0,0.0,0.0);//25
    for(int e = 0; e < 4; e++){//26
        int vidx1 = int(nSequence[int(frontIdx * 8 + int(v1[gl_Vertex.x * 4 +e]))]);//27
        int vidx2 = int(nSequence[int(frontIdx * 8 + int(v2[gl_Vertex.x * 4 +e]))]);//28
        vec3 vecV1 =  vecVertices[vidx1];//29
        vec3 vecV2 =  vecVertices[vidx2];//30
        vec3 vecStart = vecV1+vecTranslate;//31
        vec3 vecDir =normalize(vecV2-vecV1);//32
        float denom=dot(vecDir,vecView);//33 立方体の辺とスライス面が完全に平行なとき0になる。
        float lambda = (denom!= 0.0) ?  (dPlane-dot(vecStart,vecView))/denom : -1.0;
        //どこで迷子になるのか?
        if((lambda >= 0.0) && (lambda <= 1.0)) {
            Position = vecStart+  lambda * vecDir;
            break;
        }//if
    }//for
    gl_Position = gl_ModelViewProjectionMatrix* vec4(Position,1.0);//40
    uvw=(Position)+0.5;
    return;
};

遭遇したエラー

いくつかの頂点が手前の時は六角形が欠ける!

failed.png
手前の頂点インデックスがおかしい時に起こる
frontIdxが届いてなかった。ユニフォーム変数を渡すときは、glUseProgramした後じゃないとダメ。
いつも同じfrontIdxだと、例えば常にfrontIdx=0だったら、頂点2,3,4,5が手前の時、六角形が欠ける。
あるいは
nSequenceがおかしくないかチェック
縦横の頂点インデックスに重複があったらおかしくなるよ

スライス多角形がしわくちゃになる

dirty.png
 void main(){
                     float dPlane = dPlaneStart + Vin.y*dPlaneIncr;
                      vec3 Position;
                      for(int e = 0; e < 4; ++e){
                          int vidx1 = int(nSequence[int(frontIdx * 8 + int(v1[Vin.x * 4 +e]))]);
                          int vidx2 = int(nSequence[int(frontIdx * 8 + int(v2[Vin.x * 4 +e]))]);
                          vec3 vecV1 =  vecVertices[vidx1];
                          vec3 vecV2 =  vecVertices[vidx2];
                          vec3 vecStart = vecV1+vecTranslate;
                          vec3 vecDir = vecV2-vecV1;
                          float denom=dot(vecDir,vecView);
                          float lambda = (denom!= 0.0) ?  (dPlane-dot(vecStart,vecView))/denom : -1.0;
                          if((lambda >= 0.0) && (lambda <= 1.0)) {
                             Position = vecStart + lambda * vecDir;
                              break;
                          }//if
                      }//for
                      "gl_Position = modelViewProj* vec4(Position,1.0);
                      "color=  vec4(0.0,0.0,float(frontIdx)/7.0,1.0);
                      volpos=(0.5*Position)+0.5;
                      return;
}

行方不明のPositionが原因。つまり、vec3 Positionに何の値も与えられないままbreakしてしまったパターンが存在するってこと。

複数枚書くと、一部バグる。スライスがちかちかする

flick.jpg

GL_TRIANGLE_FANで複数のスライスを一気につなげて書くと、変になる。一枚一枚分けること。
良いコード

glEnableVertexAttribArray(ATTRIB_VERTEX);
    for(int i=0;i<gSliceNum;i++){
        glDrawArrays(GL_TRIANGLE_FAN,i*6,6);
    }

悪いコード
glEnableVertexAttribArray(ATTRIB_VERTEX);
glDrawArrays(GL_TRIANGLE_FAN,0,6*gSliceNum);

どうしてもはじっこに変なのがはみ出る。

dPlaneStartとdPlaneEndがぴったりすぎると、立方体からはみ出てしまい、そのせいで行方不明のPositionになる。
少し内側にずらすのがコツ。

        mPlaneEnd-=0.0001f;
        mPlaneStart+=0.0001f;//eyeの初期値(5+キューブの対角線3.464=2*√3)

ソースコード

gitに置きました。

サポートサイト Wikidot.com