• 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
    ", 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
    ", 
    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
    ", 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("可通过↑↓←→按键或者鼠标控制全景图绕旋转
    ");
    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

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

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

  • 相关阅读:
    【题解】洛谷 P3942 将军令【20201017 CSP 模拟赛】【贪心】
    ASP.NET上传文件的三种基本方法
    Android 最火的快速开发框架XUtils
    asp.net 上传文件到一般处理程序中
    Android版本:使用findViewById()用字符串/在一个循环
    android 调用系统图库查看指定路径的图片
    Android中实现日期时间选择器(DatePicker和TimePicker)
    Android自定义ListView的Item无法响应OnItemClick的解决办法
    Android开发配置,消除SDK更新时的“https://dl-ssl.google.com refused”异常
    mysql 修改密码
  • 原文地址:https://www.cnblogs.com/1024Planet/p/5667031.html
Copyright © 2020-2023  润新知