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

 

最后测试结果还发现个问题:

这是立方体,所以在屏幕窗口的宽高不想等时,拖动图片时立方体面与面连接点看到的效果会很别扭,初步的猜测是承载贴图的图形问题,比如可以改成球体,或者等宽高固定化。

posted @ 2016-07-13 15:17  追寻1024的程序猿  阅读(5584)  评论(3编辑  收藏  举报