OpenGL技術之View Volume, Viewport, Screen的關係

作者:i_dovelemon

日期:2016 / 03 / 08

來源:CSDN

主題:OpenGL,View Volume,Viewport,Screen



引言



        今天在公司的時候,基本工作做完之後,趁着一點多餘的時間,回顧了下以前學習的OpenGL的知識。在看到第一章節的時候,書中使用一個正交窗口,顯示一些很簡單的圖形。本來單單就這麼一個實例的話,是很容易實現的。但是我一直以來都沒有太搞清楚,OpenGL中各種指令到底做了些什麼工作。所以,帶着這樣的疑問,我主要探究了下OpenGL中三個比較重要的概念,View Volume,Viewport以及Screen的關係。


概念介紹



View Volume



        View Volume,有時候叫做View Frustum,也就是視景體。這個東西是定義了我們能夠通過虛擬的3D攝像機所能看到的場景。當我們在一個3D場景中站立的時候,除了我們的位置之外,同樣需要視野來定義我們所能夠看到的東西。而這個視野就是通過視景體來定義的。一般在3D中,我們有兩種不同的方式定義視景體。他們的形狀分別如下所示:


圖1


圖2

        上面給出了兩個不同的視景體,圖1表示的是中心透視視景體,而圖2表示的是正交投影視景體。這兩個幾何體都全面的定義了我們所能夠看到的視野,在OpenGL中也分別有不同的指令對應與這兩個幾何體。

        我們都知道,在3D圖形學中,我們是通過定義投影矩陣的方式來描述視景體的。通過定義中心透視矩陣來描述中心透視視景體,通過定義正交矩陣的方式來定義正交視景體。


Viewport



        Viewport,中文翻譯爲視口。它的定義具有兩個意義。一個意義是它定義了上面定義的視景體中的景物將會繪製到一張什麼尺寸的畫布之上,另外一個意義表示這個繪製好的圖像將會被顯示在屏幕的什麼區域。

        很明顯,如果我們定義的視景體的投影平面的寬高比和視口所定義的寬高比不相同的話,那麼將視景體中的物體繪製到畫布上的時候會進行拉伸或者壓縮;而當視景體投影平面的寬高比和視口所定義的寬高比一致的時候,圖像將會不進行任何縮放繪製到視口所定義的畫布之上。

      視口定義中還包含了這個視口所表示的圖像將會被繪製到屏幕的哪塊區域之上的信息。在很多的圖形應用中,我們都會發現在一個窗口中繪製多個3D場景的情況。而這個技術就是通過定義多個視口,繪製多個圖像,然後“貼在”一個比較大的屏幕的多個不同的區域。


Screen



        Screen即屏幕的意思,在真實世界中,我們都是通過屏幕上的東西來觀察3D世界的。所有的場景最終都要被光柵化成爲我們顯示器上的圖像。也就是說屏幕是3D場景的最終輸出目的地。一個Screen可以容納顯示多個視口中的內容。


三者的關係



        通過前面的介紹,我們大致的瞭解了這三個不同東西的概念。從中我們可以知道,通過定義投影矩陣,我們實際上是在虛擬的3D空間中,創建了一個視野,也就是視景體。在接着,我們通過定義視口,來描述視景體中的內容如何映射到一個虛擬的畫布之上,並且這個畫布最終將顯示在屏幕上的什麼位置。當所有的這些都設置完畢,我們繪製完畢場景之後,就能夠通過硬件在我們的顯示器屏幕上看到最終的畫面。更理論的表述就是,通過定義投影矩陣,將3D場景投影到一個投影平面之上。通過定義視口,我們將投影平面上的內容映射到這個視口中去,並且填滿它,同時根據定義視口是給定的屏幕座標的位置,將這個視口中的圖像映射到窗口的指定位置之上,最終我們就看到了圖像。


代碼演示



        爲了演示前面所講述的內容,簡單的做了一個Demo,它將在一個屏幕上繪製4個不同視口裏面的畫面,代碼如下所示:

#ifndef GLUT_DISABLE_ATEXIT_HACK  
#define GLUT_DISABLE_ATEXIT_HACK 
#endif

#include <GL\glut.h>
#include <GL\GL.h>
#include <stdio.h>

void oglDisplay();

int main()
{
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
	glutInitWindowSize(400,400);
	glutCreateWindow("Viewport");
	glutDisplayFunc(oglDisplay);

	glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

	glutMainLoop();

	return 0;
}

void oglDisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);

	// Left-Bottom
	glViewport(0,0, 200, 200);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f);

	glColor3f(1.0f, 0.0f, 0.0f);
	glRectf(-100.0f, 100.0f, 100.0f, -100.0f);

	// Right-Bottom
	glViewport(200, 0, 200, 200);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f);

	glColor3f(0.0f, 1.0f, 0.0f);
	glRectf(-100.0f, 100.0f, 100.0f, -100.0f);

	// Left-Top
	glViewport(0, 200, 200, 200);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f);

	glColor3f(0.0f, 0.0f, 1.0f);
	glRectf(-100.0f, 100.0f, 100.0f, -100.0f);

	// Right-Top
	glViewport(200, 200, 200, 200);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f);

	glColor3f(1.0f, 1.0f, 0.0f);
	glRectf(-100.0f, 100.0f, 100.0f, -100.0f);

	glFlush();
}

        運行結果如下所示:

發佈了92 篇原創文章 · 獲贊 95 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章