图形学_opengl纹理映射
学了半学期的图形学,除了几个用python或是matlab比较方便的实验外,用的大多数是opengl,在这总结一下纹理贴图实验中opengl的用法。
1、编译器连接静态库
有用到glaux.h的程序,在加入相应的.h、.lib文件后,需要加入两行代码强行连接静态库:
#pragma comment(lib, "glaux")
#pragma comment(lib, "legacy_stdio_definitions")
另外关于glaux.h,我想吐槽的是在csdn卖下载的人是有多想赚钱?……这里我把找到的glaux.h的下载链接贴出来,需要自取:
链接:https://pan.baidu.com/s/1-P44eWXlehmd9jPYuXNiHw 提取码:hbi6
2、画一个简单立方体
最终目的是要把贴图映射到一个立方体上,首先我们需要构建一个不存在任何纹理的立方体。首先构建绘制函数:
void Draw(void){
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -5.0f);
glBegin(GL_QUADS);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
glFlush();
}
首先使用大家都喜欢的(必须用的)清屏函数glClear将窗口清除成当前帧的颜色,不用的话满屏漆黑。glLoadIdentity()被用于重置观察模型矩阵(感觉这几个函数挺固定搭配的?);glTranslatef()用于移动模型,三个参数分别对应x,y,z轴线模型的移动,这里向负方向移动了5f。不挪 或者 向正方向挪,只会造成我们的视点根本无法观察到模型,负方向5f的位置相对大小比较合适。
模板一样的东西套完以后,可以注意到glBegin()和glEnd()之间有一万个(不是)glVertex3f的堆叠,用于确定立方体的点。glBegin的参数QUADS表示接下来要绘制以四个点为一组的四边形,其他参数的含义如下:
GL_POINTS:把每个顶点作为一个点进行处理,顶点n定义了点n,绘制N个点。
GL_LINES: 把每个顶点作为一个独立的线段,顶点2n-1和2n之间定义了n条线段,绘制N/2条线段
GL_LINE_STRIP:绘制从第一个顶点到最后一个顶点依次相连的一组线段,第n和n+1个顶点定义了线段n,绘制n-1条线段。
GL_LINE_LOOP: 绘制从第一个顶点到最后一个顶点依次相连的一组线段,然后最后一个顶点和第一个顶点相连,第n和n+1个顶点定义了线段n,绘制n条线段。
GL_TRIANGLES: 把每个顶点作为一个独立的三角形,顶点3n-2,3n-1和3n定义了第n个三角形,绘制了N/3个三角形。
GL_TRIANGLE_STPIP:绘制一组相连的三角形,对于奇数n,顶点n,n+1,和n+2定义了第n个三角形;对于偶数n,顶点n+1,n和n+2定义了第n个三角形,绘制N-2个三角 形。
GL_QUAD_STRIP:绘制一组相连的四边形。每个四边形是由一对顶点及其后给定的一对顶点共同确定的。顶点2n-1,2n,2n+2和2n+1定义了第n个四边形,绘制了N/2-1个 四边形。
GL_POLYGON:绘制了一个凸多边形。顶点1到n定义了这个多边形。
而glVertex3f()的三个函数对应x,y,z轴的坐标,共4*6个glVertex3f()函数调用,对应立方体6个面的4个点。最后使用glFlush()清除缓存。
再构建一个display函数用于展示,将绘制函数置于display函数中:
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
Draw();
glutSwapBuffers();
}
清屏函数还是熟悉的味道,只是多了glutSwapBuffers()用于交换缓冲区和显示图形。
接下来是一个实现绘图之后转换矩阵模式的函数,用于主函数中的回调函数glutReshapeFunc()中:
void reshape(GLsizei w, GLsizei h){
glViewport(, , w, h);
glMatrixMode(GL_PROJECTION);
gluPerspective(, (GLfloat)w / h, , );
glMatrixMode(GL_MODELVIEW);
}
绘图以后先将矩阵模式调为投影模式,在投影模式下使用gluPerspective调整投影模型(不同模式下能执行的操作不一样),四个参数分别代表视野范围(值越大,视野范围越宽阔),裁剪面的宽w高h比(影响到视野的截面有多大),近裁剪面到眼睛的距离,远裁剪面到眼睛的距离(都不能设置设置为负值)。设置完之后把矩阵设置为视图模式。
最后是main()函数:
int main(int argc, char* argv[]){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow("大立方体?");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return ;
}
main函数的固定搭配glutInit(),之后设置显示模式为RGB单缓存区,分别设置窗口大小和位置之后,使用glutDisplayFunc()调用display(),glutReshapeFunc调用reshape,所得图形是这样:

呃…这不是个正方形嘛,其实只是我们的视点正对着立方体 而已。
接下来给它贴上纹理,首先加入三轴的旋转变量与一个纹理数组:
GLfloat xrot = ;
GLfloat yrot = ;
GLfloat zrot = ;
GLuint texture[];
读入贴图文件:
AUX_RGBImageRec* LoadBMP(const char Filename[]){
FILE* File = NULL;
if (!Filename){
return NULL;
}
File = fopen(Filename, "r");
if (File) {
fclose(File);
return auxDIBImageLoadA(Filename);
}
return NULL;
}
听说是固定搭配?
有了读取位图的函数,我们需要将它转换成纹理:
int LoadGLTextures(GLuint* texture, const char bmp_file_name[], int texture_id){
int re=;
AUX_RGBImageRec* TextureImage[];
memset(TextureImage, , sizeof(void*) * );
if (TextureImage[] = LoadBMP(bmp_file_name)){
re = ;
glGenTextures(texture_id, texture);
glBindTexture(GL_TEXTURE_2D, *texture);
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[]);
}
else
printf("纹理不存在");
return re;
}
首先声明一个AUX_RGBImageRec类型的指针,memset初始化之后调用之前的函数载入位图,glGenTextures生成纹理,参数分别为生成纹理的数量与指针,使用glBindTexture 将一个命名的纹理绑定到一个纹理目标上,glTexImage2D功能是根据指定的参数,生成一个2D纹理,这里的长、宽都必须是2的整数次方,glTexParameteri……是神秘的纹理过滤函数,对我们的纹理分别进行了一次缩小与放大的线性过滤。纹理生成之后,释放原图像的空间。
接下来修改绘制函数,将纹理映射到六个面上:
void Draw(void){
glClear(GL_COLOR_BUFFER_BIT );
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -5.0f);
glRotatef(xrot, 1.0f, 0.0f, 0.0f);
glRotatef(yrot, 0.0f, 1.0f, 0.0f);
glRotatef(zrot, 0.0f, 0.0f, 1.0f);
glBindTexture(GL_TEXTURE_2D, texture[]);
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);
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);
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(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(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f);
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, 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);
glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);
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();
glFlush();
}
glRotatef用来设置opengl中绘制实体的自转方式,为我们的模型动起来做准备。比起之前的draw函数,这里多了glTexCoord2f,两参数分别为X轴坐标,Y轴坐标,用于绘制图形时指定纹理的坐标,其中x、y的坐标:0.0是纹理的左侧,1.0是纹理的右侧;0.0是纹理的底部,1.0是纹理的顶部。
void init(void){
glClearColor(1.0, 1.0, 1.0, 0.0);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
LoadGLTextures(&texture[], "111_.bmp", );
}
使用清屏函数之后,使用glCullFace禁用多边形背面上的光照、阴影和颜色计算及操作,消除不必要的渲染计算,使用glEnable开启之前的消除操作。最后载入之前生成的纹理。
给出我们修改以后的主函数:
int main(int argc, char* argv[]){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow("贴图立方体?");
init();
LoadGLTextures(&texture[], "111_.bmp", );
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return ;
}
可以注意到新增了初始化函数与纹理载入函数,结果为:

看起来还只是一个平面图?为了让它转起来,写入鼠标响应函数:
void RotateRect() {
xrot += 1.0f;
glutPostRedisplay();
yrot += 1.0f;
glutPostRedisplay();
zrot += 1.0f;
glutPostRedisplay();
Sleep();
}
void OnMouse(int button, int state, int x, int y){
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
glutIdleFunc(RotateRect);
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
glutIdleFunc(NULL);
}
}
在RotateRect中修改各个维度的旋转量,使用glutPostRedisplay进行重绘,为了不使它暴走旋转,调用winbase.h中的Sleep函数,变量改变一次暂停程序10毫秒。定义鼠标响应函数,左键启动,右键暂停(返回NULL),在回调函数glutIdleFunc中调用RotateRect功能。
修改主函数:
int main(int argc, char* argv[]){
glutInit(&argc, argv); //固定格式
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow("贴图立方体?");
init();
LoadGLTextures(&texture[], "111_.bmp", );
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(&OnMouse);
glutMainLoop();
return ;
}
到这里 纹理映射实验就基本结束了。
参考博客:
https://blog.csdn.net/dcrmg/article/details/53223680?utm_source=blogxgwz2
https://www.cnblogs.com/OctoptusLian/p/7366844.html#commentform
https://blog.csdn.net/tyxkzzf/article/details/40921713
https://blog.csdn.net/yangmeng900816/article/details/46816007
图形学_opengl纹理映射的更多相关文章
- opengl纹理映射总结
大概步骤: 1.创建纹理对象,并为他指定一个纹理. 2.确定纹理如何应用到每个像素上. 3.启用纹理贴图 4.绘制场景,提供纹理和几何坐标 过滤:由于我们提供的纹理图像很少能和最终的屏幕坐标形成对应, ...
- OpenGL_Qt学习笔记之_05(纹理映射)(转)
转自:http://www.cnblogs.com/tornadomeet/archive/2012/08/24/2654719.html 纹理映射基础知识 什么叫纹理映射,一开始我也不明白,感觉这个 ...
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记7——DirectInput&纹理映射
第15章 DirectInput接口 DirectInput作为DirectX的组件之一,依然是一些COM对象的集合.DirectInput由IDirectinput8.IDirectInputDev ...
- 《计算机图形学3D》
<计算机图形学方法原理应用> Opengl语言 光线跟踪 贝塞尔曲线 射线追踪 色彩理论 纹理映射 逆向运动 MPI 仿射 绘制流水线 透视变换 bre ...
- OpenGL实例:纹理映射
OpenGL实例:纹理映射 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 更多请查看:计算机图形学 1. 介绍 用于指定一维.二维和三维纹理的函数分别 ...
- 【Notes】现代图形学入门_02
跟着闫令琪老师的课程学习,总结自己学习到的知识点 课程网址GAMES101 B站课程地址GAMES101 课程资料百度网盘[提取码:0000] 光栅化 着色(Shading) 在图形学中,着色的定义可 ...
- 图形学3D渲染管线学习
图形学3D渲染管线 DX和OpenGL左右手坐标系不同,会有一些差距,得出的矩阵会不一样; OpenGL的投影平面不是视景体的近截面: 顶点(vertexs) 顶点坐标,颜色,法线,纹理坐标(UV), ...
- 【转】OpenGL超级宝典笔记——纹理映射Mipmap
原文地址 http://my.oschina.net/sweetdark/blog/177812 , 感谢作者,若非法转载请联系本人. 目录[-] Mipmapping Mipmap过滤 构建Mip层 ...
- texrecon进行纹理映射
使用texrecon进行纹理映射: 1) 跳转到mesh所在目录 cd meshdir 2) 参数 a) texrecon.exe b) bun ...
随机推荐
- A - Oil Deposits DFS
The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSu ...
- MVC-第一个简单的程序
来源于:https://www.cnblogs.com/miro/p/4030622.html 从空白开始,建立一个基本框架详细步骤 1,新建项目 NOTE:模板要选Empty,如果直接选MVC会产生 ...
- 支付宝开源非侵入式 Android 自动化测试工具 Soloπ
Soloπ(SoloPi)是支付宝开源的一个无线化.非侵入式的Android自动化测试工具,公测版拥有录制回放.性能测试.一机多控三项主要功能,能为测试开发人员节省宝贵时间. 本文是SoloPi团队关 ...
- Linux网络编程(2)
Preview 基于上一篇博客,本文将继续展开TCP面向连接的,客户端以及服务端各自需要进行的操作,我们按照真实TCP连接的顺序,分别阐述客户端socket(), connect()以及服务端sock ...
- pytorch 孪生神经网络DNN
代码内容请见: https://github.com/LiuXinyu12378/DNN-network
- 如何保证kafka消息不丢失
背景 这里的kafka值得是broker,broker消息丢失的边界需要对齐一下: 1 已经提交的消息 2 有限度的持久化 如果消息没提交成功,并不是broke丢失了消息: 有限度的持久化(broke ...
- SeleniumHQ
下载地址:http://www.seleniumhq.org/download/
- input框处理大全
1.去掉谷歌input记住账号或密码时默认出现的黄色背景: 直接用css的内阴影来覆盖黄色(代码中 white可换成其他颜色) input:-webkit-autofill { -webkit-box ...
- Windows SDK 的 ctype.h 里有一些有用的函数,例如字符串的大小写转换
#define _tolower(c) ((c) - 'A' + 'a') #define _toupper(c) ((c) - 'a' + 'A')
- java在指定区间内生成随机数
Random对象生成随机数 首先需要导入包含Random的包 import java.util.Random; nextInt(int)方法将生成0~参数之间的随机整数但不包括参数. 例如生成0~99 ...