zoukankan      html  css  js  c++  java
  • OpenGL(二十三) 各向异性纹理过滤

    如果使用一般的纹理过滤,当观察方向跟模型表面不是相互垂直的的情况下,会出现纹理信息的丢失,表现为图像看上去比较模糊,如下图所示,远处场景的细节信息很差:



    针对这种情况,可以采用同向异性过滤的方式处理纹理,在过滤纹理的时候,考虑到观察角度不同,使纹理本身沿着模型表面倾斜的方向进行延伸。


    使用如下语句查询当前系统支持的最大同向异性过滤的数值,数值越大,表示沿着最大变化方向所采样的纹理单元越多,显示效果就越好:


    GLfloat max_TexAni;    //查询允许的各向异性数量
    	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_TexAni);


     以“ GL_TEXTURE_MAX_ANISOTROPY_EXT ”为参数调用“ glTexParameterf ”函数,并设置同向异性过滤的数值,就可以使设置生效。以下是经过同向异性过滤设置的显示效果:




    远处纹理的细节增强了很多。以下是工程代码:


    #define WindowWidth  400    
    #define WindowHeight 400
    #define WindowTitle  "OpenGL Mip纹理贴图&&同向异性过滤"
    
    #include <Windows.h>
    #include "GL/glew.h"
    #include <GL/freeglut.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    //定义纹理对象编号    
    GLuint texGround;
    GLuint texWall;
    GLuint texSky;
    
    #define BMP_Header_Length 54  //图像数据在内存块中的偏移量    
    static GLfloat angle = 0.0f;   //旋转角度    
    static GLfloat zPosition = 10;
    
    // 函数power_of_two用于判断一个整数是不是2的整数次幂    
    int power_of_two(int n)
    {
    	if (n <= 0)
    		return 0;
    	return (n & (n - 1)) == 0;
    }
    
    /* 函数load_texture
       28.* 读取一个BMP文件作为纹理
       29.* 如果失败,返回0,如果成功,返回纹理编号
       30.*/
    GLuint load_texture(const char* file_name)
    {
    	GLint width, height, total_bytes;
    	GLubyte* pixels = 0;
    	GLuint last_texture_ID = 0, texture_ID = 0;
    
    	// 打开文件,如果失败,返回    
    	FILE* pFile = fopen(file_name, "rb");
    	if (pFile == 0)
    		return 0;
    
    	// 读取文件中图象的宽度和高度    
    	fseek(pFile, 0x0012, SEEK_SET);
    	fread(&width, 4, 1, pFile);
    	fread(&height, 4, 1, pFile);
    	fseek(pFile, BMP_Header_Length, SEEK_SET);
    
    	// 计算每行像素所占字节数,并根据此数据计算总像素字节数    
    	{
    		GLint line_bytes = width * 3;
    		while (line_bytes % 4 != 0)
    			++line_bytes;
    		total_bytes = line_bytes * height;
    	}
    
    	// 根据总像素字节数分配内存    
    	pixels = (GLubyte*)malloc(total_bytes);
    	if (pixels == 0)
    	{
    		fclose(pFile);
    		return 0;
    	}
    
    	// 读取像素数据    
    	if (fread(pixels, total_bytes, 1, pFile) <= 0)
    	{
    		free(pixels);
    		fclose(pFile);
    		return 0;
    	}
    
    	// 对就旧版本的兼容,如果图象的宽度和高度不是的整数次方,则需要进行缩放    
    	// 若图像宽高超过了OpenGL规定的最大值,也缩放    
    	{
    		GLint max;
    		glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
    		if (!power_of_two(width)
    			|| !power_of_two(height)
    			|| width > max
    			|| height > max)
    		{
    			const GLint new_width = 256;
    			const GLint new_height = 256; // 规定缩放后新的大小为边长的正方形    
    			GLint new_line_bytes, new_total_bytes;
    			GLubyte* new_pixels = 0;
    
    			// 计算每行需要的字节数和总字节数    
    			new_line_bytes = new_width * 3;
    			while (new_line_bytes % 4 != 0)
    				++new_line_bytes;
    			new_total_bytes = new_line_bytes * new_height;
    
    			// 分配内存    
    			new_pixels = (GLubyte*)malloc(new_total_bytes);
    			if (new_pixels == 0)
    			{
    				free(pixels);
    				fclose(pFile);
    				return 0;
    			}
    
    			// 进行像素缩放    
    			gluScaleImage(GL_RGB,
    				width, height, GL_UNSIGNED_BYTE, pixels,
    				new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);
    
    			// 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和height    
    			free(pixels);
    			pixels = new_pixels;
    			width = new_width;
    			height = new_height;
    		}
    	}
    
    	// 分配一个新的纹理编号    
    	glGenTextures(1, &texture_ID);
    	if (texture_ID == 0)
    	{
    		free(pixels);
    		fclose(pFile);
    		return 0;
    	}
    
    	// 绑定新的纹理,载入纹理并设置纹理参数    
    	// 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复    
    	GLint lastTextureID = last_texture_ID;
    	glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTextureID);
    	glBindTexture(GL_TEXTURE_2D, texture_ID);
    	/*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    	130.    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); */
    
    	GLfloat max_TexAni;    //查询允许的各向异性数量
    	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_TexAni);
    
    	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_TexAni);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    
    	/* glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
    	 140.    GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels); */
    
    	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
    
    	glBindTexture(GL_TEXTURE_2D, lastTextureID);  //恢复之前的纹理绑定    
    	free(pixels);
    	return texture_ID;
    }
    
    
    void Display(void)
    {
    	// 清除屏幕    
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	// 设置视角    
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();
    	gluPerspective(65, 1, 1, 100);
    	glMatrixMode(GL_MODELVIEW);
    	glLoadIdentity();
    	gluLookAt(0, 0, zPosition, 0, 0, 0, 0, 1, 0);
    	glRotatef(angle, 0.0f, 1.0f, 0.0f); //旋转    
    
    	 // 绘制左侧墙壁以及纹理    
    	glBindTexture(GL_TEXTURE_2D, texWall);
    	glBegin(GL_QUADS);
    	glTexCoord2f(0.0f, 0.0f); glVertex3f(-5.0f, -5.0f, 100.0f);
    	glTexCoord2f(30.0f, 0.0f); glVertex3f(-5.0f, -5.0f, -100.0f);
    	glTexCoord2f(30.0f, 2.0f); glVertex3f(-5.0f, 5.0f, -100.0f);
    	glTexCoord2f(0.0f, 2.0f); glVertex3f(-5.0f, 5.0f, 100.0f);
    	glEnd();
    
    	//绘制右侧墙  
    	glBegin(GL_QUADS);
    	glTexCoord2f(0.0f, 0.0f); glVertex3f(5.0f, -5.0f, 100.0f);
    	glTexCoord2f(30.0f, 0.0f); glVertex3f(5.0f, -5.0f, -100.0f);
    	glTexCoord2f(30.0f, 2.0f); glVertex3f(5.0f, 5.0f, -100.0f);
    	glTexCoord2f(0.0f, 2.0f); glVertex3f(5.0f, 5.0f, 100.0f);
    	glEnd();
    
    	//绘制地板  
    	glBindTexture(GL_TEXTURE_2D, texGround);
    	glBegin(GL_QUADS);
    	glTexCoord2f(0.0f, 0.0f); glVertex3f(-5.0f, -5.0f, 100.0f);
    	glTexCoord2f(0.0f, 1.0f); glVertex3f(5.0f, -5.0f, 100.0f);
    	glTexCoord2f(25.0f, 1.0f); glVertex3f(5.0f, -5.0f, -100.0f);
    	glTexCoord2f(25.0f, 0.0f); glVertex3f(-5.0f, -5.0f, -100.0f);
    	glEnd();
    
    	//绘制顶层  
    	glBindTexture(GL_TEXTURE_2D, texSky);
    	glBegin(GL_QUADS);
    	glTexCoord2f(0.0f, 0.0f); glVertex3f(-5.0f, 5.0f, 100.0f);
    	glTexCoord2f(0.0f, 3.0f); glVertex3f(5.0f, 5.0f, 100.0f);
    	glTexCoord2f(35.0f, 3.0f); glVertex3f(5.0f, 5.0f, -100.0f);
    	glTexCoord2f(35.0f, 0.0f); glVertex3f(-5.0f, 5.0f, -100.0f);
    	glEnd();
    	glutSwapBuffers();
    }
    
    void SpecialKey(GLint key, GLint x, GLint y)
    {
    	if (key == GLUT_KEY_UP)
    	{
    		zPosition += 1.0f;
    	}
    	if (key == GLUT_KEY_DOWN)
    	{
    		zPosition -= 1.0f;
    	}
    	if (key == GLUT_KEY_LEFT)
    	{
    		angle += 0.5f;
    	}
    	if (key == GLUT_KEY_RIGHT)
    	{
    		angle -= 0.5f;
    	}
    	glutPostRedisplay();
    }
    
    int main(int argc, char* argv[])
    {
    	// GLUT初始化    
    	glutInit(&argc, argv);
    	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    	glutInitWindowPosition(100, 100);
    	glutInitWindowSize(WindowWidth, WindowHeight);
    	glutCreateWindow(WindowTitle);
    	glEnable(GL_DEPTH_TEST);
    	glEnable(GL_TEXTURE_2D);    // 启用纹理    
    	texGround = load_texture("ground.bmp");  //加载纹理    
    	texWall = load_texture("wall.bmp");
    	texSky = load_texture("sky.bmp");
    	glutDisplayFunc(&Display);   //回调函数    
    	glutSpecialFunc(&SpecialKey);
    	glutMainLoop(); //循环调用    
    	return 0;
    }
    




  • 相关阅读:
    SQL Server2008中删除重复记录
    Php环境在Windows (server 2003) 服务器部署标准 白丁简明版
    国外服务器鸟文windows,时间12小时制,如何改成24小时呢?我来告诉你
    将Capicom调用代码封装到ActiveX——解决javascript调Capicom读取数字证书信息时,IE弹出安全提示的问题
    Linq处理List数据
    C#将窗口最小化到系统托盘,并显示图标和快捷菜单
    C# 将程序添加到启动项 (写入注册表),及从启动项中删除
    C#中string[]数组和list<string>泛型的相互转换
    IIS7.5部署ASP.NET失败
    IIS 7.5版本中一些诡异问题的解决方案
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9411901.html
Copyright © 2011-2022 走看看