OpenGl Mip贴图

Mip贴图可以用来提高游戏的性能,主要原理是把一张纹理图片按照一定侧尺寸缩放,生成一些列的图片,按照图片离照相机的距离的远近,再决定使用哪个图片

比如,离照相机远的使用小的 。

决定怎样使用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);
}

下图是使用了各向异性过滤后的效果,比之前的清晰多了,但同时也有性能上的消耗















  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值