纹理(openGL)

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





  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值