我需要在 OpenGL 中在两个不同的视口中显示相同的对象,例如,一个使用正交投影,另一个使用透视。为此,是否需要在每次调用 glViewport() 后再次绘制对象?
6 回答
Nehe 有一个关于如何做到这一点的很好的教程,他的网站通常是 OpenGL 问题的一个很好的资源。
// 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);
最小可运行示例
类似于这个答案,但更直接和可编译。输出:
主程序
#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 -渲染到纹理/
在 OpenGL 4.5.0 NVIDIA 352.63、Ubuntu 15.10 上测试。
是的,
如果它们在同一个窗口中,您还应该更改剪刀设置以在两个视图之间有一个干净的分隔。
在 GL 4 中,您可以在一个渲染过程中渲染到多个视口。请参阅ARB_viewport_array和相关概念。
将 OpenGL 想象成只是准备输出到当前正在使用的窗口的命令。
OpenGL 有两个命令,即使是 NEHE 的教程也没有告诉您其重要性:
wglCreateContext - 接受窗口设备上下文 DC,可以从任何窗口获取 - 无论是用户控件、窗口窗体、GL 窗口还是其他应用程序窗口(如记事本)。这将创建一个 OpenGL 设备上下文 - 它们称为资源上下文 - 您稍后将与 ...
wglMakeCurrent - 它接受两个参数,您正在处理的设备上下文(在 wglCreateContext 中为 Windows 设备上下文传递的参数) - 以及返回的资源上下文。
仅利用这两件事 - 这是我的建议:
NEHE 的教程提供了一种解决方案,它仅利用现有窗口并分割屏幕以进行绘图。这是教程: http: //nehe.gamedev.net/tutorial/multiple_viewports/20002/
利用 glViewport,您需要在每次更新时重新绘制。
这是一种方法。
但是还有另一种 - 图形较少且处理器密集的方法:
通过利用用户控件为每个视图创建一个窗口。
每个窗口都有自己的 hWnd。
获取 DC,处理 wglcreatecontext,然后在计时器上(我的是每秒 30 帧),如果您检测到状态更改,则为该视图选择 wglMakeCurrent 并重绘。否则,请完全跳过该部分。
这节省了宝贵的处理能力,还减少了必须手动管理窗口和视口计算的代码。