主頁 >  其他 > opengl簡單入門實體

opengl簡單入門實體

2020-09-11 09:33:00 其他

  • 實作任務目標:
    • 使用紋理貼圖,增強可視效果
    • 應用坐標變換,實作場景中不同物體重建
    • 采用雙緩沖技術,實作場景實時繪制
    • 具有一定的滑鼠、鍵盤互動功能
  • 先放效果

滑鼠的互動功能有:右鍵暫停轉動,左鍵繼續轉動,滾輪向前放大,向后縮小

  • IDE:opengl實作需要庫函式,用的編譯環境是visual studio,附上一個很好的教程【1】:在vs2017下配置opengl,(vs2019也可以用)
  • 一個很好的入門教程【2】:OpenGL入門教程(精),講得很仔細,通俗易懂,前幾課用到的庫都沒有超過glut的范圍,
  • 事實上,對于opengl的實作主要是對于各種庫函式的呼叫,所以對于各種庫函式的認知很重要,這里也給出一個很好的教程【3】:OpenGL庫函式匯總,
  • ok,在看了上面的教程以后肯定對于opengl有了一定認識,尤其是第二個教程中講解得非常仔細,所以本文接下來的內容是建立在對那個教程的學習基礎之上,對一些我在實踐中遇到的問題作出補充,
  • 下面就進入正文,
  • 所包含的頭檔案目錄
1 #include <GL/glut.h>  
2 #include <stdlib.h>
3 #include <stdio.h>
  • 最基本的功能是當然是創建自己的圖形并顯示出來,如上圖我創建的是日地月系統,需要的函式為display()和main(),
  • 這其中很重要的一個知識點就是影像的視圖變換/模型變換、投影變換和視口變換,有關這塊的內容個人覺得教程【2】中講得不夠清楚,可以參考一些別的教程,比如:OpenGL(六) gluLookAt和gluPerspective函式決議;Opengl---gluLookAt函式詳解,
  • 這里要介紹一下opengl中的坐標軸,x軸水平向右為正,y軸豎直向上為正,z軸垂直螢屏向外為正,符合右手定則,

 

  • 2020/5/15 13:06:37 對于影像的各種變換做一個小的補充
  • 視圖變換即設定/改變觀察點的位置,可以這么理解,相當于選擇一個位置和方向設定一臺照相機,針對glLookAt()函式而言,它一共有九個引數,3對坐標值,第一對三維坐標是觀察點(照相機)在世界坐標中的位置,第二對三維坐標是被觀察點(物體)的位置,從第一對坐標到第二對坐標的向量其實就指定了照相機的方向,比如說人站在臺階上,這是人在世界坐標的位置,然后人可以朝天空看,也可以朝地上看,可以朝北方看,也可以朝南方看,這個方向就是由兩對坐標所造成的向量來決定的,第三對坐標是人頭部的正向,可以指定人站著看,也可以倒立著看,類似于這樣,
  • 模型變換則是改變物體本身的位置與方向,用到的函式有glTranslate,glRotate,glScale,這些都是對物體的坐標做變換的,相當于乘以一個變換矩陣,那么這里面有兩個需要注意的點,
    •  1 變換的順序是逆向的,也就是說,如果我們寫的順序是先平移再旋轉,那么實際得到的結果應該是先旋轉再平移,所以我們可以用堆疊來實作,對于堆疊的概念不多作解釋了,如果不清楚可以去查資料結構,堆疊用到的函式是glPushMatrix()和glPopMatrix(),用法呢其實就是先宣告push,然后按照想要的順序寫好矩陣函式,最后Pop一下,就能得到想要的結果,
    •    2 比如連續使用偏移函式,則第二個偏移的結果其實是在第一次作偏移的基礎上再做偏移的,那么如果我不想這樣算怎么辦呢?清空矩陣,用到的函式就是glLoadIdentity(),它的作用是把當前矩陣設定為單位矩陣,一般在開始做變換前都是需要呼叫一次這個函式的,
  • 那么事實上,在OpenGL中,因為視圖變換和模型變換的效果是類似的,所以這兩個變換放在一個模式里面,在進行這兩種變換前,需要宣告glMatrixMode(GL_MODEVIEW),看到這個'Matrix'是不是很眼熟呢?沒錯,上面講堆疊函式的時候用到了,相信你們也會有個疑問,如果直接呼叫堆疊函式,這個堆疊是在哪里的呢?這個堆疊段不需要自己宣告了,但它其實是屬于這個模式的堆疊段,因為在接下來要將的投影變換的模式下也有自己的堆疊段,所以我也是從這個角度理解為什么要分為這兩個模式的原因,
  • 投影變換事實上時指定了一個可視空間,相當于你在外部架好了照相機,但你仍然可以在照相機的鏡頭里設定要不要放大看到的景象,在教程【2】里有有關于這個的圖,所以首先我們要宣告模式glMatrixMode(GL_PROJECTION),并單位化矩陣glLoadIdentity(),
    • 在這個模式里有透視投影和正投影(我們做3D一般用的都是透視投影),正投影的函式有glOrtho()和gluOrtho2D(),透視投影的函式有glFrustum()和gluPerspective(),我們最常用的當然就是gluPerspective()啦,
    • gluPerspective()中的第一個引數是角度,它相當于人的眼皮要睜開多大,也就是2*仰角(仰角=俯角=1/2這個角度),第二個引數是比例,應該是跟顯示的螢屏的寬高比例有關(但是這點我不是很確定,只是暫時這么理解,如果有更好的解釋,歡迎在評論區提出),第三、四個引數則是表示截取的范圍,相當于兩堵墻,兩墻之間的東西能看,墻外的都忽略,這就是透視的意義,
  • 那么最后就是視口變換,用到的函式是glViewport(),這個就不多做介紹了,

 

 1 void display(void)
 2 {
 3     glEnable(GL_DEPTH_TEST);  //3、5行代碼中跟DEPTH有關的函式是為了在同一個視窗內創建多個影像而不會被后創建的影像覆寫,
 4     glClearColor(0, 0, 0, 1);  //設定“空”色,之前看到一個很好的解釋,白紙是白色的,所以白紙上的“空”色為白色,那么信封上的“空”色就是信封的顏色,
 5     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //COLOR的那個引數是清除顏色快取,設為“空”色
 6 
 7     glMatrixMode(GL_PROJECTION);  //投影變換
 8     glLoadIdentity();
 9     gluPerspective(60.0, 1, 1.0, 100.0);
10 
11     glMatrixMode(GL_MODELVIEW);   //視圖變換/模型變換
12     glLoadIdentity();  //加載單位矩陣  
13     gluLookAt(0.0, 0.0, 60.0, 0, 0, 0, 0.0, 1.0, 0);
15    //太陽
16     glColor3f(1.0, 0, 0);
17     glutSolidSphere(6, 20, 20);
18   //地球
19     glColor3f(0.0, 0, 1.0);
20     glTranslatef(-20.0, 0, 0); //偏移矩陣
21     glutSolidSphere(3, 20, 20);
22   //月球
23     glColor3f(1.0, 1.0, 0);
24     glTranslatef(-6.0, 0, 0); //這里的偏移量是在上面已經偏移的基礎上再進行偏移
25     glutSolidSphere(1, 20, 20);
26 
27     glutSwapBuffers(); //雙緩沖函式用到,相關內容看上面的教程【2】里
28 }
  •  main()中的函式就不具體解釋了,應該都懂
 1 int main(int argc, char** argv)
 2 {
 3     glutInit(&argc, argv);
 4     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
 5     glutInitWindowSize(500, 500);
 6     glutInitWindowPosition(100, 100);
 7     glutCreateWindow("name");
 8     glutDisplayFunc(&display);
 9     glutMainLoop();
10     return 0;
11 }
  • 現在在現有程式的基礎上加入影片需要4步
  • 1 加入全域變數
1 static GLfloat angle = 0.0f; 
  • 2 在display()里面加入旋轉的函式,由于效果是讓整個畫面都轉,這句話我選擇加在gluLookAt()后面,需要加入的陳述句已標紅,
 1 void display(void)
 2 {
 3     …… ……
 4     glMatrixMode(GL_MODELVIEW);
 5     glLoadIdentity();  //加載單位矩陣  
 6     gluLookAt(place_x, 0.0, place_z, 0, 0, 0, 0.0, 1.0, 0);
 7     glRotatef(angle, 0.0f, 1.0f, 0.0f); //旋轉,改變的是x軸分量
 8 
 9     glColor3f(1.0, 0, 0);
10     …… ……
11 }
  • 3 撰寫myIdle()函式
1 void myIdle(void)
2 {
3     angle += 1.8f;
4     if (angle >= 360.0f)
5         angle = 0.0f;
6     display();
7 }
  • 4 在主函式加入glutIdleFunc(&myIdle);可以加在剛剛的display陳述句下面,
1 int main(int argc, char** argv)
2 {
3     …… ……
4     glutDisplayFunc(&display);
5     glutIdleFunc(&myIdle);
6         …… ……
7     glutMainLoop();
8     return 0;
9 }
  • ok,接下來就要為我們的程式加上紋理了,首先在網上找了兩張星空的網圖,而且,為了方便起見,我把它們的格式改成了24位色的bmp圖片,尺寸為258*258,
  • 至于怎么改格式:1 24位色可以對圖片另存為時在下拉選單里選擇,2 修改尺寸可以用win自帶的圖片編輯器,
  • 我的兩張照片分別命名為“wall.bmp”,"ground.bmp",放在源程式的同一個子目錄里面
  • 有關紋理貼圖的詳細內容繼續參考教程【2】,這里附上我寫的程式和說明,
  • 一共分為3步,
  • 1 搭建矩形框架【對我的程式來說相當于有一個支架,然后把按照點對點的方式紋理圖貼上去】
  • 在這一步中先只寫上矩形各個點的坐標,為后面建立矩形做準備,

 1 //全域變數
 2 static const GLfloat vertex_list[][3] = {
 3     - 15.0f, -20.0f, -10.0f,  //事實上6、7兩個點是用不到的,作為完整性就一起寫了,貼圖只在背面和底面貼了圖,為了更好的演示效果,
 4     40.0f, -20.0f, -10.0f,
 5     40.0f,  20.0f, -10.0f,
 6     -15.0f,  20.0f, -10.0f,
 7     -15.0f, -20.0f,  10.0f,
 8     40.0f, -20.0f,  10.0f,
 9     -15.0f,  20.0f,  10.0f,
10     40.0f,  20.0f,  10.0f,
11  };
  • 2 將紋理圖讀入,寫了一個讀檔案的函式,還是參考之前的教程【2】,不多作解釋了,以及一個參考教程:OpenGL(十二) 紋理映射(貼圖)
  1 //全域變數
  2 #define BMP_Header_Length 54 
  3 //函式
  4 // 函式power_of_two用于判斷一個整數是不是2的整數次冪
  5 int power_of_two(int n)
  6 {
  7     if (n <= 0)
  8         return 0;
  9     return (n & (n - 1)) == 0;
 10 }
 11 /* 函式load_texture
 12 * 讀取一個BMP檔案作為紋理
 13 * 如果失敗,回傳0,如果成功,回傳紋理編號
 14 */
 15 GLuint load_texture(const char* file_name)
 16 {
 17     GLint width, height, total_bytes;
 18     GLubyte* pixels = 0;
 19     GLuint last_texture_ID = 0, texture_ID = 0;
 20 
 21     // 打開檔案,如果失敗,回傳
 22     FILE* pFile;
 23     errno_t err;
 24     err = fopen_s(&pFile, file_name, "rb");  //在vs中使用fopen_s()函式的示例,
 25     if (!pFile) exit(0);
 26 
 27     // 讀取檔案中圖象的寬度和高度
 28     fseek(pFile, 0x0012, SEEK_SET);
 29     fread(&width, sizeof(width), 1, pFile);
 30     fread(&height, sizeof(height), 1, pFile);
 31     fseek(pFile, BMP_Header_Length, SEEK_SET);
 32 
 33     // 計算每行像素所占位元組數,并根據此資料計算總像素位元組數
 34     {
 35         GLint line_bytes = width * 3;
 36         while (line_bytes % 4 != 0)
 37             ++line_bytes;
 38         total_bytes = line_bytes * height;
 39     }
 40 
 41     // 根據總像素位元組數分配記憶體
 42     pixels = (GLubyte*)malloc(total_bytes);
 43     if (pixels == 0)
 44     {
 45         fclose(pFile);
 46         return 0;
 47     }
 48 
 49     // 讀取像素資料
 50     if (fread(pixels, total_bytes, 1, pFile) <= 0)
 51     {
 52         free(pixels);
 53         fclose(pFile);
 54         return 0;
 55     }
 56 
 57     // 對就舊版本的兼容,如果圖象的寬度和高度不是的整數次方,則需要進行縮放
 58     // 若影像寬高超過了OpenGL規定的最大值,也縮放
 59     {
 60         GLint max;
 61         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
 62         if (!power_of_two(width)
 63             || !power_of_two(height)
 64             || width > max
 65             || height > max)
 66         {
 67             const GLint new_width = 256;
 68             const GLint new_height = 256; // 規定縮放后新的大小為邊長的正方形
 69             GLint new_line_bytes, new_total_bytes;
 70             GLubyte* new_pixels = 0;
 71 
 72             // 計算每行需要的位元組數和總位元組數
 73             new_line_bytes = new_width * 3;
 74             while (new_line_bytes % 4 != 0)
 75                 ++new_line_bytes;
 76             new_total_bytes = new_line_bytes * new_height;
 77 
 78             // 分配記憶體
 79             new_pixels = (GLubyte*)malloc(new_total_bytes);
 80             if (new_pixels == 0)
 81             {
 82                 free(pixels);
 83                 fclose(pFile);
 84                 return 0;
 85             }
 86 
 87             // 進行像素縮放
 88             gluScaleImage(GL_RGB,
 89                 width, height, GL_UNSIGNED_BYTE, pixels,
 90                 new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);
 91 
 92             // 釋放原來的像素資料,把pixels指向新的像素資料,并重新設定width和height
 93             free(pixels);
 94             pixels = new_pixels;
 95             width = new_width;
 96             height = new_height;
 97         }
 98     }
 99 
100     // 分配一個新的紋理編號
101     glGenTextures(1, &texture_ID);
102     if (texture_ID == 0)
103     {
104         free(pixels);
105         fclose(pFile);
106         return 0;
107     }
108 
109     // 系結新的紋理,載入紋理并設定紋理引數
110     // 在系結前,先獲得原來系結的紋理編號,以便在最后進行恢復
111     GLint lastTextureID = last_texture_ID;
112     glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTextureID);
113     glBindTexture(GL_TEXTURE_2D, texture_ID);
114     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
115     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
116     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
117     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
118     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
119     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
120         GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
121     glBindTexture(GL_TEXTURE_2D, lastTextureID);  //恢復之前的紋理系結
122     free(pixels);
123     return texture_ID;
124 }
  • 3 在display()中打開狀態機->讀取紋理圖片->搭起矩形框架->貼圖->關閉狀態機,
  • 這里踩過的坑就是關于狀態機的開閉問題,如果沒有關閉狀態機,顯示的影像中之前畫的幾個球都是全黑的,這是因為紋理貼圖會干擾別的顏色,
  • 其中用到的glTexCoord2f()函式可以參考百度的這個示例,
 1 //全域變數
 2 GLuint texGround;
 3 GLuint texWall;
 4 //函式補充
 5 void display(void)
 6 {
 7     …… ……//之前內容的后面加入一下內容
 8     glEnable(GL_TEXTURE_2D); //開啟狀態機
 9     texGround = load_texture("ground.bmp");
10     texWall = load_texture("wall.bmp");
11     
12     //繪制底面
13     glBindTexture(GL_TEXTURE_2D, texGround);
14     glBegin(GL_QUADS);
15     glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertex_list[4]); //點對點
16     glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertex_list[5]);
17     glTexCoord2f(1.0f, 1.0f); glVertex3fv(vertex_list[1]);
18     glTexCoord2f(0.0f, 1.0f); glVertex3fv(vertex_list[0]);
19     glEnd();
20     //繪制立面
21     glBindTexture(GL_TEXTURE_2D, texWall);
22     glBegin(GL_QUADS);
23     glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertex_list[0]);
24     glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertex_list[1]);
25     glTexCoord2f(1.0f, 1.0f); glVertex3fv(vertex_list[2]);
26     glTexCoord2f(0.0f, 1.0f); glVertex3fv(vertex_list[3]);
27     glEnd();
28     glDisable(GL_TEXTURE_2D);//關閉狀態機
29     glutSwapBuffers();
30 }
  • ok,那么到這里我們已經完成了紋理貼圖、雙緩沖繪制和場景重建的任務啦,接下來還有滑鼠互動的任務,那么在這里先插入一個新的函式講解:reshape(),
  • 關于reshape()的原理呢可以去查查資料,我說說我的理解吧,簡單來說呢就是在你顯示視窗時,如果你拉動邊框,視窗內的影像不會隨著你拉動而改變,
  • 附上一個簡單的圖片示例,

  可以看到在右邊的圖中,我拉動了視窗的邊框,則影像的形狀也改變了,

  • reshape()就能在表單大小被改變時,視窗大小不變,影像比例也不變,
  • 那么同樣的,完成這個功能需要2步,
  • 1 寫一個reshape()函式
 1 void reshape(int w, int h)
 2 {
 3     glViewport(0, 0, 500, 500);
 4     glMatrixMode(GL_PROJECTION);
 5     glLoadIdentity();
 6     gluPerspective(60.0, 1, 1, 100.0);
 7     glMatrixMode(GL_MODELVIEW);
 8     glLoadIdentity();
 9     gluLookAt(0, 0.0, 60.0, 0, 0, 0, 0.0, 1.0, 0);
10 }
  • 2 在main函式中加入一句
1 int main(int argc, char** argv)
2 {
3     …… ……
4     glutDisplayFunc(&display);
5     glutReshapeFunc(&reshape);
6     glutIdleFunc(&myIdle);
7     …… ……
8 }
  • ok,最后的最后,要完成滑鼠的互動了,
  • 我所設定的滑鼠的功能包括:右鍵暫停、左鍵繼續;滾輪向上放大,滾輪向下縮小,
  • 前兩個改變的是轉過的角度angle,后兩個則跟我們所建立的視圖模型,也就是之前用過glLookAt()函式的引數有關,
  • 對于滑鼠互動用到的函式及參量是void myMouse(int button, int state, int x, int y);關于這個更多的資訊可以自行查找,
  • 那么同樣的,完成這個需要2 / 3步,但是我分為兩個部分來講,首先是對于右鍵暫停和左鍵繼續的部分,
  • 1 之前的顯示函式里已經有了一個angle變數用來控制角度,所以我們要做的就是停掉這個angle變數的自增,所以我們要停用myIdle函式,
 1 void myMouse(int button, int state, int x, int y)
 2 {
 3     if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
 4     {
 5         glutIdleFunc(&myIdle);
 6     }
 7     if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
 8     {
 9         glutIdleFunc(NULL);
10     }
11 }
  • 2 在主函式中加入陳述句,
1 int main(int argc, char** argv)
2 {
3     …… ……
4     glutCreateWindow("name");
5     glutMouseFunc(&myMouse);
6     glutDisplayFunc(&display);
7     …… ……
8 }
  • 對于縮放.
  • 1 因為要涉及到之前顯示函式display()中的glLookAt()的改變,所以我們將其中的值設為全域變數,
 1 //全域變數
 2 static float place_z = 60.0f;
 3 static float place_x = 0.0f;
 4 //修改函式引數
 5 void display(void)
 6 {
 7     …… …… 
 8     gluLookAt(place_x, 0.0, place_z, 0, 0, 0, 0.0, 1.0, 0);
 9     glRotatef(angle, 0.0f, 1.0f, 0.0f); //旋轉
10         …… ……
11 }
  • 2 在之前的滑鼠的函式中加入對滾輪的控制陳述句
 1 //全域變數
 2 #define  GLUT_WHEEL_UP 3 
 3 #define  GLUT_WHEEL_DOWN 4
 4 //函式中
 5 void myMouse(int button, int state, int x, int y)
 6 {
 7     …… ……
 8     if (state == GLUT_UP && button == GLUT_WHEEL_UP)
 9     {
10         glutReshapeFunc(NULL);
11         place_z -= 5.0;
12         display();        
13     }
14     if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
15     {
16         glutReshapeFunc(NULL);
17         place_z += 5.0;
18         display();
19     }
20 }
  • 這樣就ok啦,到這里就完成了一開始提出四個目標以及一個reshape()函式,效果就如最開始的gif影片一樣,
  • 這里還需要提到的一點是,影片播放的速度在不同的cpu里是不一樣的,如果太快或太慢可以通過myIdle函式的angle自增的大小來控制,
  • 為了避免混亂,最后附上完整的源代碼,
  1 #include <GL/glut.h>  
  2 #include <stdlib.h>
  3 #include <stdio.h>
  4 
  5 static const GLfloat vertex_list[][3] = {
  6     - 15.0f, -20.0f, -10.0f,
  7     40.0f, -20.0f, -10.0f,
  8     40.0f,  20.0f, -10.0f,
  9     -15.0f,  20.0f, -10.0f,
 10     -15.0f, -20.0f,  10.0f,
 11     40.0f, -20.0f,  10.0f,
 12     -15.0f,  20.0f,  10.0f,
 13     40.0f,  20.0f,  10.0f,
 14  };
 15 GLuint texGround;
 16 GLuint texWall;
 17 
 18 #define BMP_Header_Length 54  
 19 static GLfloat angle = 0.0f;   
 20 static float place_z = 60.0f;
 21 static float place_x = 0.0f;
 22 #define  GLUT_WHEEL_UP 3 
 23 #define  GLUT_WHEEL_DOWN 4
 24 
 25 // 函式power_of_two用于判斷一個整數是不是2的整數次冪
 26 int power_of_two(int n)
 27 {
 28     if (n <= 0)
 29         return 0;
 30     return (n & (n - 1)) == 0;
 31 }
 32 
 33 /* 函式load_texture
 34 * 讀取一個BMP檔案作為紋理
 35 * 如果失敗,回傳0,如果成功,回傳紋理編號
 36 */
 37 GLuint load_texture(const char* file_name)
 38 {
 39     GLint width, height, total_bytes;
 40     GLubyte* pixels = 0;
 41     GLuint last_texture_ID = 0, texture_ID = 0;
 42 
 43     // 打開檔案,如果失敗,回傳
 44     FILE* pFile;
 45     errno_t err;
 46     err = fopen_s(&pFile, file_name, "rb");
 47     if (!pFile) exit(0);
 48 
 49     // 讀取檔案中圖象的寬度和高度
 50     fseek(pFile, 0x0012, SEEK_SET);
 51     fread(&width, sizeof(width), 1, pFile);
 52     fread(&height, sizeof(height), 1, pFile);
 53     fseek(pFile, BMP_Header_Length, SEEK_SET);
 54 
 55     // 計算每行像素所占位元組數,并根據此資料計算總像素位元組數
 56     {
 57         GLint line_bytes = width * 3;
 58         while (line_bytes % 4 != 0)
 59             ++line_bytes;
 60         total_bytes = line_bytes * height;
 61     }
 62 
 63     // 根據總像素位元組數分配記憶體
 64     pixels = (GLubyte*)malloc(total_bytes);
 65     if (pixels == 0)
 66     {
 67         fclose(pFile);
 68         return 0;
 69     }
 70 
 71     // 讀取像素資料
 72     if (fread(pixels, total_bytes, 1, pFile) <= 0)
 73     {
 74         free(pixels);
 75         fclose(pFile);
 76         return 0;
 77     }
 78 
 79     // 對就舊版本的兼容,如果圖象的寬度和高度不是的整數次方,則需要進行縮放
 80     // 若影像寬高超過了OpenGL規定的最大值,也縮放
 81     {
 82         GLint max;
 83         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
 84         if (!power_of_two(width)
 85             || !power_of_two(height)
 86             || width > max
 87             || height > max)
 88         {
 89             const GLint new_width = 256;
 90             const GLint new_height = 256; // 規定縮放后新的大小為邊長的正方形
 91             GLint new_line_bytes, new_total_bytes;
 92             GLubyte* new_pixels = 0;
 93 
 94             // 計算每行需要的位元組數和總位元組數
 95             new_line_bytes = new_width * 3;
 96             while (new_line_bytes % 4 != 0)
 97                 ++new_line_bytes;
 98             new_total_bytes = new_line_bytes * new_height;
 99 
100             // 分配記憶體
101             new_pixels = (GLubyte*)malloc(new_total_bytes);
102             if (new_pixels == 0)
103             {
104                 free(pixels);
105                 fclose(pFile);
106                 return 0;
107             }
108 
109             // 進行像素縮放
110             gluScaleImage(GL_RGB,
111                 width, height, GL_UNSIGNED_BYTE, pixels,
112                 new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);
113 
114             // 釋放原來的像素資料,把pixels指向新的像素資料,并重新設定width和height
115             free(pixels);
116             pixels = new_pixels;
117             width = new_width;
118             height = new_height;
119         }
120     }
121 
122     // 分配一個新的紋理編號
123     glGenTextures(1, &texture_ID);
124     if (texture_ID == 0)
125     {
126         free(pixels);
127         fclose(pFile);
128         return 0;
129     }
130 
131     // 系結新的紋理,載入紋理并設定紋理引數
132     // 在系結前,先獲得原來系結的紋理編號,以便在最后進行恢復
133     GLint lastTextureID = last_texture_ID;
134     glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTextureID);
135     glBindTexture(GL_TEXTURE_2D, texture_ID);
136     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
137     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
138     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
139     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
140     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
141     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
142         GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
143     glBindTexture(GL_TEXTURE_2D, lastTextureID);  //恢復之前的紋理系結
144     free(pixels);
145     return texture_ID;
146 }
147 void display(void)
148 {
149     glEnable(GL_DEPTH_TEST);
150     glClearColor(0, 0, 0, 1);
151     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
152 
153     glMatrixMode(GL_PROJECTION);
154     glLoadIdentity();
155     gluPerspective(60.0, 1, 1.0, 100.0);
156 
157     glMatrixMode(GL_MODELVIEW);
158     glLoadIdentity();  //加載單位矩陣  
159     gluLookAt(place_x, 0.0, place_z, 0, 0, 0, 0.0, 1.0, 0);
160     glRotatef(angle, 0.0f, 1.0f, 0.0f); //旋轉
161 
162     glColor3f(1.0, 0, 0);
163     glutSolidSphere(6, 20, 20);
164 
165     glColor3f(0.0, 0, 1.0);
166     glTranslatef(-20.0, 0, 0);
167     glutSolidSphere(3, 20, 20);
168 
169     glColor3f(1.0, 1.0, 0);
170     glTranslatef(-6.0, 0, 0);
171     glutSolidSphere(1, 20, 20);
172 
173     glEnable(GL_TEXTURE_2D);
174     texGround = load_texture("ground.bmp");
175     texWall = load_texture("wall.bmp");
176     
177     //繪制底面
178     glBindTexture(GL_TEXTURE_2D, texGround);
179     glBegin(GL_QUADS);
180     glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertex_list[4]);
181     glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertex_list[5]);
182     glTexCoord2f(1.0f, 1.0f); glVertex3fv(vertex_list[1]);
183     glTexCoord2f(0.0f, 1.0f); glVertex3fv(vertex_list[0]);
184     glEnd();
185     //繪制立面
186     glBindTexture(GL_TEXTURE_2D, texWall);
187     glBegin(GL_QUADS);
188     glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertex_list[0]);
189     glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertex_list[1]);
190     glTexCoord2f(1.0f, 1.0f); glVertex3fv(vertex_list[2]);
191     glTexCoord2f(0.0f, 1.0f); glVertex3fv(vertex_list[3]);
192     glEnd();
193     glDisable(GL_TEXTURE_2D);
194     glutSwapBuffers();
195 }
196 void myIdle(void)
197 {
198     angle += 1.8f;
199     if (angle >= 360.0f)
200         angle = 0.0f;
201     display();
202 }
203 void myMouse(int button, int state, int x, int y)
204 {
205     if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
206     {
207         glutIdleFunc(&myIdle);
208     }
209     if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
210     {
211         glutIdleFunc(NULL);
212     }
213     if (state == GLUT_UP && button == GLUT_WHEEL_UP)
214     {
215         glutReshapeFunc(NULL);
216         place_z -= 5.0;
217         display();        
218     }
219     if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
220     {
221         glutReshapeFunc(NULL);
222         place_z += 5.0;
223         display();
224     }
225 }
226 
227 void reshape(int w, int h)
228 {
229     glViewport(0, 0, 500, 500);
230     glMatrixMode(GL_PROJECTION);
231     glLoadIdentity();
232     gluPerspective(60.0, 1, 1, 100.0);
233     glMatrixMode(GL_MODELVIEW);
234     glLoadIdentity();
235     gluLookAt(0, 0.0, 60.0, 0, 0, 0, 0.0, 1.0, 0);
236 }
237 int main(int argc, char** argv)
238 {
239     glutInit(&argc, argv);
240     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
241     glutInitWindowSize(500, 500);
242     glutInitWindowPosition(100, 100);
243     glutCreateWindow("name");
244     glutMouseFunc(&myMouse);
245     glutDisplayFunc(&display);
246     glutReshapeFunc(&reshape);
247     glutIdleFunc(&myIdle);
248     glutMainLoop();
249     return 0;
250 }

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/5191.html

標籤:其他

上一篇:openCV從入門到放棄

下一篇:高通濾波法、微分算子法、神經網路方法實作影像邊緣檢測

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more