Masking in OpenGL (L11)

2016-01-07_100026

今天要介紹如何將 Texture 蓋上一層面具,或實現一個特殊的遮蔽物。基本上是透過 L4 所講的 Blending 方式來實現,只是今天要前置處理得到一個 Texture 的 Mask ,再透過 Blending Function 來呈現。

● glBlendFunc()

首先細部解說 glBlendFunc() 函數,

void glBlendFunc (GLenum sfactor, GLenum dfactor) 函數裡有兩個主要變數分別為 sfactor 表示 source factor (新加入顏色的權重值);dfactor 表示 destination factor (原本在屏幕緩衝區裡的權重值),兩個 factor 數值介於[0,1]。

FinalColor = sfactor * SourceColor + dfactor * DestinationColor

factor 參數設定有多組型態可以設定,如下圖:2016-01-07_122533參數裡面的kG kR kB kA 代表像素的最大值(以 8bit 為例就是 255);而當選用 GL_CONSTANT_COLOR 時,需要透過 glBlendColor() 來決定混和顏色的數值。

 


● Masking

接下來就是本篇重頭戲了,要製造出 mask 的效果,必須先將你的 texture image 轉成二值化影像,將 image 有 texture 轉成 black,沒有 texture 的部分轉成 white,得到二值化影像後,接著透過 glBlendFunc(GL_DST_COLOR, GL_ZEOR) 來實現 masking 的效果。左下圖為 texture image,右下圖為 mask image。

aboutdada2 aboutdada_mask


void myopenGL::paintGL()
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glLoadIdentity();
 
 // @ masking
 glTranslatef(0.0f, 0.0f, -2.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);
 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);// set texture alpha 
 glBindTexture(GL_TEXTURE_2D, texture[0]);
 glBegin(GL_QUADS);
 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);
 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f);
 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
 glEnd();

 glEnable(GL_BLEND);
 glDisable(GL_DEPTH_TEST);

if(masking)
 {
 glBlendFunc(GL_DST_COLOR, GL_ZERO);

glPushMatrix();
 glTranslatef(0.0f, 0.0f, -0.2f); // for cookie cutter 
 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);// set texture alpha
 glBindTexture(GL_TEXTURE_2D, texture[1]);
 glBegin(GL_QUADS);
 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f,-1.1f, 0.0f);
 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f,-1.1f, 0.0f);
 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f, 1.1f, 0.0f);
 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f, 1.1f, 0.0f);
 glEnd();
 glPopMatrix();
 }

 glEnable(GL_DEPTH_TEST);
 glDisable(GL_BLEND);

}

注意到在 blending 之前要先 glDisable(GL_DEPTH_TEST),當繪製完成後,再 glEnable(GL_DEPTH_TEST),是為了避免錯誤的行為發生。 還有 mask image 的 size 會比 texture image 還來得大一些,主要是為了有好的遮蔽效果,透過 masking 參數來開關 mask,執行結果會有種餅乾切割器( cookie cutter )的效果,只會顯現出 texture 的輪廓,執行結果:picasion.com_8d092731cb98e2622b67517464af1da0

此外,這裡我另外加入兩個 mask,分別是以下兩個影像,這裡的 blending 方式就直接用自己的顏色數值來決定glBlendFunc(GL_SRC_COLOR, GL_DST_COLOR)。 

aboutdada_mask2 aboutdada_mask3


if(masking2)
 {
 glPushMatrix();
 glTranslatef(0.0f, 0.0f, 0.1f); 
 glBlendFunc(GL_SRC_COLOR, GL_DST_COLOR);
 glBindTexture(GL_TEXTURE_2D, texture[2]);

 glBegin(GL_QUADS);
 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f,-1.1f, 0.0f);
 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f,-1.1f, 0.0f);
 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f, 1.1f, 0.0f);
 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f, 1.1f, 0.0f); 
 glEnd();
 glPopMatrix();
 }
 if(masking3)
 {
 glPushMatrix();
 glTranslatef(0.0f, 0.0f, 0.2f); 
 glBlendFunc(GL_SRC_COLOR, GL_DST_COLOR);
 glBindTexture(GL_TEXTURE_2D, texture[3]);

 glBegin(GL_QUADS);
 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f,-1.1f, 0.0f);
 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f,-1.1f, 0.0f);
 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f, 1.1f, 0.0f);
 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f, 1.1f, 0.0f);
 glEnd();
 glPopMatrix();
 }

透過 masking2 與 masking3 來開關 mask,執行結果如下:

picasion.com_e76d9d3f3a2b6f6b55d7cae83462d0eb

 


reference :

http://nehe.gamedev.net/tutorial/masking/15006/

https://www.opengl.org/sdk/docs/man/html/glBlendFunc.xhtml

 

 

QThread & Taipei101 Fireworks in OpenGL

2015-12-31_130012

在 2015 的最後一天,就用 Taipei101 Firework 這個程式來做個階段型的結尾吧~猶如降龍十八掌的第十八式,集結前面所學,所施展出來的招式。今天這個 Project 也是從之前所學到的繪製 2D & 3D Object、Texture Mapping、Quadric Object、Keyboard Control 到 Particle Engine 來完成的。但今天不再細說前面曾經提過的內容,今天主要是介紹 Qt 裡面的 QThread 來實現我的煙火特效。

● QThread

在 QThread 裡面有三個主要的 Public Slots 來控制 Thread 開始、結束和退出。分別是 void start(); void terminate(); void quit();;而 Thread 要執行的內容則是透過一個 protected function : void run(); 來實現,所以今天要求 Thread 做甚麼事情全都要寫在 run() 函式裡面。

class myThread : public QThread
{
 Q_OBJECT
public:
 myThread();
 ~myThread();
public slots:
 void start_mythread();
signals:
 void signal_firework();
protected:
 void run();
};

上面的 myThread 是我在 Taipei101 Firework 這個專案裡面所設定的 Thread。

void myThread::start_mythread()
{
 this->start();
}

start_mythread() 是一個 slots,作用就是啟動我的 Thread。

void myThread::run()
{
 double a = 0;
 while(1)
 {
 if(FIREWORK_UPDATE)
 {
 emit signal_firework();
 FIREWORK_UPDATE = false;
 }}}
connect(mythread, SIGNAL(signal_firework()),
        myqgl, SLOT(firework_update()));

接著在 run() 裡面就是指派我的 Thread 裡的工作,工作內容很簡單,就是在一個 while 迴圈內一直執行 emit signal_firework() 。這個 emit 指的是去發送 signal_firework() 訊號出去,讓接收到這個訊號的人做下一步的動作。例如我這裡將 mythread 訊號與我的 mygql 做連結(connect),所以當 myqgl 接收到 signla_firework() 訊號後,就會執行 firework_update() 的動作。特別注意到我這裡用 FIREWORK_UPDATE 來控制 emit 的動作,當我完成上一個 update 後,才會再發送下一次的 signal_firework(),作用是為了避免程式不停的發送 emit ,而使序列(queue) 裡面堆積太多的訊號要執行,到最後整個程式會因為有做不完的 update 而當掉。

 

 


● Taipei101 Fireworks

這個程式有三種形式的煙火,由三種不同的 Particle Engine 來實現,分別是迴旋式煙火、階段式煙火以及噴發式煙火。Particle Engine 的設定請看 L10

101_firework

最後 demo 影片效果囉。Happy New Year~~~

 

 


reference : http://doc.qt.io/qt-4.8/qthread.html

 

Triangle Types and Particle Engine in OpenGL (L10)

 

2015-12-22_142743

今天要介紹 Particle EngineTriangle Types。本篇主要是參考 NeHe Tutorial19 所改寫的,內容概要差不多,只是呈現方式不一樣而已。

● Triangle Types

首先介紹繪畫三角形的方式,在這之前我們都會使用 glBegin(GL_QUADS) 來繪製多邊形,今天介紹三種不同繪製三角形的方法,或者說是利用三角形繪畫法來描繪不同型態的多邊形。這三種方法分別為 GL_TRIANGLESGL_TRIANGLE_STRIPGL_TRIANGLE_FAN

1334232485_5764

  1. GL_TRIANGLES 為基礎的三角形繪畫法,給定三個點座標,就可以畫出所想要的三角形了,與 GL_QUADS 作法相同。
  2. GL_TRIANGLE_STRIP 此繪畫方式可以只用 N+2 個頂點畫出 N 個三角形出來,但必須注意每個三角形在繪製頂點時的方向,必須都為順時針或逆時針來繪製。以上圖為例,繪製第一個三角形時,頂點順序為 V0, V1, V2;第二個三角形頂點順序為 V2, V1, V3;第三個三角形 V2, V3, V4 ... 以此類推。
  3. GL_TRIANGLE_FANGL_TRIANGLE_STRIP 類似,但繪畫順序為 V0, V1, V2 ... 第一個點為扇形的圓心點(V0)。
glBegin(GL_TRIANGLE_FAN); // triangle fan
glTexCoord2f(1,1);	glVertex3f(0.0f, 0.0f, z);// V0
glTexCoord2f(0,1);	glVertex3f(2.0f, 0.0f, z);// V1
glTexCoord2f(1,0);	glVertex3f(1.4f, 0.8f, z);// V2
glTexCoord2f(0,0);	glVertex3f(0.8f, 1.4f, z);// V3
glTexCoord2f(1,1);	glVertex3f(0.0f, 2.0f, z);// V4
glEnd();

 


● Particle Engine

接下來介紹本篇的重點,粒子引擎( Particle Engine )。粒子引擎的目的是在屏幕上繪出大量的粒子,再藉由畫面的更新,讓粒子在三維空間中移動,製造出像粒子爆發或者射散出去的視覺觀感。在這裡我是藉由粒子引擎模擬出婚禮拉炮的視覺效果。 首先定義出粒子的 struct 和粒子顏色。

//@ particle
struct Particle
{
 bool active;
 float life;
 float fade;
 float r, g, b;
 float x, y, z;
 float xi, yi, zi;
 float xg, yg, zg;
};
Particle particle[1000];
GLfloat particle_colors[12][3] =
{ 
 {1.0f, 0.0f, 0.0f} , {1.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 1.0f},
 {0.0f, 0.0f, 1.0f} , {1.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 0.5f}, {0.5f, 1.0f, 0.3f},
 {0.2f, 0.5f, 0.8f} , {1.0f, 0.0f, 0.5f}, {0.5f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.2f}
};

active 表示粒子是否活化;life 是粒子存活與否;fade 則是粒子褪色,這會影響到 life 參數(後面會說明);rgb 為粒子顏色;xyz 為粒子位置;xi yi zi 為粒子的移動方向;xg yg zg 為環境的重力場分量;particle[1000] 為每次在屏幕出現的粒子數為 1000 個;particle_colors 為定義多組顏色給各個不同的粒子使用。

//@ particle initialize
 for(int loop = 0; loop < 1000; loop++)
 {
 particle[loop].active = 1;
 particle[loop].life = 1.0f;
 particle[loop].fade = float(rand()%100)/1000.0f + 0.03f;
 particle[loop].r = particle_colors[loop%12][0];
 particle[loop].g = particle_colors[loop%12][1];
 particle[loop].b = particle_colors[loop%12][2];

particle[loop].x = 0.0f;
 particle[loop].y = 0.0f;
 particle[loop].z = 0.0f;

particle[loop].xi = float( rand()%50 + 25.0f) * 10.0f;
 particle[loop].yi = float((rand()%50) - 25.0f) * 10.0f;
 particle[loop].zi = float((rand()%50) - 25.0f) * 10.0f;

particle[loop].xg = 0.0f;
 particle[loop].yg = -9.8f;
 particle[loop].zg = 0.0f;
 }

接著在 initializeGL() 裡面定義粒子參數,這裡定義每個粒子的 active 都是1表示存活;life 設為 1.0f,而 fade 則會根據 rand() 函式來決定每個粒子退化的速度;rgb 與 xyz 就是顏色與起始位置;特別注意到 xi yi zi 的數值範圍,xi 介於 25~74、yi 與 zi 都介於 -25~24 之間,由於我這裡要模擬婚禮拉炮的效果,所以 x 向量的分量要是正的(單一方向),且要大於 y分量與 z分量,表示粒子大部分受力來至於 xi 的方向;重力場只有 gy=-9.8 有值,且每個粒子所受的重力一致。

void myopenGL::paintGL()
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glLoadIdentity();
 glTranslatef(0.0f, 0.0f, -40.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);

 //# blend
 glColor4f(1.0f, 1.0f, 1.0f,0.5f);
 glBlendFunc(GL_ONE, GL_ZERO);
 glEnable(GL_BLEND);
 //# texture
 glEnable(GL_TEXTURE_2D);
 glBindTexture(GL_TEXTURE_2D, texture[0]);
 //# cone
 glPushMatrix();
 glTranslatef(-20.0f, 0.0f, 0.0f);
 glRotatef(-90, 0.0f, 1.0f, 0.0f);
 gluCylinder(quadratic, 3.0f, 0.0f, 8.0f, 32, 32); //cone
 glPopMatrix();
 double slowdown = 1.0f; //velocity
 glTranslatef(-20.0f, 0.0f, 0.0f);
 for(int loop = 0; loop < 1000; loop++)
 {
 if(particle[loop].active)
 {
 float x = particle[loop].x;
 float y = particle[loop].y;
 float z = particle[loop].z;

 //# blend
 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 glColor4f(particle[loop].r, particle[loop].g, particle[loop].b, particle[loop].life);
 //# texture
 glDisable(GL_TEXTURE_2D);
 // Triangle Strip
 glBegin(GL_TRIANGLE_STRIP);
 glTexCoord2f(1,1); glVertex3f(x+0.5f,y+0.5f,z);//top right
 glTexCoord2f(0,1); glVertex3f(x-0.5f,y+0.5f,z);//top left
 glTexCoord2f(1,0); glVertex3f(x+0.5f,y-0.5f,z);//bot right
 glTexCoord2f(0,0); glVertex3f(x-0.5f,y-0.5f,z);//bot left
 glEnd();

particle[loop].x += particle[loop].xi/(slowdown*1000);
 particle[loop].y += particle[loop].yi/(slowdown*1000);
 particle[loop].z += particle[loop].zi/(slowdown*1000);

particle[loop].xi += particle[loop].xg;
 particle[loop].yi += particle[loop].yg;
 particle[loop].zi += particle[loop].zg;
 particle[loop].life -= particle[loop].fade;

 if(particle[loop].life < 0)
 {
 particle[loop].life = 1.0f;
 particle[loop].fade = float(rand()%100)/1000.0f + 0.003f;
 particle[loop].x = 0.0f;
 particle[loop].y = 0.0f;
 particle[loop].z = 0.0f;
 particle[loop].xi = float( rand()%50 + 25.0f) * 10.0f;
 particle[loop].yi = float((rand()%50) - 25.0f) * 10.0f;
 particle[loop].zi = float((rand()%50) - 25.0f) * 10.0f;
}}}}

最後就是在 paintGL() 裡繪出每個粒子的位置與顏色,可以特別注意每個粒子的位置會受到 slowdown 變數影響(粒子速度)和 重力g 影響;至於 life 會隨著 fade 而慢慢減少(life 代表每個粒子的透明度),當 life 減至零時,表示粒子已經死亡,則會再生成另一個粒子出來。另外可以注意到 code 裡面 #texture #blend 的差異,因為畫面裡的圓錐是非透明的 texture,而粒子是有透明的顏色,所以透過 texture 與 blend 的開關來做轉換。

 


執行結果:

 


reference :

http://nehe.gamedev.net/tutorial/particle_engine_using_triangle_strips/21001/

http://blog.csdn.net/xiajun07061225/article/details/7455283

 

Quadrics in OpenGL (L9)

2015-12-17_195331

以往我們只會畫平面、立方體或三角錐...等,由平面組成的立體圖形,今天要介紹複雜一點的圖形,那就是二次曲面( Quadric ),包含了圓形、扇形、球體、圓柱體以及圓錐體。實作方面不難,只要套用 GLUquadricObj 這個物件即可。

 GLuint quadratic_object;
 GLUquadric * quadratic;

首先在自己的 Class 裡面加入兩個 data members 分別是 quadratic_objectquadratic。quadratic_object 是待會用來切換不同二次曲面的參數,quadratic 則是儲存 GLUquadric 物件的指標。

quadratic = gluNewQuadric();
gluQuadricNormals(quadratic, GLU_SMOOTH);//GLU_NONE, GLU_FLAT
gluQuadricTexture(quadratic, GL_TRUE);

接著,在 initializeGL() 裡面定義 quadratic,

quadratic = gluNewQuadric() 表示建立一個二次曲面空間給 quadratic。

gluQuadricNormals(quadratic, GLU_SMOOTH) 設定外觀效果給 lighting 使用,除了 GLU_SMOOTH 外,還有 GLU_NONEGLU_FLAT 可以使用。

gluQuadricTexture(quadratic, GL_TRUE) 讓 texture 可以 mapping 到我們的二次曲面上。

switch(quadratic_object)
{
case 0:
	drawCube();	//cube
	break;
case 1:
	glTranslatef(0.0f, 0.0f, -1.5f);
	gluCylinder(quadratic, 1.0f, 1.0f, 3.0f, 32, 32);	//cylinder
	break;
case 2:
	gluDisk(quadratic, 0.5f, 1.5f, 32, 32);	//CD disk
	break;
case 3:
	gluSphere(quadratic, 1.3f, 32, 32);	//sphere
	break;
case 4:
	glTranslatef(0.0f, 0.0f, -1.5f);
	gluCylinder(quadratic, 1.0f, 0.0f, 3.0f, 32, 32);	//cone
	break;
case 5:
	int angle_start = 0;
	int sweep_angle = 180;
	gluPartialDisk(quadratic, 0.5f, 1.5f, 32, 32, angle_start, sweep_angle);	//fan
	break;
}

最後就是在 paintGL() 上繪出不同形狀的圖形了,透過不一樣的 function 來繪製不同的形狀。

drawCube() 是前面一直會用到的很簡單的立方體。


glBegin(GL_QUADS);
//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);
//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);
// 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);
//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();

gluCylinder(quadratic, 1.0f, 1.0f, 3.0f, 32, 32) 為繪製圓柱體,第一個參數是表示底部的半徑,第二個參數表示頂部的半徑,第三個參數表示圓柱體的高,第四個參數 32 表示 slices,代表多少切片圍繞在圓柱體,第五個參數 32 表示 stacks,表示圓柱體是用多少堆疊起來,數值越高表示精度越高

gluDisk(quadratic, 0.5f, 1.5f, 32, 32) 表示圓盤,0.5f 表示內圈半徑,1.5f 表示外圈半徑。內圈半徑一定要小於外圈半徑。

gluSphere(quadratic, 1.3f, 32, 32) 繪製球體,1.3f 為球體半徑。

gluCylinder(quadratic, 1.0f, 0.0f, 3.0f, 32, 32) 繪製圓錐,特別注意到這裡的 function 與繪製圓柱體一樣,只是今天第二個參數(頂部的半徑設為零),就會呈現圓錐體。

gluPartialDisk(quadratic, 0.5f, 1.5f, 32, 32, angle_start, sweep_angle) 繪製扇形。0.5f 表示內半徑,1.5f 表示外半徑,angle_start 表示扇形起始點,sweep_angle 表示掃過的角度有多少。

 

 


透過變更 quadratic_object 來選擇不同的圖形輸出,執行結果:

picasion.com_bbf0c4deb01ab0c797f51566ae4a9a0e

至於文章前面像釘子網的圖形,我是用陣列方式匯出多個圓錐形來實現的。

 

 


reference : http://nehe.gamedev.net/tutorial/quadrics/20001/

 

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

 

台灣之光-泰雅鈍頭蛇

P1330831

寫了一狗票的 OpenGL 學習文,該來個 halftime 了。泰雅鈍頭蛇( Pareas atayal ) 是今年 2015 燒燙燙剛發表的新物種,就是上圖物種,而且泰雅鈍頭蛇是史上唯一一次由台灣人自己發表自己本土的特有蛇種;台灣大部分物種,在日治時期都已經被日本籍學者給記載,距離上次在台灣發表新物種已經事隔 84 年之久了(牧茂市郎在1931年發表的金絲蛇( Amphiesma miyajimae )和標蛇( Achalinus niger )之後就不再有新種蛇類被發現)。要能證明新物種是不容易的事,要有足夠的證據證明新種不會與其他蛇類交配而混雜到他種的遺傳物質。物種定義:任何一個物種都是天然狀況下獨立的繁殖群體,不會與其他群體混種。

新種鈍頭蛇主要分布在雪山山脈以北的區域,與泰雅族傳統領域有很高的重疊性,所以取名叫做泰雅鈍頭蛇。

加上新種泰雅鈍頭蛇,目前台灣共有三種鈍頭蛇,分別是『台灣鈍頭蛇』、『駒井氏鈍頭蛇』和『泰雅鈍頭蛇』;區分方法可用眼睛顏色、鱗片形狀以及地理分佈來區分:

1.台灣鈍頭蛇:台灣全島都有分佈,眼睛橙紅色,鱗片圓滑。

2.駒井氏鈍頭蛇:分佈在中南部,眼睛橙黃色,鱗片粗糙且背部有明顯的稜脊。

3.泰雅鈍頭蛇:分佈在中北部,眼睛橙黃色,鱗片光滑度介於上面兩者之間,背部有些微的稜脊。

鈍頭蛇是南亞特有的小型蛇類,主要以蝸牛與蛞蝓為食,也由於食性專一,鈍頭蛇也演化出不對稱的下顎,牠們的右側下顎的牙齒數量通常比左側下顎的牙齒多(下圖),主要是由於蝸牛的螺殼構造所影響的,絕大多數的蝸牛殼都是“右旋”的型態,所以這樣的不對稱的牙齒有利於將蝸牛肉從螺殼中取出。這種特殊演化的發現令人感到新奇又可愛啊!

圖13:鈍頭蛇的右手性,即下頷右側牙齒數目較多。-560x245

棲地破壞、溫室效應、環境汙染、極端氣候...等等,在如此極端險惡的世代下還能有新的物種發現,真的是一大事跡,因為有科學家預言在 2050 年,全球會有 50% 物種消失。保護物種維持生物多樣性是非常重要的一門課題,這不僅僅只是影響到物種是否消失,也會間接影響到我們的食物與飲水,就像最近澳洲計畫撲殺百萬隻的流浪貓,來保護當地特有的物種(貓對於其他小型生物是個嚴重的威脅),但我想哪天台灣說要撲殺貓或狗來保護本土特有生物,我想官員可能會先被撲殺吧...台灣動物保護法只保護有毛的動物,其他生物都不是動物了...這個保護法真的必須要修,不然未來在台灣真的只能看得到有毛的動物了。

 

 


image from : http://boxturtlebox.blogspot.tw/2015/03/0327.html

reference : http://pansci.asia/archives/78287 & 科學人雜誌

 

 

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 &amp;amp;amp;amp;amp;lt; 6; yloop++)
{
 for(int xloop = 0; xloop &amp;amp;amp;amp;amp;lt; 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/