Add Fog in OpenGL (L8)

2015-12-09_153339本篇要介紹如何在 Screen 裡面加入『霧』,方法很簡單,只要定義好 fog 的參數就可以使用,有點像 Lighting (L3) 。只要 follow 以下的 code:


fogMode[0] = GL_EXP; fogMode[1] = GL_EXP2; fogMode[2] = GL_LINEAR;
fogfilter = 2;
GLfloat fogColor[4] = {0.6f, 0.6f, 0.6f, 1.0f};
glFogi(GL_FOG_MODE, fogMode[fogfilter]);
glFogfv(GL_FOG_COLOR, fogColor);
glFogf(GL_FOG_DENSITY, 0.05f);
glHint(GL_FOG_HINT, GL_DONT_CARE);
glFogf(GL_FOG_START, 15.0f);
glFogf(GL_FOG_END, 25.0f);
glEnable(GL_FOG);

在 initializeGL() 裡面,定義 fog 參數。

glFogfv(GL_FOG_COLOR, fogColor) 定義 fog 的顏色,霧不一定要是灰階,也可以是有顏色的霧。

glHint(GL_FOG_HINT, GL_DONT_CARE) 這行表示霧這個濾鏡的形式,GL_DONT_CARE 表示讓 OpenGL 本身自己決定,還有另外兩個分別是 GL_NICEST : 表示最佳的濾鏡型態和 GL_FASTEST : 速度最快的 rendering方式。

glEnable(GL_FOG) 和 glDisable(GL_FOG) 為霧氣的開關。

glFogi(GL_FOG_MODE, fogMode[fogfilter]) 表示選擇的霧氣型態,這裡有三個參數:

  1. GL_EXP 是最基礎的 fog 型態,是以一階指數函數來決定霧氣的濃度。霧氣的影響會佈滿所有畫面。
  2. GL_EXP2 則是以二階指數函數來決定霧氣的濃度。霧氣的影響也是會佈滿整個畫面。
  3. GL_LINEAR 霧氣分布呈現線性的,且用 GL_LINEAR 可以決定霧氣的分佈距離。

            expFogGraph (1)exp2FogGraphlinearFogGraph                                                     [GL_EXP;GL_EXP2;GL_LINEAR]

glFogf(GL_FOG_DENSITY, 0.03f) 這行為定義霧氣的強度,介於 0.0~1.0 之間,但這行對 GL_LINEAR 是無用的,因為 GL_LINEAR 的強度會與設定的距離有關。

glFogf(GL_FOG_START, 15.0f)glFogf(GL_FOG_END, 25.0f) 這兩個參數分別設定霧氣的起始點與終點。起始點的霧氣強度是 0.0f,終點的霧氣強度是1.0f,所以這個參數只與 fogMode 是 GL_LINEAR 有關,與 GL_EXPGL_EXP2 無關。

設定好了 fog 參數後,記得在 painGL() function 裡加入 glClearColor(0.6f, 0.6f, 0.6f, 1.0f) 把背景改成與 fog 相同的顏色,這樣 Object 才會像是處在濃霧裡。


在不同顏色霧氣下的結果:

picasion.com_50518dfbf6cbf97a4888b0d25d99e518

 

 


reference : http://nehe.gamedev.net/tutorial/cool_looking_fog/19001/

http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=15

 

Rendering Text in OpenGL (L7)

在 NeHe 的 OpengGL 教學裡的 Lesson 13 是在講解如何 透過 glCallLists 來 rendering 字串在屏幕上,但我在實作時,卻出現無法解決的問題...compile會過,但是就是秀不出文字出來,debug 解到瘋掉還是找不出原因來。在 google 後,發現也有人遇到跟我相同的問題:

http://stackoverflow.com/questions/9800555/use-opengl-bitmap-fonts-to-put-text-onto-the-screen

在內文裡有人提到說,不同的 OS 和不同版本的 Visual Studio 都可能導致這種無法解決的問題;再者,我是利用 Qt 內部與 OpenGL link 在一起,或許也會有問題,但主要的是 NeHe Lesson 13 是基於 Windows 撰寫的,使用 wgl functions 建立 text font,而我一直覺得我的 text font 定義有問題,但就是找不到哪裡錯誤阿(抓頭)。

也有人提到說可以用 glut.h 提供的函式來 render text,那就是使用 glutBitmapCharacter 來實作,但我實作後,程式會自動跳出...(瘋狂抓頭)。


最後真的沒辦法了,只好使用 QGLWidget 內部函式來實現。

2015-11-30_161754

void myopenGL::paintGL()
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glLoadIdentity();

 glTranslatef(0.0f, 0.0f, -1.0f);
 glRotatef(rota_x, 1.0f, 0.0f, 0.0f);
 glRotatef(rota_y, 0.0f, 1.0f, 0.0f);
 glRotatef(rota_z, 0.0f, 0.0f, 1.0f);

 double x = -2.0f, y = 0.0, z = -5.0f;
 QString txt = "OpenGL Learning in aboutdada.com";
 qglColor(Qt::yellow);
 renderText(x, y, z, txt, QFont("Times New Roman", 20, QFont::Normal, false) );

}

這個方法非常之簡單易懂,只需要 renderText 這個函式就可以實現了,

renderText(double x, double y, double z, const QString & str,
const QFont & fnt = QFont(), int listBase = 2000)

x,y,z 為 text 所在位置,str 為 text 內容,QFont 則是字體的大小與型態;但 renderText 只能做 2D平面的 text rendering,有關 Qt 上 的 3D text rendering 可以參考下面連結:

http://stackoverflow.com/questions/3514935/3d-text-on-qglwidget-in-qt-4-6-3

https://wiki.qt.io/Draw_Text_as_3D_Objects_with_OpenGL

 


由於無法實現 NeHe 裡的 Lesson 13(Bitmat Fonts),因而後面的 Lesson14(Outline Fonts)Lesson15(Texture Mapped Outline Fonts)Lesson17(2D Texture Font) 這幾個章節也只好跟著 pending 住,之後再想辦法解決了。

 


reference : http://nehe.gamedev.net/tutorial/lessons_11__15/28001/

 

Display Lists in OpenGL (L6)

2015-11-24_100143

Lesson 6 要介紹的是如何將 object 陣列化,簡言之,就是把 object 定義在額外的BuildLists() 內,透過 glCallList 這個 function 來調用,而不用每次都在 painGL() 內定義六面體各個面的位置。

● Color Array

static GLfloat boxcol[5][3] = {1.0f, 1.0f, 1.0f,
 1.0f, 0.0f, 0.0f,
 1.0f, 1.0f, 0.0f,
 0.0f, 1.0f, 0.0f,
 0.0f, 1.0f, 1.0f};
static GLfloat topcol[5][3] = {0.5f, 0.5f, 0.5f,
 0.5f, 0.0f, 0.0f,
 0.5f, 0.3f, 0.0f,
 0.0f, 0.5f, 0.0f,
 0.0f, 0.5f, 0.5f};

首先先定義各階層的顏色,最上層是 texture 原色,再來是紅色、黃色、綠色以及青綠色。

● Build Lists


void myopenGL::BuildLists()
{
 box = glGenLists(2); // build two list and return the pointer of the first list
 glNewList(box, GL_COMPILE);
 glBegin(GL_QUADS);
 //bottom
 glNormal3f(0.0f,-1.0f,0.0f);
 glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f,-1.0f,-1.0f);
 glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f,-1.0f,-1.0f);
 glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f,-1.0f, 1.0f);
 glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f,-1.0f, 1.0f);
 //front
 glNormal3f(0.0f,0.0f,1.0f);
 glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 1.0f);
 glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f,-1.0f, 1.0f);
 glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
 glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
 //back
 glNormal3f(0.0f,0.0f,-1.0f);
 glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f,-1.0f,-1.0f);
 glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 1.0f,-1.0f);
 glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f, 1.0f,-1.0f);
 glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f,-1.0f,-1.0f);
 //right
 glNormal3f(1.0f,0.0f,0.0f);
 glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f,-1.0f,-1.0f);
 glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f,-1.0f);
 glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
 glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f,-1.0f, 1.0f);
 //left
 glNormal3f(-1.0f,0.0f,0.0f);
 glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f,-1.0f);
 glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f,-1.0f, 1.0f);
 glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
 glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f,-1.0f);
 glEnd();
 glEndList();

top = box+1;
 glNewList(top, GL_COMPILE);
 glBegin(GL_QUADS);
 //top
 glNormal3f(0.0f,1.0f,0.0f);
 glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f,-1.0f);
 glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
 glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
 glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f,-1.0f);
 glEnd();
 glEndList();

}

BuildLists() 是新的 function ,就是將所要繪畫的物件目錄化。

box = glGenLists(2) 表示建立兩個 list 而且將 第一個 list 的 pointer 指向到 box 這個 integer 上。另一個就是 top。這裡建兩個 list 主要目的是在於 top 與其他 box 五面的顏色會不一樣,所以用此區分。

glNewList(box, GL_COMPILE) 表示告訴 opengl 將建立的 object 存在 box 這個 pointer 裡面,GL_COMPILE 的意思是告訴 opengl 要提前建立這個 object 就不需要在 runtime 時還要去理解 object 的內容與型態。

創建好了新的 BuildLists() 後,為了要在每個 texture 上染色,所以在 initializeGL() 裡面要加入 glEnable(GL_COLOR_MATERIAL) 如果不啟動的話,所有的 texture 將會顯示原始的顏色。

● painGL()


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture[2]);

if(Light)
 glEnable(GL_LIGHTING);
else
 glDisable(GL_LIGHTING);

for(int yloop = 1; yloop < 6; yloop++)
{
 for(int xloop = 0; xloop < yloop; xloop++)
 {
 glLoadIdentity();
 // position the cubes
 glTranslatef(1.4f+xloop*2.8f-yloop*1.4f, (8.0f-yloop*2.4f)-0.7f, -20.0f);
 glRotatef(45.0f-2.0f*yloop+rota_x, 1.0f, 0.0f, 0.0f);
 glRotatef(45.0f+rota_y, 0.0f, 1.0f, 0.0f);

glColor3fv(boxcol[yloop-1]);
 glCallList(box);
 glColor3fv(topcol[yloop-1]);
 glCallList(top);

}
}

透過 xloopyloop 來定義要繪畫的數量,第一列畫一個 object,第二列畫兩個,第三列畫三個...直到畫到第五列。

glColor3fv(boxcol[yloop-1] 表示選取的顏色。glColor3fv,v 代表 vector,只要給定 RGB 顏色的第一個 pointer 位置即可。

glCallList(box)glCallList(top) 則是調用剛已經定義好的 Object List。

 

 


reference : http://nehe.gamedev.net/tutorial/display_lists/15003/

Waving Texture in OpenGL (L5)

2015-11-17_111143

本篇要介紹如何將 texture mapping 到一個非平面上。以前是將整個 texture 映射到一個平面上,現在則是要將 pixel 個別映射到 3D 空間中( 每個 pixel 或 sub image 都有自己的映射平面)。

在定義的部分加入points[45][45][3],代表把 texture 影像切成 45x45 ,第三列為表示每一個 sub block 的 x, y, z 座標;Waving 則是表示讓 texture 做出像旗幟一樣飄逸的動作。記得要 include math.h ,因為會用到 sin() 函式。

#include "math.h"
#define pi 3.141592654
float points[45][45][3];
int Weaving;

load image 後,要加入以下的 code,定義多邊形( pylogon )的形式與 points 的座標位置。

	glPolygonMode(GL_BACK, GL_FILL);
	glPolygonMode(GL_FRONT, GL_LINE);
	// Waving plane
	Waving = 0;
	for(int x = 0; x < 45; x ++)
	{
		for(int y = 0; y < 45; y ++)
		{
			points[x][y][0] = float((x/5.0f) - 4.5f);
			points[x][y][1] = float((y/5.0f) - 4.5f);
			points[x][y][2] = float(sin((x/5.0f)*40.0f/180.0f*pi));			
		}
	}

glPolygonMode(GL_BACK, GL_FILL)  代表多邊形背向 rendering 的形式,GL_FILL 表示完全填滿。

glPolygonMode(GL_FRONT, GL_LINE) 則表示多邊形正向 rendering 的形式,GL_LINE表示以線條形式表現;另一種則是 GL_POINT。

waving plane 則是定義 points[45][45][3] 的三維座標位置。
2015-11-17_113415[GL_LINE]

2015-11-17_113440[GL_POINT]
 

接下來就是 painGL(),將 texture mapping 到一個 sine wave 平面上。隨著 Waving 增加而使 texture 飄逸。 

void myopenGL::paintGL()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	if(Light)
		glEnable(GL_LIGHTING);
	else
		glDisable(GL_LIGHTING);

	glTranslatef(0.0f, 0.0f, -20.0f);
	glRotatef(rota_x, 1.0f, 0.0f, 0.0f);
	glRotatef(rota_y, 0.0f, 1.0f, 0.0f);
	glRotatef(rota_z, 0.0f, 0.0f, 1.0f);

	glBindTexture(GL_TEXTURE_2D, texture[2]);

	GLfloat float_x, float_y, float_xb, float_yb;
	glBegin(GL_QUADS);
	for(int x = 0; x < 44; x ++)
	{
		for(int y = 0; y < 44; y ++)
		{
			float_x = float(x)/44.0f;
			float_y = float(y)/44.0f;
			float_xb = float(x+1)/44.0f;
			float_yb = float(y+1)/44.0f;
			
			glTexCoord2f(float_x, float_y);
			glVertex3f(points[x][y][0], points[x][y][1], points[x][y][2]);	// bottom left
			glTexCoord2f(float_x, float_yb);
			glVertex3f(points[x][y+1][0], points[x][y+1][1], points[x][y+1][2]); //top left
			glTexCoord2f(float_xb, float_yb);
			glVertex3f(points[x+1][y+1][0], points[x+1][y+1][1], points[x+1][y+1][2]); // top right
			glTexCoord2f(float_xb, float_y);
			glVertex3f(points[x+1][y][0], points[x+1][y][1], points[x+1][y][2]); // bottom right
		}
	}

	if(Waving >= 0)
	{
		for(int y = 0; y < 45; y++)
		{
			double hold = points[0][y][2];
			for(int x = 0; x < 44; x ++)
			{
				points[x][y][2] = points[x+1][y][2];
			}
			points[44][y][2] = hold;
		}
		Waving ++;
	}
	glEnd();
}

 

執行結果:picasion.com_4f4d97b463678119b3d340eef014f06c

 

 

 


reference : http://nehe.gamedev.net/tutorial/flag_effect_(waving_texture)/16002/

 

Blending & Avoid Texture Mixed with Previous Color in OpenGL (L4)

2015-11-13_160211

● Blending

本篇介紹如何將 texture 與其他顏色的混和或者將 texture 做程度上的透明化。實現 Blending 很簡單,只要在 initializeGL() 函式裡面加入以下四行程式碼就完成了。

glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);

glColor4f() 四個參數中,分別代表(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha),除了 RGB 外多了一個參數叫做 Alpha,Alpha 用意為表示透明度,1 表示完全不透明的,0 則表示完全透明;所以你可以選擇不同顏色及不同透明程度的 blending 數值。

glBlendFunc(GL_SRC_ALPHA, GL_ONE) 為設定 blending type 的函式。glBlendFunc (GLenum sfactor, GLenum dfactor) 裡面 sfactor 表示 source blending 的強度( source 為新加入的顏色或紋理),dfactor 則代表 destination 的強度(原本在 buffer 裡面的顏色或紋理),這兩個 factor 都在 [ 0, 1 ] 的範圍內。這裡的 GL_SRC_ALPHA 表示 source 本身 alpha 的強度, GL_ONE (dfactor) 為疊加上去的強度。如果今天不想要讓 texture 混和,就把 factor 設為 GL_ZERO。 

glEnable(GL_BLEND) 將 GL_BLEND 給啟動。

glDisable(GL_DEPTH_TEST) 為告訴 OpenGL 要繪製後面像素的內容,意思是說當啟動時,OpenGL 只會繪畫前面的圖形而已,躲在屏幕後方的像素是不會被繪製的,所以當調用 glEnable(GL_BLEND) 時,都要把 GL_DEPTH_TEST 給關閉,才會看到混和效果。

2015-11-13_160539[ 可以看到GL_DEPTH_TEST 開啟時,左後方與下方的資訊 OpenGL 是不做任何繪製的,只會看到前方所顯現的資訊而已。]

 


● Avoid Texture Mixed with Previous Color

在 texture mapping 後,如果有再繪製其他顏色的幾何圖形時,這時候會使 GL_BLEND 混和的顏色被蓋掉。以下為例,當我在立方體旁邊再繪製一個綠色的三角形時,GL_BLEND 所認定的顏色會變成綠色,如下圖。2015-11-13_163554

所以在 Blending 之前最好加上一行當初設定好的顏色與透明度( glColor4f(1.0f, 1.0f, 1.0f, 0.5f) ),就可以避免掉上述的問題了。

2015-11-13_164039

glPushMatrix();
glTranslatef(-10.0f, 0.0f, -50.f);
glRotatef(rota_x, 1.0f, 0.0f, 0.0f);
glRotatef(rota_y, 0.0f, 1.0f, 0.0f);
glRotatef(rota_z, 0.0f, 0.0f, 1.0f);
glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, texture[2]);	

// Front Face
glBegin( GL_QUADS );
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-D, -D,  D);  // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f( D, -D,  D);  // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( D,  D,  D);  // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(-D,  D,  D);  // Top Left Of The Texture and Quad
glEnd();
//Back Face
glBegin( GL_QUADS );
glNormal3f( 0.0f, 0.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-D, -D, -D);  // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(-D,  D, -D);  // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f( D,  D, -D);  // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f( D, -D, -D);  // Bottom Left Of The Texture and Quad
glEnd();
// Top Face
glBegin( GL_QUADS );
glNormal3f( 0.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-D,  D, -D);  // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-D,  D,  D);  // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f( D,  D,  D);  // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( D,  D, -D);  // Top Right Of The Texture and Quad
glEnd();
// Bottom Face
glBegin( GL_QUADS );
glNormal3f( 0.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( D, -D,  D);  // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(-D, -D,  D);  // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-D, -D, -D);  // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f( D, -D, -D);  // Bottom Right Of The Texture and Quad
glEnd();
// Right face
glBegin( GL_QUADS );
glNormal3f( 1.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( D, -D, -D);  // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( D,  D, -D);  // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f( D,  D,  D);  // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f( D, -D,  D);  // Bottom Left Of The Texture and Quad
glEnd();
// Left Face
glBegin( GL_QUADS );
glNormal3f(-1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-D, -D, -D);  // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f(-D, -D,  D);  // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(-D,  D,  D);  // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(-D,  D, -D);
glEnd();
glPopMatrix();

glPushMatrix();
glTranslatef(10.0f, 0.0f, -30.0f);
double T = 5.0;
glDisable(GL_TEXTURE_2D);
glColor3f(  0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);
glVertex3f( 0, T, 0);
glVertex3f(-T,-T, 0);
glVertex3f( T,-T, 0);
glEnd();
glPopMatrix();

 

 


reference : http://nehe.gamedev.net/tutorial/blending/16001/

Lighting and Keyboard Control in OpenGL (L3)

本篇要介紹如何在屏幕裡面增加光源以及鍵盤控制。

● Lighting

想要在屏幕裡打光的話就需要定義光源的位置、顏色、強度,以及物體反光係數。OpenGL 裡主要可以設定兩種光,分別是環境光( Ambient Light ) 和 散射光( Diffuse Light ),環境光就是一般的光源,是無方向性的;散射光則是指物體本身的反光,散射的強度與物體的材質有關。除了光源的特性外,還有光的位置( Light Position )要被定義,才能決定光呈現的效果。

在 initializeGL() function 裡面,先定義好光的特性:


 GLfloat LightAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f};
 GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
 GLfloat LightPosition[] = {0.0f, 0.0f, 2.0f, 1.0f};
 //@ key control
 Light = false;
 //@ glLight 
 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
 glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
 glEnable(GL_LIGHT1);

LightAmbient[] 是定義光源的顏色強度,分別代表{ R, G, B, Alpah}。

LightDiffuse[] 則是物體表面反光強度,一樣 index 代表著 { R, G, B, Alpah}。

可以改變光源顏色與反光顏色,會有不同的效果。我上面的設定是強度最強的白光而反光係數也是最強。

LightPosition[] 前三個 index 表示光源所在的位置(x, y, z),第四個參數則是代表著定義在已訂的座標空間。

glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient)

glLightfv(GL_LIGHT1,GL_DIFFUSE, LightDiffuse)

glLightfv(GL_LIGHT1, GL_POSITION, LightPosition) 表示把剛的光源設定建議在 GL_LIGHT1 裡面。

glEnable(GL_LIGHT1) 則是啟動 GL_LIGHT1 這個光。

接下來就是如何 rendering 在屏幕上了,


 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
 glLoadIdentity();

//@ key control
 if(Light)
 glEnable(GL_LIGHTING);
 else
 glDisable(GL_LIGHTING);

 double D = 10; // size 
 glTranslatef(0.0f, 0.0f, -50.f);
 glRotatef(rota_x, 1.0f, 0.0f, 0.0f);
 glRotatef(rota_y, 0.0f, 1.0f, 0.0f);
 glRotatef(rota_z, 0.0f, 0.0f, 1.0f); 
 glBindTexture( GL_TEXTURE_2D, texture[2]); 
 
 // Front Face
 glBegin( GL_QUADS );
 glNormal3f( 0.0f, 0.0f, 1.0f); 
 glTexCoord2f(0.0f, 0.0f); glVertex3f(-D, -D, D); // Bottom Left Of The Texture and Quad
 glTexCoord2f(1.0f, 0.0f); glVertex3f( D, -D, D); // Bottom Right Of The Texture and Quad
 glTexCoord2f(1.0f, 1.0f); glVertex3f( D, D, D); // Top Right Of The Texture and Quad
 glTexCoord2f(0.0f, 1.0f); glVertex3f(-D, D, D); // Top Left Of The Texture and Quad
 glEnd();
 //Back Face
 glBegin( GL_QUADS ); 
 glNormal3f( 0.0f, 0.0f, -1.0f); 
 glTexCoord2f(1.0f, 0.0f); glVertex3f(-D, -D, -D); // Bottom Right Of The Texture and Quad
 glTexCoord2f(1.0f, 1.0f); glVertex3f(-D, D, -D); // Top Right Of The Texture and Quad
 glTexCoord2f(0.0f, 1.0f); glVertex3f( D, D, -D); // Top Left Of The Texture and Quad
 glTexCoord2f(0.0f, 0.0f); glVertex3f( D, -D, -D); // Bottom Left Of The Texture and Quad
 glEnd();
 // Top Face
 glBegin( GL_QUADS ); 
 glNormal3f( 0.0f, 1.0f, 0.0f); 
 glTexCoord2f(0.0f, 1.0f); glVertex3f(-D, D, -D); // Top Left Of The Texture and Quad
 glTexCoord2f(0.0f, 0.0f); glVertex3f(-D, D, D); // Bottom Left Of The Texture and Quad
 glTexCoord2f(1.0f, 0.0f); glVertex3f( D, D, D); // Bottom Right Of The Texture and Quad
 glTexCoord2f(1.0f, 1.0f); glVertex3f( D, D, -D); // Top Right Of The Texture and Quad
 glEnd();
 // Bottom Face
 glBegin( GL_QUADS ); 
 glNormal3f( 0.0f,-1.0f, 0.0f); 
 glTexCoord2f(1.0f, 1.0f); glVertex3f( D, -D, D); // Top Right Of The Texture and Quad
 glTexCoord2f(0.0f, 1.0f); glVertex3f(-D, -D, D); // Top Left Of The Texture and Quad
 glTexCoord2f(0.0f, 0.0f); glVertex3f(-D, -D, -D); // Bottom Left Of The Texture and Quad
 glTexCoord2f(1.0f, 0.0f); glVertex3f( D, -D, -D); // Bottom Right Of The Texture and Quad
 glEnd();
 // Right face
 glBegin( GL_QUADS ); 
 glNormal3f( 1.0f, 0.0f, 0.0f); 
 glTexCoord2f(1.0f, 0.0f); glVertex3f( D, -D, -D); // Bottom Right Of The Texture and Quad
 glTexCoord2f(1.0f, 1.0f); glVertex3f( D, D, -D); // Top Right Of The Texture and Quad
 glTexCoord2f(0.0f, 1.0f); glVertex3f( D, D, D); // Top Left Of The Texture and Quad
 glTexCoord2f(0.0f, 0.0f); glVertex3f( D, -D, D); // Bottom Left Of The Texture and Quad
 glEnd();
 // Left Face
 glBegin( GL_QUADS );
 glNormal3f(-1.0f, 0.0f, 0.0f); 
 glTexCoord2f(0.0f, 0.0f); glVertex3f(-D, -D, -D); // Bottom Left Of The Texture and Quad
 glTexCoord2f(1.0f, 0.0f); glVertex3f(-D, -D, D); // Bottom Right Of The Texture and Quad
 glTexCoord2f(1.0f, 1.0f); glVertex3f(-D, D, D); // Top Right Of The Texture and Quad
 glTexCoord2f(0.0f, 1.0f); glVertex3f(-D, D, -D); 
 glEnd();

glNormal3f 是定義每個面的法向量,代表每個面朝外的方位,這樣光才能正確地打在每個平面上。若不加上 glNormal3f 的話,光不會出現在正確的地方,光源會隨著你的物體旋轉而跟著旋轉。這裡要注意到,glLightfv(GL_LIGHT1, GL_POSITION, LightPosition) 一定要定義在物體做旋轉或平移之前,不然光源也會跟著物體旋轉。

 


● Keyboard Control

在 keyboard control 的部分我是套用 Qt 裡的 <QKeyEvent> widget 來實作,那這裡主要的作用就是 Lighting 的開關, L 按鍵來做開關的動作。


void QtGL::keyPressEvent(QKeyEvent * event)
{
	if(event->key() == Qt::Key_Escape)
	{
		qApp->quit();
	}
	if(event->key() == Qt::Key_L)
	{
		myqgl->Light = !myqgl->Light;
	}
    myqgl->GLupdate();
}

 

執行結果:

  1. Light 開關

picasion.com_349410d8f8b7faf61be3ab125811092d

  1. 物體旋轉下打光的變化

picasion.com_d323d25c632f98b7fde39052abac8e9a

 

 


 

reference : http://nehe.gamedev.net/tutorial/texture_filters,_lighting_&_keyboard_control/

iron image : http://www.dreamstime.com/

 

Difference Between GL_PROJECTION and GL_MODELVIEW in glMatrixMode

Opengl 裡的 矩陣模型有兩種,一個是 GL_PROJECTION,另一個是 GL_MODELVIEW,這兩個有甚麼差別呢?

PROJECTION 矩陣是定義相機本身的可視角度、視窗長寬比以及繪圖範圍(定義 clipping plane)。所以在調用 glMatrixMode(GL_PROJECTION) 後,會再呼叫 gluPerspective() 這個函式,來定義上面所述說的參數值。

void gluPerspective (
GLdouble fovy,      //可視角度
GLdouble aspect,  //視窗長寬比
GLdouble zNear,   //繪畫區域(z軸最近位置)
GLdouble zFar);    //繪畫區域(z軸最遠位置)

MODELVIEW 矩陣則是定義你的物體在做平移(glTranslatef(x,y,z))、旋轉(glRotatef(angle,x,y,z))和縮放(glScalef(x,y,z))使用。

一般情況下,PROJECTION 矩陣只會調用一次;而大部分在做矩陣旋轉平移的時候,就只會需要用到 MODELVIEW 矩陣。

 


Example

void myopenGL::resizeGL(int width, int height)
{
	if(height == 0)
		height = 1;

	glViewport(0, 0, width, height); //reset the current view port
	glMatrixMode(GL_PROJECTION); //select the projection matrix
	glLoadIdentity(); // reset the model view matrix
	WHratio = (double)width/height;
	gluPerspective(fov, WHratio, 0.1f, 100.0f); //fovy : view angle(0~180 degree), (0.1f, 100.0f) : drawing area

	glMatrixMode(GL_MODELVIEW); // select model view matrix
	glLoadIdentity();	// reset the model view matrix
}

在 resizeGL() function 裡面,GL_PROJECTION 就是針對視窗的視野角度做一次定義後,之後都交由 GL_MODELVIEW 來處理物體的型態轉換。

 

 

Texture Mapping in OpenGL (L2)

未命名Drawing 2D&3D 這篇文章裡,已經說明了如何繪製立體圖形及上色,這篇主要說明如何將圖片貼在三維空間的平面上。首先必須要先能讀取圖片檔案,我這裡是使用 QImage 存取,再者就是建立一個 texture 放入圖片資訊。圖片選擇上要注意的地方就是圖片大小,圖片長與寬的大小必須是2的冪次方( 2,4,8,16,32,64...) 再參考網頁裡,他說長寬最好大於 64 pixels 且為了兼容性(Compatability),不要大於 256 pixels(但我範例裡使用的 Lena 圖是 512x512,效果也不差,所以見仁見智囉)。

而整體來說就是多一個 loadGLTexture function,來做 texture mapping。

● Load Texture

void myopenGL::loadGLTexture(string &amp;amp;amp;amp;amp;amp;amp; input_file)
{
	//@ load input_file into Qimage(img)
	QImage img, GL_img;
	if(!img.load(input_file.c_str()))
	{
		qWarning("Could not read the image file.");
		QImage dummy(512, 512, QImage::Format_RGB32);
		dummy.fill(Qt::green);
		img = dummy;
	}
	GL_img = QGLWidget::convertToGLFormat( img ); // convert QImage to GLformat

	//@ create the texture
	glGenTextures(1, &amp;amp;amp;amp;amp;amp;amp;texture[0]);
	glBindTexture(GL_TEXTURE_2D, texture[0]); // bind the named texture[0]
	//@ generate the texture
	glTexImage2D(GL_TEXTURE_2D, 0, 3, GL_img.width(), GL_img.height(), 0,
				 GL_RGBA, GL_UNSIGNED_BYTE, GL_img.bits());
	//@ interoolation type for scaling
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

}

dummy 指的是如果 load image failure 時,會輸出一張綠色的圖。

未命名

QGLWidget::convertToGLFormat( img ) 指的是將 QImage format 轉成 OpenGL format,不轉的話圖片顏色會怪怪的

glGenTextures(1, &texture[0]) 產生一個 texture memory 在 texture[0] 的位置。

glBindTexture( GL_TEXTURE_2D, texture[0]) 將 texture[0] 與 GL_TEXTURE_2D 捆再一起,告訴 OpenGL 有個 texture memory 在 texture[0]。

glTexImage2D(GL_TEXTURE_2D, 0, 3, GL_img.width(), GL_img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_img.bits()) 透過 GL_TEXTURE_2D 將圖片資訊存到 texture[0] 這個位置裡。glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) 函式裡 level & border 通常都設為 0;target 就是 GL_TEXTURE_2D;特別注意的是 format ,在參考網頁裡寫的是 GL_RGB,但我使用 GL_RGB 卻無法正常顯示圖形,必須使用 GL_RGBA,多個 Alpha 後才會正常顯示。

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

這兩個 functions 則是決定在圖片放大縮小時,interpolation 是要使用甚麼方式,可用 GL_LINEAR(效果好) 或 GL_NEAREST(較快)。

 

loadGLTexture(in_file);
glEnable(GL_TEXTURE_2D);

然後,只要在 initialize 裡面加入上面的 function loadGLTexture(in_file) 和啟動GL_TEXTURE_2D glEnable(GL_TEXTURE_2D)

 

glTranslatef(0.0f, 0.0f, -50.f);
glRotatef(rota_x, 1.0f, 0.0f, 0.0f);
glRotatef(rota_y, 0.0f, 1.0f, 0.0f);
glRotatef(rota_z, 0.0f, 0.0f, 1.0f);
glBindTexture( GL_TEXTURE_2D, texture[0]);	// using texture[0]
// Front Face
glBegin( GL_QUADS );
glTexCoord2f(0.0f, 0.0f); glVertex3f(-D, -D,  D);  // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f( D, -D,  D);  // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( D,  D,  D);  // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(-D,  D,  D);  // Top Left Of The Texture and Quad
glEnd();

最後在 draw scene 裡要注意 glTexCoord2fglVertex3f 方位要一致,不然畫出來的圖形會翻轉或顛倒;而 glBindTexture(GL_TEXTURE_2D, texture[0]) 不能放在 glBegin()glEnd() 裡面。

 

 


● Texture Filter

texture[0] 裡,我們使用的 Filter 是 GL_LINEAR,若圖片在側邊被擠壓成很細小時,圖片的內容因為 rendering 的不夠細膩而使很多細節消失;使用 GL_NEAREST Filter 情況更為糟糕。如下圖所示,六面體中,右方與下方的圖有明顯的鋸齒狀。

未命名                                                    [GL_LINEAR FILTER]

未命名2                                                [GL_NEAREST FILTER]

因此,為了使細節不因畫面壓縮而產生鋸齒狀,可以使用另一種 Filter,叫做 Mipmapped texture,說穿了他只是對 texture 做個 low pass filter ,再 rendering 到屏幕上而已,因此視覺效果會比較平順舒服,主體細節不會因為擠壓而有鋸齒狀產生。未命名3

                                               [MIPMAPPING FILTER]

	//@ texture 1
	glGenTextures(1, &amp;amp;texture[0]);
	glBindTexture(GL_TEXTURE_2D, texture[0]); // bind the named texture[0]
	glTexImage2D(GL_TEXTURE_2D, 0, 3, GL_img.width(), GL_img.height(), 0,
				 GL_RGBA, GL_UNSIGNED_BYTE, GL_img.bits());// 0 : iamge level usual use 0, second zero means border
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

	//@ texture 2
	glGenTextures(1, &amp;amp;texture[1]);
	glBindTexture(GL_TEXTURE_2D, texture[1]);
	glTexImage2D(GL_TEXTURE_2D, 0, 3, GL_img.width(), GL_img.height(), 0,
				  GL_RGBA, GL_UNSIGNED_BYTE, GL_img.bits());
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	//@ texture 3 MipMapped texture
	glGenTextures(1, &amp;amp;texture[2]);
	glBindTexture(GL_TEXTURE_2D, texture[2]);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, GL_img.width(), GL_img.height(),
					  GL_RGBA, GL_UNSIGNED_BYTE, GL_img.bits());

 


reference : http://nehe.gamedev.net/tutorial/texture_mapping/12038/

Lena Image : http://www.cs.cmu.edu/~chuck/lennapg/lenna.shtml

 

Drawing 2D & 3D Objects in OpenGL (L1)

Rending OpenGL Graphics in Qt 裡介紹如何定義 Qt 函式來繪製 OpenGL 物件,基本上所有物件繪製都寫在 paintGL() 這個 function 內。而今天要介紹如何繪製 2D&3D 物件、上色與物體旋轉。

● 2D OBJECT

glTranslatef(-1.5, 0.0f, -6.0f);
// Rotate the object
glRotatef(rota_x, 1.0f, 0.0f, 0.0f);
glRotatef(rota_y, 0.0f, 1.0f, 0.0f);
glRotatef(rota_z, 0.0f, 0.0f, 1.0f);

// draw a square
glColor3f( 0.0f, 1.0f, 0.0f);
glBegin(GL_QUADS);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glEnd();

glLoadIdentity();
glTranslatef(1.5f, 0.0f, -6.0f);
glRotatef(rota_x, 1.0f, 0.0f, 0.0f);
glRotatef(rota_y, 0.0f, 1.0f, 0.0f);
glRotatef(rota_z, 0.0f, 0.0f, 1.0f);

//glTranslatef(3.0f, 0.0f, 0.0f);// move right 3 units

// draw a triagle
glBegin(GL_TRIANGLES);
glColor3f ( 0.0f, 0.0f, 1.0f);
glVertex3f( 0.0f, 1.0f, 0.0f); // x , y , z
glColor3f ( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glColor3f ( 1.0f, 0.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 是清除 color 和 depth                                                                                                               buffers。

glLoadIdentity() 是指重置觀看矩陣模型,將觀看座標移至座標中心。

glTranslatef(x, y, z) 將物體沿著各軸移動;x 指左右移動(左負右正)、y 指上下移動(上正                                   下負)、z 指移入移出屏幕(移出正 移入負)

glRotatef( angle, x, y, z) 可以針對不同向量(x,y,z)做 angle 角度的旋轉,旋轉方向符合右                                           手定則

glColor3f(R,G,B) RGB 為三個 channel 的數值,範圍 [0.0 ~1.0]。

glBegin(object type) 表示開始繪畫物件,() 裡的 object type 代表繪畫的樣式,                                                    GL_QUADS 表示繪畫方形,GL_TRANGLES 表示三角形。

glVertex3f(x, y, z) 標記點,(x,y,z) 代表在空間中的座標點位置。

glEnd() 表示繪圖結束,與glBegin() 是一對的。

執行結果(rota_x = 0, rota_y = 10, rota_z = 0):

未命名

 

 

● 3D OBJECT

glTranslated(-1.5f, 0.0f,-6.0f);
glRotatef(15, 1.0f, 0.0f, 0.0f);
glRotatef(0, 0.0f, 1.0f, 0.0f);
glRotatef(0, 0.0f, 0.0f, 1.0f);

glBegin(GL_TRIANGLES);
// front
glColor3f(  1.0f, 0.0f, 0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(  0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glColor3f(  0.0f, 0.0f, 1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
// right
glColor3f(  1.0f, 0.0f, 0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(  0.0f, 0.0f, 1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glColor3f(  0.0f, 1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
// left
glColor3f(  1.0f, 0.0f, 0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(  0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glColor3f(  0.0f, 0.0f, 1.0f);
glVertex3f(-1.0f,-1.0f,1.0f);
//back
glColor3f(  1.0f, 1.0f, 1.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(  0.0f, 1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
glColor3f(  0.0f, 0.0f, 1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glEnd();

glLoadIdentity();
glTranslatef(1.5f, 0.0f, -7.0f);
glRotatef(20, 1.0f, 0.0f, 0.0f);
glRotatef(0, 0.0f, 1.0f, 0.0f);
glRotatef(0, 0.0f, 0.0f, 1.0f);

glBegin(GL_QUADS);
//top
glColor3f(  1.0, 0.0, 0.0);
glVertex3f(-1.0, 1.0,-1.0);
glVertex3f( 1.0, 1.0,-1.0);
glVertex3f( 1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
//front
glColor3f(  0.0, 1.0, 0.0);
glVertex3f(-1.0, 1.0,-1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f( 1.0,-1.0,-1.0);
glVertex3f( 1.0, 1.0,-1.0);
//right
glColor3f(  0.0, 1.0, 1.0);
glVertex3f( 1.0, 1.0,-1.0);
glVertex3f( 1.0,-1.0,-1.0);
glVertex3f( 1.0,-1.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0);
//back
glColor3f(  0.0, 0.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0);
glVertex3f( 1.0,-1.0, 1.0);
glVertex3f(-1.0,-1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
//left
glColor3f(  1.0, 1.0, 0.0);
glVertex3f(-1.0, 1.0,-1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(-1.0,-1.0, 1.0);
glVertex3f(-1.0,-1.0,-1.0);
//bottom
glColor3f(  1.0, 0.0, 1.0);
glVertex3f( 1.0,-1.0,-1.0);
glVertex3f( 1.0,-1.0, 1.0);
glVertex3f(-1.0,-1.0, 1.0);
glVertex3f(-1.0,-1.0,-1.0);
glEnd();

3D 物件繪畫方式與 2D 相同,只是 2D 的延伸。例如:一個立方體有六面,那就表示要畫六次 2D 平面;然而三角錐有四面,就是要畫四個平面。唯一要注意的地方就是,在繪畫任何一個方體的時候,每一面的繪畫點一定要都是順時針繞或逆時針繞,不能一面用順時針標點,另一面用逆時針標點,這樣 OpenGL 是判別不出來的,所以每一面一定要同個方向繞點。 執行結果:

未命名

 

 


reference : http://nehe.gamedev.net/tutorial/lessons_01__05/22004/

 

Rendering OpenGL Graphics in Qt

若今天不使用 GLUT 的視窗介面而改用 Qt 來 rendering (渲染) 3D 圖形時,則要藉由 QGLWidget 這個 Class 來實現。

QGLWidget 提供三個非常方便的虛擬函式( Virtual Function) ,分別是 initializeGL()resizeGL() paintGL()。所以在衍生類別的 function naming 要與上述的三個 function 相符合,不然無法 rendering OpenGL 的圖形。

initializeGL() :: 初始設定 rendering 的預設參數,在第一次使用 resizeGL() 和 paintGL() 之前,會先呼叫 initializeGL() 。執行順序是 initializeGL() --> resizeGL() --> paintGL() 。

resizeGL() :: 設定 OpenGL 的觀看位置、矩陣型態、視野角度以及 OpenGL drawing 的範圍...等等。除了第一次 widget 被 create 時會被呼叫,之後只要 widget 有被 resized 時都會重新被呼叫。

paintGL() :: Rendering OpenGL 的畫面,你所畫的物件都應該在這個 function 裡定義。

 


** Example **

class myQGL : public QGLWidget
{
	Q_OBJECT

public:
	myQGL(QWidget *parent = 0);
	~myQGL();

	// &gt;&gt;&gt; QGLWidget protected funs
	virtual void initializeGL();
	virtual void paintGL();
	virtual void resizeGL(int width, int height);
	// &lt;&lt;&lt; QGLWidget portected funs

	public slots:
		void GLupdate();
private:
};
void myQGL::initializeGL()
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // background ( R, G, B, Alpha)
	glClearDepth(1.0f);	//depth buffer setup
	glShadeModel(GL_SMOOTH); // enables smooth shading
	glEnable(GL_DEPTH_TEST); // enable depth testing
	glDepthFunc(GL_LEQUAL); // the type of depth test to do

	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void myQGL::resizeGL(int width, int height)
{
	if(height == 0)
		height = 1;

	glViewport(0, 0, width, height); //reset the current view port
	glMatrixMode(GL_PROJECTION); //select the model view matrix
	glLoadIdentity(); // reset the model view matrix 

	//calculate the aspect ratio of the window
	gluPerspective(45, (GLfloat)width/height, 0.1f, 100.0f); //fovy : view angle, (0.1f, 100.0f) : drawing area
	glMatrixMode(GL_MODELVIEW); // select model view matrix
	glLoadIdentity();	// reset the model view matrix

}

void myQGL::paintGL()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	glTranslatef(-1.5, 0.0f, -6.0f);

	// draw a triagle
	glBegin(GL_TRIANGLES);
	glColor3f( 0.0f, 0.0f, 1.0f);
	glVertex3f( 0.0f, 1.0f, 0.0f); // x , y , z
	glColor3f( 0.0f, 1.0f, 0.0f);
	glVertex3f(-1.0f,-1.0f, 0.0f);
	glColor3f( 1.0f, 0.0f, 0.0f);
	glVertex3f( 1.0f,-1.0f, 0.0f);
	glEnd();
	glTranslatef(3.0f, 0.0f, 0.0f);// move right 3 units

	// draw a square
	glColor3f( 1.0f, 1.0f, 0.0f);
	glBegin(GL_QUADS);
	glVertex3f(-1.0f, 1.0f, 0.0f);
	glVertex3f( 1.0f, 1.0f, 0.0f);
	glVertex3f( 1.0f,-1.0f, 0.0f);
	glVertex3f(-1.0f,-1.0f, 0.0f);
	glEnd();
}

執行結果

triangle & squad                                                      [ Triangle and Square ]


 

reference : http://doc.qt.io/qt-4.8/qglwidget.html#details