OpenGl Mip贴图
2015-08-30 11:29
369 查看
Mip贴图可以用来提高游戏的性能,主要原理是把一张纹理图片按照一定侧尺寸缩放,生成一些列的图片,按照图片离照相机的距离的远近,再决定使用哪个图片
比如,离照相机远的使用小的 。
决定怎样使用mip贴图,取决于当前设置的mip贴图的过滤模式,mip贴图的过滤模式遵守GL_FILTER_MIPMAP_SELECTOR的形式,FILTER指定了被选择的Mip层将要使用的纹理过滤器,SELECTOR指定了如何选择Mip层,列如GL_LINEAR_MIPMAP_LINEAR表示,从最邻近的Mip层之间执行线性插值得到图片后,再执行线性过滤。
我们这一节要实现的效果如下图:
我们可以看到远处的砖块逐渐模糊,我们可以按键盘的方向键来进行行走
下面是代码实现
首先是要包含的头文件和全局变量
下面是主函数main
下面是窗口大小改变时的回调函数ChangeSize
下面是响应键盘方向键的函数SpecialKeys
下面是初始化函数SetupRC
下面是渲染函数RenderScene
下面是程序退出时的清理函数ShutdownRC
各向异性过滤
如果在进行纹理过滤时考虑了观察者的角度,那么这种方法就成为各向异性过滤
假如说你在观察一个三角形,三角形上有一点A,当从正面观察时,和从侧面观察时,A点的纹理数据的会有所不同,因为在生成A点的纹理数据时,会根据观察的
方向来采取周围纹理数据进行运算
在使用各向异性过滤模式之前,我们需要测试硬件支不支持这种过滤模式,我们可以使用函数gltIsExtSupported("GL_EXT_texture_filter_anisotropic")在检测,
返回1标示支持,0表示不支持,
我们使用函数 void GLAPIENTRY glGetFloatv (GLenum pname, GLfloat *params) 来得到最大支持的各向异性过滤的最大数量
我们使用函数 GLAPIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param) 来启用各向异性过滤模式
我们可以把渲染函数RenderScene中的代码
换成如下的代码,来使用各向异性过滤模式
下图是使用了各向异性过滤后的效果,比之前的清晰多了,但同时也有性能上的消耗
比如,离照相机远的使用小的 。
决定怎样使用mip贴图,取决于当前设置的mip贴图的过滤模式,mip贴图的过滤模式遵守GL_FILTER_MIPMAP_SELECTOR的形式,FILTER指定了被选择的Mip层将要使用的纹理过滤器,SELECTOR指定了如何选择Mip层,列如GL_LINEAR_MIPMAP_LINEAR表示,从最邻近的Mip层之间执行线性插值得到图片后,再执行线性过滤。
我们这一节要实现的效果如下图:
我们可以看到远处的砖块逐渐模糊,我们可以按键盘的方向键来进行行走
下面是代码实现
首先是要包含的头文件和全局变量
#include <GLTools.h> #include <GLShaderManager.h> #include <GLFrustum.h> #include <GLBatch.h> #include <GLFrame.h> #include <GLMatrixStack.h> #include <GLGeometryTransform.h> #define FREEGLUT_STATIC #include <GL/glut.h> GLShaderManager shaderManager; //着色器管理类 GLMatrixStack modelViewMatrix; //模型视图矩阵 GLMatrixStack projectionMatrix; //投影矩阵 GLFrustum viewFrustum; // 视景体 GLGeometryTransform transformPipeline; // 几何变换管线 GLBatch floorBatch; GLBatch ceilingBatch; GLBatch leftWallBatch; GLBatch rightWallBatch; GLfloat viewZ = -65.0f; //纹理对象 #define TEXTURE_BRICK 0 #define TEXTURE_FLOOR 1 #define TEXTURE_CEILING 2 #define TEXTURE_COUNT 3 GLuint textures[TEXTURE_COUNT]; const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };
下面是主函数main
int main(int argc, char *argv[]) { //设置工作路径 gltSetWorkingDirectory(argv[0]); //初始化glut glutInit(&argc, argv); //申请一个带有双缓冲区,颜色缓冲区的窗口 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //窗口大小 glutInitWindowSize(800, 600); //窗口名字 glutCreateWindow("Mip"); //窗口大小改变时的回调函数 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; }
下面是窗口大小改变时的回调函数ChangeSize
void ChangeSize(int w, int h) { GLfloat fAspect; if(h == 0) h = 1; //设置视口大小 glViewport(0, 0, w, h); fAspect = (GLfloat)w/(GLfloat)h; //设置视口变换矩阵 viewFrustum.SetPerspective(80.0f,fAspect,1.0,120.0); //设置模型变换矩阵 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); //将视图变换矩阵 和 模型 变换矩阵统一管理起来 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix); }
下面是响应键盘方向键的函数SpecialKeys
void SpecialKeys(int key, int x, int y) { if(key == GLUT_KEY_UP) viewZ += 0.5f; if(key == GLUT_KEY_DOWN) viewZ -= 0.5f; //刷新窗口 glutPostRedisplay(); }
下面是初始化函数SetupRC
void SetupRC() { GLbyte *pBytes; GLint iWidth, iHeight, iComponents; GLenum eFormat; GLint iLoop; // Black background glClearColor(0.0f, 0.0f, 0.0f,1.0f); shaderManager.InitializeStockShaders(); // 生成纹理对象 glGenTextures(TEXTURE_COUNT, textures); for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) { //绑定纹理对象 glBindTexture(GL_TEXTURE_2D, textures[iLoop]); //加载纹理数据 pBytes = gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight, &iComponents, &eFormat); //设置纹理过滤模式 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_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //生成纹理图片 glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes); //生成Mip层 glGenerateMipmap(GL_TEXTURE_2D); //删除原纹理数据内存 free(pBytes); } // 地面数据 GLfloat z; floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); for(z = 60.0f; z >= 0.0f; z -=10.0f) { floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f); floorBatch.Vertex3f(-10.0f, -10.0f, z); floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f); floorBatch.Vertex3f(10.0f, -10.0f, z); floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f); floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f); floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f); floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f); } floorBatch.End(); //天花板数据 ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); for(z = 60.0f; z >= 0.0f; z -=10.0f) { ceilingBatch.MultiTexCoord2f(0, 0.0f, 1.0f); ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f); ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f); ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f); ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f); ceilingBatch.Vertex3f(-10.0f, 10.0f, z); ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f); ceilingBatch.Vertex3f(10.0f, 10.0f, z); } ceilingBatch.End(); //左墙面数据 leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); for(z = 60.0f; z >= 0.0f; z -=10.0f) { leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f); leftWallBatch.Vertex3f(-10.0f, -10.0f, z); leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f); leftWallBatch.Vertex3f(-10.0f, 10.0f, z); leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f); leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f); leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f); leftWallBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f); } leftWallBatch.End(); //右墙面数据 rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); for(z = 60.0f; z >= 0.0f; z -=10.0f) { rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f); rightWallBatch.Vertex3f(10.0f, -10.0f, z); rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f); rightWallBatch.Vertex3f(10.0f, 10.0f, z); rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f); rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f); rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f); rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f); } rightWallBatch.End(); }
下面是渲染函数RenderScene
void RenderScene(void) { // 清除后台缓冲区 glClear(GL_COLOR_BUFFER_BIT); //设置视图变换矩阵 modelViewMatrix.PushMatrix(); modelViewMatrix.Translate(0.0f, 0.0f, viewZ); shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0); //设置mip贴图过滤模式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); //绘制地板 glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]); floorBatch.Draw(); //绘制天花板 glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]); ceilingBatch.Draw(); //绘制左墙面和右墙面 glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]); leftWallBatch.Draw(); rightWallBatch.Draw(); modelViewMatrix.PopMatrix(); //交换缓冲区 glutSwapBuffers(); }
下面是程序退出时的清理函数ShutdownRC
void ShutdownRC(void) { //删除纹理对象 glDeleteTextures(TEXTURE_COUNT, textures); }
各向异性过滤
如果在进行纹理过滤时考虑了观察者的角度,那么这种方法就成为各向异性过滤
假如说你在观察一个三角形,三角形上有一点A,当从正面观察时,和从侧面观察时,A点的纹理数据的会有所不同,因为在生成A点的纹理数据时,会根据观察的
方向来采取周围纹理数据进行运算
在使用各向异性过滤模式之前,我们需要测试硬件支不支持这种过滤模式,我们可以使用函数gltIsExtSupported("GL_EXT_texture_filter_anisotropic")在检测,
返回1标示支持,0表示不支持,
我们使用函数 void GLAPIENTRY glGetFloatv (GLenum pname, GLfloat *params) 来得到最大支持的各向异性过滤的最大数量
我们使用函数 GLAPIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param) 来启用各向异性过滤模式
我们可以把渲染函数RenderScene中的代码
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
换成如下的代码,来使用各向异性过滤模式
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); }
下图是使用了各向异性过滤后的效果,比之前的清晰多了,但同时也有性能上的消耗
相关文章推荐
- (3)使用Highcharts开发JVM监控内存
- linux程序包安装、管理工具rpm、yum和源码安装
- 虚拟机安装Centos7
- Linux下nc的参数详解
- Windows上编译最新的CURL,含有zlib,openssl
- linux下修改path
- 简单之美-Dubbo架构设计详解
- Tomcat介绍及性能优化
- 我的openwrt学习笔记(十九):linux便捷开发命令之strace
- Hbase架构简介、实践
- Linux系统查找
- Apache+Tomcat集群配置
- Photo Shop
- 玩玩负载均衡---在window与linux下配置nginx
- Codeforces 436C Gargari and Bishops
- CentOS 6.5 32-bit 配置IP地址
- Centos下Yum安装PHP5.5,5.6
- linux学习--扫盲笔记
- 高性能网站建设的14个原则
- opencv widthstep 理解