您的位置:首页 > 运维架构

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层之间执行线性插值得到图片后,再执行线性过滤。

我们这一节要实现的效果如下图:



我们可以看到远处的砖块逐渐模糊,我们可以按键盘的方向键来进行行走

下面是代码实现

首先是要包含的头文件和全局变量

#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);
}


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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: