OpenGL的幾何變換3之內觀察全景圖


繼續上一篇文章的例子:OpenGL的幾何變換2之內觀察立方體

上一篇是通過繪圖方式得到的立方體,沒有貼圖,這次加上紋理貼圖。

通過紋理貼圖有兩種方案:

1、圖片分割化,即是把一張完整的全景圖片(就是支持720度全景圖片)人工的分隔成前后左右上下六張圖片(靜態),然后分別加載這六張圖片;

2、數據分割化,即是保留一張完整的全景圖片,加載圖片以后,對圖片數據進行上下左右前后進行數據切割,或者應該說進行圖片切割(動態)。

這一篇文章主要用到的技術點是紋理映射,具體不再累述,可以參考OpenGL的glTexCoord2f紋理坐標配置

 

本篇文章的案例主要是采用第一種(圖片分割化),先附上代碼:

  1 #include <stdio.h>
  2 #include <windows.h>
  3 #include <gl/glut.h>    //引用相關包
  4 #include <gl/glaux.h>
  5 
  6 GLfloat  xangle = 0.0;    //X 旋轉量
  7 GLfloat  yangle = 0.0;    //Y 旋轉量
  8 GLfloat  zangle = 0.0;    //Z 旋轉量
  9 GLuint  texturesArr[6];    //存儲6個紋理
 10 
 11 //交叉點的坐標
 12 int cx = 0;
 13 int cy = 0;
 14 
 15 //載入位圖圖象
 16 AUX_RGBImageRec *loadBMP(CHAR *Filename)
 17 {
 18     FILE *File = NULL;    //文件句柄
 19     if (!Filename)    //確保文件名已提供
 20     {
 21         return NULL;    //如果沒提供,返回 NULL
 22     }
 23 
 24     File = fopen(Filename,"r");    //嘗試打開文件
 25     if (File)    //文件存在么?
 26     {
 27         fclose(File);    //關閉句柄
 28         return auxDIBImageLoadA(Filename);    //載入位圖並返回指針
 29     }
 30     return NULL;    //如果載入失敗,返回 NULL
 31 }
 32 
 33 //載入位圖(調用上面的代碼)並轉換成紋理
 34 int loadGLTextures()
 35 {
 36     int Status = FALSE;    //狀態指示器
 37     char *imgArr[6] = {
 38         "pano/pano_f.bmp",    //前面
 39         "pano/pano_b.bmp",    //后面 
 40         "pano/pano_u.bmp",     //頂面
 41         "pano/pano_d.bmp",     //底面
 42         "pano/pano_r.bmp",     //右面
 43         "pano/pano_l.bmp"    //左面
 44     };
 45     AUX_RGBImageRec *textureImage[6];    //創建紋理的存儲空間
 46 
 47     memset(texturesArr, 0x0, sizeof(texturesArr));
 48     memset(textureImage,0,sizeof(textureImage));    //將指針設為NULL
 49 
 50     for (int i = 0; i < 6; i++) {
 51         Status = FALSE;
 52         //載入位圖,檢查有無錯誤,如果位圖沒找到則退出
 53         if (textureImage[i] = loadBMP(imgArr[i]))
 54         {
 55             Status = TRUE;    //將 Status 設為 TRUE
 56             glGenTextures(1, &texturesArr[i]);    //創建紋理
 57 
 58             //使用來自位圖數據生成 的典型紋理
 59             glBindTexture(GL_TEXTURE_2D, texturesArr[i]);
 60             //生成紋理
 61             glTexImage2D(GL_TEXTURE_2D, 0, 3, textureImage[i]->sizeX, textureImage[i]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, textureImage[i]->data);
 62 
 63             glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);    //線形濾波
 64             glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);    //線形濾波
 65         }
 66 
 67         if (textureImage[i])    //紋理是否存在
 68         {
 69             if (textureImage[i]->data)    //紋理圖像是否存在
 70             {
 71                 free(textureImage[i]->data);    //釋放紋理圖像占用的內存
 72             }
 73             free(textureImage[i]);    //釋放圖像結構
 74         }
 75         if (Status == FALSE) {
 76             break;
 77         }
 78     }
 79     return Status;    //返回 Status
 80 }
 81 
 82 //從這里開始進行所有的繪制
 83 void drawCube(void)
 84 {
 85     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    //清除屏幕和深度緩存
 86     glMatrixMode(GL_MODELVIEW);
 87     glLoadIdentity();    //重置當前的模型觀察矩陣
 88 
 89     glPushMatrix();
 90     {
 91         gluLookAt(0, 0, -5, 0, 0, 0, 0, 1, 0);
 92         glTranslatef(0.0f, 0.0f, -5.0f);    //移入屏幕 5 個單位
 93         glRotatef(xangle, 1.0f, 0.0f, 0.0f);    //繞X軸旋轉
 94         glRotatef(yangle, 0.0f, 1.0f, 0.0f);    //繞Y軸旋轉
 95         glRotatef(zangle, 0.0f, 0.0f, 1.0f);    //繞Z軸旋轉
 96 #if (0)    //顯示反面
 97         glBindTexture(GL_TEXTURE_2D, texturesArr[0]);    //選擇紋理
 98         glBegin(GL_QUADS); {
 99             //前面:逆時針
100             glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    //紋理和四邊形的左下
101             glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    //紋理和四邊形的右下
102             glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    //紋理和四邊形的右上
103             glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    //紋理和四邊形的左上
104         }glEnd();
105     
106         glBindTexture(GL_TEXTURE_2D, texturesArr[1]);    //選擇紋理
107         glBegin(GL_QUADS); {
108             //后面:逆時針
109             glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    //紋理和四邊形的左下
110             glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    //紋理和四邊形的右下
111             glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    //紋理和四邊形的右上
112             glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    //紋理和四邊形的左上
113         }glEnd();
114     
115         glBindTexture(GL_TEXTURE_2D, texturesArr[2]);    //選擇紋理
116         glBegin(GL_QUADS); {
117             //頂面:逆時針
118             glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    //紋理和四邊形的左下
119             glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    //紋理和四邊形的右下
120             glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    //紋理和四邊形的右上
121             glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    //紋理和四邊形的左上
122         }glEnd();
123     
124         glBindTexture(GL_TEXTURE_2D, texturesArr[3]);    //選擇紋理
125         glBegin(GL_QUADS); {
126             //底面:逆時針
127             glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    //紋理和四邊形的左下
128             glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    //紋理和四邊形的右下
129             glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    //紋理和四邊形的右上
130             glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    //紋理和四邊形的左上
131         }glEnd();
132     
133         glBindTexture(GL_TEXTURE_2D, texturesArr[4]);    //選擇紋理
134         glBegin(GL_QUADS); {
135             //右面:逆時針
136             glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    //紋理和四邊形的左下
137             glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    //紋理和四邊形的右下
138             glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    //紋理和四邊形的右上
139             glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    //紋理和四邊形的左上
140         }glEnd();
141     
142         glBindTexture(GL_TEXTURE_2D, texturesArr[5]);    //選擇紋理
143         glBegin(GL_QUADS); {
144             //左面:逆時針
145             glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    //紋理和四邊形的左下
146             glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    //紋理和四邊形的右下
147             glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    //紋理和四邊形的右上
148             glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    //紋理和四邊形的左上
149         }glEnd();
150 #else    //顯示正面
151         glBindTexture(GL_TEXTURE_2D, texturesArr[0]);    //選擇紋理
152         glBegin(GL_QUADS); {
153             //前面:紋理順時針,立方體逆時針
154             glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    //紋理和四邊形的左下
155             glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    //紋理和四邊形的左上
156             glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    //紋理和四邊形的右上
157             glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    //紋理和四邊形的右下
158         }glEnd();
159     
160         glBindTexture(GL_TEXTURE_2D, texturesArr[1]);    //選擇紋理
161         glBegin(GL_QUADS); {
162             //后面:紋理順時針,立方體逆時針
163             glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    //紋理和四邊形的左下
164             glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    //紋理和四邊形的左上
165             glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    //紋理和四邊形的右上
166             glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    //紋理和四邊形的右下
167         }glEnd();
168     
169         glBindTexture(GL_TEXTURE_2D, texturesArr[2]);    //選擇紋理
170         glBegin(GL_QUADS); {
171             //頂面:紋理順時針,立方體逆時針
172             glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    //紋理和四邊形的左下
173             glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    //紋理和四邊形的左上
174             glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    //紋理和四邊形的右上
175             glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    //紋理和四邊形的右下
176         }glEnd();
177     
178         glBindTexture(GL_TEXTURE_2D, texturesArr[3]);    //選擇紋理
179         glBegin(GL_QUADS); {
180             //底面:紋理順時針,立方體逆時針
181             glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    //紋理和四邊形的左下
182             glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    //紋理和四邊形的左上
183             glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    //紋理和四邊形的右上
184             glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    //紋理和四邊形的右下
185         }glEnd();
186     
187         glBindTexture(GL_TEXTURE_2D, texturesArr[5]);    //選擇紋理
188         glBegin(GL_QUADS); {
189             //右面:紋理順時針,立方體逆時針
190             glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    //紋理和四邊形的左下
191             glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    //紋理和四邊形的左上
192             glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    //紋理和四邊形的右上
193             glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    //紋理和四邊形的右下
194         }glEnd();
195     
196         glBindTexture(GL_TEXTURE_2D, texturesArr[4]);    //選擇紋理
197         glBegin(GL_QUADS); {
198             //左面:紋理順時針,立方體逆時針
199 
200             glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    //紋理和四邊形的左下
201             glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    //紋理和四邊形的左上
202             glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    //紋理和四邊形的右上
203             glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    //紋理和四邊形的右下
204         }glEnd();
205 #endif
206     }glPopMatrix();
207     glFlush();
208 }
209 
210 //初始化
211 void init(void)
212 {
213     glClearColor (0.0, 0.0, 0.0, 0.0);    //清理顏色,為黑色,(也可認為是背景顏色)
214 
215     glCullFace(GL_FRONT);    //背面裁剪(背面不可見)
216     glEnable(GL_CULL_FACE);    //啟用裁剪
217     glEnable(GL_TEXTURE_2D);
218     loadGLTextures();    //載入紋理貼圖
219 }
220 
221 void display(void)
222 {
223     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    //清楚顏色數據和深度數據(清屏)
224     glLoadIdentity();    //Reset The View
225 
226     drawCube();
227 
228     glutSwapBuffers();    //交換緩沖區。顯示圖形
229     
230     //xangle += 0.3f;
231     //yangle += 0.3f;
232     //zangle += 0.3f;
233     Sleep(10);
234 }
235 
236 //當窗口大小改變時,會調用這個函數
237 void reshape(GLsizei w,GLsizei h)
238 {
239     //這里小說明一下:矩陣模式是不同的,他們各自有一個矩陣。投影相關
240     //只能用投影矩陣。(只是目前情況下哦,等我學多了可能就知道為什么了。)
241     
242     glViewport(0,0,w,h);    //設置視口
243     glMatrixMode(GL_PROJECTION);    //設置矩陣模式為投影變換矩陣,
244     glLoadIdentity();    //變為單位矩陣
245     gluPerspective(90, (GLfloat)w / h, 0.1f, 100.0f);    //設置投影矩陣
246     glMatrixMode(GL_MODELVIEW);    //設置矩陣模式為視圖矩陣(模型)
247     glLoadIdentity();    //變為單位矩陣
248 }
249 
250 //處理鼠標點擊
251 void Mouse(int button, int state, int x, int y)
252 {
253     if(state == GLUT_DOWN) //第一次鼠標按下時,記錄鼠標在窗口中的初始坐標
254     {
255         //記住鼠標點擊后光標坐標
256         cx = x;
257         cy = y;
258         //printf("Mouse: x=%d, y=%d, oldx_Translatef=%f, oldy_Translatef=%f\n", x, y, oldx_Translatef, oldy_Translatef);
259     }
260 }
261 
262 //處理鼠標拖動
263 void onMouseMove(int x, int y)
264 {
265     float offset = 0.18;
266     //計算拖動后的偏移量,然后進行xy疊加減
267     yangle -= ((x - cx) * offset);
268 
269     if (xangle < 90 && y > cy) {//往下拉
270         xangle += ((y - cy) * offset);
271     } else if (xangle > -90 && y < cy) {//往上拉
272         xangle += ((y - cy) * offset);
273     }
274     //printf("Move: x=%d(%d)[%d], y=%d(%d)[%d], xangle=%f, yangle=%f\n", 
275     //    x, cx, x-cx, 
276     //    y, cy, y-cy, 
277     //    xangle, yangle);
278     glutPostRedisplay();
279 
280     //保存好當前拖放后光標坐標點
281     cx = x;
282     cy = y;
283 }
284 
285 //鍵盤輸入事件函數
286 void keyboard(unsigned char key,int x,int y)
287 {
288     switch(key)
289     {
290         case 'x':        //當按下鍵盤上d時,以沿X軸旋轉為主
291             if (xangle < 85.0f)
292             {
293                 xangle += 1.0f;    //設置旋轉增量
294             }
295             break;
296         case 'X':
297             if (xangle > -85.0f)
298             {
299                 xangle -= 1.0f;    //設置旋轉增量
300             }
301             break;
302         case 'y':
303             yangle += 1.0f;
304             break;
305         case 'Y':
306             yangle -= 1.0f;
307             break;
308         //case 'z':
309         //    zangle += 1.0f;
310         //    break;
311         //case 'Z':
312         //    zangle -= 1.0f;
313         //    break;
314         default:
315             return;
316     }
317     glutPostRedisplay();    //重繪函數
318 }
319 
320 //特殊按鍵
321 void specialKey(int key, int x, int y)
322 {
323     float offset = 1.5;
324     printf("key=%d\n", key);
325     switch (key)
326     {
327     case GLUT_KEY_UP:    //腦袋向上往前看
328         if (xangle < 90.0f)
329         {
330             xangle += offset;    //設置旋轉增量
331         }
332         break;
333     case GLUT_KEY_DOWN:    //腦袋向下往前看
334         if (xangle > -90.0f)
335         {
336             xangle -= offset;    //設置旋轉增量
337         }
338         break;
339     case GLUT_KEY_LEFT:    //腦袋想左往前看
340         yangle -= offset;
341         break;
342     case GLUT_KEY_RIGHT:    //腦袋向右往前看
343         yangle += offset;
344         break;
345     default:
346         break;
347     }
348     glutPostRedisplay();
349 }
350 
351 int main(int argc, char *argv[])
352 {
353     printf("可通過↑↓←→按鍵或者鼠標控制全景圖繞旋轉\n");
354 
355     glutInit(&argc, argv);    //固定格式
356     glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); 
357     glutInitWindowSize(1024/2, 1024/2);    //顯示框的大小
358     glutInitWindowPosition(100,100);    //確定顯示框左上角的位置
359     glutCreateWindow("OpenGL紋理貼圖");
360 
361     init();    //初始化資源,這里一定要在創建窗口以后,不然會無效。
362     glutDisplayFunc(display);
363     //glutIdleFunc(display);
364     glutReshapeFunc(reshape);    //繪制圖形時的回調
365     //glutKeyboardFunc(keyboard);
366     glutMouseFunc(Mouse);
367     glutMotionFunc(onMouseMove);
368     glutKeyboardFunc(keyboard);
369     glutSpecialFunc(specialKey); //特殊按鍵
370     glutMainLoop();
371     return 0;
372 }

 

附上全景圖片:

附上代碼運行結果:

最后附上可執行的EXE鏈接: https://pan.baidu.com/s/1dGf0GAt 密碼: xzd5

 

最后測試結果還發現個問題:

這是立方體,所以在屏幕窗口的寬高不想等時,拖動圖片時立方體面與面連接點看到的效果會很別扭,初步的猜測是承載貼圖的圖形問題,比如可以改成球體,或者等寬高固定化。


免責聲明!

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



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