如何在OpenGL中使用多个视口?

时间:2022-01-01 05:14:40

I need to show the same object in OpenGL in two different viewports, for instance, one using ortographic projection and the other using perspective. In order to do this, do I need to draw again the object after each call to glViewport()?

我需要在两个不同的视口中在OpenGL中显示相同的对象,例如,一个使用ortographic投影,另一个使用透视。为了做到这一点,我是否需要在每次调用glViewport()后再次绘制对象?

6 个解决方案

#1


Nehe has a good tutorial on how to do this, and his site is generally a good resource for OpenGL questions.

Nehe有一个关于如何做到这一点的好教程,他的网站通常是OpenGL问题的一个很好的资源。

#2


 // normal mode
  if(!divided_view_port)
    glViewport(0, 0, w, h);
else
{
    // right bottom
    glViewport(w/2, h/2, w, h);
    glLoadIdentity ();
    gluLookAt(5.0f, 5.0f, 5.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    display();

    // left bottom
    glViewport(0, h/2, w/2, h);
    glLoadIdentity();
    gluLookAt (5.0f, 0.0f, 0.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    display();

    // top right
    glViewport(w/2, 0, w, h/2);
    glLoadIdentity();
    gluLookAt(0.0f, 0.0f, 5.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    display();

    // top left
    glViewport(0, 0, w/2, h/2);
    glLoadIdentity();
    gluLookAt(0.0f, 5.0f, 0.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    display();
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

if (w <= h)
    glOrtho(-2.0, 2.0, 
            -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w, 
    -10.0, 100.0); 
else
    glOrtho(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h, 
    -2.0, 2.0, 
    -10.0, 100.0);

glMatrixMode(GL_MODELVIEW);

#3


yes,

and you should also change the scissor settings to have a clean separation between the two views if they are in the same window.

如果两个视图位于同一窗口中,您还应该更改剪刀设置以使两个视图之间保持清晰的分离。

#4


Minimal runnable example

最小的可运行示例

Similar to this answer, but more direct and compilable. Output:

与此答案类似,但更直接和可编译。输出:

如何在OpenGL中使用多个视口?

Code:

#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

static int width;
static int height;

static void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0f, 0.0f, 0.0f);

    glViewport(0, 0, width/2, height/2);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glutWireTeapot(1);

    glViewport(width/2, 0, width/2, height/2);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glutWireTeapot(1);

    glViewport(0, height/2, width/2, height/2);
    glLoadIdentity();
    gluLookAt(0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    glutWireTeapot(1);

    glViewport(width/2, height/2, width/2, height/2);
    glLoadIdentity();
    gluLookAt(0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    glutWireTeapot(1);

    glFlush();
}

static void reshape(int w, int h) {
    width = w;
    height = h;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return EXIT_SUCCESS;
}

Compile with:

gcc -lGL -lGLU -lglut main.c

Tested on OpenGL 4.5.0 NVIDIA 352.63, Ubuntu 15.10.

在OpenGL 4.5.0 NVIDIA 352.63,Ubuntu 15.10上测试。

TODO: I think that in modern OpenGL 4 you should just render to textures, and then place those textures orthogonaly on the screen, see this as a starting point: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/

TODO:我认为在现代OpenGL 4中你应该只渲染到纹理,然后将这些纹理正交放在屏幕上,看看这是一个起点:http://www.opengl-tutorial.org/intermediate-tutorials/tutorial -14渲染到纹理/

#5


In GL 4 you can render to many viewports in one rendering pass. See ARB_viewport_array and related concepts.

在GL 4中,您可以在一个渲染过程中渲染到许多视口。请参阅ARB_viewport_array和相关概念。

#6


Think of OpenGL as being nothing more than commands which prepare you to output to the window you're currently working with.

将OpenGL视为只是准备输出到您当前正在使用的窗口的命令。

There's two commands with OpenGL that even NEHE's tutorials don't tell you the importance of:

OpenGL有两个命令,甚至NEHE的教程也没有告诉你重要性:

wglCreateContext - which takes a window device context DC, can be obtained from ANY window - whether it's a user control, a windows form, a GL window, or another application window (like notepad). This creates an OpenGL device context - they refer to as a resource context - which you later use with ...

wglCreateContext - 它采用窗口设备上下文DC,可以从任何窗口获取 - 无论是用户控件,窗体,GL窗口还是其他应用程序窗口(如记事本)。这将创建一个OpenGL设备上下文 - 它们称为资源上下文 - 您稍后将使用它...

wglMakeCurrent - which takes two parameters, the Device Context you're dealing with (the parameter passed in for the Windows Device Context in wglCreateContext) - and the Resource Context that returns.

wglMakeCurrent - 它有两个参数,你正在处理的设备上下文(wglCreateContext中为Windows设备上下文传入的参数) - 以及返回的资源上下文。

Leveraging ONLY these two things - here's my advice:

只利用这两件事 - 这是我的建议:

NEHE's tutorial provides a solution that leverages the existing window ONLY and segments the screen for drawing. Here's the tutorial: http://nehe.gamedev.net/tutorial/multiple_viewports/20002/

NEHE的教程提供的解决方案仅利用现有窗口并将屏幕分段以进行绘制。这是教程:http://nehe.gamedev.net/tutorial/multiple_viewports/20002/

Leveraging glViewport you'll need to re-draw on every update.

利用glViewport,您需要在每次更新时重新绘制。

That's one method.

这是一种方法。

But there's another - less graphically and processor intense method:

但还有另一种 - 图形和处理器强度较低的方法:

Create a window for each view by leveraging a user control.

通过利用用户控件为每个视图创建一个窗口。

Each window has it's own hWnd.

每个窗口都有自己的hWnd。

Get the DC, process the wglcreatecontext, and then, on a timer (mine is 30 frames a second), if you detect state change, then select wglMakeCurrent for that view and redraw. Otherwise, just skip the section entirely.

获取DC,处理wglcreatecontext,然后在计时器上(我的每秒30帧),如果检测到状态更改,则为该视图选择wglMakeCurrent并重绘。否则,只需完全跳过该部分。

This conserves valuable processing power, and also reduces the code from having to manage the window and viewport calculations manually.

这节省了宝贵的处理能力,并且还减少了必须手动管理窗口和视口计算的代码。

#1


Nehe has a good tutorial on how to do this, and his site is generally a good resource for OpenGL questions.

Nehe有一个关于如何做到这一点的好教程,他的网站通常是OpenGL问题的一个很好的资源。

#2


 // normal mode
  if(!divided_view_port)
    glViewport(0, 0, w, h);
else
{
    // right bottom
    glViewport(w/2, h/2, w, h);
    glLoadIdentity ();
    gluLookAt(5.0f, 5.0f, 5.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    display();

    // left bottom
    glViewport(0, h/2, w/2, h);
    glLoadIdentity();
    gluLookAt (5.0f, 0.0f, 0.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    display();

    // top right
    glViewport(w/2, 0, w, h/2);
    glLoadIdentity();
    gluLookAt(0.0f, 0.0f, 5.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    display();

    // top left
    glViewport(0, 0, w/2, h/2);
    glLoadIdentity();
    gluLookAt(0.0f, 5.0f, 0.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    display();
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

if (w <= h)
    glOrtho(-2.0, 2.0, 
            -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w, 
    -10.0, 100.0); 
else
    glOrtho(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h, 
    -2.0, 2.0, 
    -10.0, 100.0);

glMatrixMode(GL_MODELVIEW);

#3


yes,

and you should also change the scissor settings to have a clean separation between the two views if they are in the same window.

如果两个视图位于同一窗口中,您还应该更改剪刀设置以使两个视图之间保持清晰的分离。

#4


Minimal runnable example

最小的可运行示例

Similar to this answer, but more direct and compilable. Output:

与此答案类似,但更直接和可编译。输出:

如何在OpenGL中使用多个视口?

Code:

#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

static int width;
static int height;

static void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0f, 0.0f, 0.0f);

    glViewport(0, 0, width/2, height/2);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glutWireTeapot(1);

    glViewport(width/2, 0, width/2, height/2);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glutWireTeapot(1);

    glViewport(0, height/2, width/2, height/2);
    glLoadIdentity();
    gluLookAt(0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    glutWireTeapot(1);

    glViewport(width/2, height/2, width/2, height/2);
    glLoadIdentity();
    gluLookAt(0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
    glutWireTeapot(1);

    glFlush();
}

static void reshape(int w, int h) {
    width = w;
    height = h;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return EXIT_SUCCESS;
}

Compile with:

gcc -lGL -lGLU -lglut main.c

Tested on OpenGL 4.5.0 NVIDIA 352.63, Ubuntu 15.10.

在OpenGL 4.5.0 NVIDIA 352.63,Ubuntu 15.10上测试。

TODO: I think that in modern OpenGL 4 you should just render to textures, and then place those textures orthogonaly on the screen, see this as a starting point: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/

TODO:我认为在现代OpenGL 4中你应该只渲染到纹理,然后将这些纹理正交放在屏幕上,看看这是一个起点:http://www.opengl-tutorial.org/intermediate-tutorials/tutorial -14渲染到纹理/

#5


In GL 4 you can render to many viewports in one rendering pass. See ARB_viewport_array and related concepts.

在GL 4中,您可以在一个渲染过程中渲染到许多视口。请参阅ARB_viewport_array和相关概念。

#6


Think of OpenGL as being nothing more than commands which prepare you to output to the window you're currently working with.

将OpenGL视为只是准备输出到您当前正在使用的窗口的命令。

There's two commands with OpenGL that even NEHE's tutorials don't tell you the importance of:

OpenGL有两个命令,甚至NEHE的教程也没有告诉你重要性:

wglCreateContext - which takes a window device context DC, can be obtained from ANY window - whether it's a user control, a windows form, a GL window, or another application window (like notepad). This creates an OpenGL device context - they refer to as a resource context - which you later use with ...

wglCreateContext - 它采用窗口设备上下文DC,可以从任何窗口获取 - 无论是用户控件,窗体,GL窗口还是其他应用程序窗口(如记事本)。这将创建一个OpenGL设备上下文 - 它们称为资源上下文 - 您稍后将使用它...

wglMakeCurrent - which takes two parameters, the Device Context you're dealing with (the parameter passed in for the Windows Device Context in wglCreateContext) - and the Resource Context that returns.

wglMakeCurrent - 它有两个参数,你正在处理的设备上下文(wglCreateContext中为Windows设备上下文传入的参数) - 以及返回的资源上下文。

Leveraging ONLY these two things - here's my advice:

只利用这两件事 - 这是我的建议:

NEHE's tutorial provides a solution that leverages the existing window ONLY and segments the screen for drawing. Here's the tutorial: http://nehe.gamedev.net/tutorial/multiple_viewports/20002/

NEHE的教程提供的解决方案仅利用现有窗口并将屏幕分段以进行绘制。这是教程:http://nehe.gamedev.net/tutorial/multiple_viewports/20002/

Leveraging glViewport you'll need to re-draw on every update.

利用glViewport,您需要在每次更新时重新绘制。

That's one method.

这是一种方法。

But there's another - less graphically and processor intense method:

但还有另一种 - 图形和处理器强度较低的方法:

Create a window for each view by leveraging a user control.

通过利用用户控件为每个视图创建一个窗口。

Each window has it's own hWnd.

每个窗口都有自己的hWnd。

Get the DC, process the wglcreatecontext, and then, on a timer (mine is 30 frames a second), if you detect state change, then select wglMakeCurrent for that view and redraw. Otherwise, just skip the section entirely.

获取DC,处理wglcreatecontext,然后在计时器上(我的每秒30帧),如果检测到状态更改,则为该视图选择wglMakeCurrent并重绘。否则,只需完全跳过该部分。

This conserves valuable processing power, and also reduces the code from having to manage the window and viewport calculations manually.

这节省了宝贵的处理能力,并且还减少了必须手动管理窗口和视口计算的代码。