您的位置:首页 > 运维架构

纹理(openGL)

2016-01-08 14:56 423 查看
0.概述

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);



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: