尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
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示例基础上扩展代码如下#includesphereworld5.h#includeGLTools.h#includeGLShaderManager.h#includeGLFrustum.h#includeGLBatch.h#includeGLMatrixStack.h#includeGLGeometryTransform.h#includeStopWatch.h#includemath.h#includestdio.h#ifndefFREEGLUT_STATIC#defineFREEGLUT_STATIC#endif#includeGL/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(inti0;iNUM_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;pBitsgltReadTGABits(szFileName,nWidth,nHeight,nComponents,eFormat);if(pBitsNULL)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(minFilterGL_LINEAR_MIPMAP_LINEAR||minFilterGL_LINEAR_MIPMAP_NEAREST||minFilterGL_NEAREST_MIPMAP_LINEAR||minFilterGL_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 texSize10.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(inti0;iNUM_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;floatyRotrotTimer.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){floatlinear0.1f;floatangularfloat(m3dDegToRad(5.0f));if(keyGLUT_KEY_UP)cameraFrame.MoveForward(linear);if(keyGLUT_KEY_DOWN)cameraFrame.MoveForward(-linear);if(keyGLUT_KEY_LEFT)cameraFrame.RotateWorld(angular,0.0f,1.0f,0.0f);if(keyGLUT_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;}}效果预览
RELATED

相关推荐

WPF MVVM模式下关闭窗体的四种实现方案与最佳实践

WPF MVVM模式下关闭窗体的四种实现方案与最佳实践

1. 项目概述:为什么MVVM模式下关闭窗体是个“问题”? 刚接触WPF MVVM模式的朋友,十有八九会在“关闭窗体”这个看似简单的操作上卡壳。在传统的WinForm或事件驱动编程里,一句 this.Close() 就搞定了,但在MVVM的世界里…

📅 2026/9/1 19:42:37
RedHat系Linux镜像源配置全攻略:从原理到实战,解决yum/dnf慢与内网部署

RedHat系Linux镜像源配置全攻略:从原理到实战,解决yum/dnf慢与内网部署

1. 项目概述:为什么我们需要关注RedHat的镜像源?如果你在运维RedHat系列(包括RHEL、CentOS、Rocky Linux、AlmaLinux等)的服务器,或者正在学习Linux系统管理,那么“yum源”这个词你一定不陌生。它就像是Lin…

📅 2026/9/2 2:15:21
112.ABAP ALV GRID 自定义字段目录开发详解

112.ABAP ALV GRID 自定义字段目录开发详解

摘要 SAP系统是企业级ERP的标杆,其底层开发语言ABAP(Advanced Business Application Programming)是理解SAP生态的钥匙。本文不讨论SAP GUI的鼠标操作,而是从工程化视角切入,系统拆解ABAP的数据类型体系、内表(Internal Table)内存模型、Open SQL与RFC通信机制。通过一…

📅 2026/9/17 20:52:02
MORE NEWS

更多资讯

📰

智能车竞赛芯片选型指南:从主频、资源到双核与生态的决策链

1. 为什么第十五届的“芯片选型”忽然成了所有人绕不开的话题从第十五届备赛周期开始,智能车竞赛里的一个趋势变得非常明显:你打开官方通知后,第一件事不再是去翻上届学长传下来的代码,而是先去看“主控芯片”那一栏还能不能沿用老…

📰

MCP Kubernetes Server 实战:用 TaoToken 统一 Key 打通集群管理工具链

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

全球开源榜第一的国产模型实测:用 TaoToken 统一 Key 跑通 MiniMax M2 Agent 编程链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬