簡體   English   中英

用於桌面VR的OpenGL Asymmetric Frustum

[英]OpenGL Asymmetric Frustum for Desktop VR

我正在制作一個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時,我的場景直接從觀察者的角度渲染,渲染的場景按照應有的方式填充窗口,但是眼睛/攝像機的視角丟失了。

真的,我想要的是通過眼睛/相機的適當的x和y值來轉換2D像素,投影平面,以便保持對象的中心(其xy中心為(0,0))渲染圖像的中心。 我以教科書“交互式計算機圖形:基於着色器的OpenGL(第6版)自上而下的方法”中的示例為指導。 使用與網上免費提供的書籍配對的文件,我將繼續使用行主要方法。

不使用矩陣C創建MV時拍攝以下圖像。 當我使用C創建MV時,所有場景看起來都像下面的第一張圖片。 我希望z中沒有翻譯,所以我將其保留為0。

因為投影平面和我的相機平面是平行的,所以從一個坐標系到另一個坐標系的轉換只是一個平移和inv(T)〜-T。

這是我在(0,0,50)的眼睛圖像: 這是我在(0,0,50)的眼睛圖像:

這是我在56(-16,50)處的眼睛圖像: 這是我在56(-16,50)處的眼睛圖像:

解決方案是更新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();
}

}

透視矩陣的重新定義使得渲染圖像不會被翻譯。 我仍然有攝像頭捕獲和屏幕抓取同步問題,但我能夠創建像下面的圖像實時更新用戶的位置:

在此輸入圖像描述

我發現的所有例子都要求相機/眼睛位於原點

這不是一個需求。 OpenGL沒有定義相機,它歸結為轉換。 這些通常稱為投影和模型視圖(模型和視圖變換相結合)。 相機,即視圖變換只是相機在世界空間中定位的反轉。 所以說你自己為你的相機C建立了一個矩陣,那么你可以預先模擬它在模型視圖上的反轉。

mat4 MV = inv(C) * V

另外,您的着色器代碼是錯誤的:

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

在着色器中不會進行均勻划分,因為它是硬連線到渲染管道中的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM