OpenGL_Qt学习笔记之_05(纹理映射)(转)

时间:2022-12-31 13:13:57

转自:http://www.cnblogs.com/tornadomeet/archive/2012/08/24/2654719.html

纹理映射基础知识

  什么叫纹理映射,一开始我也不明白,感觉这个词好专业(毕竟没有学过图形学),后面经过网上查找资料和这次实验稍微理解了点。纹理映射简单的讲,就是把一个纹理(其实说白了,纹理可以理解为一幅图像)映射到空间物体的表面上,因此纹理映射也叫贴图,这个表明不一定是矩形,比如说我可以是球面,或者是任意曲面。在上一篇文章OpenGL_Qt学习笔记之_04(3D图形的绘制和旋转)中,我们绘制的空间体的表面都是一些光滑的颜色,如果要在其表面采用那种方法绘制图像的话,则必须利用微分的思想,一个一个的绘制小图像,然后拼接起来,可想而知,这个过程是多么的复杂,opengl的纹理映射就可以很好的解决这一问题。

下面来看看纹理映射的一个示意图片(百度百科上的):

  OpenGL_Qt学习笔记之_05(纹理映射)(转)

  这个示意图说明,将中间的纹理(即图片)映射到左边的茶壶曲面上,就形成了右边的图了。在右边的图中,可以看到茶壶的表面上布满了图片,这就像中国古代的陶器绘图一样。

  纹理映射另外一个好处是能够保证在变换多边形时,多边形上的纹理也会随之变化。

  纹理映射相关函数

  要进行纹理映射,得先了解下opengl中有关纹理映射的一些相关函数。

  void glGenTextures(GLsizei n, GLuint *textures);

  该函数的作用是开辟存储纹理的内存空间,其中参数n为开辟纹理内存的个数,texture为存储纹理的地址索引。

  void glBindTexture(GLenum target,   GLuint texture);

  该函数的作用是把存储纹理的对象texture绑定到纹理目标target上,在opengl中纹理目标分为GL_TEXTURE_1D和GL_TEXTURE_2D。该句代码运行完后,对target的操作也对应于对texture指向的内容的操作。

  void glTexImage2D(GLenum target,GLint level,GLint components,GLsizei width, glsizei height,GLint border,GLenum format,GLenum type, const GLvoid *pixels);

  参数1为纹理目标;参数2为目标的层次,即目标的详细程度,一般情况采用0即可;参数3表示的是数据成分的个数,如果数据由RGB构成,则将该参数设置为3;参数4和5分别为创建纹理数据的长和宽;参数6为边框的值,一般也设为0;参数8为数据的通道格式;参数9为纹理的数据元素类型;参数10为纹理的数据内容。

  这个函数的功能是创建一个纹理,并为该纹理分配了数据。

  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

  该函数表示的是当所显示的纹理比加载进来的纹理小时,采用GL_LINEAR的方法来处理。

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  和上面的函数类似,注意该函数的参数2为GL_TEXTURE_MAG_FILTER,不要误认为是GL_TEXTURE_MAG_FILTER。

  glTexCoord2f(x, y);

  第一个参数是X坐标。 0.0f 是纹理的左侧。 0.5f 是纹理的中点, 1.0f 是纹理的右侧。第二个参数是Y坐标。0.0f 是纹理的底部。0.5f 是纹理的中点,1.0f 是纹理的顶部。

  给定一张纹理图,它的坐标示意图如下:

  OpenGL_Qt学习笔记之_05(纹理映射)(转)

  其中纹理的中心点坐标为(0.5, 0.5).

  实验说明:

  这个实验室在上一篇博文OpenGL_Qt学习笔记之_04(3D图形的绘制和旋转) 绘制的立方体上贴每个面上贴上一张纹理(即图片)。

  我们需要在GLWidget这个类中添加一个函数来加载纹理数据,该函数为loadTextures().

  另外,在QGLWidget这个类中,initializeGL(), paintGL(), resizeGL()这3个函数的执行顺序是该类启动时就执行initializeGL(),主要用于初始化opengl,通常用来设置一些前期的背景色,光照参数等等。paintGL()用于渲染整个场景;resizeGL()用于在widget大小变化的时候产生合理view。

  注意,本实验给的图片长和宽必须是2的n次方,最大不要超过256,最小也不要小于64。我这里采用的是256*256像素的图片。

  实验结果:

  加载纹理的图像为:

  OpenGL_Qt学习笔记之_05(纹理映射)(转)

 

  纹理映射后的效果如下:

  OpenGL_Qt学习笔记之_05(纹理映射)(转) 

 

  实验主要部分代码及注释(附录有工程code下载地址):

OpenGL_Qt学习笔记之_05(纹理映射)(转)
#include "glwidget.h"
#include "ui_glwidget.h" #include <QtGui>
#include <QtCore>
#include <QtOpenGL> GLWidget::GLWidget(QGLWidget *parent) :
QGLWidget(parent),
ui(new Ui::GLWidget)
{
// setCaption("The Opengl for Qt Framework");
ui->setupUi(this);
fullscreen = false;
rotate_angle = 0.0;
} //这是对虚函数,这里是重写该函数
void GLWidget::initializeGL()
{
setGeometry(300, 150, 500, 500);//设置窗口初始位置和大小
loadTextures();
glEnable(GL_TEXTURE_2D);//允许采用2D纹理技术
glShadeModel(GL_SMOOTH);//设置阴影平滑模式
glClearColor(0.0, 0.0, 0.0, 0);//改变窗口的背景颜色,不过我这里貌似设置后并没有什么效果
glClearDepth(1.0);//设置深度缓存
glEnable(GL_DEPTH_TEST);//允许深度测试
glDepthFunc(GL_LEQUAL);//设置深度测试类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//进行透视校正
} void GLWidget::paintGL()
{
//glClear()函数在这里就是对initializeGL()函数中设置的颜色和缓存深度等起作用
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /*下面开始画立方体,并对其进行纹理映射*/
glLoadIdentity();
glRotatef(rotate_angle, -0.2f, 0.2f, -0.3f);
glBegin(GL_QUADS);
//上顶面
glTexCoord2f(0.0, 1.0);//将2D的纹理坐标映射到3D的空间物体表面上
glVertex3f(-0.3f, 0.3f, -0.3f);
glTexCoord2f(0.0, 0.0);
glVertex3f(-0.3f, 0.3f, 0.3f);
glTexCoord2f(1.0, 0.0);
glVertex3f(0.3f, 0.3f, 0.3f);
glTexCoord2f(1.0, 1.0);
glVertex3f(0.3f, 0.3f, -0.3f);
//下顶面
glTexCoord2f(0.0, 1.0);
glVertex3f(-0.3f, -0.3f, -0.3f);
glTexCoord2f(0.0, 0.0);
glVertex3f(-0.3f, -0.3f, 0.3f);
glTexCoord2f(1.0, 0.0);
glVertex3f(0.3f, -0.3f, 0.3f);
glTexCoord2f(1.0, 1.0);
glVertex3f(0.3f, -0.3f, -0.3f);
//正前面
glTexCoord2f(0.0, 1.0);
glVertex3f(-0.3f, 0.3f, 0.3f);
glTexCoord2f(0.0, 0.0);
glVertex3f(-0.3f, -0.3f, 0.3f);
glTexCoord2f(1.0, 0.0);
glVertex3f(0.3f, -0.3f, 0.3f);
glTexCoord2f(1.0, 1.0);
glVertex3f(0.3f, 0.3f, 0.3f);
//右侧面
glTexCoord2f(0.0, 1.0);
glVertex3f(0.3f, 0.3f, 0.3f);
glTexCoord2f(0.0, 0.0);
glVertex3f(0.3f, -0.3f, 0.3f);
glTexCoord2f(1.0, 0.0);
glVertex3f(0.3f, -0.3f, -0.3f);
glTexCoord2f(1.0, 1.0);
glVertex3f(0.3f, 0.3f, -0.3f);
//背后面
glTexCoord2f(0.0, 1.0);
glVertex3f(-0.3f, 0.3f, -0.3f);
glTexCoord2f(0.0, 0.0);
glVertex3f(0.3f, 0.3f, -0.3f);
glTexCoord2f(1.0, 0.0);
glVertex3f(0.3f, -0.3f, -0.3f);
glTexCoord2f(1.0, 1.0);
glVertex3f(-0.3f, -0.3f, -0.3f);
//左侧面
glTexCoord2f(0.0, 1.0);
glVertex3f(-0.3f, 0.3f, -0.3f);
glTexCoord2f(0.0, 0.0);
glVertex3f(-0.3f, -0.3f, -0.3f);
glTexCoord2f(1.0, 0.0);
glVertex3f(-0.3f, -0.3f, 0.3f);
glTexCoord2f(1.0, 1.0);
glVertex3f(-0.3f, 0.3f, 0.3f);
rotate_angle -= 3;
glEnd();
} //该程序是设置opengl场景透视图,程序中至少被执行一次(程序启动时).
void GLWidget::resizeGL(int width, int height)
{
if(0 == height)
height = 1;//防止一条边为0
glViewport(0, 0, (GLint)width, (GLint)height);//重置当前视口,本身不是重置窗口的,只不过是这里被Qt给封装好了
glMatrixMode(GL_PROJECTION);//选择投影矩阵
glLoadIdentity();//重置选择好的投影矩阵
// gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);//建立透视投影矩阵
glMatrixMode(GL_MODELVIEW);//以下2句和上面出现的解释一样
glLoadIdentity(); }
void GLWidget::keyPressEvent(QKeyEvent *e)
{
switch(e->key())
{
//F1键为全屏和普通屏显示切换键
case Qt::Key_F1:
fullscreen = !fullscreen;
if(fullscreen)
showFullScreen();
else
{
setGeometry(300, 150, 500, 500);
showNormal();
}
updateGL();
break;
//Ese为退出程序键
case Qt::Key_Escape:
close();
}
} /*装载纹理*/
void GLWidget::loadTextures()
{
QImage tex, buf;
if(!buf.load("../opengl_nehe_05/cherry.jpg"))
{
qWarning("Cannot open the image...");
QImage dummy(128, 128, QImage::Format_RGB32);//当没找到所需打开的图片时,创建一副128*128大小,深度为32位的位图
dummy.fill(Qt::green);
buf = dummy;
}
tex = convertToGLFormat(buf);//将Qt图片的格式buf转换成opengl的图片格式tex
glGenTextures(1, &texture[0]);//开辟一个纹理内存,内存指向texture[0]
glBindTexture(GL_TEXTURE_2D, texture[0]);//将创建的纹理内存指向的内容绑定到纹理对象GL_TEXTURE_2D上,经过这句代码后,以后对
//GL_TEXTURE_2D的操作的任何操作都同时对应与它所绑定的纹理对象
glTexImage2D(GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());//开始真正创建纹理数据
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//当所显示的纹理比加载进来的纹理小时,采用GL_LINEAR的方法来处理
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//当所显示的纹理比加载进来的纹理大时,采用GL_LINEAR的方法来处理
} GLWidget::~GLWidget()
{
delete ui;
}
OpenGL_Qt学习笔记之_05(纹理映射)(转)

  总结:

  了解了opengl中的纹理映射机制后,对空间体的表面进行贴图还是比较方便的。

  参考资料:

   http://nehe.gamedev.net/

   http://www.owlei.com/DancingWind/

   http://blog.csdn.net/qp120291570/article/details/7853513

http://www.qiliang.net/old/nehe_qt/

  附录:

  实验工程code下载

作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet 欢迎转载或分享,但请务必声明文章出处。 (新浪微博:tornadomeet,欢迎交流!)

OpenGL_Qt学习笔记之_05(纹理映射)(转)的更多相关文章

  1. OpenGL&lowbar;Qt学习笔记之&lowbar;03&lpar;平面图形的着色和旋转&rpar;(转)

    http://www.cnblogs.com/tornadomeet/archive/2012/08/23/2653305.html 在这一节中主要简单介绍下怎样给平面几何着色,以及怎样让绘制出来的几 ...

  2. SharpGL学习笔记&lpar;十五&rpar; 纹理映射

    纹理映射非常实用,在游戏场景中已经无所不在了. 一个较少的多边形构成的模形,配合好的纹理贴图进行映射,可以得到逼真的效果.游戏中的天空,地面,墙面,和植物都是纹理贴图进行映射的. 例如最终幻想8的男女 ...

  3. SharpGL学习笔记&lpar;十一&rpar; 光源创建的综合例子:光源参数可调节的测试场景

    灯光的测试例子:光源参数可以调节的测试场景 先看一下测试场景和效果. 场景中可以切换视图, 以方便观察三维体和灯光的位置.环境光,漫射光,镜面反射光都可以在四种颜色间切换. 灯光位置和摄像机位置(Lo ...

  4. DirectX 总结和DirectX 9&period;0 学习笔记

    转自:http://www.cnblogs.com/graphics/archive/2009/11/25/1583682.html DirectX 总结 DDS DirectXDraw Surfac ...

  5. 【Unity Shaders】学习笔记——SurfaceShader(十一)光照模型

    [Unity Shaders]学习笔记——SurfaceShader(十一)光照模型 转载请注明出处:http://www.cnblogs.com/-867259206/p/5664792.html ...

  6. 【Unity Shaders】学习笔记——渲染管线

    [Unity Shaders]学习笔记——Shader和渲染管线 转载请注明出处:http://www.cnblogs.com/-867259206/p/5595924.html 写作本系列文章时使用 ...

  7. WebGL three&period;js学习笔记 法向量网格材质MeshNormalMaterial的介绍和创建360度全景天空盒的方法

    WebGL学习----Three.js学习笔记(5) 点击查看demo演示 Demo地址:https://nsytsqdtn.github.io/demo/360/360 简单网格材质 MeshNor ...

  8. WebGL three&period;js学习笔记 6种类型的纹理介绍及应用

    WebGL three.js学习笔记 6种类型的纹理介绍及应用 本文所使用到的demo演示: 高光贴图Demo演示 反光效果Demo演示(因为是加载的模型,所以速度会慢) (一)普通纹理 计算机图形学 ...

  9. DirectX 11游戏编程学习笔记之1&colon; 开场白

    本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com           这是我之前的博客系列"DirectX9.0c游戏开发手记之'龙书'第二版学习笔记 ...

随机推荐

  1. Oracle存储过程-自定义数据类型&comma;集合&comma;遍历取值

    摘要 Oracle存储过程,自定义数据类型,集合,遍历取值 目录[-] 0.前言 1.Packages 2.Packages bodies 3.输出结果 0.前言 在Oracle的存储过程中,可能会遇 ...

  2. Windows2003 SQL2005解决系统Administrator密码不知道的问题

    Windows2003 SQL2005解决系统Administrator密码不知道的问题 今天上班的时候,有个同事说不知道谁设置了开机密码,那台电脑一直没有开机密码的他现在进不了桌面 那台电脑没有光驱 ...

  3. PHP回调函数的几种用法

    PHP回调函数的实现方法 目录 前言      全局函数的回调      类静态函数的回调      对象的方法的回调      PHP事件模型(观察者模式)的实现思路    前言 最近在开发一个PH ...

  4. 静态库 &amp&semi;&amp&semi; 动态库

    http://weihe6666.iteye.com/blog/1100065 http://www.cnblogs.com/skynet/p/3372855.html 静态库: 在链接阶段,将汇编生 ...

  5. java&period;util&period;TreeSet源码分析

    TreeSet是基于TreeMap实现的,元素的顺序取决于元素自身的自然顺序或者在构造时提供的比较器. 对于add,remove,contains操作,保证log(n)的时间复杂度. 因为Set接口的 ...

  6. MQ-传输方式Topic和Queue的对比

    Jms规范里的两种message传输方式Topic和Queue,两者的对比如下表():   Topic Queue 概要 Publish  Subscribe messaging 发布订阅消息 Poi ...

  7. Delphi下创建异形窗体

    procedure TForm1.FormCreate(Sender: TObject);var  pt: array [0 .. 4] of TPoint;  m_rgn: HRGN;begin   ...

  8. Elasticsearch安装ik中文分词插件(四)

    一.IK简介 IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包.从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本.最初,它是以开源项目Lu ...

  9. EasyNetQ之多态发布和订阅

    你能够订阅一个接口,然后发布基于这个接口的实现. 让我们看下一个示例.我有一个接口IAnimal和两个实现Cat和Dog: public interface IAnimal { string Name ...

  10. python打包压缩文件夹zip&plus;组装文件夹

    无意间想到的一个需求,然后就顺手写了写,留下来,方便以后用 列表版:(基本没用,仅提供思路,字典版稍微改动可以直接用) 大体需求: 把重复的文件名进行改名,达到浏览器下载相同文件的效果 下载完成后再把 ...