洞察探索如何利用兼容微信生态的小程序容器,实现跨平台开发,助力金融和车联网行业的数字化转型。
1323
2022-11-20
OpenGL:纹理基本概念和参数
前言
在openGL使用纹理贴图时:发现很多关于纹理很多参数和概念不清楚先整理一下
原始图像数据 像素包装 图像数据在内存中很少以紧密包装的形式存在。在许多硬件平台上,处于性能上的考虑,一幅图像的每一行都应该从一种特定字节对齐地址开始。绝大多数编译器会自动把变量和缓冲区放置在一个针对该架构对齐优化的地址上。 例如一个包含3个分量的rgb图像,每个分量存储在一个字节中,如果图像有199个像素,那么一行需要597个像素。如果硬件本身的体系结构是4字节排列,那么图像每一行的末尾将由额外的3个空字符进行填充达到600字节。 我们可以使用下列函数改变或者回复像素的存储方式。
void glPixelStorei(GLenum pname,Glint param);void glPixelStoref(GLenum pname,GLfloat param);
例如,改成紧密包装(文件格式以1个字节排列,没有补齐):
glPixelStorei(GL_UNPACK_ALLGNMENT,1);
其中GL_UNPACK_ALIGNMENT指定OpenGL如何从数据缓冲区中解包图像数据。 glPixelStore参数
参数名 类型 初始值 GL_PACK_SWAP_BYTES GLboolean GL_FALSE GL_UNPACK_SWAP_BYTES GLboolean GL_FALSE GL_PACK_LSB_FIRST GLboolean GL_FALSE GL_UNPACK_LSB_FIRST GLboolean GL_FALSE GL_PACK_ROW_LENGTH GLint 0 GL_UNPACK_ROW_LENGTH GLint 0 GL_PACK_SKIP_ROWS GLint 0 GL_UNPACK_SKIP_ROWS GLint 0 GL_PACK_SKIP_PIXELS GLint 0 GL_UNPACK_SKIP_PIXELS GLint 0 GL_PACK_ALIGNMENT GLint 4 GL_UNPACK_ALIGNMENT GLint 4 GL_PACK_IMAGE_HEIGHT GLint 0 GL_UNPACK_IMAGE_HEIGHT GLint 0 GL_PACK_SKIP_IMAGES GLint 0 GL_UNPACK_SKIP_IMAGES GLint 0 像素图 每个像素需要一个以上的存储位来表示,附加位允许存储强度(亮度)。在OpenGL核心版本中,我们无法直接将一个像素图绘制到颜色缓冲区中,但是可以使用下面的函数将颜色缓冲区的内容作为像素图直接读取。
void glReadPixels(Glint x,Glint y,GLSizei width,GLSizei height,GLenum format,GLenum type,const void *pixels);
我们将x和y值指定为矩形左下角的窗口坐标,然后再指定矩形的width和height值(像素形式)。如果颜色缓冲区存储的数据与我们要求的不同,OpenGL将负责进行必要的转换。 第4个变量format指定pixels指向的数据元素的颜色布局,如下表:
OpenGL像素格式 常量 描述 GL_RGB 按照红、绿、蓝顺序排列的颜色 GL_RGBA 按照红、绿、蓝、Alpha顺序排列的颜色 GL_BGR 按照蓝、绿、红顺序排列的颜色 GL_BGRA 按照蓝、绿、红、Alpha顺序排列的颜色 GL_RED 每个像素值包含一个红色分量 GL_GREEN 每个像素值包含一个绿色分量 GL_BLUE 每个像素值包含一个蓝色分量 GL_RG 每个像素依次包含一个红色和一个绿色分量 GL_RED_INTEGER 每个像素包含一个整数形式的红色分量 GL_GREEN_INTEGER 每个像素包含一个整数形式的绿色分量 GL_BLUE_INTETER 每个像素包含一个整数形式的蓝色分量 GL_RG_INTEGER 每个玄素依次包含一个整数形式的红色和一个整数形式的绿色分量 GL_RGB_INTEGER 每个像素依次包含整数形式的红色、绿色和蓝色分量 GL_RGBA_INTEGER 每个像素一次包含整数形式的红色、绿色、蓝色和Alpha分量 GL_BGR_INTEGER 每个像素依次包含整数形式的蓝色、绿色和红色分量 GL_BGRA_INTEGER 每个像素依次包含整数形式的蓝色、绿色、红色和Alpha分量 GL_STENCIL_INDEX 每个像素只包含一个模板值 GL_DEPTH_COMPONENT 每个像素只包含一个深度值 GL_DEPTH_STENCIL 每个像素包含一个深度值和一个模板值 参数type解释参数*pixels指向的诗句,它告诉OpenGL使用缓冲区中的什么数据类型来存储颜色分量。如下表: 像素数据的数据类型
常量 描述 GL_UNSIGNED_BYTE 每种颜色分量都是一个8位无符号整数 GL_BYTE 8位有符号整数 GL_UNSIGNED_SHORT 16位无符号整数 GL_SHORT 16位有符号整数 GL_UNSIGNED_INT 32位无符号整数 GL_INT 32位有符号整数 GL_FLOAT 单精度浮点数 GL_HALF_FLOAT 半精度浮点数 GL_UNSIGNED_BYTE_3_2_2 包装的RGB值 GL_UNSIGNED_BYTE_2_3_3_REV 包装的RGB值 GL_UNSIGNED_SHORT_5_6_5 包装的RGB值 GL_UNSIGNED_SHORT_5_6_5_REV 包装的RGB值 GL_UNSIGNED_SHORT_4_4_4_4 包装的RGB值 GL_UNSIGNED_SHORT_4_4_4_4_REV 包装的RGB值 GL_UNSIGNED_SHORT_5_5_5_1 包装的RGB值 GL_UNSIGNED_SHORT_1_5_5_5_REV 包装的RGB值 GL_UNSIGNED_INT_8_8_8_8 包装的RGB值 GL_UNSIGNED_INT_8_8_8_8_REV 包装的RGB值 GL_UNSIGNED_INT_10_10_10_2 包装的RGB值 GL_UNSIGNED_INT_2_10_10_10_REV 包装的RGB值 GL_UNSIGNED_INT_24_8 包装的RGB值 GL_UNSIGNED_INT_10F_11F_REV 包装的RGB值 GL_FLOAT_24_UNSIGNED_INT_24_8_REV 包装的RGB值 glReadPixels从图形硬件中复制数据,通常通过总线传输到系统内存。在这种情况下,应用程序将被阻塞,直到内存传输完成。此外,如果我们制定一个与图形硬件的本地排列不同的像素不具,那么在数据进行重定格式时将产生额外的性能开销。
包装的像素格式 默认情况下,对于glReadPixels函数来说,读取操作在双缓冲区渲染环境下将在后台缓冲区进行,而在单缓冲区渲染环境下则在前台缓冲区进行。我们可以用下面的函数改变这些像素操作的源。 void glReadBuffer(GLenum mode); 模式参数可以取GL_FRONT、GL_BACK、GL_LEFT、GL_RIGHT、GL_FRONT_LEFT、GL_FRONT_RIGHT、GL_BACK_LEFT、GL_BACK_RIGHT或者甚至是GL_NONE中的任意一个。
保存像素 GLTools库中的gltWriteTGA函数从前台颜色缓冲区中读取颜色数据,并将这些数据存储到一个Targa文件格式的图像文件中。
GLint gltWriteTGA(const char *szFileName){ FILE *pFile; // 文件指针 TGAHEADER tgaHeader; // tga文件头 unsigned long lImageSize; // 图像的大小 GLbyte *pBits = NULL; // 图像数据 GLint iViewport[4]; // 视口 GLenum lastBuffer; // 保存当前读取缓冲区的设置 // 取得当前视口大小 glGetIntegerv(GL_VIEWPORT, iViewport); // 获得图像大小,因为tga的图像数据是紧密包装的,所以用视口的宽高乘以3个字节 lImageSize = iViewport[2] * 3 * iViewport[3]; // 分配内存用于存储读取出来的图像数据 pBits = (GLbyte *)malloc(lImageSize); if(pBits == NULL) return 0; // 设置为逐个像素的方式读取 glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); // 保存当前的设置,后面再恢复它 glGetIntegerv(GL_READ_BUFFER, (GLint *)&lastBuffer); glReadBuffer(GL_FRONT); glReadPixels(0, 0, iViewport[2], iViewport[3], GL_BGR_EXT, GL_UNSIGNED_BYTE, pBits); glReadBuffer(lastBuffer); // 初始化tag文件头的格式 tgaHeader.identsize = 0; tgaHeader.colorMapType = 0; tgaHeader.imageType = 2; tgaHeader.colorMapStart = 0; tgaHeader.colorMapLength = 0; tgaHeader.colorMapBits = 0; tgaHeader.xstart = 0; tgaHeader.ystart = 0; tgaHeader.width = iViewport[2]; tgaHeader.height = iViewport[3]; tgaHeader.bits = 24; tgaHeader.descriptor = 0; // 苹果操作需要,进行大小端的转换#ifdef __APPLE__ LITTLE_ENDIAN_WORD(&tgaHeader.colorMapStart); LITTLE_ENDIAN_WORD(&tgaHeader.colorMapLength); LITTLE_ENDIAN_WORD(&tgaHeader.xstart); LITTLE_ENDIAN_WORD(&tgaHeader.ystart); LITTLE_ENDIAN_WORD(&tgaHeader.width); LITTLE_ENDIAN_WORD(&tgaHeader.height);#endif // 打开文件 pFile = fopen(szFileName, "wb"); if(pFile == NULL) { free(pBits); return 0; } // 写文件头 fwrite(&tgaHeader, sizeof(TGAHEADER), 1, pFile); // 写图像数据 fwrite(pBits, lImageSize, 1, pFile); // 释放临时分配的内存空间 free(pBits); fclose(pFile); // 成功了 return 1;}
读取像素gltReadTGABits从磁盘中载入Targa文件。GLbyte *gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat){ FILE *pFile; // 文件指针 TGAHEADER tgaHeader; // TGA 文件头 unsigned long lImageSize; // 图像的大小,用字节表示 short sDepth; // 像素深度 GLbyte *pBits = NULL; // 指向位的指针 // 默认/失败值 *iWidth = 0; *iHeight = 0; *eFormat = GL_BGR_EXT; *iComponents = GL_RGB; // 尝试打开文件 pFile = fopen(szFileName, "rb"); if(pFile == NULL) return NULL; // 读入文件(二进制) fread(&tgaHeader, 18/* sizeof(TGAHEADER)*/, 1, pFile); // 为大小字节存储顺序问题而进行字节交换#ifdef __APPLE__ LITTLE_ENDIAN_WORD(&tgaHeader.colorMapStart); LITTLE_ENDIAN_WORD(&tgaHeader.colorMapLength); LITTLE_ENDIAN_WORD(&tgaHeader.xstart); LITTLE_ENDIAN_WORD(&tgaHeader.ystart); LITTLE_ENDIAN_WORD(&tgaHeader.width); LITTLE_ENDIAN_WORD(&tgaHeader.height);#endif // 获取纹理的宽度、高度和深度 *iWidth = tgaHeader.width; *iHeight = tgaHeader.height; sDepth = tgaHeader.bits / 8; // 这里进行一些有效性检验,非常简单,我们只要懂得或者说关心8位、24位或32位 //的targa if(tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32) return NULL; // 计算图像缓冲区的大小 lImageSize = tgaHeader.width * tgaHeader.height * sDepth; // 进行内存定位并进行成功检验 pBits = (GLbyte*)malloc(lImageSize * sizeof(GLbyte)); if(pBits == NULL) return NULL; // 读入位 // 检查读取错误。这项操作应该发现RLE或者其他我们不想识别的奇怪格式 if(fread(pBits, lImageSize, 1, pFile) != 1) { free(pBits); return NULL; } // 设置希望的OpenGL格式 switch(sDepth) { case 3: // 最可能的情况 *eFormat = GL_BGR; *iComponents = GL_RGB; break; case 4: *eFormat = GL_BGRA_EXT; *iComponents = GL_RGBA8; break; case 1: *eFormat = GL_LUMINANCE; *iComponents = GL_LUMINANCE8;break;default: // RGB// 如果是在iPhone上TGA为BGR,并且iPhone不支持没有Alpha的BGR,//但是它支持RGB,所以只要将红色和蓝色调整一下就能满足要求。//但是为了加快iPhone的载入速度,请保存带有Alpha的TGA。#ifdef OPENGL_ES for(int i=0;i 载入纹理 有3个OpenGL函数最经常用来从存储器缓冲区中载入(比如说,从一个磁盘文件中读取)纹理数据。 void glTexImage1D(GLenum target,Glint level,Glint internalformat,GLsizei width,Glint border,GLenum format,GLenum type,void *data);void glTexImage2D(GLenum target,Glint level,Glint internalformat,GLsizei width,GLsizei height,Glint border,GLenum format,GLenum type,void *data);void glTexImage3D(GLenum target,Glint level,Glint internalformat,GLsizei width,GLsizei height,GLsizei depth,Glint border,GLenum format,GLenum type,void *data); 这些函数中的target变量应分别为GL_TEXTURE_1D、GL_TEXTURE_2D或GL_TEXTURE_3D。我们也可以指定代理纹理(Proxy texture),方法是指定GL_PROXY_TEXTURE_1D、GL_PROXY_TEXTURE_2D或GL_PROXY_TEXTURE_3D,并使用glGetTexPatameter函数提取代理查询的结果。 Level参数指定了这些函数所加在的mip贴图层次。 internalformat参数告诉OpenGL我们希望在每个纹理单元中存储多少颜色成分,并在可能的情况下说明这些成分的存储大小,以及是否希望对纹理进行压缩。 最常用的纹理内部格式 常量 含义 GL_ALPHA 按照alpha值存储纹理单元 GL_LUMINANCE 按照亮度值存储纹理单元 GL_LUMINANCE_ALPHA 按照亮度值和alpha值存储纹理单元 GL_RGB 按照红、绿、蓝成分存储纹理单元 GL_RGBA 按照红、绿、蓝和alpha成分存储纹理单元 使用颜色缓冲区 一维和二维的纹理也可以从颜色缓冲区加在数据。我们可以从颜色缓冲区读取一幅图像,并通过下面这两个函数将它化为一个新的纹理使用。 void glCopyTexImage1D(GLenum target,Glint level,GLenum internalformat,Glint x,Glint y,GLsizei width,Glint border);void glCopyTexImage2D(GLenum target,Glint level,GLenum internalformat,Glint x,Glint y,GLsizei width,GLsizei height,Glint border); 这两个函数的操作类似于glTexImage,但在这里x和y在颜色缓冲区中指定了开始读取纹理数据的位置。源缓冲区是通过glReadBuffer函数设置的。并不存在glCopyTexImage3D。 更新纹理 替换一个纹理图像常常要比直接使用glTexImage重新加载一个新纹理快得多: void glTexSubImage1D(GLenum target,Glint level,Glint xOffset,GLsizei width,GLenum format,GLenum type,const GLvoid *data);void glTexSubImage2D(GLenum target,Glint level,Glint xOffset,Glint yOffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const GLvoid *data);void glTexSubImage3D(GLenum target,Glint level,Glint xOffset,Glint yOffset,Glint zOffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const GLvoid *data); 下面函数允许沃恩从颜色缓冲区读取纹理,并插入或替换原来纹理的一部分。 void glCopyTexSubImage1D(GLenum target,Glint level,Glint xoffset,Glint x,Glint y,GLsizei width);void glCopyTexSubImage2D(GLenum target,Glint level,Glint xoffset,Glint yoffset,Glint x,Glint y,GLsizei width,GLsizei height);void glCopyTexSubImage3D(GLenum target,Glint level,Glint xoffset,Glint yoffset,Glint zoffset,Glint x,Glint y,GLsizei width,GLsizei height); 纹理对象 纹理对象允许我们一次加载一个以上的纹理状态(包括纹理图像),以及在它们之间快速切换。纹理状态是由当前绑定的纹理对象维护的,而纹理对象是由一个无符号整数标识的: 按所需加载纹理数量初始化纹理对象: void glGenTextures(GLsizei n,GLuint *textures); 为了绑定纹理状态,我们可以调用下面这个函数: void glBindTexture(GLenum target,GLuint texture); 为了删除纹理对象,可以调用下面这个函数: void glDeleteTextures(GLsizei n,GLuint *textures); 我们可以使用下面这个函数对纹理对象名(或句柄)进行测试,判断它们是否有效: GLboolean glIsTexture(GLuint texture); 如果这个证书是一个以前已经分配的纹理对象名,则返回GL_TRUE。 纹理应用 纹理坐标 典型情况下,纹理坐标是作为0.0到1.0范围内的浮点值指定的。纹理坐标命名为s、t、r和q,支持从一维到三维纹理坐标。 纹理参数 很多参数的应用都会影响渲染的规则和纹理贴图的行为,这些参数通过下列函数的变量来进行设置: void glTexParameterf(GLenum target,GLenum pname,GLfloat param);void glTexParamereri(GLenum target,GLenum pname,Glint param);void glTexParameterfv(GLenum target,GLenum pname,GLfloat *params);void glTexParameteriv(GLenum target,GLenum pname,Glint *params); 第一个参数target指定这些参数将要应用到哪个纹理模式上,它可以是GL_TEXTURE_1D、GL_TEXTURE_2D和GL_TEXTURE_3D.第二个参数pname指定了需要设置哪个纹理参数,而最后一个参数param或params用于设置特定的纹理参数的值。 基本过滤 根据一个拉伸或收缩的纹理贴图计算颜色片段的过程称为纹理过滤。使用OpenGL的纹理参数函数,可以同事设置放大和缩小过滤器。这两种过滤器的参数名分别是GL_TEXTURE_MAG_FILTER和GL_TEXTURE_MIN_FILTER。就目前来说,我们可以为他们从两种基本的纹理过滤器GL_NEAREST和GL_LINEAR中进行选择,它们分别对应于最邻近过滤和线性过滤。 我们可以使用下面这两个函数,为放大和缩小过滤器设置纹理过滤器: glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 我们可以使用下面这几行代码,简单地设置线性过滤: glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 纹理环绕 我们可以调glTexParameteri函数(并分别使用GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T或GL_TEXTURE_WRAP_R作为参数)、为每个坐标分别设置环绕模式。然后,我们可以把环绕模式设置为下面几个值之一:GL_REPEAT、GL_CLAMT、GL_CLAMP_TO_EDGE或GL_CLAMP_TO_BORDER。 综合运用 加载纹理 GLuint textureID;glGenTextures(1,&textureID);glBindTexture(GL_TEXTURE_2D,textureID);loadTGATexture(“stone.tga”,GL_LINEAR,GL_LINEAR,GL_CLAMP_TO_EDGE); 其中,加载纹理的loadTGATexture定义如下: 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; //设置放大和缩小过滤 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode); //设置线性过滤 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, GL_COMPRESSED_RGB, 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) //生成Mip层 glGenerateMipmap(GL_TEXTURE_2D); return true;} 指定纹理坐标 添加顶点: pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f); 为一个面计算表面法线,然后再在所有3个顶点使用它: m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);pyramidBatch.Normal3fv(n);pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);pyramidBatch.Vertex3fv(vApex); pyramidBatch.Normal3fv(n);pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);pyramidBatch.Vertex3fv(vFrontLeft); pyramidBatch.Normal3fv(n);pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);pyramidBatch.Vertex3fv(vFrontRight); 实际渲染: glBindTexture(GL_TEXTURE_2D, textureID);shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vWhite, 0);pyramidBatch.Draw(); Mip贴图 Mip贴图纹理由一些列纹理图像组成,每个图像大小在每个轴的方向上都缩小一半。 如果想指定只加载0层至第4层,应如下操作: glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVEL,0);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL,4); Mip贴图过滤 经过Mip贴图的纹理过滤 常量 描述 GL_NEAREST 在Mip基层上执行最邻近过滤 GL_LINEAR 在Mip基层上执行线性过滤 GL_NEAREST_MIPMAP_NEAREST 选择最邻近Mip层,并执行最邻近过滤 GL_NEAREST_MIPMAP_LINEAR 在Mip层之间执行线性插补,并执行最邻近过滤 GL_LINEAR_MIPMAP_NEAREST 选择最邻近Mip层,并执行线性过滤 GL_LINEAR_MIPMAP_LINEAR 在Mip层之间执行线性插补,并执行线性过滤,又称三线性Mip贴图 生成Mip层 void glGenerateMipmap(GLenum target); 目标参数可以是GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D、GL_TEXTURE_CUBE_MAP、GL_TEXTURE_1D_ARRAY或GL_TEXTURE_2D_ARRAY 各项异性过滤 首先,必须确认这种扩展是得到支持的: if(gltIsExtSupported(“GL_EXT_texture_filter_anisotropic”)); 然后,查询得到支持的各向异性过滤的最大数量: GLfloat fLargest; …… …… glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&fLargest); 最后,设置想要应用的各向异性过滤的数量: glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,fLargest); 纹理压缩 压缩纹理 纹理压缩是通过在glTexImage函数中把internalFormat参数设置为下表的任意值实现的: 通用压缩纹理格式 压缩格式 基本内部格式 GL_COMPRESSED_RGB GL_RGB GL_COMPRESSED_RGBA GL_RGBA GL_COMPRESSED_SRGB GL_RGB GL_COMPRESSED_SRGB_ALPHA GL_RGBA GL_COMPRESSED_RED GL_RED GL_COMPRESSED_RG GL_RG(Red Green) 可以用如下方法来判断这个纹理是否被成功压缩: Glint compFlag; …… glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_COMPRESSED,&compFlag); glGetTexLevelParameter函数提取的压缩纹理格式 参数 返回 GL_TEXTURE_COMPRESSED 如果纹理被压缩,返回1,否则返回0 GL_TEXTURE_COMPRESSED_IMAGE_SIZE 压缩后的纹理的大小(以字节为单位) GL_TEXTURE_INTERNAL_FORMAT 所使用的压缩格式 GL_NUM_COMPRESSED_TEXTURE_FORMATS 受支持的研所为例格式的数量 GL_COMPRESSED_TEXTURE_FORMATS 一个包含了一些常量值的数组,每个常量值对应于一种受支持的压缩纹理格式 GL_TEXTURE_COMPRESSION_HINT 纹理压缩提示的值(GL/NICEST/GL_FASTEST) 我们可以使用glHint指定希望OpenGL根据最快速度还是最佳质量算法来选择压缩格式: glHint(GL_TEXTURE_COMPRESSION_HINT,GL_FASTEST);glHint(GL_TEXTURE_COMPRESSION_HINT,GL_NICEST);glHint(GL_TEXTURE_COMPRESSION_HINT,GL_DONT_CARE); GL_EXT_texture_conpression_s3tc的压缩格式 格式 描述 GL_COMPRESSED_RGB_S3TC_DXT1 RGB数据被压缩alpha值时钟是1.0 GL_COMPRESSED_RGBA_S3TC_DXT1 RGB数据被压缩,alpha值是1.0或0.0 GL_COMPRESSED_RGBA_S3TC_DXT2 RGB数据被压缩,alpha值用4位存储 GL_COMPRESSED_RGBA_S3TC_DXT3 RGB数据被压缩,alpha值是一些8位置的加权平均值 加载压缩纹理 为了加载预先经过压缩的纹理数据,可以使用下列函数之一: void glCompressedTexImage1D(GLenum target,Glint level,GLenum internalFormat,GLsizei width,Glint border,GLsizei imageSize,void *data);void glCompressedTexImage2D(GLenum target,Glint level,GLenum internalFormat,GLsizei width,GLsizei height,Glint border,GLsizei imageSize,void *data);void glCompressedTexImage3D(GLenum target,Glint level,GLenum internalFormat,GLsizei width,GLsizei height,GLsizei depth,Glint border,GLsizei imageSize,GLvoid *data); 示例 为了显示纹理的使用,本示例在学习笔记3(注意:UseStockShader的第一个参数要改为GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF才能成功使用纹理 #include "glew/glew.h"#include "glfw/glfw3.h"#include "glm/glm.hpp"#include "glm/gtc/matrix_transform.hpp"#include "glm/gtc/type_ptr.hpp"#include "camera.h"#include "filesystem.h"#include "mesh.h"#include "model.h"#include "root_directory.h"#include "shader.h"#include "stb_image.h"#include (1)3.1.1.debug_quad.vs 顶点着色器程序 #version 450 corelayout (location = 0) in vec3 aPos;//layout (location = 1) in vec3 aNormal;layout (location = 1) in vec2 aTexCoords;out vec2 TexCoords;uniform mat4 model;uniform mat4 view;uniform mat4 projection;void main(){ TexCoords = aTexCoords;// gl_Position = vec4(aPos, 1.0f); gl_Position = projection * view * vec4(aPos, 1.0f);} 再来一张贴图 (2)3.1.1.debug_quad_depth.fs 片元着色器程序 #version 450 coreout vec4 FragColor;in vec2 TexCoords;uniform sampler2D depthMap;uniform float near_plane;uniform float far_plane;// required when using a perspective projection matrixfloat LinearizeDepth(float depth){ float z = depth * 2.0f - 1.0f; // Back to NDC return (2.0f * near_plane * far_plane) / (far_plane + near_plane - z *(far_plane - near_plane));}void main(){ float depthValue = texture(depthMap, TexCoords).r;// FragColor = vec4(vec3(LinearizeDepth(depthValue) / far_plane), 1.0f); // perspective FragColor = vec4(vec3(depthValue), 1.0f); // orthographic} 在来一张贴图 (3)3.1.1.shadow_mapping_depth.vs 顶点着色器程序 #version 450 corelayout (location = 0) in vec3 aPos;layout (location = 1) in vec2 aTexCoords;out vec2 TexCoords;uniform mat4 lightSpaceMatrix;uniform mat4 model;uniform sampler2D floorTexture;void main(){ TexCoords = aTexCoords; gl_Position = lightSpaceMatrix * model * vec4(aPos, 1.0f);} 再来一张贴图 (4)3.1.1.shadow_mapping_depth.fs 片元着色器程序 #version 450 coreout vec2 TexCoords;uniform sampler2D floorTexture;void main(){ //什么要注释?因为不需要片元着色器处理// gl_FragDepth = gl_FragCoord.z; // vec3 color = texture(floorTexture, TexCoords).rgb;// gl_FragColor = vec4(color, 1.0f); gl_FragDepth = gl_FragCoord.z; } 再来一张贴图 工程源码-: 参考
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~