第五課
     
  延伸自上一課, 我們現在將會建構真正的 3D 物件, 而非 3D 世界中的 2D 物件. 我們會在三角形中加入左面, 後面, 和右邊的面; 在正方形中加入左, 右, 後, 上, 下的面. 這麼做就可以把三角形變為 3D 的金字塔, 方形變為立方體.

我們將在金字塔中用混合的色彩, 以建立平滑色彩的物件, 對於立方體, 每個面會給定不同的顏色.
 
     
int DrawGLScene(GLvoid)						// Here's Where We Do All The Drawing
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
	glLoadIdentity();					// Reset The View
	glTranslatef(-1.5f,0.0f,-6.0f);				// Move Left And Into The Screen

	glRotatef(rtri,0.0f,1.0f,0.0f);				// Rotate The Pyramid On It's Y Axis

	glBegin(GL_TRIANGLES);					// Start Drawing The Pyramid
     
  有一些程式碼你已經在上一個課程中獲得了, 並且你自己建了 3D 物件. 我常常被問到的就是 "為什麼我的物件不是繞著本身的軸旋轉? 而是繞著整個畫面旋轉". 為了讓你的物件繞著特定的軸旋轉. 你要記得任何物件的中心點應該都是在 X 的 0, Y 的 0, 和 Z 的 0.

接下來的程式碼就會建立一個金字塔繞著中心軸. 金字塔上面的頂點是中心高的點, 金字塔的底面的點就是中心低的點. 上面頂點的位置在中間是正確的 (零值), 而底部的點則是一個在中心的左邊, 一個在中心的右邊.

注意到所有的三角形在畫的順序上都是逆時針的, 這很重要的, 而以後的課程中會解釋原因的, 現在的話, 只要知道好好的練習用順時針或是逆時針來作物件就可以了; 但是你不應該混合這兩種方法, 除非你有你的理由.

我們開始畫正面. 因為所有的面都共用上面的頂點, 我們將會讓所有三角形的這一個點都用紅色的. 三角形下面兩個點的顏色則會輪流替換著綠色和藍色. 正面的平面左邊是綠色而右邊是藍色. 接下來右邊的三角形的會是左邊藍色而右邊綠色. 輪流替換綠色和藍色兩個顏色在平面的底部, 我們就為每個平面底部的點上好顏色了.
 
     
		glColor3f(1.0f,0.0f,0.0f);			// Red
		glVertex3f( 0.0f, 1.0f, 0.0f);			// Top Of Triangle (Front)
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f(-1.0f,-1.0f, 1.0f);			// Left Of Triangle (Front)
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f( 1.0f,-1.0f, 1.0f);			// Right Of Triangle (Front)
     
  現在我們畫出右邊的平面. 注意到下面的兩個點都會在中心的右邊, 而上面的點會在 y 軸上一個單位, 並且在 x 軸中心上. 所以平面會由中心上面的點傾斜到右下的底部.

注意到左邊的點這次被畫成藍色的. 畫成藍色的就會和正面的右下角的點一樣顏色了. 混合的藍色就會穿過金字塔的正面和右面.

注意到剩下的三個平面會和第一個平面類似的, 同樣在 glBegin(GL_TRIANGLES) 和 glEnd() 中, . 因為我們整個物件都是用三角形構成的, OpenGL 會知道每三個點要畫一個三角形. 一但畫了三個點的三角形後, 如果又有另外三個點, 就會被認定為要畫另一個三角形了. 如果你置入四個點, 而不是三個點, OpenGL 會畫出前三個點的三角形, 並且假定第四個點是一個新的三角形的起始點. 它不會畫出四邊形的. 所以請確定你不會不小心加一些多餘的點.
 
     
		glColor3f(1.0f,0.0f,0.0f);			// Red
		glVertex3f( 0.0f, 1.0f, 0.0f);			// Top Of Triangle (Right)
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f( 1.0f,-1.0f, 1.0f);			// Left Of Triangle (Right)
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f( 1.0f,-1.0f, -1.0f);			// Right Of Triangle (Right)
     
  現在回到背面. 再一次的切換色彩. 左邊的點現在又會是綠色, 因為這個角落要和右面的三角形共用綠色點.  
     
		glColor3f(1.0f,0.0f,0.0f);			// Red
		glVertex3f( 0.0f, 1.0f, 0.0f);			// Top Of Triangle (Back)
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f( 1.0f,-1.0f, -1.0f);			// Left Of Triangle (Back)
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f(-1.0f,-1.0f, -1.0f);			// Right Of Triangle (Back)
     
  最後畫出左邊的平面. 最後一次切換顏色. 左邊的點會是藍色, 混合這背面的右邊的點. 右邊的點會是綠色, 混合著正面的左邊的點.

我們完成了金字塔的繪製. 因為金字塔只會繞著 Y 軸旋轉, 我們就看不到金字塔的底部, 因此不需要放個底部在金字塔. 如果你想試驗, 可以在底下加一個四邊形, 然後旋轉 X 軸, 來看看你做的正不正確. 要確定四邊形每個角落的顏色符合金字塔四個角落的顏色.
 
     
		glColor3f(1.0f,0.0f,0.0f);			// Red
		glVertex3f( 0.0f, 1.0f, 0.0f);			// Top Of Triangle (Left)
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f(-1.0f,-1.0f,-1.0f);			// Left Of Triangle (Left)
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f(-1.0f,-1.0f, 1.0f);			// Right Of Triangle (Left)
	glEnd();						// Done Drawing The Pyramid
     
  現在我們將要畫立方體. 它由六個四邊形構成. 所有的四邊形要依照逆時針的順序繪製. 也就是說第一個點在右上, 第二個點在左上, 第三個點在左下, 最後一個點在右下. 當我們在畫背面, 它的繪製順序可能有點像是順時針, 但你要記住, 如果我們由背後來看這個立方體時, 原本在右邊的四邊形面看起來就會在左邊, 原本在左邊的四邊形面看起來就會在右邊.

注意到在這一課中, 我們會把立方體移的深入畫面一些. 這麼一來立方體的大小看起來會比較接近金字塔. 如果你只移入畫面六個單位, 那立方體看起來會比金字塔大一些, 立方體的一部份可能會被畫面切掉. 你可以玩玩看這樣的設定, 看看立方體移的更深入畫面時, 會看起來更小些, 而移的較靠近畫面時, 看起來就會比較大. 原因就是因為是透視觀點. 越遠的物件看起來會越小 :)
 
     
	glLoadIdentity();
	glTranslatef(1.5f,0.0f,-7.0f);				// Move Right And Into The Screen

	glRotatef(rquad,1.0f,1.0f,1.0f);			// Rotate The Cube On X, Y & Z

	glBegin(GL_QUADS);					// Start Drawing The Cube
     
  我們將開始畫立方體的上面. 我們由立方體中心向上移一個單位. 注意 Y 值都是 1. 然後畫一個四邊形在 Z 平面上. 也就是指垂直於畫面. 開始畫立方體上方平面的右上的點. 右上的點會是一個單位向右, 一個單位深入畫面. 第二個點是一個單位向左,一個單位深入畫面. 現在畫四邊形下面的點, 也就是朝向觀察者, 而不是深入畫面, 因此朝畫面移動一個單位. 好懂嗎?  
     
		glColor3f(0.0f,1.0f,0.0f);			// Set The Color To Blue
		glVertex3f( 1.0f, 1.0f,-1.0f);			// Top Right Of The Quad (Top)
		glVertex3f(-1.0f, 1.0f,-1.0f);			// Top Left Of The Quad (Top)
		glVertex3f(-1.0f, 1.0f, 1.0f);			// Bottom Left Of The Quad (Top)
		glVertex3f( 1.0f, 1.0f, 1.0f);			// Bottom Right Of The Quad (Top)
     
  底部要畫的和上面是一樣的, 不過因為它是底部的面, 所以畫的位置是在立方體中心下面一個單位. 注意 Y 值都是 -1. 如果我們在立方體下, 看到底部四邊形時, 你會注意到右上角的點會比較靠近觀察者, 而不是遠離觀察者的. 我們就會先畫較靠近觀察者的點, 再畫較靠近觀察者左邊的點, 然後才畫下面兩個深入畫面的點.

如果你真的不在乎多邊形點畫的順序 (是不是順時針), 那你只要複製上面多邊形的程式碼, 再把其中 Y 軸的值改為 -1, 那就可以了, 不過忽略四邊形點的順序, 在你要加入一些像貼圖的效果時, 會導致奇怪的結果.
 
     
		glColor3f(1.0f,0.5f,0.0f);			// Set The Color To Orange
		glVertex3f( 1.0f,-1.0f, 1.0f);			// Top Right Of The Quad (Bottom)
		glVertex3f(-1.0f,-1.0f, 1.0f);			// Top Left Of The Quad (Bottom)
		glVertex3f(-1.0f,-1.0f,-1.0f);			// Bottom Left Of The Quad (Bottom)
		glVertex3f( 1.0f,-1.0f,-1.0f);			// Bottom Right Of The Quad (Bottom)
     
  我們將開始畫立方體的前面四邊形. 我們移往畫面一個單位, 離中心一個單位的位置來畫前方的面. 注意到 Z 軸的值都是 1. 在金字塔中, Z 軸的值不會都是 1, 上面的點的 Z 值是 0. 如果你試著把下列程式碼 Z 軸的值改為 0, 你會注意到該角落會傾斜出畫面. 這不是我們現在要做的事 :)  
     
		glColor3f(1.0f,0.0f,0.0f);			// Set The Color To Red
		glVertex3f( 1.0f, 1.0f, 1.0f);			// Top Right Of The Quad (Front)
		glVertex3f(-1.0f, 1.0f, 1.0f);			// Top Left Of The Quad (Front)
		glVertex3f(-1.0f,-1.0f, 1.0f);			// Bottom Left Of The Quad (Front)
		glVertex3f( 1.0f,-1.0f, 1.0f);			// Bottom Right Of The Quad (Front)
     
  背面和前面是一樣的四邊形, 不過它是較深入畫面中的位置. 注意到這時每個點的 Z 值都是 -1.  
     
		glColor3f(1.0f,1.0f,0.0f);			// Set The Color To Yellow
		glVertex3f( 1.0f,-1.0f,-1.0f);			// Bottom Left Of The Quad (Back)
		glVertex3f(-1.0f,-1.0f,-1.0f);			// Bottom Right Of The Quad (Back)
		glVertex3f(-1.0f, 1.0f,-1.0f);			// Top Right Of The Quad (Back)
		glVertex3f( 1.0f, 1.0f,-1.0f);			// Top Left Of The Quad (Back)
     
  現在只剩下兩個四邊形要畫了. 就像之前的一樣, 你會注意到每個點有一個軸的值都會是一樣的. 本例中 X 值都會是 -1, 因為我們畫在中心左邊的位置上, 那就是左邊的面了.  
     
		glColor3f(0.0f,0.0f,1.0f);			// Set The Color To Blue
		glVertex3f(-1.0f, 1.0f, 1.0f);			// Top Right Of The Quad (Left)
		glVertex3f(-1.0f, 1.0f,-1.0f);			// Top Left Of The Quad (Left)
		glVertex3f(-1.0f,-1.0f,-1.0f);			// Bottom Left Of The Quad (Left)
		glVertex3f(-1.0f,-1.0f, 1.0f);			// Bottom Right Of The Quad (Left)
     
  這是完成立方體最後一個面了. X 軸都會是 1. 依照逆時針繪製. 如果你想的話, 可以不畫這個面, 那做出來的就像一個盒子 :)

或是如果你喜歡試驗的話, 可以試著改變立方體每一個點的顏色, 那就會像金字塔一樣有混合顏色. 你可以看看一個有混色立方體的例子: 下在我的網頁的 Evil 第一個 GL 展示範例. 執行它並按下 TAB 鍵. 你會看到一個漂亮彩色的立方體, 顏色流過每個面.
 
     
		glColor3f(1.0f,0.0f,1.0f);			// Set The Color To Violet
		glVertex3f( 1.0f, 1.0f,-1.0f);			// Top Right Of The Quad (Right)
		glVertex3f( 1.0f, 1.0f, 1.0f);			// Top Left Of The Quad (Right)
		glVertex3f( 1.0f,-1.0f, 1.0f);			// Bottom Left Of The Quad (Right)
		glVertex3f( 1.0f,-1.0f,-1.0f);			// Bottom Right Of The Quad (Right)
	glEnd();						// Done Drawing The Quad

	rtri+=0.2f;						// Increase The Rotation Variable For The Triangle 
	rquad-=0.15f;						// Decrease The Rotation Variable For The Quad 
	return TRUE;						// Keep Going
}
     
  在這課程的最後, 你應該對於如何在三度空間中建立物件有更多的認識. 你可以想像 OpenGL 畫面就像是由一片一片的繪圖紙所組成, 並有許多的透明層. 幾乎像一個巨大的, 由點構成的立方體. 在立方體中一些點由左而右, 一些點由上而下, 一些點由前到後. 如果你可以想像畫面的深度, 那你在設計新的 3D 物件應該就不會有任何問題了.

如果你沒有努力的了解三度空間, 也不用失意. 一開始要掌握這是有些困難. 由學習用一個像是立方體的物件是一個好的例子. 如果你有注意到, 背面和正面其實是一樣的, 只不過背面是更深入畫面罷了. 玩玩這個程式碼, 如果你不能掌控它, 寄電子郵件給我, 我會試著回答你的問題.

Jeff Molofee (NeHe)

* 下載 Visual C++ 程式碼給本課程的.
* 下載 Visual Basic Code For This Lesson. ( Conversion by Ross Dawson )
* 下載 Delphi 程式碼給本課程的. ( Conversion by Peter De Jaegher )
* 下載 ASM 程式碼給本課程的. ( Conversion by Foolman )
* 下載 Visual Fortran 程式碼給本課程的. ( Conversion by Jean-Philippe Perois )
* 下載 Linux 程式碼給本課程的. ( Conversion by Richard Campbell )
* 下載 Irix 程式碼給本課程的. ( Conversion by Lakmal Gunasekara )
* 下載 Solaris 程式碼給本課程的. ( Conversion by Lakmal Gunasekara )
* 下載 Mac OS 程式碼給本課程的. ( Conversion by Anthony Parker )
* 下載 Power Basic 程式碼給本課程的. ( Conversion by Angus Law )
* 下載 BeOS 程式碼給本課程的. ( Conversion by Chris Herborth )
* 下載 Java 程式碼給本課程的. ( Conversion by Darren Hodges )
* 下載 MingW32 & Allegro 程式碼給本課程的. ( Conversion by Peter Puck )
* 下載 Borland C++ Builder 4.0 程式碼給本課程的. ( Conversion by Patrick Salmons )
* 下載 Python 程式碼給本課程的. ( Conversion by Tony Colston )
 
     
 
Back To NeHe Productions!
回到 OpenGL 教學索引
中文版由 Macbear 翻譯