マウスピッキングで頂点を編集する

処理の流れは,こうなります.(マウスでピックしたものは手前のものであると仮定する)

  • マウスでピッキングする.
  • ピックしたオブジェクトの識別番号を取得する.
  • ピックしたウィンドウ座標と,ピクセルのデプスバッファからCGの3次元座標を求める.
  • 得られた3次元座標データをオブジェクト識別番号を元にフィードバックする.
  • ピックしたオブジェクトの識別番号の取得は"マウスピッキング"セクションを参考にしてください.

    glReadPixelsでデプスバッファを読み取る

    描画されたオブジェクトをクリックします.通常の描画方法であれば,そのオブジェクトは当然最も手前にあるものになります.このときデプスバッファを使用しているならばすべてのピクセルに対して深さ情報が付加されています.そして,OpenGLではその深さ情報を元に世界座標での3次元座標を算出することが可能です.ここでの世界座標とはOpenGL内で描画するときのあらゆる行列計算がなされた後の頂点の座標のことを指します.
    これがクリックした点からデプスバッファを取得する関数です.

    //クリックしたところの描画したもののデプス値を取得する.
    float returnDepth(int x, int y){
    float z;
    GLint viewport[4];                      //ビューポート
    //デバイス座標系とウィンドウ座標系の変換
    glGetIntegerv(GL_VIEWPORT,viewport);    //現在のビューポートを代入
    glReadPixels(x,viewport[3]-y,1,1,
    GL_DEPTH_COMPONENT,
    GL_FLOAT,
    &z);
    // デプスバッファの値を返す.
    return z;
    }
    

    glReadPixelsを用いてデプスバッファを取得します.
    3つ目の引数にGL_DEPTH_COMPONENTを指定することで指定したピクセル内のデプスバッファを取得することが出来ます.glReadPixelsに関しては"描画結果をBitmapに保存する."セクションも参考にしてみてください.

    gluUnproject

    gluUnProjectによってウィンドウ座標をデプスバッファを元に,描画するときのオブジェクトの3次元座標を復元することが出来ます.
    glUnProjectは,いくつかの引数を持ちます.最初の3つはウィンドウ座標X, Yとデプスバッファです.次の3つはModelView行列,Projection行列,Viewportを入れたポインタとなります.これらの値はglGetIntegerv,glGetDoublevなどで取得することが出来ます.
    最後の3つは算出された世界座標が戻される3つの変数のポインタとなります.

    ////////////////////////////////////////////////////////////////////
    //クリックした点にあるピクセルのデプス値を用いて,世界座標を割り出す.
    void  CalculateWorldCo(
    int x, int y, float depth,
    double &wx, double &wy,double &wz){
    // 4*4行列を二つ用意する
    GLdouble mvMatrix[16],pjMatrix[16];
    // ビューポート用配列
    GLint viewport[4];
    // パラメータを取得する.
    glGetIntegerv(GL_VIEWPORT, viewport);
    glGetDoublev(GL_MODELVIEW_MATRIX, mvMatrix);
    glGetDoublev(GL_PROJECTION_MATRIX, pjMatrix);
    //世界座標を取得する
    gluUnProject((double)x,(double)viewport[3]-y,depth,
    mvMatrix,
    pjMatrix,
    viewport,
    &wx,
    &wy,
    &wz);
    }
    

    これで世界座標を取得することが出来ました.

    コーディング

    後はこれらの処理をどうつないでいくかが問題になります.今回のサンプルではこういう流れになっています.


    データベースと呼ぶほどのものを作ってはいませんwこういった処理は工夫のしどころがたくさんあると思います.

  • オブジェクトがヒットするとそのオブジェクトの識別番号を取得します.
  • その番号からオブジェクトの座標データを取得.
  • gluUnProjectで処理しながらデータベースの座標を修正していく・・.
  • という流れになっています.

    ソースコード

    http://code.google.com/p/sonson-code/source/browse/#svn/trunk/gl/feedback_pick
    本ソースコードを使用したことによる如何なる損害も製作者は責任を負いません.