實驗3 OpenGL幾何變換


1.實驗目的:

理解掌握一個OpenGL程序平移、旋轉、縮放變換的方法。

2.實驗內容:

(1)閱讀實驗原理,運行示范實驗代碼,掌握OpenGL程序平移、旋轉、縮放變換的方法;

(2)根據示范代碼,嘗試完成實驗作業;

3.實驗原理:

(1)OpenGL下的幾何變換

在OpenGL的核心庫中,每一種幾何變換都有一個獨立的函數,所有變換都在三維空間中定義。

平移矩陣構造函數為glTranslate<f,d>(tx, ty, tz),作用是把當前矩陣和一個表示移動物體的矩陣相乘。tx, ty,tz指定這個移動物體的矩陣,它們可以是任意的實數值,后綴為f(單精度浮點float)或d(雙精度浮點double),對於二維應用來說,tz=0.0。

旋轉矩陣構造函數為glRotate<f,d>(theta, vx, vy, vz),作用是把當前矩陣和一個表示旋轉物體的矩陣相乘。theta, vx, vy, vz指定這個旋轉物體的矩陣,物體將繞着(0,0,0)到(x,y,z)的直線以逆時針旋轉,參數theta表示旋轉的角度。向量v=(vx, vy,vz)的分量可以是任意的實數值,該向量用於定義通過坐標原點的旋轉軸的方向,后綴為f(單精度浮點float)或d(雙精度浮點double),對於二維旋轉來說,vx=0.0,vy=0.0,vz=1.0。

縮放矩陣構造函數為glScale<f,d>(sx, sy, sz),作用是把當前矩陣和一個表示縮放物體的矩陣相乘。sx, sy,sz指定這個縮放物體的矩陣,分別表示在x,y,z方向上的縮放比例,它們可以是任意的實數值,當縮放參數為負值時,該函數為反射矩陣,縮放相對於原點進行,后綴為f(單精度浮點float)或d(雙精度浮點double)。

注意這里都是說“把當前矩陣和一個表示移動<旋轉, 縮放>物體的矩陣相乘”,而不是直接說“這個函數就是旋轉”或者“這個函數就是移動”,這是有原因的,馬上就會講到。

假設當前矩陣為單位矩陣,然后先乘以一個表示旋轉的矩陣R,再乘以一個表示移動的矩陣T,最后得到的矩陣再乘上每一個頂點的坐標矩陣v。那么,經過變換得到的頂點坐標就是((RT)v)。由於矩陣乘法滿足結合率,((RT)v) = R(Tv)),換句話說,實際上是先進行移動,然后進行旋轉。即:實際變換的順序與代碼中寫的順序是相反的。由於“先移動后旋轉”和“先旋轉后移動”得到的結果很可能不同,初學的時候需要特別注意這一點。

(2)OpenGL下的各種變換簡介

我們生活在一個三維的世界——如果要觀察一個物體,我們可以:

1、從不同的位置去觀察它(人運動,選定某個位置去看)。(視圖變換)

2、移動或者旋轉它,當然了,如果它只是計算機里面的物體,我們還可以放大或縮小它(物體運動,讓人看它的不同部分)。(模型變換)

3、如果把物體畫下來,我們可以選擇:是否需要一種“近大遠小”的透視效果。另外,我們可能只希望看到物體的一部分,而不是全部(指定看的范圍)。(投影變換)

4、我們可能希望把整個看到的圖形畫下來,但它只占據紙張的一部分,而不是全部(指定在顯示器窗口的那個位置顯示)。(視口變換)

這些,都可以在OpenGL中實現。

從“相對移動”的觀點來看,改變觀察點的位置與方向和改變物體本身的位置與方向具有等效性。在OpenGL中,實現這兩種功能甚至使用的是同樣的函數。

由於模型和視圖的變換都通過矩陣運算來實現,在進行變換前,應先設置當前操作的矩陣為“模型視圖矩陣”。設置的方法是以GL_MODELVIEW為參數調用glMatrixMode函數,像這樣:

glMatrixMode(GL_MODELVIEW);

該語句指定一個4×4的建模矩陣作為當前矩陣。

通常,我們需要在進行變換前把當前矩陣設置為單位矩陣。把當前矩陣設置為單位矩陣的函數為:

glLoadIdentity();

我們在進行矩陣操作時,有可能需要先保存某個矩陣,過一段時間再恢復它。當我們需要保存時,調用glPushMatrix()函數,它相當於把當前矩陣壓入堆棧。當需要恢復最近一次的保存時,調用glPopMatrix()函數,它相當於從堆棧棧頂彈出一個矩陣為當前矩陣。OpenGL規定堆棧的容量至少可以容納32個矩陣,某些OpenGL實現中,堆棧的容量實際上超過了32個。因此不必過於擔心矩陣的容量問題。

通常,用這種先保存后恢復的措施,比先變換再逆變換要更方便,更快速。

注意:模型視圖矩陣和投影矩陣都有相應的堆棧。使用glMatrixMode來指定當前操作的究竟是模型視圖矩陣還是投影矩陣。

4.示范代碼:

  1 #include <GL/glut.h>
  2 
  3 void init (void)
  4 
  5 {
  6 
  7 glClearColor (1.0, 1.0, 1.0, 0.0);
  8 
  9 glMatrixMode (GL_PROJECTION);
 10 
 11 gluOrtho2D (-5.0, 5.0, -5.0, 5.0); //設置顯示的范圍是X:-5.0~5.0, Y:-5.0~5.0
 12 
 13 glMatrixMode (GL_MODELVIEW);
 14 
 15 }
 16 
 17 void drawSquare(void) //繪制中心在原點,邊長為2的正方形
 18 
 19 {
 20 
 21 glBegin (GL_POLYGON); //頂點指定需要按逆時針方向
 22 
 23 glVertex2f (-1.0f,-1.0f);//左下點
 24 
 25 glVertex2f (1.0f,-1.0f);//右下點
 26 
 27 glVertex2f (1.0f, 1.0f);//右上點
 28 
 29 glVertex2f (-1.0f,1.0f);//左上點
 30 
 31 glEnd ( );
 32 
 33 }
 34 
 35 void myDraw (void)
 36 
 37 {
 38 
 39 glClear (GL_COLOR_BUFFER_BIT); //清空
 40 
 41 glLoadIdentity(); //將當前矩陣設為單位矩陣
 42 
 43 glPushMatrix();
 44 
 45 glTranslatef(0.0f,2.0f,0.0f);
 46 
 47 glScalef(3.0,0.5,1.0);
 48 
 49 glColor3f (1.0, 0.0, 0.0);
 50 
 51 drawSquare(); //上面紅色矩形
 52 
 53 glPopMatrix();
 54 
 55 glPushMatrix();
 56 
 57 glTranslatef(-3.0,0.0,0.0);
 58 
 59 glPushMatrix();
 60 
 61 glRotatef(45.0,0.0,0.0,1.0);
 62 
 63 glColor3f (0.0, 1.0, 0.0);
 64 
 65 drawSquare(); //中間左菱形
 66 
 67 glPopMatrix();
 68 
 69 glTranslatef(3.0,0.0,0.0);
 70 
 71 glPushMatrix();
 72 
 73 glRotatef(45.0,0.0,0.0,1.0);
 74 
 75 glColor3f (0.0, 0.7, 0.0);
 76 
 77 drawSquare(); //中間中菱形
 78 
 79 glPopMatrix();
 80 
 81 glTranslatef(3.0,0.0,0.0);
 82 
 83 glPushMatrix();
 84 
 85 glRotatef(45.0,0.0,0.0,1.0);
 86 
 87 glColor3f (0.0, 0.4, 0.0);
 88 
 89 drawSquare(); //中間右菱形
 90 
 91 glPopMatrix();
 92 
 93 glPopMatrix();
 94 
 95 glTranslatef(0.0,-3.0,0.0);
 96 
 97 glScalef(4.0,1.5,1.0);
 98 
 99 glColor3f (0.0, 0.0, 1.0);
100 
101 drawSquare(); //下面藍色矩形
102 
103 glFlush ( );
104 
105 }
106 
107 void main (int argc, char** argv)
108 
109 {
110 
111 glutInit (&argc, argv);
112 
113 glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
114 
115 glutInitWindowPosition (0, 0);
116 
117 glutInitWindowSize (600, 600);
118 
119 glutCreateWindow ("幾何變換函數綜合示例");
120 
121 init();
122 
123 glutDisplayFunc (myDraw);
124 
125 glutMainLoop ( );
126 
127 }

 附上本實驗的VC++工程代碼(VC++2008)

程序運行結果:

clip_image008

5. 實驗作業:

繪制如下圖形:

clip_image010

提示:

(1)寫一個繪制菱形的函數drawDiamond(void);

void drawDiamond(void) //繪制中心在原點的菱形

{

glBegin (GL_POLYGON); //頂點指定需要按逆時針方向

glVertex2f (0.0f,-1.0f);//下點

glVertex2f (2.0f,0.0f);//右點

glVertex2f (0.0f, 1.0f);//上點

glVertex2f (-2.0f,0.0f);//左點

glEnd ( );

}

  

(2)用幾何變換繪制三個不同位置、旋轉角度、顏色的菱形。

 

附上其它變換實例,供有興趣的讀者參考:

(1)、Translate示例

#include <GL/glut.h>

void init (void)

{

glClearColor (1.0, 1.0, 1.0, 0.0);

glMatrixMode (GL_PROJECTION);

gluOrtho2D (-5.0, 5.0, -5.0, 5.0); //設置顯示的范圍是X:-5.0~5.0, Y:-5.0~5.0

glMatrixMode (GL_MODELVIEW);

}

void drawSquare(void) //繪制中心在原點,邊長為2的正方形

{

glBegin (GL_POLYGON); //頂點指定需要按逆時針方向

glVertex2f (-1.0f,-1.0f);//左下點

glVertex2f (1.0f,-1.0f);//右下點

glVertex2f (1.0f, 1.0f);//右上點

glVertex2f (-1.0f,1.0f);//左上點

glEnd ( );

}

void myDraw1 (void)

{

glClear (GL_COLOR_BUFFER_BIT); //清空

glLoadIdentity(); //將當前矩陣設為單位矩陣

glColor3f (1.0, 0.0, 0.0);

drawSquare(); //在原點處繪制邊長為2紅色正方形

glTranslatef(2.0,3.0,0.0); //向右移動2單位,向上移動3單位

glColor3f (0.0, 1.0, 0.0);

drawSquare(); //繪制邊長為2綠色正方形

glTranslatef(0.0,-3.0,0.0); //再向下移動3單位

glColor3f (0.0, 0.0, 1.0);

drawSquare(); //繪制邊長為2藍色正方形

glFlush ( );

}

void myDraw2 (void)

{

glClear (GL_COLOR_BUFFER_BIT); //清空

glLoadIdentity(); //將當前矩陣設為單位矩陣

glColor3f (1.0, 0.0, 0.0);

drawSquare(); //在原點處繪制邊長為2紅色正方形

glPushMatrix();

glTranslatef(2.0,3.0,0.0); //向右移動2單位,向上移動3單位

glColor3f (0.0, 1.0, 0.0);

drawSquare(); //繪制邊長為2綠色正方形

glPopMatrix();

glTranslatef(2.0,0.0,0.0); //再向右移動2單位

glColor3f (0.0, 0.0, 1.0);

drawSquare(); //繪制邊長為2藍色正方形

glFlush ( );

}

void main (int argc, char** argv)

{

glutInit (&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);

glutInitWindowPosition (0, 0);

glutInitWindowSize (600, 600);

glutCreateWindow ("Translate函數示例");

init();

glutDisplayFunc (myDraw1);

glutMainLoop ( );

}

  

生成圖形:

clip_image002

注意理解:myDraw1()和myDraw2()生成的圖形完全相同,為什么?

(2)、Rotate示例

#include <GL/glut.h>

void init (void)

{

glClearColor (1.0, 1.0, 1.0, 0.0);

glMatrixMode (GL_PROJECTION);

gluOrtho2D (-5.0, 5.0, -5.0, 5.0); //設置顯示的范圍是X:-5.0~5.0, Y:-5.0~5.0

glMatrixMode (GL_MODELVIEW);

}

void drawSquare(void) //繪制中心在原點,邊長為2的正方形

{

glBegin (GL_POLYGON); //頂點指定需要按逆時針方向

glVertex2f (-1.0f,-1.0f);//左下點

glVertex2f (1.0f,-1.0f);//右下點

glVertex2f (1.0f, 1.0f);//右上點

glVertex2f (-1.0f,1.0f);//左上點

glEnd ( );

}

void myDraw1 (void)

{

glClear (GL_COLOR_BUFFER_BIT); //清空

glLoadIdentity(); //將當前矩陣設為單位矩陣

glColor3f (1.0, 0.0, 0.0);

drawSquare(); //在原點處繪制邊長為2紅色正方形

glTranslatef(2.0,3.0,0.0); //向右移動2單位,向上移動3單位

glRotatef(30,0.0,0.0,1.0); //順時針旋轉30角度

glColor3f (0.0, 1.0, 0.0);

drawSquare(); //繪制邊長為2綠色正方形

glLoadIdentity(); //將當前矩陣設為單位矩陣

glTranslatef(-2.0,-3.0,0.0); //向左移動2單位,向下移動3單位

glRotatef(-30,0.0,0.0,1.0); //逆時針旋轉30角度

glColor3f (0.0, 0.0, 1.0);

drawSquare(); //繪制邊長為2藍色正方形

glFlush ( );

}

void myDraw2 (void)

{

glClear (GL_COLOR_BUFFER_BIT); //清空

glLoadIdentity(); //將當前矩陣設為單位矩陣

glColor3f (1.0, 0.0, 0.0);

drawSquare(); //在原點處繪制邊長為2紅色正方形

glPushMatrix(); //把當前矩陣壓入堆棧

glTranslatef(2.0,3.0,0.0); //向右移動2單位,向上移動3單位

glRotatef(30,0.0,0.0,1.0); //順時針旋轉30角度

glColor3f (0.0, 1.0, 0.0);

drawSquare(); //繪制邊長為2綠色正方形

glPopMatrix(); //從堆棧棧頂彈出一個矩陣為當前矩陣

glTranslatef(-2.0,-3.0,0.0); //向左移動2單位,向下移動3單位

glRotatef(-30,0.0,0.0,1.0); //逆時針旋轉30角度

glColor3f (0.0, 0.0, 1.0);

drawSquare(); //繪制邊長為2藍色正方形

glFlush ( );

}

void main (int argc, char** argv)

{

glutInit (&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);

glutInitWindowPosition (0, 0);

glutInitWindowSize (600, 600);

glutCreateWindow ("Rotate函數示例");

init();

glutDisplayFunc (myDraw1);

glutMainLoop ( );

}

  

生成圖形:

clip_image004

注意理解:myDraw1()和myDraw2()生成的圖形完全相同,為什么?

(3)、Scale示例

 

#include <GL/glut.h>

void init (void)

{

glClearColor (1.0, 1.0, 1.0, 0.0);

glMatrixMode (GL_PROJECTION);

gluOrtho2D (-5.0, 5.0, -5.0, 5.0); //設置顯示的范圍是X:-5.0~5.0, Y:-5.0~5.0

glMatrixMode (GL_MODELVIEW);

}

void drawSquare(void) //繪制中心在原點,邊長為2的正方形

{

glBegin (GL_POLYGON); //頂點指定需要按逆時針方向

glVertex2f (-1.0f,-1.0f);//左下點

glVertex2f (1.0f,-1.0f);//右下點

glVertex2f (1.0f, 1.0f);//右上點

glVertex2f (-1.0f,1.0f);//左上點

glEnd ( );

}

void myDraw1 (void)

{

glClear (GL_COLOR_BUFFER_BIT); //清空

glLoadIdentity(); //將當前矩陣設為單位矩陣

glColor3f (1.0, 0.0, 0.0);

drawSquare(); //在原點處繪制邊長為2紅色正方形

glTranslatef(2.0,3.0,0.0); //向右移動2單位,向上移動3單位

glScalef(1.0,1.5,1.0); //X和Z方向保持不變,Y方向放大為原來的1.5倍

glColor3f (0.0, 1.0, 0.0);

drawSquare(); //繪制邊長為2綠色正方形

glLoadIdentity(); //將當前矩陣設為單位矩陣

glTranslatef(-2.0,-3.0,0.0); //向左移動2單位,向下移動3單位

glScalef(0.5,1.5,1.0); //Z方向保持不變,X方向縮小為原來的0.5倍,Y方向放大為原來的1.5倍

glColor3f (0.0, 0.0, 1.0);

drawSquare(); //繪制邊長為2藍色正方形

glFlush ( );

}

void myDraw2 (void)

{

glClear (GL_COLOR_BUFFER_BIT); //清空

glLoadIdentity(); //將當前矩陣設為單位矩陣

glColor3f (1.0, 0.0, 0.0);

drawSquare(); //在原點處繪制邊長為2紅色正方形

glPushMatrix(); //把當前矩陣壓入堆棧

glTranslatef(2.0,3.0,0.0); //向右移動2單位,向上移動3單位

glScalef(1.0,1.5,1.0); //X和Z方向保持不變,Y方向放大為原來的1.5倍

glColor3f (0.0, 1.0, 0.0);

drawSquare(); //繪制邊長為2綠色正方形

glPopMatrix(); //從堆棧棧頂彈出一個矩陣為當前矩陣

glTranslatef(-2.0,-3.0,0.0); //向左移動2單位,向下移動3單位

glScalef(0.5,1.5,1.0); //Z方向保持不變,X方向縮小為原來的0.5倍,Y方向放大為原來的1.5倍

glColor3f (0.0, 0.0, 1.0);

drawSquare(); //繪制邊長為2藍色正方形

glFlush ( );

}

void main (int argc, char** argv)

{

glutInit (&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);

glutInitWindowPosition (0, 0);

glutInitWindowSize (600, 600);

glutCreateWindow ("Scale函數示例");

init();

glutDisplayFunc (myDraw1);

glutMainLoop ( );

}

  生成圖形:

clip_image006

注意理解:myDraw1()和myDraw2()生成的圖形完全相同,為什么?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM