최신 OpenGL이 포함 된 다중 뷰포트?


9

나는 SDL2를 사용 한다 .

현재 내 유일한 셰이더에는 MVP 행렬 이 있으며 그 점으로 변환합니다.

GLM이있는 카메라의 뷰 및 프로젝션 매트릭스를 계산합니다.

glm::lookAt(pos, pos + forward, up);
glm::perspective(fov, aspectRatio, zNear, zFar);

검색했지만 여러 뷰포트의 기존 구현 만 찾을 수 있습니다.

예를 들어 4 대의 카메라를 만들고 모든 카메라가 렌더링 할 화면다른 1/4을 갖는 것을 제외하고 는 모두 동일 하다고 가정 해 봅시다 . (따라서 같은 내용의 4 개의 뷰포트를 원합니다)

어떻게해야합니까? 충분한 정보를 제공하지 않으면 죄송합니다.


구체적으로 렌더링을 4 번 수행하거나 한 번 렌더링하여 결과를 4 개의 다른 위치에 표시하려고합니까?
trichoplax

렌더링을 4 번 수행하십시오. 내가 쓴 것은 간단한 예입니다. 예를 들어 메인 카메라가 전체 창에서 자동차를 렌더링하고 다른 카메라가 측면 중 하나에서 모서리 중 하나의 작은 사각형으로 자동차를 렌더링하려고합니다.
Tudvari

내가 이것을 올바르게 이해했다면 창을 예를 들어 4 부분으로 나누고 각 부분에서 장면의 다른 부분을 그와 같이 렌더링 해야 합니까?
narthex

예, 그러나 엄격하게 4 개 부품은 아닙니다. 융통성이 있기를 바랍니다. 뷰포트 직사각형의 유연한 크기와 위치.
Tudvari

답변:


8

동일한 화면의 다른 뷰포트 (파트)로 렌더링하는 방법은 다음과 같습니다.

예를 들어 화면을 4 개의 부분으로 나누고 동일한 유니폼과 다른 뷰포트를 사용하여 각 장면에 동일한 장면을 4 번 렌더링합니다.

bindFramebuffer();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
scene->setConstPerFrameUniforms();

//left bottom
glViewport(0, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(1);
scene->draw();

//right bottom
glViewport(WindowWidth*0.5, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(2);
scene->draw();

//left top
glViewport(0, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(3);
scene->draw();

//right top
glViewport(WindowWidth*0.5, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(4);
scene->draw();

glViewport(0, 0, WindowWidth, WindowHeight); //restore default

따라서 glViewPort ()를 사용하여 다음에 그릴 위치를 정의 할 수 있으며 glBlendFunc를 사용하여 GPU가 겹치는 영역 (프레임 버퍼)을 서로 혼합하는 방법을 정의 할 수 있습니다. 제가 맞습니까?
Tudvari

1
그렇습니다. 의 매개 변수 viewport는 x, y 청크 왼쪽 하단 모서리 및 너비, 청크 높이입니다. 블렌딩을 사용하면 실험 할 수 있습니다.
narthex

1
왜 혼합? 질문과 어떻게 관련이 있습니까?
Raxvan

3
블렌딩 또는 여러 프레임 버퍼가 필요하지 않습니다. 렌더링은 현재 glViewport 사각형 외부의 픽셀에 쓰지 않으므로 각 뷰포트를 차례로 설정하고 그릴 수 있습니다. BTW를 사용하면 뷰포트가 겹치는 경우 가위 테스트 를 사용하여 간격 을 특정 사각형으로 제한 할 수 있습니다 .
Nathan Reed

2
블렌딩은 이것과 아무 관련이 없으며 대답을 더 혼란스럽게 만듭니다. 뷰포트 설정은 필요한 모든 것
기본

11

자신의 정점 / 조각 셰이더를 작성하는 경우이를 수행 할 수있는 또 다른 가능성이 있습니다. 훨씬 더 복잡하지만 귀하 및 / 또는 다른 사람들에게 유용 할 수 있습니다. 또한 그리기 명령에 한 번의 호출 만 사용하므로 전체 그리기 프로세스 속도가 향상됩니다. 최대 뷰포트 수는 GL_MAX_VIEWPORTS에 의해 정의되며 일반적으로 16입니다.

OpenGL 4.1부터 glViewportArrayv 메소드 가 존재합니다. 뷰포트의 배열을 정의 할 수 있습니다. 이 방법으로 작성된 뷰포트에는 인덱스가 할당되어 있습니다.

이 인덱스는 정점 셰이더에서 장면이 렌더링되는 뷰포트를 설정하는 데 사용될 수 있습니다. 셰이더 코드에 " ARB_shader_viewport_layer_array "확장명 을 포함시켜야합니다.

귀하의 경우 다음을 수행하는 것이 좋습니다.

  • 4 개의 카메라 매트릭스를 Shader Storage Buffer (mat4의 배열)에 저장하여 버텍스 쉐이더에 담습니다
  • 색인화 된 도면을 사용하십시오 ( 예 : glDrawElementsInstanced).
  • Vertex Shader의 gl_InstanceID 빌드 를 사용하여 카메라 매트릭스 배열에 액세스
  • Fragment Shader에서 변수 출력 변수 gl_ViewportIndex의 빌드를 gl_InstanceID로 설정하십시오. (자세한 내용은 ARB_fragment_layer_viewport 참조 )

" 이 인덱스는 정점 셰이더에서 장면이 렌더링되는 뷰포트를 설정하는 데 사용될 수 있습니다. "아닙니다. ARB_shader_viewport_layer_array 확장 또는 AMD 등가물이없는 것은 아닙니다. GL 4.5의 표준은 없습니다. 아마도 Geometry Shaders를 생각하고있을 것입니다.
Nicol Bolas

@Nicol,이 힌트에 감사드립니다! 확장명을 포함시켜야한다는 점을 언급하지 않았습니다. 답변을 편집하겠습니다.
Christian_B

5

이것은 @narthex의 답변 사본입니다. 뷰포트 만 있으면 충분합니다. 왜 프레임 버퍼 / 블렌드 재료가 그의 대답에 포함되어 있는지 잘 모르겠습니다.

//left bottom
glViewport(0, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//right bottom
glViewport(WindowWidth*0.5, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//left top
glViewport(0, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//right top
glViewport(WindowWidth*0.5, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

glViewport(0, 0, WindowWidth, WindowHeight); //restore default

1

이것들은 모두 좋은 대답이지만 다른 방법이 있습니다. (항상 그렇지 않습니까?)

가상 현실의 인기가 높아짐에 따라 OculusVR 직원들은 다음과 같은 "Multiview"확장 트리오를 개발했습니다.

  1. OVR_multiview ,
  2. OVR_multiview2
  3. OVR_multiview_multisampled_render_to_texture

이러한 확장을 사용하면 동일한 장면의 여러 뷰를 단일 드로우 콜로 렌더링 할 수 있으므로 각 눈의 관점에서 동일한 상태로 동일한 장면을 렌더링하는 중복성이 제거됩니다. VR의 목적으로 개발되었지만 개발자가 반드시 두 가지 관점으로 제한되는 것은 아닙니다. 오히려이 확장은 MAX_VIEWS_OVR이 지정한 만큼의 보기를 허용 합니다.

이러한 확장을 사용하기 전에 개발자는 다음 코드를 추가하여 사용자의 그래픽 드라이버에서 지원 여부를 확인해야합니다.

const GLubyte* extensions = GL_CHECK( glGetString( GL_EXTENSIONS ) );
char * found_extension = strstr( (const char*)extensions, "GL_OVR_multiview" );
if (NULL == found_extension)
{
     exit( EXIT_FAILURE );
}

여기에서이 기능을 활용하기 위해 프레임 버퍼를 설정해야합니다.

glFramebufferTextureMultisampledMultiviewOVR = PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEDMULTIVIEWOVR(eglGetProcAddress("glFramebufferTextureMultisampleMultiviewOVR"));
glFramebufferTextureMultisampledMultiviewOVR (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureID, 0, 0, 2);

마찬가지로 셰이더에서도

#version 300 es
#extension GL_OVR_multiview : enable

layout(num_views = 2) in;
in vec3 vertexPosition;
uniform mat4 MVP[2];

void main(){
    gl_Position = MVP[gl_ViewID_OVR] * vec4(vertexPosition, 1.0f);
}

CPU 바운드 응용 프로그램에서이 확장 기능은 특히 복잡한 장면에서 렌더링 시간을 크게 줄일 수 있습니다 .

다시 점과 일반 스테레오 사이의 상대적 CPU 시간.  x 축의 큐브 수와 y 축의 상대 시간으로 작을수록 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.