2013-04-17 25 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

我有解決方案,將很快發佈... –