2009-04-07 50 views
27

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

回答

12

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

+3

对我来说,链接的文章提出了一个“是的,[你必须]”的答案 - 但是它的作者似乎希望在每个视口上绘制不同的东西。因此,如果有人以明白的语言确认是“是的,你必须在每个视口重绘对象”,或者“不,你不必 - 看到” – akavel 2010-09-21 19:29:45

+0

因为我明白OpenGL流水线,为了从不同的转换中重新绘制某些东西,顶点必须通过新的转换返回到管道中,所以是的,你必须确定重绘。 – user1294021 2012-11-07 01:52:19

3

是,

,你也应该改变剪刀设置有两种观点之间的完全分离,如果他们是在同一个窗口。

9
// 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); 
0

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

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

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

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

利用只有这两样东西 - 这是我的建议是:

NEHE的教程规定,只有和段利用现有的窗口,屏幕绘图解决方案。这里的教程:http://nehe.gamedev.net/tutorial/multiple_viewports/20002/

利用glViewport你需要重新绘制每一个更新。

这是一种方法。

但还有另一个 - 更少图形和处理器激烈方法:

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

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

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

这节省了宝贵的处理功率,并且还降低了从具有手动管理窗口和视计算的代码。

3

最小运行的例子

类似this answer,但更直接的和编译。输出:

代码:

#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 -lGL -lGLU -lglut main.c 

测试基于OpenGL 4.5.0 NVIDIA 352.63,Ubuntu的15.10。

TODO:我认为,在现代的OpenGL 4,你应该只是渲染到纹理,然后orthogonaly把那些纹理在屏幕上,看到这作为一个起点:http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/

0

在GL 4,你可以使很多一次渲染过程中的视口。见ARB_viewport_array及相关概念。