(在學期末作的圖形學課程設計,特將學習心得整理以下)html
1,設計一個平面的時鐘;git
按照 鐘面——>中心點——>刻度——>時針——>分針——>秒針 的順序繪製。github
2,利用紋理貼圖的知識使平面時鐘變成立體的時鐘;數組
3,設置鍵盤交互;緩存
4,測試,修改,整理代碼。函數
void keyboard(unsigned char key, int x, int y) { switch (key) { case 'x': //當按下鍵盤上d時,以沿X軸旋轉爲主 xrot += 6.0f; //設置旋轉增量 glutPostRedisplay(); //重繪函數 break; case 'y': yrot += 6.0f; glutPostRedisplay(); break; case 'z': zrot += 6.0f; glutPostRedisplay(); break; default: break; } }
float Myhour(struct tm *ptr) { if (0 < ptr->tm_hour&&ptr->tm_hour < 12) { return((Pi / 2) - ((float)ptr->tm_hour + Mymin(ptr) / 60.0) / 12.0 * 2 * Pi); } else{ return((Pi / 2) - ((ptr->tm_hour - 12.0 + Mymin(ptr) / 60.0) / 12) * 2 * Pi); } } glLineWidth(5.0f); //設置線的寬度 glColor4f(1.0, 0.0, 1.0, 0.5); //洋紅色 glBegin(GL_LINES); //畫線函數 glRotatef((angle / 3600.0), 0.0, 0.0, 1.0); glVertex2f(0.0, 0.0); glVertex2f(cos(Myhour(ptr))*R*0.55, sin(Myhour(ptr))*R*0.55); glEnd();
請參照這篇文章:用OpenGL進行立方體表面紋理貼圖---不會飛的章魚oop
Github地址學習
#include "stdafx.h" #include<Windows.h> #include<GL\glut.h> #include<GL\GLAUX.H> #include<stdio.h> #include<stdlib.h> #include<math.h> #include<time.h> #pragma comment(lib, "glut32.lib") #pragma comment(lib, "glaux.lib") GLfloat xrot = 0; // X 旋轉量 GLfloat yrot = 0; // Y 旋轉量 GLfloat zrot = 0; // Z 旋轉量 GLuint texture[1]; // 存儲一個紋理---數組 const GLfloat Pi = 3.1415926536; const GLfloat R = 0.8f; const int n = 200; static GLfloat angle = 2 * Pi; //載入位圖圖象到內存 AUX_RGBImageRec *LoadBMP(CHAR *Filename) { FILE *File = NULL; // 文件句柄 if (!Filename) // 確保文件名已提供 { return NULL; // 若是沒提供,返回 NULL } File = fopen(Filename, "r"); // 嘗試打開文件 if (File) // 判斷文件是否存在 { fclose(File); // 關閉句柄 return auxDIBImageLoadA(Filename); // 載入位圖並返回指針 } return NULL; // 若是載入失敗,返回 NULL } //載入位圖並轉換成紋理 //參數:紋理指針、bmp文件名、用戶指定的紋理編號 int LoadGLTextures(GLuint *texture, char *bmp_file_name, int texture_id) { int Status = FALSE; // 狀態指示器 // 建立紋理的存儲空間 AUX_RGBImageRec *TextureImage[1]; memset(TextureImage, 0, sizeof(void *) * 1); // 將指針設爲 NULL // 載入位圖,檢查有無錯誤,若是位圖沒找到則退出 if (TextureImage[0] = LoadBMP(bmp_file_name)) { Status = TRUE; // 將 Status 設爲 TRUE //生成(generate)紋理 glGenTextures(texture_id, texture); //&texture[0]); //綁定2D紋理對象 glBindTexture(GL_TEXTURE_2D, *texture); //texture[0]); //關聯圖像數據與紋理對象 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); //圖形繪製時所使用的濾波器參數 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 線形濾波 } //釋放圖像的內存,由於已經生成紋理了,沒用了 if (TextureImage[0]) // 紋理是否存在 { if (TextureImage[0]->data) // 紋理圖像是否存在 { free(TextureImage[0]->data); // 釋放紋理圖像佔用的內存 } free(TextureImage[0]); // 釋放圖像結構 } else printf("紋理不存在"); return Status; // 返回 Status } void DrawCube(void) // 從這裏開始進行全部的繪製 { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度緩存 glLoadIdentity(); // 重置當前的模型觀察矩陣 glTranslatef(0.0f, 0.0f, -5.0f); // 移入屏幕 5 個單位 glRotatef(xrot, 1.0f, 0.0f, 0.0f); // 繞X軸旋轉 glRotatef(yrot, 0.0f, 1.0f, 0.0f); // 繞Y軸旋轉 glRotatef(zrot, 0.0f, 0.0f, 1.0f); // 繞Z軸旋轉 glColor4f(1.0, 1.0, 1.0, 1.0); glBindTexture(GL_TEXTURE_2D, texture[0]); // 選擇紋理 glBegin(GL_QUADS); // 前面 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(); glColor4f(1.0, 1.0, 0.0, 1.0); glBindTexture(GL_TEXTURE_2D, texture[1]); glBegin(GL_QUADS); 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); // 紋理和四邊形的左下 // 頂面 glEnd(); glColor4f(1.0, 1.0, 0.0, 1.0); glBegin(GL_QUADS); 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(); glColor4f(1.0, 1.0, 0.0, 1.0); glBegin(GL_QUADS); 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); // 紋理和四邊形的右下 // 右面 glEnd(); glColor4f(1.0, 1.0, 0.0, 1.0); glBegin(GL_QUADS); 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); // 紋理和四邊形的左下 // 左面 glEnd(); glColor4f(1.0, 1.0, 0.0, 1.0); glBegin(GL_QUADS); 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(); glFlush(); //glutSwapBuffers(); } float Mysecond(struct tm *ptr) { return((Pi / 2) - (((float)ptr->tm_sec) / 60) * 2 * Pi); } float Mymin(struct tm *ptr) { return((Pi / 2) - ((ptr->tm_min + (Mysecond(ptr) / 60)) / 60) * 2 * Pi); } float Myhour(struct tm *ptr) { if (0 < ptr->tm_hour&&ptr->tm_hour < 12) { return((Pi / 2) - ((float)ptr->tm_hour + Mymin(ptr) / 60.0) / 12.0 * 2 * Pi); } else{ return((Pi / 2) - ((ptr->tm_hour - 12.0 + Mymin(ptr) / 60.0) / 12) * 2 * Pi); } } void myDisplay(void) { struct tm *ptr; //獲取系統時間 time_t it; it = time(NULL); ptr = localtime(&it); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除顏色 glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); DrawCube();//鐘盤 glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPushMatrix(); glTranslatef(0, -0.0, 1.0); glColor4f(1.0, 0.0, 0.0, 0.5); //洋紅色 glBegin(GL_POLYGON); for (int i = 0; i < n; i++){ glVertex2f(R*cos(2 * Pi / n*i), R*sin(2 * Pi / n*i)); } glEnd(); //刻度 glColor4f(1.0, 1.0, 1.0, 0.5); //白色 glBegin(GL_POINTS); glPointSize(5.0f); for (int j = 0; j < 12; j++) { glVertex2f(0.75*cos(2 * Pi / 12 * j), 0.75*sin(2 * Pi / 12 * j)); } glEnd(); //錶盤上的中心點 glPointSize(5.0f); glColor4f(0.0, 0.0, 0.0, 0.2); glBegin(GL_POINTS); glVertex2f(0.0, 0.0); glEnd(); //時針 glLineWidth(5.0f); //設置線的寬度 glColor4f(1.0, 0.0, 1.0, 0.5); //洋紅色 glBegin(GL_LINES); //畫線函數 glRotatef((angle / 3600.0), 0.0, 0.0, 1.0); glVertex2f(0.0, 0.0); glVertex2f(cos(Myhour(ptr))*R*0.55, sin(Myhour(ptr))*R*0.55); glEnd(); //分針 glLineWidth(5.0f); glColor4f(0.0, 1.0, 0.0, 0.5); //綠色 glBegin(GL_LINES); glRotatef((angle / 60.0), 0.0, 0.0, 1.0); glVertex2f(0.0, 0.0); glVertex2f(cos(Mymin(ptr))*R*0.65, sin(Mymin(ptr))*R*0.65); glEnd(); //秒針 glLineWidth(3.0f); glColor4f(0.0, 0.0, 1.0, 0.5); //藍色 glBegin(GL_LINES); glRotatef(angle, 0.0, 0.0, 1.0); glVertex2f(0.0, 0.0); glVertex2f(cos(Mysecond(ptr))*R*0.85, sin(Mysecond(ptr))*R*0.85); glEnd(); glPopMatrix(); glutSwapBuffers();// glFlush(); //保證前面的OpenGL命令當即執行,而不是讓它們在緩衝區中等待 } void init(void) { glClearColor(1.0, 1.0, 1.0, 1.0); //清理顏色,爲白色,(也可認爲是背景顏色) glCullFace(GL_BACK); //背面裁剪(背面不可見) glEnable(GL_CULL_FACE); //啓用裁剪 glEnable(GL_TEXTURE_2D); LoadGLTextures(&texture[0], "clock3.bmp", 1); //載入紋理貼圖 LoadGLTextures(&texture[1], "clock3.bmp", 2); } //當窗口大小改變時,會調用這個函數 void reshape(GLsizei w, GLsizei h) { //這裏小說明一下:矩陣模式是不一樣的,他們各自有一個矩陣。投影相關 //只能用投影矩陣。 glViewport(0, 0, w, h); //設置視口 glMatrixMode(GL_PROJECTION); //設置矩陣模式爲投影變換矩陣, glLoadIdentity(); //變爲單位矩陣 gluPerspective(60, (GLfloat)w / h, 0, 1000); //設置投影矩陣 glMatrixMode(GL_MODELVIEW); //設置矩陣模式爲視圖矩陣(模型) glLoadIdentity(); //變爲單位矩陣 } //鍵盤輸入事件函數 void keyboard(unsigned char key, int x, int y) { switch (key) { case 'x': //當按下鍵盤上d時,以沿X軸旋轉爲主 xrot += 6.0f; //設置旋轉增量 glutPostRedisplay(); //重繪函數 break; case 'y': yrot += 6.0f; glutPostRedisplay(); break; case 'z': zrot += 6.0f; glutPostRedisplay(); break; default: break; } } void myIdle(void) { angle -= ((2 * Pi) / 60); Sleep(1000); if (angle < 0.0f){ angle = 2 * Pi; } myDisplay(); } int main(int argc, char *argv[]) { glutInit(&argc, argv); //對GLUT進行初始化 // glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); //設置顯示方式 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);//設置雙緩存 //GLUT_RGB表示使用RGB顏色,GLUT_SINGLE表示使用單緩衝 glutInitWindowPosition(200, 200); //設置窗口在屏幕中的位置 glutInitWindowSize(500, 500); //設置窗口的大小 glutCreateWindow("OpenGL時鐘"); //設置窗口的標題 init(); //初始化資源,這裏必定要在建立窗口之後,否則會無效。 LoadGLTextures(&texture[0], "clock3.bmp", 1); LoadGLTextures(&texture[1], "clock3.bmp", 2); glutDisplayFunc(&myDisplay); //調用畫圖函數 glutIdleFunc(&myIdle); glutReshapeFunc(reshape); //繪製圖形時的回調 glutKeyboardFunc(keyboard); glutMainLoop(); //進行一個消息循環。顯示窗口,並等待窗口關閉後纔會返回 return 0; }
平面效果:測試
動態效果:ui
這次設計主要用了紋理貼圖和二維繪圖的知識。
我還記得最開始設計時鐘時,背景圖是黑色的,並且圖片也是隨便貼了一張上去,給指導老師看過了後,他評價道:「你可否讓我看起來你像是作了個時鐘?好比把背景顏色調一調,紋理換一換。」
我恍然大悟。是啊!作課程設計原本也是一件藝術品,要用心設計,才能讓有興趣的人願意爲此駐足欣賞。