2013-04-17 1 views
4

화면과 관련하여 사용자 위치를 추적하고 렌더링 된 장면을 사용자의 시점으로 업데이트하는 OpenGL C++ 응용 프로그램을 만들고 있습니다. 이것은 "데스크탑 VR"로 알려져 있거나 화면을 디오라마 또는 수족관으로 생각할 수 있습니다. OpenGL을 처음 접했을 뿐이며 지금까지는 아주 단순한 장면을 정의한 것입니다. 처음에는 올바르게 렌더링되었습니다.데스크탑 용 OpenGL Asymmetric Frustum

문제는 내가 움직이기 시작하고 큐브 씬을 다시 렌더링하기를 원할 때 프로젝션 비행기가 번역 된 것 같아서 내가해야한다고 생각하는 것을 보지 못합니다. 나는이 비행기를 고정시키고 싶다. 레이 트레이서를 쓰고 있다면 내 창은 항상 고정되지만 내 눈은 방황 할 수 있습니다. 누군가 내 카메라/눈을 비 원점 좌표에서 방황하면서 원하는 효과 (보기 창 고정)를 달성 할 수있는 방법을 설명해 주시겠습니까?

나는 카메라/눈이 원점에있을 것을 요구하는 모든 예제를 보았지만 개념적으로는 편리하지 않습니다. 또한 이것은 "수조"이므로 내 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를 사용하여 (+/- 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 (유휴)에서이 작업을 수행합니다.

#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; 
} 

좋아, 나는 내 코드의 일부를 변경했으나 성공하지 :

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

여기 내 쉐이더 코드입니다. 버텍스 쉐이더에서 MV 대신 MV를 사용할 때 원하는대로 모든 것이 보이고 원근감이 정확하며 객체의 크기는 적당하지만 카메라의 변위로 장면이 변환됩니다.

MV를 얻기 위해 C와 V를 사용하면 내 장면이 관찰자의 시점에서 직선으로 렌더링되고 렌더링 된 장면이 창을 채우지 만 눈/카메라의 시점은 손실됩니다.

실제로 내가 원하는 것은 눈/카메라의 적절한 x 값과 y 값으로 2D 픽셀, 즉 투영 평면을 변환하여 객체 중심을 유지하는 것입니다 (xy 중심은 (0, 0))를 렌더링합니다. 나는 교과서 "Interactive Computer Graphics : Shader 기반 OpenGL (6th Edition)을 사용한 하향식"의 예제를 통해 안내를받습니다. 웹에서 자유롭게 사용할 수있는 책과 짝을 이루는 파일을 사용하여 행 주요 접근법을 계속 수행하고 있습니다.

다음 이미지는 매트릭스 C를 사용하여 MV를 생성하지 않을 때의 이미지입니다. MV를 만들 때 C를 사용하면 모든 장면이 아래의 첫 번째 이미지처럼 보입니다. 나는 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 :// /kr.youtube.com/watch?v=EkRiAxPImeo) –

0

나는 카메라/아이가 원점에있을 것을 요구하는 모든 예제를 발견했다.

이것은 요구 사항이 아니다. OpenGL은 카메라를 정의하지 않으며, 모든 것이 변형됩니다. 그것들은 일반적으로 투영 및 모델 뷰 (모델 및 뷰 변환 결합)라고합니다. 카메라, 즉 뷰 변환은 단순히 월드 공간에서의 카메라 위치 결정의 역이다. 그래서 카메라 C에 대한 매트릭스를 만든다고 가정하십시오. 그러면 모델 뷰에서 반전됩니다. 보조 노트에

mat4 MV = inv(C) * V 

, 당신의 쉐이더 코드가 잘못되었습니다 : 그것이 렌더링 파이프 라인에 하드 와이어로

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

균질 한 분열은 셰이더에서 수행 할 하지입니다.

+0

위의 내 업데이 트를 참조하십시오. –

+0

@DerLuftmensch : 당신의 업데이트에서 당신은'MV = C * V'; 나는 inv (C) * MV를 제안했다. 어쨌든 몇 가지 스크린 샷을 올리시겠습니까? 또한 어떤 수학 라이브러리를 사용하는지 기재하십시오. 귀하의 매트릭스는 약간 특이한 행 주요 순서로 작성된 것 같습니다. – datenwolf

+0

나는 해결책을 가지고 있으며 곧 게시 할 것이다 ... –