画面に対するユーザーの位置を追跡し、レンダリングされたシーンをユーザーの視点に合わせて更新する 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)での目の画像です:
(56,-16,50) での目の画像は次のとおりです。