继续上一篇文章的例子:OpenGL的几何变换2之内观察立方体

上一篇是通过绘图方式得到的立方体,没有贴图,这次加上纹理贴图。

通过纹理贴图有两种方案:

1、图片分割化,即是把一张完整的全景图片(就是支持720度全景图片)人工的分隔成前后左右上下六张图片(静态),然后分别加载这六张图片;

2、数据分割化,即是保留一张完整的全景图片,加载图片以后,对图片数据进行上下左右前后进行数据切割,或者应该说进行图片切割(动态)。

这一篇文章主要用到的技术点是纹理映射,具体不再累述,可以参考OpenGL的glTexCoord2f纹理坐标配置

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

 #include <stdio.h>
#include <windows.h>
#include <gl/glut.h> //引用相关包
#include <gl/glaux.h> GLfloat xangle = 0.0; //X 旋转量
GLfloat yangle = 0.0; //Y 旋转量
GLfloat zangle = 0.0; //Z 旋转量
GLuint texturesArr[]; //存储6个纹理 //交叉点的坐标
int cx = ;
int cy = ; //载入位图图象
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
} //载入位图(调用上面的代码)并转换成纹理
int loadGLTextures()
{
int Status = FALSE; //状态指示器
char *imgArr[] = {
"pano/pano_f.bmp", //前面
"pano/pano_b.bmp", //后面
"pano/pano_u.bmp", //顶面
"pano/pano_d.bmp", //底面
"pano/pano_r.bmp", //右面
"pano/pano_l.bmp" //左面
};
AUX_RGBImageRec *textureImage[]; //创建纹理的存储空间 memset(texturesArr, 0x0, sizeof(texturesArr));
memset(textureImage,,sizeof(textureImage)); //将指针设为NULL for (int i = ; i < ; i++) {
Status = FALSE;
//载入位图,检查有无错误,如果位图没找到则退出
if (textureImage[i] = loadBMP(imgArr[i]))
{
Status = TRUE; //将 Status 设为 TRUE
glGenTextures(, &texturesArr[i]); //创建纹理 //使用来自位图数据生成 的典型纹理
glBindTexture(GL_TEXTURE_2D, texturesArr[i]);
//生成纹理
glTexImage2D(GL_TEXTURE_2D, , , textureImage[i]->sizeX, textureImage[i]->sizeY, , GL_RGB, GL_UNSIGNED_BYTE, textureImage[i]->data); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //线形滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //线形滤波
} if (textureImage[i]) //纹理是否存在
{
if (textureImage[i]->data) //纹理图像是否存在
{
free(textureImage[i]->data); //释放纹理图像占用的内存
}
free(textureImage[i]); //释放图像结构
}
if (Status == FALSE) {
break;
}
}
return Status; //返回 Status
} //从这里开始进行所有的绘制
void drawCube(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); //重置当前的模型观察矩阵 glPushMatrix();
{
gluLookAt(, , -, , , , , , );
glTranslatef(0.0f, 0.0f, -5.0f); //移入屏幕 5 个单位
glRotatef(xangle, 1.0f, 0.0f, 0.0f); //绕X轴旋转
glRotatef(yangle, 0.0f, 1.0f, 0.0f); //绕Y轴旋转
glRotatef(zangle, 0.0f, 0.0f, 1.0f); //绕Z轴旋转
#if (0) //显示反面
glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
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(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
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(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
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(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
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(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
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(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
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();
#else //显示正面
glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
glBegin(GL_QUADS); {
//前面:纹理顺时针,立方体逆时针
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); //纹理和四边形的左下
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //纹理和四边形的左上
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); //纹理和四边形的右上
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); //纹理和四边形的右下
}glEnd(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
glBegin(GL_QUADS); {
//后面:纹理顺时针,立方体逆时针
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和四边形的左下
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); //纹理和四边形的左上
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); //纹理和四边形的右上
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); //纹理和四边形的右下
}glEnd(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
glBegin(GL_QUADS); {
//顶面:纹理顺时针,立方体逆时针
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //纹理和四边形的左下
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); //纹理和四边形的左上
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); //纹理和四边形的右上
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); //纹理和四边形的右下
}glEnd(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
glBegin(GL_QUADS); {
//底面:纹理顺时针,立方体逆时针
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); //纹理和四边形的左下
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f); //纹理和四边形的左上
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); //纹理和四边形的右上
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和四边形的右下
}glEnd(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
glBegin(GL_QUADS); {
//右面:纹理顺时针,立方体逆时针
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); //纹理和四边形的左下
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); //纹理和四边形的左上
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //纹理和四边形的右上
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); //纹理和四边形的右下
}glEnd(); glBindTexture(GL_TEXTURE_2D, texturesArr[]); //选择纹理
glBegin(GL_QUADS); {
//左面:纹理顺时针,立方体逆时针 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); //纹理和四边形的左下
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); //纹理和四边形的左上
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); //纹理和四边形的右上
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和四边形的右下
}glEnd();
#endif
}glPopMatrix();
glFlush();
} //初始化
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0); //清理颜色,为黑色,(也可认为是背景颜色) glCullFace(GL_FRONT); //背面裁剪(背面不可见)
glEnable(GL_CULL_FACE); //启用裁剪
glEnable(GL_TEXTURE_2D);
loadGLTextures(); //载入纹理贴图
} void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清楚颜色数据和深度数据(清屏)
glLoadIdentity(); //Reset The View drawCube(); glutSwapBuffers(); //交换缓冲区。显示图形 //xangle += 0.3f;
//yangle += 0.3f;
//zangle += 0.3f;
Sleep();
} //当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
//这里小说明一下:矩阵模式是不同的,他们各自有一个矩阵。投影相关
//只能用投影矩阵。(只是目前情况下哦,等我学多了可能就知道为什么了。) glViewport(,,w,h); //设置视口
glMatrixMode(GL_PROJECTION); //设置矩阵模式为投影变换矩阵,
glLoadIdentity(); //变为单位矩阵
gluPerspective(, (GLfloat)w / h, 0.1f, 100.0f); //设置投影矩阵
glMatrixMode(GL_MODELVIEW); //设置矩阵模式为视图矩阵(模型)
glLoadIdentity(); //变为单位矩阵
} //处理鼠标点击
void Mouse(int button, int state, int x, int y)
{
if(state == GLUT_DOWN) //第一次鼠标按下时,记录鼠标在窗口中的初始坐标
{
//记住鼠标点击后光标坐标
cx = x;
cy = y;
//printf("Mouse: x=%d, y=%d, oldx_Translatef=%f, oldy_Translatef=%f\n", x, y, oldx_Translatef, oldy_Translatef);
}
} //处理鼠标拖动
void onMouseMove(int x, int y)
{
float offset = 0.18;
//计算拖动后的偏移量,然后进行xy叠加减
yangle -= ((x - cx) * offset); if (xangle < && y > cy) {//往下拉
xangle += ((y - cy) * offset);
} else if (xangle > - && y < cy) {//往上拉
xangle += ((y - cy) * offset);
}
//printf("Move: x=%d(%d)[%d], y=%d(%d)[%d], xangle=%f, yangle=%f\n",
// x, cx, x-cx,
// y, cy, y-cy,
// xangle, yangle);
glutPostRedisplay(); //保存好当前拖放后光标坐标点
cx = x;
cy = y;
} //键盘输入事件函数
void keyboard(unsigned char key,int x,int y)
{
switch(key)
{
case 'x': //当按下键盘上d时,以沿X轴旋转为主
if (xangle < 85.0f)
{
xangle += 1.0f; //设置旋转增量
}
break;
case 'X':
if (xangle > -85.0f)
{
xangle -= 1.0f; //设置旋转增量
}
break;
case 'y':
yangle += 1.0f;
break;
case 'Y':
yangle -= 1.0f;
break;
//case 'z':
// zangle += 1.0f;
// break;
//case 'Z':
// zangle -= 1.0f;
// break;
default:
return;
}
glutPostRedisplay(); //重绘函数
} //特殊按键
void specialKey(int key, int x, int y)
{
float offset = 1.5;
printf("key=%d\n", key);
switch (key)
{
case GLUT_KEY_UP: //脑袋向上往前看
if (xangle < 90.0f)
{
xangle += offset; //设置旋转增量
}
break;
case GLUT_KEY_DOWN: //脑袋向下往前看
if (xangle > -90.0f)
{
xangle -= offset; //设置旋转增量
}
break;
case GLUT_KEY_LEFT: //脑袋想左往前看
yangle -= offset;
break;
case GLUT_KEY_RIGHT: //脑袋向右往前看
yangle += offset;
break;
default:
break;
}
glutPostRedisplay();
} int main(int argc, char *argv[])
{
printf("可通过↑↓←→按键或者鼠标控制全景图绕旋转\n"); glutInit(&argc, argv); //固定格式
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(/, /); //显示框的大小
glutInitWindowPosition(,); //确定显示框左上角的位置
glutCreateWindow("OpenGL纹理贴图"); init(); //初始化资源,这里一定要在创建窗口以后,不然会无效。
glutDisplayFunc(display);
//glutIdleFunc(display);
glutReshapeFunc(reshape); //绘制图形时的回调
//glutKeyboardFunc(keyboard);
glutMouseFunc(Mouse);
glutMotionFunc(onMouseMove);
glutKeyboardFunc(keyboard);
glutSpecialFunc(specialKey); //特殊按键
glutMainLoop();
return ;
}

附上全景图片:

附上代码运行结果:

最后附上可执行的EXE链接: https://pan.baidu.com/s/1dGf0GAt 密码: xzd5

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

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

OpenGL的几何变换3之内观察全景图的更多相关文章

  1. OpenGL的几何变换4之内观察全景图

    上一次写了OpenGL的几何变换3之内观察全景图 上次采用的是图片分割化方式,这次采用数据分割化方式. 先说下思路,数据分割化方式呢,是只读取一张图片imgData,然后通过glTexCoord2f( ...

  2. OpenGL的几何变换2之内观察立方体

    我想实现的一个场景是:一个立方体,相机的坐标在立方体的中心点,相机不变,立方体旋转,可以站在立方体中心点查看立方体内部. 实际上就是立方体图像,这是在全景图片当作比较简单的方式,画面不会变形和扭曲,但 ...

  3. OpenGL的几何变换[转]

    OpenGL的几何变换 1.实验目的: 理解掌握一个OpenGL程序平移.旋转.缩放变换的方法. 2.实验内容: (1)阅读实验原理,运行示范实验代码,掌握OpenGL程序平移.旋转.缩放变换的方法: ...

  4. OpenGL的glViewPort窗口设置函数实现分屏

    之前实现过全景图片查看(OpenGL的几何变换3之内观察全景图),那么我们需要进行分屏该如何实现呢?如下图: 没错就是以前提过的glViewPort函数,废话不多说了,我直接上代码: //从这里开始进 ...

  5. OpenGL的gluPerspective和gluLookAt的关系[转]

    函数原型void gluLookAt(GLdoble eyex, GLdouble eyey, GLdouble eyez,  GLdouble centerx, GLdouble centery, ...

  6. OPenGL中三维图形的矩阵变换

    对于二维的图形开发,拿简单的图片显示来说,我们主要的目的:就是在一块显示buffer中,不停的把每个像素进行着色,然后就可以绘制出来了.为了速度,很多其他的加速方法,但原理基本上就是这样了. 很直观, ...

  7. OpenGL一些函数详解(二)

    OpenGL ES顶点数据绘制技巧 在OpenGL中,绘制一个长方体,需要将每个顶点的坐标放在一个数组中.保存坐标时有一些技巧(由于字母下标不好表示,因此将下标表示为单引号,如A1将在后文中表示为A' ...

  8. DirectX12 3D 游戏开发与实战第五章内容

    渲染流水线 学习目标: 了解用于在2D图像中表现出场景立体感和空间深度感等真实效果的关键因素 探索如何用Direct3D表示3D对象 学习如何建立虚拟摄像机 理解渲染流水线,根据给定的3D场景的几何描 ...

  9. 360Vedio To NFOV Vedio

    Deep 360 Pilot Learning a Deep Agent for Piloting through 360° Sports Videos 源码.数据集和视频演示 ego-centric ...

随机推荐

  1. -WEBKIT-USER-SELECT:NONE导致输入框无法输入

    原文:http://hicc.me/post/webkit-user-select-none-disabling-text-field.html 最近在webview中写页面的时候发现个别Androi ...

  2. PL/SQL注册码

    code:j6stndb9tk72xfbhbqczcdqnjd8lyj466n number:882851 ps:xs374ca

  3. opencv通过dll调用matlab函数,图片作为参数

    [blog 项目实战派]opencv通过dll调用matlab函数,图片作为参数                   前文介绍了如何“csharp通过dll调用opencv函数,图片作为参数”.而在实 ...

  4. The Blacksmith学习的相关资源

    1.Unity官网的Blacksmith主页 https://unity3d.com/pages/the-blacksmith 2.WRINKLE MAPS IN THE BLACKSMITH 褶皱贴 ...

  5. 安装python-devel 在升级到python2.7之后

    分别执行如下命令: # yum update # yum install centos-release-SCL # yum search all python27 在搜索出的列表中发现python27 ...

  6. python中zip函数

    zip函数接受任意多个(包括0个和1个)序列作为参数,返回一个tuple列表.(在海豚实习时自己写了一个要用到zip的函数,那个例子非常代表性) 示例1 for i,j in zip(range(3) ...

  7. FZU 2168 防守阵地 I

    Problem Description 部队中共有N个士兵,每个士兵有各自的能力指数Xi,在一次演练中,指挥部确定了M个需要防守的地点,按重要程度从低到高排序,依次以数字1到M标注每个地点的重要程度, ...

  8. mysql正则匹配解决查询一个字段是否在另一个字段中

    select b.filter_name , count(*) from at_goods a , at_search_filter bwhere a.application REGEXP b.fil ...

  9. 首先,定义描述学生的类——Student,包括学号(int)、 姓名(String)、年龄(int)等属性;二个方法:Student(int stuNo,String name,int age) 用于对对象的初始化,outPut()用于输出学生信息。其次,再定义一个主类—— TestClass,在主类的main方法中创建多个Student类的对象,使用这些对象来测 试Student类的功能。

    package lianxi; public class Student { String Name; int XveHao,Age; Student(String Name,int XveHao,i ...

  10. 转 Android 对话框(Dialog)大全 建立你自己的对话框

    Activities提供了一种方便管理的创建.保存.回复的对话框机制,例如 onCreateDialog(int), onPrepareDialog(int, Dialog), showDialog( ...