上一次写了OpenGL的几何变换3之内观察全景图
上次采用的是图片分割化方式,这次采用数据分割化方式。
先说下思路,数据分割化方式呢,是只读取一张图片imgData,然后通过glTexCoord2f()配置纹理坐标和glVertex3f()配置图形坐标,然后该分隔的分隔,该组合的组合。
这次的代码使用的图片处理结果有些瑕疵,因为一张完整的全景图片是有角度拉伸的,且有些模糊化,将就着看吧
附上代码:
#include <stdio.h>
#include <math.h>
#include <windows.h>
#include <gl/glut.h> //引用相关包
#include <gl/glaux.h> #define pi 3.141592654 GLfloat xangle = 0.0; //X 旋转量
GLfloat yangle = 0.0; //Y 旋转量
GLfloat zangle = 0.0; //Z 旋转量
GLuint textureArr[]; //存储6个纹理 //交叉点的坐标
int cx = ;
int cy = ; float vertex[][][];
float texpoint[][][]; //载入位图图象
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 loadGLTexture2()
{
int Status = FALSE; //状态指示器
AUX_RGBImageRec *textureImage[]; //创建纹理的存储空间 memset(textureArr, 0x0, sizeof(textureArr));
memset(textureImage,,sizeof(textureImage)); //将指针设为NULL //载入位图,检查有无错误,如果位图没找到则退出
if (textureImage[] = loadBMP("pano/pano_sphere.bmp"))
{
Status = TRUE; //将 Status 设为 TRUE
glGenTextures(, &textureArr[]); //创建纹理 //使用来自位图数据生成 的典型纹理
glBindTexture(GL_TEXTURE_2D, textureArr[]);
//生成纹理
glTexImage2D(GL_TEXTURE_2D, , , textureImage[]->sizeX, textureImage[]->sizeY, , GL_RGB, GL_UNSIGNED_BYTE, textureImage[]->data); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //线形滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //线形滤波
} if (textureImage[]) //纹理是否存在
{
if (textureImage[]->data) //纹理图像是否存在
{
free(textureImage[]->data); //释放纹理图像占用的内存
}
free(textureImage[]); //释放图像结构
} 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, textureArr[]); //选择纹理
glBegin(GL_QUADS); {
//前面:纹理顺时针,立方体逆时针
float fx = 1024.0/8.0;
float fy = 512.0/4.0; float tx0 = fx*3.0/1024.0;
float ty0 = fy*1.0/512.0;
float tx1 = fx*5.0/1024.0;
float ty1 = fy*3.0/512.0;
//printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*3.0, tx0, fy*1.0, ty0, fx*5.0, tx1, fy*3.0, ty1);
glTexCoord2f(tx0, ty0); glVertex3f( 1.0f, -1.0f, 1.0f); //纹理和四边形的左下
glTexCoord2f(tx0, ty1); glVertex3f( 1.0f, 1.0f, 1.0f); //纹理和四边形的左上
glTexCoord2f(tx1, ty1); glVertex3f(-1.0f, 1.0f, 1.0f); //纹理和四边形的右上
glTexCoord2f(tx1, ty0); glVertex3f(-1.0f, -1.0f, 1.0f); //纹理和四边形的右下 //后面:纹理顺时针,立方体逆时针
tx0 = fx*0.0/1024.0;
ty0 = fy*1.0/512.0;
tx1 = fx*1.0/1024.0;
ty1 = fy*3.0/512.0;
//printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*0.0, tx0, fy*1.0, ty0, fx*1.0, tx1, fy*3.0, ty1);
glTexCoord2f(tx0, ty0); glVertex3f( 0.0f, -1.0f, -1.0f); //纹理和四边形的左下
glTexCoord2f(tx0, ty1); glVertex3f( 0.0f, 1.0f, -1.0f); //纹理和四边形的左上
glTexCoord2f(tx1, ty1); glVertex3f( 1.0f, 1.0f, -1.0f); //纹理和四边形的右上
glTexCoord2f(tx1, ty0); glVertex3f( 1.0f, -1.0f, -1.0f); //纹理和四边形的右下 tx0 = fx*7.0/1024.0;
ty0 = fy*1.0/512.0;
tx1 = fx*8.0/1024.0;
ty1 = fy*3.0/512.0;
//printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*7.0, tx0, fy*1.0, ty0, fx*8.0, tx1, fy*3.0, ty1);
glTexCoord2f(tx0, ty0); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和四边形的左下
glTexCoord2f(tx0, ty1); glVertex3f(-1.0f, 1.0f, -1.0f); //纹理和四边形的左上
glTexCoord2f(tx1, ty1); glVertex3f( 0.0f, 1.0f, -1.0f); //纹理和四边形的右上
glTexCoord2f(tx1, ty0); glVertex3f( 0.0f, -1.0f, -1.0f); //纹理和四边形的右下 //顶面:纹理顺时针,立方体逆时针
tx0 = fx*3.0/1024.0;
ty0 = fy*3.0/512.0;
tx1 = fx*5.0/1024.0;
ty1 = fy*4.0/512.0;
//printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*3.0, tx0, fy*3.0, ty0, fx*5.0, tx1, fy*4.0, ty1);
glTexCoord2f(tx0, ty0); glVertex3f( 1.0f, 1.0f, 1.0f); //纹理和四边形的左下
glTexCoord2f(tx0, ty1); glVertex3f( 1.0f, 1.0f, -1.0f); //纹理和四边形的左上
glTexCoord2f(tx1, ty1); glVertex3f(-1.0f, 1.0f, -1.0f); //纹理和四边形的右上
glTexCoord2f(tx1, ty0); glVertex3f(-1.0f, 1.0f, 1.0f); //纹理和四边形的右下 //底面:纹理顺时针,立方体逆时针
tx0 = fx*3.0/1024.0;
ty0 = fy*0.0/512.0;
tx1 = fx*5.0/1024.0;
ty1 = fy*1.0/512.0;
//printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*3.0, tx0, fy*0.0, ty0, fx*5.0, tx1, fy*1.0, ty1);
glTexCoord2f(tx0, ty0); glVertex3f( 1.0f, -1.0f, -1.0f); //纹理和四边形的左下
glTexCoord2f(tx0, ty1); glVertex3f( 1.0f, -1.0f, 1.0f); //纹理和四边形的左上
glTexCoord2f(tx1, ty1); glVertex3f(-1.0f, -1.0f, 1.0f); //纹理和四边形的右上
glTexCoord2f(tx1, ty0); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和四边形的右下 //左面:纹理顺时针,立方体逆时针
tx0 = fx*1.0/1024.0;
ty0 = fy*1.0/512.0;
tx1 = fx*3.0/1024.0;
ty1 = fy*3.0/512.0;
//printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*1.0, tx0, fy*1.0, ty0, fx*3.0, tx1, fy*3.0, ty1);
glTexCoord2f(tx0, ty0); glVertex3f( 1.0f, -1.0f, -1.0f); //纹理和四边形的左下
glTexCoord2f(tx0, ty1); glVertex3f( 1.0f, 1.0f, -1.0f); //纹理和四边形的左上
glTexCoord2f(tx1, ty1); glVertex3f( 1.0f, 1.0f, 1.0f); //纹理和四边形的右上
glTexCoord2f(tx1, ty0); glVertex3f( 1.0f, -1.0f, 1.0f); //纹理和四边形的右下 //右面:纹理顺时针,立方体逆时针
tx0 = fx*5.0/1024.0;
ty0 = fy*1.0/512.0;
tx1 = fx*7.0/1024.0;
ty1 = fy*3.0/512.0;
//printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*5.0, tx0, fy*1.0, ty0, fx*7.0, tx1, fy*3.0, ty1);
glTexCoord2f(tx0, ty0); glVertex3f(-1.0f, -1.0f, 1.0f); //纹理和四边形的左下
glTexCoord2f(tx0, ty1); glVertex3f(-1.0f, 1.0f, 1.0f); //纹理和四边形的左上
glTexCoord2f(tx1, ty1); glVertex3f(-1.0f, 1.0f, -1.0f); //纹理和四边形的右上
glTexCoord2f(tx1, ty0); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和四边形的右下
}glEnd();
#else
glBindTexture(GL_TEXTURE_2D, textureArr[]); // 选择纹理,有多个纹理时这句话是必要de
glBegin(GL_QUADS); { //四边形绘制开始
for(int i=; i<; i++) {
for(int j=; j<; j++) {
//第一个纹理坐标(左下角)
glTexCoord2f(texpoint[i][j][], texpoint[i][j][]);
glVertex3f(vertex[i][j][], vertex[i][j][], vertex[i][j][]); //第二个纹理坐标(左上角)
glTexCoord2f(texpoint[i][j][], texpoint[i][j+][]);
glVertex3f(vertex[i][j+][], vertex[i][j+][], vertex[i][j+][]); //第三个纹理坐标(右上角)
glTexCoord2f(texpoint[i+][j+][], texpoint[i+][j+][]);
glVertex3f(vertex[i+][j+][], vertex[i+][j+][], vertex[i+][j+][]); //第四个纹理坐标(右下角)
glTexCoord2f(texpoint[i+][j][], texpoint[i][j][]);
glVertex3f(vertex[i+][j][], vertex[i+][j][], vertex[i+][j][]);
}
}
}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);
loadGLTexture2(); //载入纹理贴图 //初始化数据
for(int i=; i<=; i+=)
{
for( int j=; j>=; j-=)
{
vertex[i/][(-j)/][] = cos((float)i/180.0*pi)*sin((float)j/180.0*pi)*;
vertex[i/][(-j)/][] = cos((float)j/180.0*pi)*;
vertex[i/][(-j)/][] = sin((float)i/180.0*pi)*sin((float)j/180.0*pi)*;
}
}
for(int i=; i<; i++)
{
for(int k=; k<; k++)
{
texpoint[i][k][]= (float)i/60.0; //生成X浮点值
texpoint[i][k][]= (float)k/30.0; //生成Y浮点值
}
}
printf("...\n");
} 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_Textures=%f, yangle_Textures=%f\n",
// x, cx_Textures, x-cx_Textures,
// y, cy_Textures, y-cy_Textures,
// xangle_Textures, yangle_Textures);
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;
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); //绘制图形时的回调
glutMouseFunc(Mouse);
glutMotionFunc(onMouseMove);
glutKeyboardFunc(keyboard);
glutSpecialFunc(specialKey); // 特殊按键
glutMainLoop();
return ;
}
执行结果:
附上执行程序链接: https://pan.baidu.com/s/1dSVNP0 密码: 8anf