当前位置: 首页 > news >正文

OpenGL(十四)- 压缩纹理

压缩纹理

为了利用OpenGL对压缩纹理的支持,纹理数据一开始并不需要进行压缩。

我们可以在加载一幅纹理图像时请求OpenGL对它进行压缩,这是通过在glTexImage函数中设置internalFormat参数实现的。可选参数如下:

通过这种方式进行图像压缩增加了纹理加载的开销,但却能够通过更有效地使用纹理存储空间来增加纹理性能。

如果由于某些原因而无法对纹理进行压缩,OpenGL就会使用上表所列出的基本内部格式,并加载未经压缩的纹理。

当我们试图按照这种方式加载并压缩一个纹理时,可以使用glGetTexLevelParameteriv函数(以GL_TEXTURE_COMPRESSED为参数)来判断这个纹理是否被成功压缩。

GLint compFlag;……glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_COMPRESSED,&compFlag);

glGetTexLevelParameteriv函数可以接受几个新的参数名,它们都和压缩纹理有关。

当纹理进行压缩之后,OpenGL会选择最适当的纹理压缩格式。

我们可以使用glHint指定希望OpenGL根据最快速度还是最佳质量算法来选择压缩格式。

glHint(GL_TEXTURE_COMPRESSION_HINT,GL_FASTEST);glHint(GL_TEXTURE_COMPRESSION_HINT,GL_NICEST);glHint(GL_TEXTURE_COMPRESSION_HINT,GL_DONT_CARE);

加载压缩纹理

用glGetCompressedTexImage函数(相当于未压缩纹理的glTexImage函数)提取经过压缩的数据并把它保存到磁盘中。在后续的纹理加载中,可以使用原始压缩数据,从而极大地提高纹理的加载速度。

为了加载预先经过压缩的纹理数据,可以使用下列函数:

voidglCompressedTexImage1D(GLenum target,GLint level,GLenum internalFormat,GLsizei width,GLint border,GLsizei imageSize,void*data);voidglCompressedTexImage2D(GLenum target,GLint level,GLenum internalFormat,GLsizei width,GLsizei height,GLint border,GLsizei imageSize,void*data);voidglCompressedTexImage3D(GLenum target,GLint level,GLenum internalFormat,GLsizei width,GLsizei height,GLsizei depth,GLint border,Glsizei imageSize,GLvoid*data);

纹理压缩是一种非常流行的纹理特性。较小的纹理所占据的空间更小、通过网络传输的速度更快、从磁盘加载的速度更快、复制到图形内存也更加快速,并且允许更多的纹理加载到硬件中,而且使纹理的启用更加快速!

但是,不要忘了,和生活中的很多事情一样,天下没有免费的午餐。

使用纹理压缩也要付出一些代价。例如,GL_EXT_texture_compression_s3tc方法是通过从每个纹理单元提取颜色数据进行工作的。

对于有些纹理,这样可能会导致图像质量的损失(尤其是那些包含了平滑颜色过渡的纹理)。

在其他一些时候,具有大量细节的纹理在视觉上几乎与未压缩的源纹理相同,颜色的变化几乎无法察觉。

纹理压缩方法的选择(或选择不使用纹理压缩)可能极大地依赖于底层图像的本质。

示例

在此前分享的SphereWorld示例基础上扩展,代码如下:

#include"sphereworld5.h"#include<GLTools.h>#include<GLShaderManager.h>#include<GLFrustum.h>#include<GLBatch.h>#include<GLMatrixStack.h>#include<GLGeometryTransform.h>#include<StopWatch.h>#include<math.h>#include<stdio.h>#ifndefFREEGLUT_STATIC#defineFREEGLUT_STATIC#endif#include<GL/glut.h>#defineNUM_SPHERES50namespacesphereworld5{GLFrame spheres[NUM_SPHERES];GLShaderManager shaderManager;GLMatrixStack modelViewMatrix;GLMatrixStack projectionMatrix;GLFrustum viewFrustum;GLGeometryTransform transformPipeline;GLFrame cameraFrame;GLTriangleBatch torusBatch;GLTriangleBatch sphereBatch;GLBatch floorBatch;GLuint uiTextures[3];voidDrawSongAndDance(floatyRot){staticGLfloat vWhite[]={1.0f,1.0f,1.0f,1.0f};staticGLfloat vLightPos[]={0.0f,3.0f,0.0f,1.0f};// 获取眼空间中的光源位置M3DVector4f vLightTransformed;M3DMatrix44f mCamera;modelViewMatrix.GetMatrix(mCamera);m3dTransformVector4(vLightTransformed,vLightPos,mCamera);// 绘制光源modelViewMatrix.PushMatrix();modelViewMatrix.Translatev(vLightPos);shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vWhite);sphereBatch.Draw();modelViewMatrix.PopMatrix();glBindTexture(GL_TEXTURE_2D,uiTextures[2]);for(inti=0;i<NUM_SPHERES;i++){modelViewMatrix.PushMatrix();modelViewMatrix.MultMatrix(spheres[i]);shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),transformPipeline.GetProjectionMatrix(),vLightTransformed,vWhite,0);sphereBatch.Draw();modelViewMatrix.PopMatrix();}modelViewMatrix.Translate(0.0f,0.2f,-2.5f);modelViewMatrix.PushMatrix();modelViewMatrix.Rotate(yRot,0.0f,1.0f,0.0f);// 绘制与相机相关的内容glBindTexture(GL_TEXTURE_2D,uiTextures[1]);shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),transformPipeline.GetProjectionMatrix(),vLightTransformed,vWhite,0);torusBatch.Draw();modelViewMatrix.PopMatrix();modelViewMatrix.Rotate(yRot*-2.0f,0.0f,1.0f,0.0f);modelViewMatrix.Translate(0.8f,0.0f,0.0f);glBindTexture(GL_TEXTURE_2D,uiTextures[2]);shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),transformPipeline.GetProjectionMatrix(),vLightTransformed,vWhite,0);sphereBatch.Draw();}boolLoadTGATexture(constchar*szFileName,unsignedintminFilter,unsignedintmagFilter,unsignedintwrapMode){GLbyte*pBits;intnWidth,nHeight,nComponents;GLenum eFormat;pBits=gltReadTGABits(szFileName,&nWidth,&nHeight,&nComponents,&eFormat);if(pBits==NULL)returnfalse;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)glGenerateMipmap(GL_TEXTURE_2D);returntrue;}voidSetupRC(){glewInit();shaderManager.InitializeStockShaders();glEnable(GL_DEPTH_TEST);glEnable(GL_CULL_FACE);glClearColor(0.0f,0.0f,0.0f,1.0f);gltMakeTorus(torusBatch,0.4f,0.15f,40,20);gltMakeSphere(sphereBatch,0.1f,26,13);GLfloat texSize=10.0f;floorBatch.Begin(GL_TRIANGLE_FAN,4,1);floorBatch.MultiTexCoord2f(0,0.0f,0.0f);floorBatch.Vertex3f(-20.0f,-0.41f,20.0f);floorBatch.MultiTexCoord2f(0,texSize,0.0f);floorBatch.Vertex3f(20.0f,-0.41f,20.0f);floorBatch.MultiTexCoord2f(0,texSize,texSize);floorBatch.Vertex3f(20.0f,-0.41f,-20.0f);floorBatch.MultiTexCoord2f(0,0.0f,texSize);floorBatch.Vertex3f(-20.0f,-0.41f,-20.0f);floorBatch.End();glGenTextures(3,uiTextures);glBindTexture(GL_TEXTURE_2D,uiTextures[0]);LoadTGATexture("./src/chapter_5/src/SphereWorld/marble.tga",GL_LINEAR_MIPMAP_LINEAR,GL_LINEAR,GL_REPEAT);glBindTexture(GL_TEXTURE_2D,uiTextures[1]);LoadTGATexture("./src/chapter_5/src/SphereWorld/marslike.tga",GL_LINEAR_MIPMAP_LINEAR,GL_LINEAR,GL_CLAMP_TO_EDGE);glBindTexture(GL_TEXTURE_2D,uiTextures[2]);LoadTGATexture("./src/chapter_5/src/SphereWorld/moonlike.tga",GL_LINEAR_MIPMAP_LINEAR,GL_LINEAR,GL_CLAMP_TO_EDGE);for(inti=0;i<NUM_SPHERES;i++){GLfloat x=((GLfloat)((rand()%400)-200)*0.1f);GLfloat z=((GLfloat)((rand()%400)-200)*0.1f);spheres[i].SetOrigin(x,0.0f,z);}}voidShutdownRC(){glDeleteTextures(3,uiTextures);}voidRenderScene(){staticCStopWatch rotTimer;floatyRot=rotTimer.GetElapsedSeconds()*60.0f;glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);modelViewMatrix.PushMatrix();M3DMatrix44f mCamera;cameraFrame.GetCameraMatrix(mCamera);modelViewMatrix.MultMatrix(mCamera);modelViewMatrix.PushMatrix();modelViewMatrix.Scale(1.0f,-1.0f,1.0f);modelViewMatrix.Translate(0.0f,0.8f,0.0f);glFrontFace(GL_CW);DrawSongAndDance(yRot);glFrontFace(GL_CCW);modelViewMatrix.PopMatrix();glEnable(GL_BLEND);glBindTexture(GL_TEXTURE_2D,uiTextures[0]);glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);staticGLfloat vFloorColor[]={1.0f,1.0f,1.0f,0.75f};shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor,0);floorBatch.Draw();glDisable(GL_BLEND);DrawSongAndDance(yRot);modelViewMatrix.PopMatrix();glutSwapBuffers();glutPostRedisplay();}voidSpecialKeys(intkey,intx,inty){floatlinear=0.1f;floatangular=float(m3dDegToRad(5.0f));if(key==GLUT_KEY_UP)cameraFrame.MoveForward(linear);if(key==GLUT_KEY_DOWN)cameraFrame.MoveForward(-linear);if(key==GLUT_KEY_LEFT)cameraFrame.RotateWorld(angular,0.0f,1.0f,0.0f);if(key==GLUT_KEY_RIGHT)cameraFrame.RotateWorld(-angular,0.0f,1.0f,0.0f);}voidChangeSize(intw,inth){glViewport(0,0,w,h);transformPipeline.SetMatrixStacks(modelViewMatrix,projectionMatrix);viewFrustum.SetPerspective(35.0f,float(w)/float(h),1.0f,100.0f);projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());modelViewMatrix.LoadIdentity();}intsphereworld5_test(intargc,char*argv[]){gltSetWorkingDirectory(argv[0]);glutInit(&argc,argv);glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);glutInitWindowSize(800,600);glutCreateWindow("OpenGL SphereWorld");glutReshapeFunc(ChangeSize);glutDisplayFunc(RenderScene);glutSpecialFunc(SpecialKeys);SetupRC();glutMainLoop();ShutdownRC();return0;}}

效果预览:

http://www.jsqmd.com/news/1380225/

相关文章:

  • 湖州装修公司实战核验,2026年如何规避家装主流套路? - 优企甄选
  • 解剖 AI 黑盒:用概念瓶颈模型 (CBM) 为深度学习植入「可解释大脑」
  • C++与C语言核心差异解析:从过程式到多范式编程的思维升级
  • 机械设备KC认证服务解析:沃德检测机械安全实验室 - 生活动态圈
  • TLPI 第30 章 练习:Threads: Thread Synchronization
  • 5分钟掌握Minemap:无需安装Minecraft的地图查看器实战指南
  • Ansible自动化部署Node Exporter:运维监控的标准化实践
  • 模糊控制算法完整详解(C# 原生实现,无第三方库)
  • 202页满分PPT | 某生物产业园区产业生态圈整体分析报告
  • Unity项目上传GitHub全攻略:从.gitignore配置到可复现仓库搭建
  • Vite工程化前端集成Qwen Image多模态生图模型实战指南
  • 2026 苏州服装出口美国新规!合规物流避免货物扣留退运 - 生活动态圈
  • 量子场论与元初混沌一气对称规则对照
  • 微服务网关登录校验与JWT实战配置
  • 驾校网站建设方案如何打造高转化招生平台?全方位解析驾校网站建设方案落地实施
  • 【2014-04-04】【转】OpenGL ES 混合的理解
  • HS2汉化补丁完整指南:15分钟快速实现游戏中文界面
  • 新手也能上手 AI论文网站推荐:2026最新测评与对比
  • Vibe Coding:重塑前端开发体验的现代范式与实践指南
  • 低脂鱼丸哪家品质好:【深鲜季】配方清爽 - 17728098551
  • 大型品牌如何审核TikTok代运营报价?账号矩阵、本地化与KOC费用完整拆解及采购重点
  • 深入理解计算机系统原理与性能优化实战
  • 【2014-05-19】某《魔鬼训练营》读书笔记:msfpayload的使用及免杀工具
  • Linux PipeWire深度解析之pw_properties_new_dict调用流程与实战(五十七)
  • 神州数码交换机配置实战:从VLAN划分到安全策略全解析
  • Linux 终端命令速查表 -- 07 文件与文件夹速查表
  • LangGraph核心三要素与智能体构建实战:从状态管理到复杂工作流编排
  • 《专利法》规定,专利申请必须提交至国家知识产权局(CNIPA),由其依法进行形式审查和实质审查
  • BilibiliDown终极指南:如何轻松下载B站视频与高质量音频
  • 实点科技5系列一体式I/O EI5R模块介绍