我正在制作一个OpenGL c ++应用程序,它跟踪与屏幕相关的用户位置,然后将渲染的场景更新为用户的视角。这被称为“桌面VR”,或者您可以将屏幕视为立体模型或鱼缸。我是OpenGL的新手,到目前为止只定义了一个非常简单的场景,只是一个立方体,它最初是正确渲染的。
问题在于,当我开始移动并想要重新渲染立方体场景时,投影平面似乎被翻译,我看不到我认为应该的东西。我希望这架飞机固定。如果我正在写一个光线追踪器,我的窗户将永远固定,但我的眼睛可以徘徊。有人可以向我解释一下,当我的相机/眼睛在非原点坐标上徘徊时,我能达到我想要的效果(固定观察窗口)吗?
我发现的所有例子都要求相机/眼睛位于原点,但这对我来说在概念上并不方便。另外,因为这是一个“鱼缸”,我将我的d_near设置为xy平面,其中z = 0。
在屏幕/世界空间中,我将屏幕中心指定为(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计算用户的眼睛(实际上是我脸上的网络摄像头)通常在(+/- 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;
从我在网上看到的内容来看,我的view_dir和up将保持固定状态。这意味着我只需要更新d_near和d_far以及d_x,d_y和d_y?我在glutIdleFunc(空闲)中执行此操作;
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;
}
好的,我对代码进行了一些更改,但没有成功。当我在顶点着色器中使用V代替MV时,一切看起来都像我想要的那样,透视是正确的并且对象是正确的尺寸,但是,场景是由相机的位移来转换的。
当使用C和V来获得MV时,我的场景将从观察者的视角直接渲染,渲染的场景将按照应有的方式填充窗口,但是眼睛/相机的视角会丢失。
真的,我想要的是将2D像素(投影平面)转换为眼睛/相机的适当x和y值,以保持对象的中心(其xy中心为(0,0) ))在渲染图像的中心。我以教科书“交互式计算机图形:基于着色器的OpenGL(第6版)自上而下的方法”中的示例为指导。使用与网上免费提供的书籍配对的文件,我将继续使用行主要方法。
不使用矩阵C创建MV时拍摄以下图像。当我使用C创建MV时,所有场景看起来都像下面的第一张图片。我希望z中没有翻译,所以我把它留作0.
因为投影平面和我的相机平面是平行的,所以从一个坐标系到另一个坐标系的转换只是一个平移和inv(T)〜-T。
以下是(0,0,50)的眼睛图像:
以下是(56,-16,50)的眼睛图像:
答案 0 :(得分: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();
}
}
透视矩阵的重新定义使渲染图像不会被翻译。我仍然有摄像头捕获和屏幕抓取同步问题,但我能够创建像下面的图像实时更新用户的位置:
答案 1 :(得分:0)
我发现的所有例子都要求相机/眼睛位于原点
这不是需求。 OpenGL没有定义相机,它归结为转换。这些通常称为投影和模型视图(模型和视图变换相结合)。相机,即视图变换仅仅是相机在世界空间中定位的反转。所以说你自己建立了一个相机的矩阵C
,然后你在模型视图上预测它是反向的。
mat4 MV = inv(C) * V
另外,您的着色器代码错误:
gl_Position = P * ( (V * vPosition ) / vPosition.w );
^^^^^^^^^^^^^^
在着色器中完成均匀划分 ,因为它已硬连线到渲染管道中。