现代OpenGL有多个视口?


9

我使用SDL2

目前,我唯一的着色器具有MVP矩阵,并使用该矩阵转换点。

我使用GLM计算摄像机的视图和投影矩阵:

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

我进行了搜索,但是我只能找到多个视口的旧版实现。

例如,如果我创建了4个摄像机,并且假设它们都相同,则除了每个摄像机要渲染的屏幕不同之外,其他的四分之一。(所以我想要4个视口具有相同的内容)

我怎样才能做到这一点?抱歉,如果我没有提供足够的信息,请随时提出。


您是专门执行4次渲染还是只渲染一次并在4个不同的位置显示结果?
trichoplax

进行渲染4次。我写的只是一个简化的示例,例如,我希望主摄像机在全窗口中渲染汽车,而另一个摄像机从侧面在一个角的小正方形中渲染汽车。
Tudvari

如果我理解正确的这个,所以你需要你的窗口拆分例如4个部分,并在各部分像渲染场景的其他部分
narthex

是的,但并非严格分为四个部分。我希望它具有灵活性。视口矩形的大小和位置灵活。
Tudvari '17

Answers:


8

可以按以下步骤渲染到同一屏幕的不同视口(部分):

例如,将屏幕分为四个部分,并使用不同的制服和不同的视口将同一场景四次渲染到每个角上四次:

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如何将重叠区域(帧缓冲区)彼此融合。我对么?
塔德瓦里

1
是的,您可以随意设置参数。由于参数viewport是块左下角的x,y和块的宽度,高度。通过融合,您可以进行实验。
narthex

1
为什么混合?它与问题有什么关系?
Raxvan

3
您不需要混合或多个帧缓冲区。渲染不会写入当前glViewport矩形外部的任何像素,因此您可以依次设置和绘制每个视口。顺便说一句,如果您想要重叠视口,还可以使用剪刀测试将清除限制为特定矩形。
内森·里德

2
混合与此无关,并且使答案更加混乱。只需设置视口即可
默认设置为2002年

11

如果您正在编写自己的“顶点/片段着色器”,则还有另一种可能性。它要复杂得多,但对您和/或其他人可能有用。此外,由于它仅使用一次对绘制命令的调用,因此可以加快整个绘制过程。视口的最大数量由GL_MAX_VIEWPORTS定义,通常为16。

从OpenGL 4.1开始,存在方法glViewportArrayv。它可以定义一个视口数组。用此方法创建的视口已分配了索引。

可以在“顶点着色器”中使用此索引来设置将场景渲染到的视口。(您必须在着色器代码中包括“ ARB_shader_viewport_layer_array ”扩展名)

对于您的情况,我建议您执行以下操作:

  • 将4个相机矩阵存储在着色器存储缓冲区(mat4数组)中,以将其放在“顶点着色器”中
  • 使用索引绘图,例如:glDrawElementsInstanced
  • 使用Vertex Shader的gl_InstanceID内置版本访问相机矩阵阵列
  • 将片段着色器中的内置变量输出变量gl_ViewportIndex设置为gl_InstanceID。(有关详细信息,请参见ARB_fragment_layer_viewport

此索引可在Vertex Shader中用于设置将场景渲染到的视口。 ”不,它不能。好吧,并非没有ARB_shader_viewport_layer_array扩展或AMD等效产品。这些都不是GL 4.5中的标准。您可能正在考虑“几何着色器”。
Nicol Bolas's

@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轴上的相对时间。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.