4

画面に対するユーザーの位置を追跡し、レンダリングされたシーンをユーザーの視点に合わせて更新する OpenGL c++ アプリケーションを作成しています。これは「デスクトップ VR」と呼ばれ、画面をジオラマや水槽と考えることができます。私は OpenGL の初心者で、これまで非常に単純なシーン (立方体のみ) しか定義しておらず、最初は正しくレンダリングされていました。

問題は、移動を開始して立方体シーンを再レンダリングしたいときに、投影面が変換されたように見え、本来あるべき姿が見えないことです。この飛行機を直してほしい。レイ トレーサーを書いている場合、ウィンドウは常に固定されますが、目はさまよいます。カメラ/目を非原点座標でさまよいながら、希望する効果(表示ウィンドウを固定する)を実現する方法を誰かに説明してもらえますか?

私が見つけたすべての例は、カメラ/目が原点にあることを要求していますが、これは私にとって概念的に便利ではありません。また、これは「水槽」であるため、d_near を z = 0 の xy 平面に設定しています。

画面/ワールド空間では、画面の中心を (0,0,0) に割り当て、その 4 つのコーナーを次のように割り当てます: TL(-44.25, 25, 0) TR( 44.25, 25, 0) BR( 44.25,-25 , 0) BL(-44.25,-25, 0) これらの値は、16x9 ディスプレイの場合の cm 単位です。

次に、POSIT を使用してユーザーの目 (実際には私の顔の Web カメラ) を計算し、通常は (+/-40、+/-40、40-250) の範囲のどこかにあるようにします。私の POSIT メソッドは正確です。

パースペクティブ用に独自のマトリックスを定義し、変換を表示し、シェーダーを使用しています。

次のように初期化します。

float right = 44.25;
float left = -44.25;
float top = 25.00;
float bottom = -25.00; 

vec3 eye = vec3(0.0, 0.0, 100.0);
vec3 view_dir = vec3(0.0, 0.0, -1.0);
vec3 up = vec3(0.0, 1.0, 0.0);
vec3 n = normalize(-view_dir);
vec3 u = normalize(cross(up, n)); 
vec3 v = normalize(cross(n, u));

float d_x = -(dot(eye, u));
float d_y = -(dot(eye, v));
float d_z = -(dot(eye, n));

float d_near = eye.z;
float d_far = d_near + 50;

// perspective transform matrix
mat4 P = mat4((2.0*d_near)/(right-left ), 0, (right+left)/(right-left), 0, 
            0, (2.0*d_near)/(top-bottom), (top+bottom)/(top-bottom), 0,
            0, 0, -(d_far+d_near)/(d_far-d_near), -(2.0*d_far*d_near)/(d_far-d_near),
            0, 0, -1.0, 0);

// viewing transform matrix
mat4 V = mat4(u.x, u.y, u.z, d_x,
              v.x, v.y, v.z, d_y,
              n.x, n.y, n.z, d_z,
              0.0, 0.0, 0.0, 1.0);

mat4 MV = C * V;
//MV = V;

Web で調べたところ、view_dir 以降は修正されたままです。これは、d_near と d_far だけでなく、d_x、d_y、d_y を更新するだけでよいことを意味します。私は glutIdleFunc( idle ); でこれを行います。

void idle (void) {  

    hBuffer->getFrame(hFrame);
    if (hFrame->goodH && hFrame->timeStamp != timeStamp) {
        timeStamp = hFrame->timeStamp;
        std::cout << "(" << hFrame->eye.x << ", " <<
                    hFrame->eye.y << ", " <<
                    hFrame->eye.z << ") \n";

        eye = vec3(hFrame->eye.x, hFrame->eye.y, hFrame->eye.z);

        d_near = eye.z;
        d_far = eye.z + 50;

        P = mat4((2.0*d_near)/(right-left), 0, (right+left)/(right-left), 0, 
                 0, (2.0*d_near)/(top-bottom), (top+bottom)/(top-bottom), 0,
                 0, 0, -(d_far+d_near)/(d_far-d_near), -(2.0*d_far*d_near)/(d_far-d_near),
                 0, 0, -1.0, 0);

        d_x = -(dot(eye, u));
        d_y = -(dot(eye, v));
        d_z = -(dot(eye, n));

        C = mat4(1.0, 0.0, 0.0, eye.x,
                 0.0, 1.0, 0.0, eye.y,
                 0.0, 0.0, 1.0, 0.0,
                 0.0, 0.0, 0.0, 1.0);

        V = mat4(u.x, u.y, u.z, d_x,
                 v.x, v.y, v.z, d_y,
                 n.x, n.y, n.z, d_z,
                 0.0, 0.0, 0.0, 1.0);

        MV = C * V;
        //MV = V;

        glutPostRedisplay();
    }
}

ここに私のシェーダーコードがあります:

#version 150

uniform mat4 MV;
uniform mat4 P;
in vec4 vPosition;
in vec4 vColor;
out vec4 color;

void 
main() 
{ 
    gl_Position = P * MV * vPosition;
    color = vColor;
}

OK、コードにいくつかの変更を加えましたが、成功しませんでした。頂点シェーダーで MV の代わりに V を使用すると、すべてが思いどおりに見え、遠近法は正しく、オブジェクトは適切なサイズになりますが、シーンはカメラの変位によって変換されます。

C と V を使用して MV を取得すると、シーンはオブザーバーの視点からまっすぐにレンダリングされ、レンダリングされたシーンはウィンドウを埋めますが、目/カメラの視点は失われます。

本当に、私が望むのは、オブジェクトの中心 (xy 中心が (0,0) である) をレンダリング イメージの中心。教科書「Interactive Computer Graphics: A Top-Down Approach with Shader-Based OpenGL (6th Edition)」の例を参考にしています。Web で無料で入手できる本とペアになっているファイルを使用して、行優先のアプローチを続けています。

以下の画像は、マトリックスCを使用してMVを作成しない場合に撮影されます。C を使用して MV を作成すると、すべてのシーンが下の最初の画像のようになります。z を平行移動させたくないので、0 のままにします。

投影面と私のカメラ面は平行なので、一方の座標系から他方の座標系への変換は単純な変換と inv(T) ~ -T です。

これが(0,0,50)での目の画像です: これが(0,0,50)での目の画像です:

(56,-16,50) での目の画像は次のとおりです。 (56,-16,50) での目の画像は次のとおりです。

4

2 に答える 2

3

解決策は、新しい目の位置を考慮して d_x、d_y、および d_z を更新することですが、u、v、または n は決して変更しないでください。さらに、カメラ/目の新しい位置に関連するため、行列 P を左、右、上、下の新しい値で更新する必要があります。

私はこれで初期化します:

float screen_right = 44.25;
float screen_left = -44.25;
float screen_top = 25.00;
float screen_bottom = -25.00; 
float screen_front = 0.0;
float screen_back = -150;

これで、アイドル関数は次のようになります。上、下、右、左の計算に注意してください。

void idle (void) {  

hBuffer->getFrame(&hFrame);
if (hFrame.goodH && hFrame.timeStamp != timeStamp) {
    timeStamp = hFrame.timeStamp;
    //std::cout << "(" << hFrame.eye.x << ", " <<
    //                  hFrame.eye.y << ", " <<
    //                  hFrame.eye.z << ") \n";

    eye = vec3(hFrame.eye.x, hFrame.eye.y, hFrame.eye.z);

    d_near = eye.z;
    d_far = eye.z + abs(screen_back) + 1;

    float top = screen_top - eye.y;
    float bottom = top - 2*screen_top;
    float right = screen_right - eye.x;
    float left = right - 2*screen_right;

    P = mat4((2.0 * d_near)/(right - left ), 0.0, (right + left)/(right - left), 0.0, 
             0.0, (2.0 * d_near)/(top - bottom), (top + bottom)/(top - bottom), 0.0,
             0.0, 0.0, -(d_far + d_near)/(d_far - d_near), -(2.0 * d_far * d_near)/(d_far - d_near),
             0.0, 0.0, -1.0, 0.0);

    d_x = -(dot(eye, u));
    d_y = -(dot(eye, v));
    d_z = -(dot(eye, n));

    V = mat4(u.x, u.y, u.z, d_x,
             v.x, v.y, v.z, d_y,
             n.x, n.y, n.z, d_z,
             0.0, 0.0, 0.0, 1.0);

    glutPostRedisplay();
}

}

この遠近法マトリックスの再定義により、レンダリングされたイメージが移動しなくなります。カメラ キャプチャとスクリーン グラブの同期の問題はまだありますが、次のような画像を作成して、ユーザーの位置をリアルタイムで更新することができます。

ここに画像の説明を入力

于 2013-04-21T19:33:19.903 に答える