本實(shí)例是利用矩陣對模型進(jìn)行平移、縮放、旋轉等變換,雖然實(shí)際應用中都有特定的方法,用起來(lái)很簡(jiǎn)單,但此矩陣算法是你理解opengl必須要學(xué)會(huì )的。也是模型變換的原理。
//包含所需的glut頭文件。該頭文件已經(jīng)默認包含gl.h,和glu.h。
#include <glut.h>
//還可以包含其他頭文件
#include<math.h> //數學(xué)函數的頭文件
#include <iostream>
using namespace std;
//定義頂點(diǎn)的個(gè)數
#define VERTEX_NUM 3
#define pi 3.14159265
//二維坐標系中的一個(gè)點(diǎn)的表示方法
typedef struct
{
GLfloat x;
GLfloat y;
GLfloat h;
}vertex2D;
//三角形的三個(gè)頂點(diǎn)的位置坐標
float matrixT[3][3];
vertex2D vOld[VERTEX_NUM] = {{50,50,1},{200,100,1},{150,300,1}};
vertex2D vNew[VERTEX_NUM];
//定義默認的窗口大小常量
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
//定義全局變量,隨時(shí)保存窗口被改變后,當前窗口的大小
GLsizei gWidth;
GLsizei gHeight;
//為了程序更加清晰,將在整個(gè)程序中只需要調用一次的
//用于完成初始化工作的函數在此處調用。
void init()
{
//用于清屏的顏色rgba,在0--1之間的浮點(diǎn)數
glClearColor(0.0, 0.0, 0.0, 0.0);
//指定渲染模式:Flat(整個(gè)圖元一個(gè)顏色), Smooth(光滑,插值)
glShadeModel(GL_FLAT); //默認狀態(tài)下就是光滑模式
}
//(1)當窗口的內容需要進(jìn)行重繪時(shí)將要被調用的函數。
//如:窗口剛被打開(kāi),被彈出,窗口的內容遭到破壞等。
//該函數中定義具體要繪制圖形的語(yǔ)句。
void display()
{
cout<<"窗口被重繪"<<endl;
//執行清屏工作。參數表示清除哪個(gè)緩存
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0,1,1);
//調用glBegin、glEnd函數繪制圖元
glBegin(GL_TRIANGLES); //開(kāi)始繪制---利用參數指定圖元類(lèi)型為三角形
for(int i=0; i<VERTEX_NUM; i++)
{
//glVertex2f(vNew[i].x, vNew[i].y);
glVertex2f(vOld[i].x, vOld[i].y);
}
glEnd(); //繪制結束
//強制執行opengl函數,不緩存
glFlush();
}
//創(chuàng )建用于執行平移操作的矩陣,
// ty:分別是沿x軸,沿y軸的平移量
void CreateTranslateMatrix(float tx, float ty)
{
//平移矩陣如下
//[1, 0, tx]
//[0, 1, ty]
//[0, 0, 1 ]
matrixT[0][0] = 1;
matrixT[0][1] = 0;
matrixT[0][2] = tx;
matrixT[1][0] = 0;
matrixT[1][1] = 1;
matrixT[1][2] = ty;
matrixT[2][0] = 0;
matrixT[2][1] = 0;
matrixT[2][2] = 1;
}
//等比縮放
// ty:分別是沿x軸,沿y軸的平移量
void sfjz(float tx, float ty)
{
//平移矩陣如下
//[0.8, 0, tx]
//[0, 0.8, ty]
//[0, 0, 0.8 ]
matrixT[0][0] = 0.8;
matrixT[0][1] = 0;
matrixT[0][2] = tx;
matrixT[1][0] = 0;
matrixT[1][1] = 0.8;
matrixT[1][2] = ty;
matrixT[2][0] = 0;
matrixT[2][1] = 0;
matrixT[2][2] = 0.8;
}
void xz()
{
//平移矩陣如下
//[cos(pi/10), -sin(pi/10), 0]
//[sin(pi/10), cos(pi/10), 0]
//[ 0, 0, 1]
matrixT[0][0] = cos(pi/10);
matrixT[0][1] = -sin(pi/10);
matrixT[0][2] = 0;
matrixT[1][0] = sin(pi/10);
matrixT[1][1] = cos(pi/10);
matrixT[1][2] = 0;
matrixT[2][0] = 0;
matrixT[2][1] = 0;
matrixT[2][2] = 1;
}
/**********************實(shí)現二維物體的平移操作*****************************/
void TranslateVertex(vertex2D *newPos, float mT[3][3], vertex2D *oldPos)
{
//利用矩陣乘法,將平移矩陣同原始頂點(diǎn)坐標相乘,得到新的坐標點(diǎn)。
for(int i=0; i<3; i++)
{
newPos->x = mT[0][0] * oldPos->x + mT[0][1] * oldPos->y + mT[0][2] * oldPos->h;
newPos->y = mT[1][0] * oldPos->x + mT[1][1] * oldPos->y + mT[1][2] * oldPos->h;
newPos->h = mT[2][0] * oldPos->x + mT[2][1] * oldPos->y + mT[2][2] * oldPos->h;
}
}
void sf(vertex2D *newPos, float mT[3][3], vertex2D *oldPos)
{
//利用矩陣乘法,將平移矩陣同原始頂點(diǎn)坐標相乘,得到新的坐標點(diǎn)。
for(int i=0; i<3; i++)
{
newPos->x = mT[0][0] * oldPos->x + mT[0][1] * oldPos->y + mT[0][2] * oldPos->h;
newPos->y = mT[1][0] * oldPos->x + mT[1][1] * oldPos->y + mT[1][2] * oldPos->h;
newPos->h = mT[2][0] * oldPos->x + mT[2][1] * oldPos->y + mT[2][2] * oldPos->h;
}
}
void DNP() //重繪
{
//清除背景顏色
glClear(GL_COLOR_BUFFER_BIT);
//調用glBegin、glEnd函數將平移后的圖形繪制出來(lái)
glBegin(GL_TRIANGLES); //開(kāi)始繪制---利用參數指定圖元類(lèi)型為三角形
for(int i=0; i<VERTEX_NUM; i++)
{
glVertex2f(vNew[i].x, vNew[i].y);
}
glEnd(); //繪制結束
glFlush();
}
//繪制變換過(guò)后的圖。三個(gè)頂點(diǎn)都執行平移操作
void DrawNewPos(float tx, float ty)
{
CreateTranslateMatrix(tx, ty);
//對三個(gè)頂點(diǎn),調用函數進(jìn)行平移操作。
for(int i=0; i<VERTEX_NUM; i++)
{
TranslateVertex(&(vNew[i]), matrixT, &(vOld[i]));
vOld[i]=vNew[i];
}
DNP();
}
//繪制縮放后的圖
void DrawNewPossf(float tx, float ty)
{
sfjz(tx,ty);
//對三個(gè)頂點(diǎn),調用函數進(jìn)行平移操作。
for(int i=0; i<VERTEX_NUM; i++)
{
TranslateVertex(&(vNew[i]), matrixT, &(vOld[i]));
vOld[i]=vNew[i];
}
DNP();
}
//繪制旋轉后的圖
void DrawNewPosxz()
{
xz();
//對三個(gè)頂點(diǎn),調用函數進(jìn)行平移操作。
for(int i=0; i<VERTEX_NUM; i++)
{
TranslateVertex(&(vNew[i]), matrixT, &(vOld[i]));
vOld[i]=vNew[i];
}
DNP();
}
//當屏幕第一次被創(chuàng )建,或窗口的大小改變,窗口被移動(dòng)的時(shí)候調用這個(gè)函數
void reshape(int w, int h)
{
//輸出被改變的新的窗口大小
cout<<"新的窗口大?。?<<w<<", "<<h<<endl;
//設置新的畫(huà)布大小,也就是我們看到的窗口的矩形區域大小---視口大小
//視口:是個(gè)矩形的窗口區域,圖形就是在這個(gè)區域中繪制的。
//視口是用窗口坐標來(lái)測量的。默認情況下,視口被設置為占據打開(kāi)窗口的整個(gè)像素矩形。
//我們還可以對窗口進(jìn)行劃分,在同一個(gè)窗體中顯示分隔屏幕的效果。
//參數分別為:窗口左下角,窗口的寬度和高度。
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
//設置投影矩陣---glMatrixMode:指定哪一個(gè)矩陣是當前矩陣
glMatrixMode(GL_PROJECTION); //標明接下來(lái)的函數影響投影矩陣,而不是模型變換矩陣。
//單位化,消除前面的矩陣留下的影響
glLoadIdentity();
//正投影:參數分別為左右,下上。裁剪區域為矩形。
gluOrtho2D(0.0, 600, 0.0, 400); //定義坐標系范圍--視景體
}
//當鍵盤(pán)上的某個(gè)鍵被按下的時(shí)候調用這個(gè)函數。
void keyboard(unsigned char key, int x, int y)
{
cout<<key<<"鍵被按下。"<<"鼠標位置為:"<<x<<","<<y<<endl;
float kx=5,ky=5;
//若用戶(hù)按下t鍵,對三角形進(jìn)行平移
switch(key)
{
case (unsigned char)'t':
case (unsigned char)'T':
DrawNewPos(kx,ky);
break;
//等比縮放
case (unsigned char)'m':
case (unsigned char)'M':
DrawNewPossf(kx,ky);
break;
//旋轉
case (unsigned char)'x':
case (unsigned char)'X':
DrawNewPosxz();
break;
}
}
void motion(int x, int y)
{
cout<<"鼠標被按下,并移動(dòng)。 位置為:"<<x<<", "<<y<<endl;
}
int main(int argc, char** argv)
{
//初始化GLUT,在所有g(shù)lut函數調用之前調用該函數
glutInit(&argc, argv);
//初始化顯示模式:RGBA顏色模式, 單緩存
glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE);
//初始化窗口位置
glutInitWindowPosition(0, 0);
//初始化窗口大小
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
//創(chuàng )建上述函數定義的窗口,參數為窗口標題
glutCreateWindow("才才——利用矩陣移動(dòng)、縮放、旋轉模型");
//進(jìn)行繪圖前的一些初始化工作
init();
display();
glutDisplayFunc(display); //設置窗口顯示回調函數
glutReshapeFunc(reshape); //設置窗口大小改變回調函數
glutKeyboardFunc(keyboard); //設置鍵盤(pán)回調函數
//glutMouseFunc(mouse); //設置鼠標回調函數
glutMotionFunc(motion); //設置鼠標按住移動(dòng)回調函數
//glutIdleFunc(idle); //設置空閑回調函數
//進(jìn)入事件循環(huán),等待事件和消息,直到程序退出為止
glutMainLoop();
return 0;
}
最終效果如下:
當按下T,模型平移;按下M,模型會(huì )縮放;按下X,模型會(huì )旋轉。
聯(lián)系客服