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

发布于 2024-07-16 18:20:55 字数 99 浏览 6 评论 0原文

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

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()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

趁微风不噪 2024-07-23 18:20:55

Nehe 有一个关于如何执行此操作的很好的教程,他的网站通常是OpenGL 问题的好资源。

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

白首有我共你 2024-07-23 18:20:55
 // 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);
 // 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);
情深如许 2024-07-23 18:20:55

最小可运行示例

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

main.c

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

编译并运行:

gcc -o main.out main.c -lGL -lGLU -lglut
./main.out

我认为在现代 OpenGL 4 中,您应该只渲染纹理,然后将这些纹理正交放置在屏幕上,将此视为起点: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render -to-texture/

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

Minimal runnable example

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

main.c

#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 and run:

gcc -o main.out main.c -lGL -lGLU -lglut
./main.out

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/

Tested on OpenGL 4.5.0 NVIDIA 352.63, Ubuntu 15.10.

画离情绘悲伤 2024-07-23 18:20:55

是的,

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

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.

﹏雨一样淡蓝的深情 2024-07-23 18:20:55

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

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

居里长安 2024-07-23 18:20:55

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

OpenGL 有两个命令,即使 NEHE 的教程也没有告诉你它们的重要性:

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

wglMakeCurrent 一起使用 - 它采用两个参数,即您正在处理的设备上下文(在 wglCreateContext 中为 Windows 设备上下文传入的参数) ) - 以及返回的资源上下文。

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

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

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

这是一种方法。

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

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

每个窗口都有它自己的 hWnd。

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

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

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

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

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 ...

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.

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/

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

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.

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.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文