纹理对象的使用:纹理图像数据的类型,图像数据的导入导出方式,纹理的使用过程:图像数据的加载,纹理参数的设置,纹理的绑定。
一、图像数据的分类:位图图像和像素图像
二、像素图像数据的包装:
在OpenGL中:使用4字节的行对齐方式,每一行补全到4的倍数,使用glPixelStorei(pname,param)可以改变或者恢复像素的存储方式
介绍常用的两组:内存<->缓冲区的压缩和解包
glPixcelStorei(GL_UNPACK_ALIGNMENT) ----图像数据从内存到缓冲区的解包设置
glPixcelStorei(GL_PACK_ALIGNMENT) ---- 图像数据从缓冲区到内存的封包设置
三、像素图的存储过程(从颜色缓冲区中获取图像保存为图片)
1、从颜色缓冲区读取像素数据到内存中:glReadPixcels(x,y,width,height,format,type,*pixcels)
pixcels:必须有足够的存储空间
format:指定颜色布局,类似GL_RGB,GL_RBGA之类
type:颜色分量的数据类型,类似GL_UNSIGHED_BYTE,GL_BYTE之类
2、从内存到硬盘的图像文件保存
四、像素图数据的获取过程(从硬盘到内存)
gltReadTGABits(szFileName,iWidth,iHeight,iComponents,eFormat)
获取:图片位图数据,宽高,iComponents:颜色成分的存储大小和压缩状况,eFormat:颜色布局
这些数据是位图数据从内存加载到缓冲区的时候,OpenGL需要的数据
五、纹理载入方式一(图像数据从内存到纹理缓冲区):
glTexImage1D/glTexImage2D/glTexImage3D
glTexImage2D(target,level,internalformat,width,height,border,format,type,*data)
target:GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D
level:指定mip贴图的层次
internalformat:就是上述获取到的iComponents的数据
border:为纹理贴图指定一个边界宽度
format,type,data:和用于把图像数据放入颜色缓冲区的glDrawPixcels函数对应的参数一致
六、纹理载入方式二(图像数据从颜色缓冲区读取到纹理缓冲区):
glCopyTexImage2D(target,level,internalformat,x,y,width,height,border)
源缓冲区是通过glReadBuffer(mode)函数设置的。 mode为GL_FRONT,GL_LEFT 等参数
七、纹理更新操纵:更新替换原纹理的一部分数据
glTexSubImage2D(target,level,xOffset,yOffset,width,height,format,type,*data)
从颜色缓冲区中提取纹理作为数据去更新:
glCopyTexSubImage2D(target,level,xOffset,yOffset,width,height)
八、纹理对象的使用:由于使用glTexImage和glTexSubImage这样的函数加载和更新纹理太耗费内存,所以引用纹理对象
特点:纹理对象是允许我们一次加载一个以上的纹理状态(包括纹理图像)以及可以在它们之间快速切换的。
纹理对象的创建:glGenTextures(GLsizei n,GLuint* textures)
n:纹理对象数量
textures:不同纹理状态的句柄数组
纹理状态的绑定:glBindTexture(GLenum target,Gluint texture)
target:GL_TEXTURE_2D.....
texture:需要绑定的特定纹理状态
纹理对象的销毁:glDeleteTextures(n,textures)
纹理状态的确认:glIsTexure(GLuint texture)
九、纹理应用:
1、加载纹理数据
2、提供纹理坐标
s,t,r相当于x,y,z
3、设置纹理坐标的环绕模式(相对每个纹理坐标轴的)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT)
环绕模式:
GL_REPEAT:超出1.0的对纹理进行重复
GL_CLAMP:使用纹理边界或者既定设置的边界颜色
GL_CLAMP_EDGE:使用纹理单元的最后一行或者一列数据
GL_CLAMP_BORDER:使用边界纹理单元
4、设置纹理的过滤(相对于拉伸和缩小的)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
过滤模式:
GL_NEAREST:最邻近过滤,快速,但是如果纹理被拉伸过大会出现大片的斑驳像素
GL_LINEAR:线性过滤,开销大,但是效果比较好
十、综合运用的例子:可以旋转带光照纹理的金字塔
// Pyramid.cpp // OpenGL SuperBible, Chapter 5 // Demonstrates Texture mapping a pyramid // Program by Richard S. Wright Jr. #include <GLTools.h> // OpenGL toolkit #include <GLMatrixStack.h> #include <GLFrame.h> #include <GLFrustum.h> #include <GLBatch.h> #include <GLGeometryTransform.h> #include <math.h> #ifdef __APPLE__ #include <glut/glut.h> #else #define FREEGLUT_STATIC #include <GL/glut.h> #endif ///////////////////////////////////////////////////////////////////////////////// // An assortment of needed classes GLShaderManager shaderManager; GLMatrixStack modelViewMatrix; GLMatrixStack projectionMatrix; GLFrame cameraFrame; GLFrame objectFrame; GLFrustum viewFrustum; GLBatch pyramidBatch; GLuint textureID; GLGeometryTransform transformPipeline; M3DMatrix44f shadowMatrix; void MakePyramid(GLBatch& pyramidBatch) { pyramidBatch.Begin(GL_TRIANGLES, 18, 1); <span style="white-space:pre"> </span>//手动设置金字塔的顶点数据,包括位置,纹理坐标和光照法线向量 // Bottom of pyramid pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); pyramidBatch.Vertex3f(1.0f, -1.0f, -1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f); pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f); pyramidBatch.Vertex3f(-1.0f, -1.0f, 1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f); pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f); M3DVector3f vApex = { 0.0f, 1.0f, 0.0f }; M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f }; M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f }; M3DVector3f vBackLeft = { -1.0f, -1.0f, -1.0f }; M3DVector3f vBackRight = { 1.0f, -1.0f, -1.0f }; M3DVector3f n; // 根据三个点计算法线向量 m3dFindNormal(n, vApex, vFrontLeft, vFrontRight); pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f); pyramidBatch.Vertex3fv(vApex); // Apex pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3fv(vFrontLeft); // Front left corner pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); pyramidBatch.Vertex3fv(vFrontRight); // Front right corner m3dFindNormal(n, vApex, vBackLeft, vFrontLeft); pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f); pyramidBatch.Vertex3fv(vApex); // Apex pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); pyramidBatch.Vertex3fv(vBackLeft); // Back left corner pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3fv(vFrontLeft); // Front left corner m3dFindNormal(n, vApex, vFrontRight, vBackRight); pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f); pyramidBatch.Vertex3fv(vApex); // Apex pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); pyramidBatch.Vertex3fv(vFrontRight); // Front right corner pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3fv(vBackRight); // Back right cornder m3dFindNormal(n, vApex, vBackRight, vBackLeft); pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f); pyramidBatch.Vertex3fv(vApex); // Apex pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3fv(vBackRight); // Back right cornder pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); pyramidBatch.Vertex3fv(vBackLeft); // Back left corner pyramidBatch.End(); } //获取纹理图像数据,并且设置纹理参数并得到一个纹理状态放入纹理对象中 bool loadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode) { GLbyte *pBits; int nWidth,nHeight,nComponents; GLenum eFormat; pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat); if(pBits == NULL) return false; <span style="white-space:pre"> </span>//S,T轴上的纹理环绕模式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode); <span style="white-space:pre"> </span>//放大和缩小的过滤 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,minFilter); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,magFilter); glPixelStorei(GL_UNPACK_ALIGNMENT,1); //图像数据解包,从内存区到缓存区 glTexImage2D(GL_TEXTURE_2D,0,nComponents,nWidth,nHeight,0,eFormat,GL_UNSIGNED_BYTE,pBits); free(pBits); if(minFilter == GL_LINEAR_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_NEAREST_MIPMAP_NEAREST) glGenerateMipmap(GL_TEXTURE_2D); return true; } void SetupRC(){ glClearColor(0.7f,0.7f,0.7f,1.0f); shaderManager.InitializeStockShaders(); glEnable(GL_DEPTH_TEST); glGenTextures(1,&textureID); glBindTexture(GL_TEXTURE_2D,textureID); loadTGATexture("stone.tga",GL_LINEAR,GL_LINEAR,GL_CLAMP_TO_EDGE); MakePyramid(pyramidBatch); <span style="white-space:pre"> </span>//场景的照相机 cameraFrame.MoveForward(-7.0f); } void ShutdownRC(){ glDeleteTextures(1,&textureID); } void RenderScene(){ static GLfloat vLightPos[] = {1.0f,1.0f,0.0f}; static GLfloat vWhite[] = {1.0f,1.0f,1.0f,1.0f}; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); modelViewMatrix.PushMatrix(); M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.MultMatrix(mCamera); M3DMatrix44f mObjectFrame; objectFrame.GetCameraMatrix(mObjectFrame); modelViewMatrix.MultMatrix(mObjectFrame); <span style="white-space:pre"> </span>//在提交批绘制的时候,绑定我们需要使用的纹理 glBindTexture(GL_TEXTURE_2D,textureID); shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(),vLightPos,vWhite,0); pyramidBatch.Draw(); modelViewMatrix.PopMatrix(); glutSwapBuffers(); } void SpecialKeys(int key,int x,int y){ if(key == GLUT_KEY_UP) objectFrame.RotateWorld(m3dDegToRad(-5.0f),1.0f,0.0f,0.0f); if(key == GLUT_KEY_DOWN) objectFrame.RotateWorld(m3dDegToRad(5.0f),1.0f,0.0f,0.0f); if(key == GLUT_KEY_LEFT) objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f); if(key == GLUT_KEY_RIGHT) objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f); glutPostRedisplay(); } void ChangeSize(int w,int h){ glViewport(0,0,w,h); viewFrustum.SetPerspective(35.0f,float(w)/float(h),1.0f,500.0f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); transformPipeline.SetMatrixStacks(modelViewMatrix,projectionMatrix); } int main(int argc, char* argv[]) { gltSetWorkingDirectory(argv[0]); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); glutInitWindowSize(800, 600); glutCreateWindow("Pyramid"); glutReshapeFunc(ChangeSize); glutSpecialFunc(SpecialKeys); glutDisplayFunc(RenderScene); GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } SetupRC(); glutMainLoop(); ShutdownRC(); return 0; }