2013-04-17 34 views
4

我正在制作一个OpenGL C++应用程序,用于跟踪用户相对于屏幕的位置,然后将呈现的场景更新为用户的视角。这被称为“桌面VR”,或者您可以将屏幕想象为立体布景或鱼缸。我对OpenGL相当陌生,迄今为止只定义了一个非常简单的场景,只是一个立方体,并且它最初是正确渲染的。OpenGL桌面虚拟现实的非对称Fr 012

问题是,当我开始移动并想要重新渲染立方体场景时,投影平面似乎已经翻译过了,我没有看到我认为我应该做的事。我想要修理这架飞机。如果我正在写一个光线追踪器,我的窗口将永远是固定的,但我的眼睛可以漫步。有人可以向我解释如何让我的相机/眼睛在非原点坐标上漂移时如何达到我想要的效果(固定观看窗口)?

我发现所有的例子都要求相机/眼睛在原点,但这对我来说在概念上并不方便。另外,因为这是一个“鱼缸”,所以我将d_near设置为z = 0的xy平面。

在屏幕/世界空间中,我将屏幕中心分配给(0,0 ,0)以及它的四个角落到: TL(-44.25,25,0) TR(44.25,25,0) BR(44.25,-25,0) BL(-44.25,-25,0) 对于16x9显示器,这些值以厘米为单位。

然后,我使用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上最多是保持固定。这意味着我只需要更新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(); 
    } 
} 

这里是我的shader代码:

#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时,我的场景从观察者的视角直接渲染,渲染的场景按照它应该填充的窗口,但是眼睛/相机的视角丢失。

真的,我想要的是通过适当的眼睛/相机的x和y值来平移2D像素,即投影平面,以保持物体的中心(其xy中心为(0, 0))在渲染图像的中心。我在教科书“交互式计算机图形学:基于Shader的OpenGL(第6版)的自顶向下方法”中得到了指导。使用与网络上免费提供的图书配对的文件,我继续采用主要方法。

当不使用矩阵C创建MV时会拍摄以下图像。当我使用C创建MV时,所有场景看起来像下面的第一张图片。我希望在z中没有翻译,所以我把它作为0。

因为投影平面和我的摄像机平面是平行的,所以从一个坐标系转换到另一个坐标系仅仅是一个平移和inv(T)〜-T。

这里是我的眼睛图像在(0,0,50): Here is my image for the eye at (0,0,50):

这里是在我的眼睛图像(56,-16,50): Here is my image for the eye at (56,-16,50):

回答

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(); 
} 

}

透视矩阵的这种重新定义使翻译后的图像不被翻译。我仍然有相机捕捉和抓住画面的同步问题,但我能够创造出相似图片实时下列更新用户的位置:

enter image description here

+0

一些视频链接到该项目:[背景](https://www.youtube.com/watch?v=Hnn-uZPdJIY)和[结果](https:/ /www.youtube.com/watch?v=EkRiAxPImeo) –

0

所有的例子,我觉得需要相机/眼原点

这不是一个需求。 OpenGL没有定义一个摄像头,这一切都归结为转换。这些通常称为投影和模型视图(模型和视图变换组合)。相机即视角变换仅仅是相机在世界空间中的定位的倒数。所以假设你为自己的相机建立了一个矩阵,然后在模型视图中预先乘上相反的矩阵。

mat4 MV = inv(C) * V 

在一个侧面说明,你的shader代码是错误的:

gl_Position = P * ((V * vPosition)/vPosition.w); 
            ^^^^^^^^^^^^^^ 

的同质鸿沟在着色器来完成,因为它是硬连接到渲染管线。

+0

见上面我的更新。 –

+0

@DerLuftmensch:在你的更新中你写了'MV = C * V';我建议'inv(C)* MV'。无论如何,你可以请张贴一些截图吗?另请说明你使用的是什么数学库。你的矩阵似乎写得很重要,这有点不寻常。 – datenwolf

+0

我有解决方案,将很快发布... –