纹理(openGL)
2016-01-08 14:56
465 查看
0.概述
a.小栗子
对两个正方形进行纹理贴图
b.小栗子总结纹理贴图的基本步骤
1)使用glTexImageXD创建纹理对象。
之前包括对纹理管道中某个纹理图像的命名glGenTextures(1,&textureName);,将该纹理图像绑定到GL_TEXTURE_XD上glBindTexture(GL_TEXTURE_2D,textureName);和一些意外状况的处理glTexParameteri
2)确定纹理怎样应用到图元上
3)启用纹理贴图功能
4)绘制场景,指定纹理坐标与顶点坐标
1.指定纹理
a.拷贝
b.更新纹理(替换纹理图像的一部分或全部)
直接跟在glTexImageXD后面就行
c.从颜色缓冲区中读入像素更新纹理
d.mipmap
本节来自于:http://my.oschina.net/sweetdark/blog/177812
mipmap用以提高渲染性能和场景视觉质量,解决闪烁(物体表面明显小于纹理图像时)和性能问题。
mipmap加载时不单单是加载一个纹理,而是加载一系列从大到小的纹理(加载一套纹理图案相同,但大小不同的纹理)当mipmapped纹理状态中。
下面栗子:源栗子中用到gtool的加载外部tag文件功能函数,此处用加载bmp图像文件的函数代替。
切换了几种纹理过滤模式,砖块图片没选好,看不出丝毫效果
2.纹理高级用法(本节转自:http://my.oschina.net/sweetdark/blog/179590?fromerr=MYOaqIxi)
a.各向异性过滤
当我们的视角是垂直于该几何图形的时候,这样的方式没有问题。然而当我们的视角与几何图形形成一个斜角的时候,以常规的方式对周边纹理进行采样会丢失一些纹理的信息,它看起来变模糊了。更真实和精确的采样是,沿着平面倾斜的方向,拉长纹理的采样。如下的第二个图:
b.镜面光高亮
一般情况下,我们设置纹理的环境为GL_MODULATE模式,在这种情况下,受到光照的几何图形会和纹理的颜色进行结合。正常情况下,OpenGL进行光照计算,并根据标准的光照模型进行单个片段的颜色计算。然后,再把片段的颜色乘以纹理的颜色,等到结合后的颜色。但是这样的话会削弱图形的光照效果。因为经过光照计算过后的片段的颜色值最大值是1.0(即最亮的颜色),任何值乘以小于1.0的值,必定小于其本身(即不可能比原来更亮)。(if y <= 1.0 then x * y <= x. x y是正数)。
a.小栗子
对两个正方形进行纹理贴图
#include "grapg.h" #define Width 64 #define Height 64 GLubyte image_texture_001[Height][Width][4];//rgba GLuint textureName; void texture_001_create() { int c; for(int i=0;i<Height;i++) { for(int j=0;j<Width;j++) { c=(((i&0x8)==0)^((j&0x8)==0))*255; image_texture_001[i][j][0]=(GLubyte)c; image_texture_001[i][j][1]=(GLubyte)c; image_texture_001[i][j][2]=(GLubyte)c; image_texture_001[i][j][3]=(GLubyte)255; } } } void setup_texture_001() { glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); texture_001_create(); glPixelStorei(GL_UNPACK_ALIGNMENT,1);//边界对齐,应用程序从内存读出像素的过程称为解码UNPACK,而纹理内存写像素的过程为编码PACK glGenTextures(1,&textureName);//纹理管道中可存在多个纹理图像,命名标号为1的纹理图像的可用名字为textureName glBindTexture(GL_TEXTURE_2D,textureName);//创建纹理对象,将GL_TEXTURE_2D绑定为名字为textureName的纹理图像 //纹理的包装形式,并且指定当纹理图像中的纹理单元与屏幕上的像素并不完全匹配时,纹理颜色应该如何进行过滤 //纹理过滤 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);//GL_TEXTURE_WRAP_S:二维图像x方向?GL_REPEAT:当纹理比表面小时重复使用纹理以填满每一个点 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);//GL_CLAMP:把1大的当作1,比0小的当作0,相当于填充? glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);//纹理图像素坐标(0.x)*纹理像素个数=采用从哪儿到哪儿的纹理像素,然后这个计算得到的哪儿到哪儿的边界不一定会是个整数,此处用于判断当出现这种问题时,该用哪个像素。 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);//GL_TEXTURE_MIN_FILTER:缩小的处理方法;GL_NEAREST:取比较接近的那个像素 //将纹理加载到内存中去 //目标纹理,执行细节级别,纹理中的颜色组件,纹理宽,纹理宽,纹理边框宽度,像素数据的颜色格式,像素数据的数据类型,内存中指向图像的指针 glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,Width,Height,0,GL_RGBA,GL_UNSIGNED_BYTE,image_texture_001); } void texture_001_display() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D);//启用纹理贴图功能 glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);//设置纹理模式,GL_REPLACE替换模式 glBindTexture(GL_TEXTURE_2D,textureName); glColor3f(1.0,1.0,0.0); glBegin(GL_QUADS);//绘制场景,提供纹理坐标和几何坐标 //纹理坐标:是指使用纹理的哪部分,每个绘制顶点前面跟个纹理坐标,表示整个图元都会被贴图 glTexCoord2f(0.0,0.0);glVertex3f(-2.0,-1.0,0.0);//指定绘制图形时指定纹理的坐标 ,x坐标:0.0是纹理左侧,0.5是纹理中点,1.0是纹理右侧 glTexCoord2f(0.0,0.5);glVertex3f(-2.0,1.0,0.0); glTexCoord2f(0.5,0.5);glVertex3f(0.0,1.0,0.0); glTexCoord2f(0.5,0.0);glVertex3f(0.0,-1.0,0.0); glTexCoord2f(0.0,0.0);glVertex3f(1.0,-1.0,0.0); glTexCoord2f(0.0,1.0);glVertex3f(1.0,1.0,0.0); glTexCoord2f(1.0,1.0);glVertex3f(2.41421,1.0,-1.41421); glTexCoord2f(1.0,0.0);glVertex3f(2.41421,-1.0,-1.41421); glEnd(); glFlush(); glDisable(GL_TEXTURE_2D); } void reshape_001_texture(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0,(GLfloat)w/(GLfloat)h,1.0,30.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0,0.0,-4); } int main_texture_001() { glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowSize(500, 500); glutCreateWindow("text"); setup_texture_001(); glutDisplayFunc(texture_001_display); glutReshapeFunc(reshape_001_texture); glutMainLoop(); return 0; }
b.小栗子总结纹理贴图的基本步骤
1)使用glTexImageXD创建纹理对象。
之前包括对纹理管道中某个纹理图像的命名glGenTextures(1,&textureName);,将该纹理图像绑定到GL_TEXTURE_XD上glBindTexture(GL_TEXTURE_2D,textureName);和一些意外状况的处理glTexParameteri
2)确定纹理怎样应用到图元上
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);//设置纹理模式,GL_REPLACE替换模式
3)启用纹理贴图功能
glEnable(GL_TEXTURE_2D);//启用纹理贴图功能
4)绘制场景,指定纹理坐标与顶点坐标
glTexCoord2f(0.0,0.0);glVertex3f(-2.0,-1.0,0.0);
1.指定纹理
a.拷贝
glCopyTexImage2D(Target,Level,internalformat,x,y,width,height,border);操作和glCopyPixels()差不多,但像素是放在纹理内存中,而不是放在帧缓冲区中。
b.更新纹理(替换纹理图像的一部分或全部)
glTexSubImage2D(GL_TEXTURE_2D,0,20,20,subWidth,subHeight,GL_RGBA,GL_UNSIGNED_BYTE,subimage_texture_000);
直接跟在glTexImageXD后面就行
c.从颜色缓冲区中读入像素更新纹理
void glCopyTexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset, Glint x, GLint y, GLsizei width, GLsizei height);
d.mipmap
本节来自于:http://my.oschina.net/sweetdark/blog/177812
mipmap用以提高渲染性能和场景视觉质量,解决闪烁(物体表面明显小于纹理图像时)和性能问题。
mipmap加载时不单单是加载一个纹理,而是加载一系列从大到小的纹理(加载一套纹理图案相同,但大小不同的纹理)当mipmapped纹理状态中。
下面栗子:源栗子中用到gtool的加载外部tag文件功能函数,此处用加载bmp图像文件的函数代替。
#include "grapg.h" //定义宏常量 #define CEILING 0 #define BRICK 1 #define FLOOR 2 #define TEXTURENUM 3 //纹理图像的路径 const char* texFileName[] = {"D:\\数据\\学习\\图形\\project\\image\\ceiling.bmp", "D:\\数据\\学习\\图形\\project\\image\\brick.bmp", "D:\\数据\\学习\\图形\\project\\image\\floor.bmp"}; //纹理对象名称 GLuint tName[TEXTURENUM]; //旋转与移动 GLfloat yRot = 0.0f; GLfloat zPos = 0.0f; //切换不同的纹理过滤模式 void processmenu(int value) { switch (value) { case 0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); break; case 1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); break; case 2: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); break; case 3: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); break; case 4: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); break; case 5: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); break; default: break; } glutPostRedisplay(); } void setup_texture_002() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //开启深度测试,消除隐藏面,避免后画的墙画到前面来 glEnable(GL_DEPTH_TEST); //纹理图像的信息 GLint iWidth, iHeight; //设置纹理环境,GL_REPLACE:直接替换 glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV, GL_REPLACE); //生成纹理对象 glGenTextures(TEXTURENUM, tName);//数量,数组 for (int i = 0; i < TEXTURENUM; ++i) { void *pImage =gltloadbmp(texFileName[i], &iWidth, &iHeight);//读入bmp图像,在function中实现 if (pImage) { //绑定纹理对象,生成mipmap glBindTexture(GL_TEXTURE_2D, tName[i]); //与glTexImage2D功能相似,都是生成纹理不同的是glTexImage2D只支持64*64、128*128、256*256的位图,而gluBuild2DMipmaps支持任意分辨率的位图 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, iWidth, iHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, pImage); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } free(pImage); } glEnable(GL_TEXTURE_2D); } void ShutdownRC() { //最后删除纹理对象 glDeleteTextures(TEXTURENUM, tName); } void texture_002_display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); //移动和旋转 glTranslatef(0.0f, 0.0f, zPos); glRotatef(yRot, 0.0f, 1.0f, 0.0f); for(GLfloat z = -60.0f; z <= 0.0f; z += 10.0f) { //绑定地板纹理绘制地板,注意glBeindTexture在glBegin和glEnd中是无效的 glBindTexture(GL_TEXTURE_2D, tName[FLOOR]); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-10.0f, -10.0f, z); glTexCoord2f(1.0f, 0.0f); glVertex3f(-10.0f, -10.0f, z + 10.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(10.0f, -10.0f, z + 10.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(10.0f, -10.0f, z); glEnd(); //绑定天花板纹理 glBindTexture(GL_TEXTURE_2D, tName[CEILING]); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-10.0f, 10.0f, z); glTexCoord2f(1.0f, 0.0f); glVertex3f(-10.0f, 10.0f, z + 10.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(10.0f, 10.0f, z + 10.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(10.0f, 10.0f, z); glEnd(); //绑定砖墙的纹理 glBindTexture(GL_TEXTURE_2D, tName[BRICK]); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-10.0f, -10.0f, z); glTexCoord2f(1.0f, 0.0f); glVertex3f(-10.0f, 10.0f, z); glTexCoord2f(1.0f, 1.0f); glVertex3f(-10.0f, 10.0f, z + 10.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-10.0f, -10.0f, z + 10.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(10.0f, -10.0f, z); glTexCoord2f(1.0f, 0.0f); glVertex3f(10.0f, 10.0f, z); glTexCoord2f(1.0f, 1.0f); glVertex3f(10.0f, 10.0f, z + 10.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(10.0f, -10.0f, z + 10.0f); glEnd(); } glPopMatrix(); glutSwapBuffers(); } void reshape_texture_002(GLsizei w, GLsizei h) { if (h == 1) h = 0; glViewport(0, 0, w, h); GLfloat aspect = (GLfloat)w/(GLfloat)h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(35.5, aspect, 1.0, 150.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glutPostRedisplay(); } void SpecialKey(int value, int x, int y) { if (value == GLUT_KEY_LEFT) { yRot += 0.5f; } if (value == GLUT_KEY_RIGHT) { yRot -= 0.5f; } if (value == GLUT_KEY_UP) { zPos += 0.5f; } if (value == GLUT_KEY_DOWN) { zPos -= 0.5f; } if (yRot > 365.5f) { yRot = 0.0f; } glutPostRedisplay(); } int main_texture_002() { glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(800, 600); glutCreateWindow("text"); setup_texture_002(); glutDisplayFunc(texture_002_display); glutReshapeFunc(reshape_texture_002); glutSpecialFunc(SpecialKey); glutCreateMenu(processmenu); glutAddMenuEntry("GL_NEAREST", 0); glutAddMenuEntry("GL_LINEAR", 1); glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST", 2); glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 3); glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 4); glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5); glutAttachMenu(GLUT_RIGHT_BUTTON); glutMainLoop(); ShutdownRC(); return 0; }
GLbyte* gltloadbmp(const char *szfilename,GLint *iwidth,GLint *iheight) { //打开文件 FILE *pfile=fopen(szfilename,"rb"); if(pfile==0) { exit(0); } //读取图像大小 bmp图像宽高放在前两个字节? fseek(pfile,0x0012,SEEK_SET);//pfile指向偏移0x0012位,不成功则指向SEEK_SET即文件开头 fread(iwidth,sizeof(*iwidth),1,pfile);//最多读1个元素,每个元素sizeof(*iwidth)个字节,iwidth用于接收数据的内存地址 fread(iheight,sizeof(*iheight),1,pfile); //计算像素长度 GLint pixellength=(*iwidth)*3;//3:BGR(blue、green、red) while(pixellength%4!=0)//读取的时候是按int读取的,也就是4字节 { pixellength++; } pixellength=pixellength*(*iheight); //读取像素数据 GLbyte *pixeldata=(GLbyte*)malloc(pixellength); if(pixeldata==0) { exit(0); } fseek(pfile,54,SEEK_SET); fread(pixeldata,pixellength,1,pfile); //关闭文件 fclose(pfile); return pixeldata; }
切换了几种纹理过滤模式,砖块图片没选好,看不出丝毫效果
2.纹理高级用法(本节转自:http://my.oschina.net/sweetdark/blog/179590?fromerr=MYOaqIxi)
a.各向异性过滤
当我们的视角是垂直于该几何图形的时候,这样的方式没有问题。然而当我们的视角与几何图形形成一个斜角的时候,以常规的方式对周边纹理进行采样会丢失一些纹理的信息,它看起来变模糊了。更真实和精确的采样是,沿着平面倾斜的方向,拉长纹理的采样。如下的第二个图:
GLfloat fLargest; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
b.镜面光高亮
一般情况下,我们设置纹理的环境为GL_MODULATE模式,在这种情况下,受到光照的几何图形会和纹理的颜色进行结合。正常情况下,OpenGL进行光照计算,并根据标准的光照模型进行单个片段的颜色计算。然后,再把片段的颜色乘以纹理的颜色,等到结合后的颜色。但是这样的话会削弱图形的光照效果。因为经过光照计算过后的片段的颜色值最大值是1.0(即最亮的颜色),任何值乘以小于1.0的值,必定小于其本身(即不可能比原来更亮)。(if y <= 1.0 then x * y <= x. x y是正数)。
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); //开启镜面光高亮来解决这个问题,当然一开始得设置一个镜面光了
GLfloat specular[]={1.0f,1.0f,1.0f,1.0f};//设置镜面光源 GLfloat lightPos[] = { -50.f, 50.0f, 100.0f, 1.0f }; glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0,GL_SPECULAR,specular); glLightfv(GL_LIGHT0,GL_POSITION,lightPos); glEnable(GL_LIGHT0); GLfloat specref[]={1.0f,1.0f,1.0f,1.0f};//设置材料反射镜面光 glMaterialfv(GL_FRONT,GL_SPECULAR,specref); glMateriali(GL_FRONT,GL_SHININESS,128);
相关文章推荐
- 关闭windows.open()窗口,刷新父页面
- Linux自学笔记(一)
- centos搭建samba服务器(新手简易篇)
- 解决 Linux 下 virtualenv 中 pip 安装 Mysql-python 报错的问题
- java支持跨平台获取cpuid、主板id、硬盘id、mac地址 (兼容windows、Linux)
- OpenGL 2D渲染性能
- 解决linux下cocos2dx不能播放声音
- How to use TFTP to transfer files from develop board to your host server?
- nginx 服务器重启命令,关闭 (转)
- Hadoop2.6 HDFS EDIT LOG分析
- centos-6.6安装nginx-1.9.7和php7.0.0(一)
- Docker:最简实践笔记
- Linux 发行版下的Ubuntu、CentOS、Debian的异同
- android 开发常用的不可不知的几个网站
- 升级10.11后使用CocoaPod出现-bash: pod: command not found 解决办法 及其CocoaPod的安装
- CentOS下通过postfix使用自己的gmail邮箱发送邮件
- Makefile:130: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.
- 一步一步安装hive2,beeline
- Linux的SOCKET编程详解
- Nginx + CGI/FastCGI + C/Cpp