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;
}
OpenGL(二十三) 各向异性纹理过滤的更多相关文章
- Android OpenGL ES(七)----理解纹理与纹理过滤
1.理解纹理 OpenGL中的纹理能够用来表示图像.照片,甚至由一个数学算法生成的分形数据.每一个二维的纹理都由很多小的纹理元素组成.它们是小块的数据,类似于我们前面讨论过的片段和像素.要使用纹理,最 ...
- Mipmap与纹理过滤
为了加快渲染速度和减少纹理锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件,这样的贴图被称为Mipmap. 使用DirectX Texture Tool(DX自带工具)预生成Mipmap ...
- OpenGL ES 详解纹理生成和纹理映射步骤以及函数
通常一个纹理映射的步骤是: 创建纹理对象.就是获得一个新的纹理句柄 ID. 指定纹理.就是将数据赋值给 ID 的纹理对象,在这一步,图像数据正式加载到了 ID 的纹理对象中. 设定过滤器.定义了ope ...
- 【Visual C++】游戏开发五十六 浅墨DirectX教程二十三 打造游戏GUI界面(一)
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/16384009 作者:毛星云 ...
- FreeSql (二十三)分组、聚合
IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.MySql, "Data ...
- 纹理过滤模式中的Bilinear、Trilinear以及Anistropic Filtering
1. 为什么在纹理采样时需要texture filter(纹理过滤). 我们的纹理是要贴到三维图形表面的,而三维图形上的pixel中心和纹理上的texel中心并不一至(pixel不一定对应textur ...
- WPF入门教程系列二十三——DataGrid示例(三)
DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...
- Bootstrap <基础二十三>页面标题(Page Header)
页面标题(Page Header)是个不错的功能,它会在网页标题四周添加适当的间距.当一个网页中有多个标题且每个标题之间需要添加一定的间距时,页面标题这个功能就显得特别有用.如需使用页面标题(Page ...
- Web 前端开发精华文章推荐(HTML5、CSS3、jQuery)【系列二十三】
<Web 前端开发精华文章推荐>2014年第2期(总第23期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...
随机推荐
- [CSS] Control Image Aspect Ratio Using CSS
Resize images and videos to fill their parent and maintain their aspect ratio with pure CSS. The new ...
- C++中的虚析构函数、纯虚析构函数具体解释
C++中析构函数能够为纯虚函数吗? 众所周知.在实现多态的过程中,一般将基类的析构函数设为virtual.以便在delete的时候能够多态的链式调用.那么析构函数能否够设为纯虚呢? class CBa ...
- Java文档上传问题设计
近期公司让做一个文档上传的功能,功能描写叙述大概是这样子滴 书籍名称.书籍定价.书籍封面图片(须要上传).文档内容 (须要上传) .还有其它相关的描写叙述信息. 我的设计 表 A 包括以上字段 , ...
- 关于JavaScript对象概念的总结
原文 https://www.jianshu.com/p/88213b499c4b 大纲 前言 1.对象的相关概念 2.对象的创建(简单创建) 3.对象的属性 3.1.数据属性 3.2.访问器属性 4 ...
- Android多线程研究(7)——Java5中的线程并发库
从这一篇开始我们将看看Java 5之后给我们添加的新的对线程操作的API,首先看看api文档: java.util.concurrent包含许多线程安全.测试良好.高性能的并发构建块,我们先看看ato ...
- Android 闹钟最终版
以下是我发现的几点闹钟中重要的点,分享一下: (1)在闹钟中有AudioManager管理机制,这个机制可以申请和释放OnAudioFocusChangeListener监听. 还有mTelephon ...
- tplink-如何远程WEB管理路由器?
http://service.tp-link.com.cn/detail_article_185.html 如何远程WEB管理路由器? 新版tplink怎么远程Web管理? https://www.1 ...
- JavaEE 三层架构的浅谈
三层架构 三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI).业务逻辑层(BLL).数据访问层(DAL).区分层次的目的即为了“高内聚,低 ...
- 【31.58%】【codeforces 719B】 Anatoly and Cockroaches
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
- 《iOS Human Interface Guidelines》——Segmented Control
分段控件 分段控件是一组线性段.每一个button相应的功能能够显示一个不同的视图. API NOTE 查看UISegmentedControl来学习很多其它关于在你的代码中定义一个分段控件的内容. ...