web-dev-qa-db-ja.com

OpenGLで複数のビューポートを使用する方法

OpenGLで同じオブジェクトを2つの異なるビューポートに表示する必要があります。たとえば、1つは正射投影を使用し、もう1つは透視投影を使用します。これを行うには、glViewport()を呼び出すたびにオブジェクトを再度描画する必要がありますか?

28
Victor Araújo

Nehe には、これを行う方法に関する優れたチュートリアルがあり、彼のサイトは一般にOpenGLの質問に役立つリソースです。

13
Ed James
 // 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);
9
p govind rao

最小限の実行可能な例

この答え に似ていますが、より直接的でコンパイル可能です。出力:

コード:

#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では、テクスチャにレンダリングしてから、それらのテクスチャを画面上に直交させて配置する必要があると思います。これを開始点として参照してください。 http://www.opengl-tutorial.org/intermediate -tutorials/tutorial-14-render-to-texture /

はい、

また、2つのビューが同じウィンドウにある場合は、はさみの設定を変更して2つのビューを明確に分離する必要があります。

3
fa.

GL 4では、1つのレンダリングパスで多くのビューポートにレンダリングできます。 ARB_viewport_array および関連する概念を参照してください。

OpenGLは、現在作業中のウィンドウに出力する準備をするコマンドにすぎないと考えてください。

OpenGLには2つのコマンドがあり、NEHEのチュートリアルでも重要性を説明していません。

wglCreateContext-ウィンドウのデバイスコンテキストDCを取得します。これは、ユーザーコントロール、ウィンドウフォーム、GLウィンドウ、または別のアプリケーションウィンドウ(メモ帳など)のいずれでも)から取得できます。 OpenGLデバイスコンテキストを作成します-それらはリソースコンテキストと呼ばれ、後で使用します...

wglMakeCurrent-2つのパラメーターを受け取ります。処理するデバイスコンテキスト(wglCreateContextでWindowsデバイスコンテキストに渡されるパラメーター)と、返されるリソースコンテキストです。

これらの2つだけを活用する-これが私のアドバイスです。

NEHEのチュートリアルは、既存のウィンドウのみを活用し、描画のために画面を分割するソリューションを提供します。これがチュートリアルです: http://nehe.gamedev.net/tutorial/multiple_viewports/20002/

GlViewportを利用すると、更新のたびに再描画する必要があります。

それが一つの方法です。

しかし、別の方法があります-グラフィックが少なく、プロセッサーに負荷がかかる方法です。

ユーザーコントロールを利用して、各ビューのウィンドウを作成します。

各ウィンドウには独自のhWndがあります。

DCを取得し、wglcreatecontextを処理してから、タイマー(1秒あたり30フレーム)で状態の変化を検出したら、そのビューでwglMakeCurrentを選択して再描画します。それ以外の場合は、セクション全体をスキップしてください。

これにより、貴重な処理能力が節約され、ウィンドウとビューポートの計算を手動で管理する必要のあるコードも削減されます。