opengl编程学习笔记(四)(纹理映射)(结合nvdia OpenglSDk 的nvimage类)

Opengl中的纹理映射(texture mapping)是它的精华部分,在opengl的书中这一章也是所有章节中最为多的,在所有的opengl技术中,关于纹理映射的技术也是最多最丰富的,同时也是被开发人员使用各种trick最多的,因为纹理映射可以做很多的工作。在opengl的书中关于纹理映射有着很多的高级话题,而在这里,我只记录关于纹理映射的基础。

 

在纹理矩阵中的一个元素被称为texel,纹理矩阵可是是一维、二维、三维,texel也可以有rgba分量。纹理映射不能工作在索引颜色模式下

纹理映射的一般步骤:

产生纹理物体的名字glgentexture

绑定这个纹理物体glbind

glTexParameter设定纹理的各种参数

为纹理物体指定纹理gltextureimage

打开各种开关

在绘制时为绘制物体产生纹理坐标

 

1.       产生纹理物体:在opengl中,纹理映射是一个状态,同一时刻只能有一种纹理活动,但是我们的程序中通常需要定义大量的不同的纹理,在这些纹理间需要随时的切换,纹理物体就好比一个存储一种纹理状态的变量,当程序中一个纹理物体被绑定后,所有对纹理的参数的设定都是改变当前这个纹理物体代表的纹理映射的。需要先用glgentexture来产生一个纹理物体的名字。然后用glbind来绑定这个纹理后,就激活了这个纹理,这是程序中的活跃纹理是当前这个纹理,对纹理各种属性的修改也是对这个纹理,直到再绑定另外一个纹理。

2.       glTexParameteri()指定纹理的各种属性:这些属性包括:

GL_TEXTURE_MIN/MAG_FILTER 当纹理贴图需要被放大或缩小时的插值方式

                               此属性通常必须要指定,否则可能看不到贴图

GL_TEXTURE_MIN/MAG_LOD  设定纹理的最小和最大LOD级别(可为正负)

GL_TEXTURE_MAX_LOD 设定最小的那个mipmap的序号

GL_TEXTURE_MAX_LEVE设定最大的那个mipmap的序号

GL_TEXTURE_WRAP_S/T/R 设定纹理坐标的扩展方式,在这个参数下,可以使用的扩展方式有:GL_CLAMP(夹紧), GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT, or GL_REPEAT(重复),各种铺陈方式的效果如图:

 

GL_TEXTURE_BORDER_COLOR 设置纹理的边界(BORDER)颜色

GL_TEXTURE_PRIORITY 设置纹理在GPU缓存中的优先级,通常为了性能考虑,纹理会被放在GPU的缓存中,但是存放的数量是有限的,这个参数可以设定在GPU中的存放优先级

GL_GENERATE_MIPMAP 设定当base mipmap改变后是否更新所有的mipmap

 

GL_TEXTURE_COMPARE_MODE GL_TEXTURE_COMPARE_FUNC和GL_DEPTH_TEXTURE_MODE属性是专门为阴影贴图(shadow map)使用的,将在后面讲解

3使用glTexEnv (   GLenum       target, GLenum    pname, GLfloat    param);来设定纹理值是怎么样起作用的:

glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,…)来指定纹理的颜色与物体的原来颜色的混合方式,有GL_ADD, GL_MODULATE, GL_DECAL, GL_BLEND, GL_REPLACE, or GL_COMBINE.

4产生纹理:

  前面设定好纹理及生成方式的各种属性后,就该实际的产生纹理了,产生纹理在opengl中有一下几种方式:

  从内存数据产生纹理:这是最直接的生成纹理的方式,就是用void glTexImage2D(         GLenum          target,

        GLint      level,

        GLint      internalFormat,

        GLsizei  width,

        GLsizei  height,

        GLint      border,

        GLenum          format,

        GLenum          type,

          const GLvoid *     data)函数,从内存大数据构建纹理,通常你可以读入一个图像然后得到这个图像的数据作为data。

  直接产生LOD纹理:用gluBuild2DMipmaps可以从一片内存数据构建一个LOD的纹理

  从帧缓存产生纹理:glCopyTexImage2D可以将当前的一块帧缓存作为纹理,使用它时glPixelStore是起作用的。

5为绘制物体产生纹理坐标

产生纹理坐标有两种方式:

用glTexCoord指定当前的纹理坐标,它时一个状态函数,设定后如果不改变,所有之后的绘制的顶点的纹理坐标都是它

自动生成纹理:opengl有着强大的自动为物体生成纹理的机制,生成方式是依靠glTexGeni函数:自动生成纹理的过程是:

  用glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,…)设定生成纹理的平面参考方式

它可以是GL_EYE_LINEAR或者GL_OBJECT_LINEAR,即用视平面或者物体平面做参考。

  用glTexGenfv(GL_S,GL_EYE_PLANE,param)来设定这个平面,param为{p1,p2,p3,p4},最后生成纹理坐标为p1x0 + p2y0 + p3z0 + p4w0,这个param其实就是平面方程的参数

  视平面与物体平面的区别就是视平面中纹理坐标是相对于视坐标系的,视角变了纹理坐标也就随着变了

两种方式产生的纹理的区别如图:

 

6纹理矩阵:纹理也是一个矩阵,也可以用opengl中的各种矩阵操作来改变它,只不过在修改纹理矩阵的时候要先使用glmatrixmode(GL_TEXTURE)来切换到纹理矩阵

7需要打开的开关

在做纹理映射的时候,需要打开这些开关

最开始要打开

glEnable(GL_TEXTURE_1D/2D/CUBE_MAP);

如果使用了自动产生纹理坐标就还要打开

glEnable(GL_TEXTURE_GEN_S);

glEnable(GL_TEXTURE_GEN_T);

glEnable(GL_TEXTURE_GEN_R);

 

 

高级话题:

Cube map:cubemap是假想在绘制物体是可以反光的,它四周(六个面)有一个空间,然后将这六个面的图像映射到这个物体上,最后会产生这个物体反射空间景物的效果,常常可以提高绘制的真实感,CUBE MAP的步骤为:

用glBindTexture(GL_TEXTURE_CUBE_MAP,cubMapTextureName)将一个纹理物体绑定到CUBE MAP纹理上;

用glTexGeni(GL_S/T/R,GL_TEXTURE_GEN_MODE,…)为纹理物体产生纹理坐标,这里的产生方式只能是GL_REFLECTION_MAP或者GL_NORMAL_MAP,这两种的效果区别为:

reflection

normal

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X,0,GL_RGB…)为每一个面选择那个面的图像数据,一共要贴6个面

注意:在opengl中默认的用这种方式为物体产生坐标是在视坐标系中的,也就是说如果视角转动,纹理不会改变,如果想更加的真是,就应该让这个坐标在世界坐标系下,应该将这个纹理矩阵乘上视矩阵的逆矩阵。

 

Shadow map:

为了增强真实感,在绘制中产生阴影是及其重要的,其中一个重要的生成阴影的方法就是使用阴影贴图。阴影贴图的技术思想为:

首先将视角定位到光源的位置,视角的朝向为光源的朝向,在这个位置截取当前帧缓存中的深度值作为后面的纹理贴图。

然后为物体产生纹理坐标,产生的方式是按照模型为参考,参考面的参数就是这是modelview矩阵的逆矩阵,这时产生的纹理坐标的R就是该点的深度值。

最后设定glTexParameteri(GL_DEPTH_TEXTURE_MODE为GL_LUMINANCE),它将最后用一个灰度值来绘制点的纹理颜色

设定glTexParameteri(GL_TEXTURE_COMPARE_MODE)为GL_COMPARE_R_TO_TEXTURE,也就是比较该店的R坐标,它此时已经代表了该点的Z值

设定glTexParameteri(GL_TEXTURE_COMPARE_FUNC)为LEQUAL,也就是用该店的R坐标与此时深度图的Z值比较,如果比Z深,则用1来绘制,就是阴影了。

最后将视角切换回来

 

 

使用nvdia openg sdk 的nvimage类做辅助:

NVdia OpenGl SDK中的nvImage类封装了一个图片类,它专门用来做opengl中的贴图,这个类作用很大,因为我们在处理纹理映射时,通常要用一些图片文件来做贴图,而读取保存这些图片的数据通常很费力气,这个类为我们提供了一些辅助的功能。它的几个主要功能接口如下:

1.       它可以直接读取解析的图片格式为png hdr(这是一种高动态范围图片,图片质量相当高,颜色级范围很高,非常适用高真实感的cubemap或者天空盒等) dds(D3D的一种压缩图片)

2.       它可以得到当前图像的尺寸、深度、mipmaplevel、faces、Format和InternalFormat这些属性

3.       他可以知道当前图片是否可以做一个大的cubemap,

4.       他可以将一个cubemap的交叉图像(就是将6面绘制在一张图片上的图像)转变为6个face的CUBEMAP,然后可以单独得到各个面,注意:这个类只可以支持宽高比为3:4的交叉图像,并且宽高为2的幂的3倍和4倍。

5.       他可以将当前数据写入PNG图片文件。

时间: 2024-12-21 22:27:30

opengl编程学习笔记(四)(纹理映射)(结合nvdia OpenglSDk 的nvimage类)的相关文章

opengl编程学习笔记(三)(2D绘图)

在opengl中可以绘制二维图像,分为两种,BITMAP和image 1.bitmap和image的区别有: bitmap中对图像的每个像素只存储一位(0或1),用来表示用当前颜色绘制还是不绘制,而image是图像的每个像素存储可能很多位,存储它的各个通道的颜色信息: bitmap是绘制在三位空间中的一群点,其中每个点都受各变换矩阵的影响,等同于一群Gl_begin(GL_POINTS)操作联合在一起 ,而image是直接绘制在帧缓存上,在绘制原点所投影到的屏幕坐标处开始绘制,就是直接在二维屏幕

Opengl编程学习笔记(五)——从FRAGMENT到PIXEL(framebuffer 帧缓存)

1.帧缓存包括颜色.scissor.alpha.stencil.depth这些缓存,所以帧缓存不是一片缓存,而是所有这些缓存的组合,帧缓存它对应了屏幕上的每一个pixel(不是真正的pixel,而是一个fragment所对应的位置)的各种这些信息(颜色.ZBUFFER.等等),几何体的fragment时没有帧缓存的,帧缓存时屏幕上的,一个缓存的一位就对应一个位片面. Colorbuffer是最终表现在屏幕上的,但是其他缓存决定了最后这些color是否和怎样绘制在屏幕上.,其中除了colorbuf

Socket网络编程学习笔记(3):利用套接字助手类

在上一篇中已经介绍了利用Socket建立服务端和客户端进行通信,如果需要 的朋友可访问<Socket网络编程学习笔记(2):面向连接的Socket>.在本篇 中,将利用C#套接字的助手类来简化Socket编程,使得刚刚接触到网络编程的 朋友们更容易上手. 跟上篇一样,通过C#套接字的助手类来编程同样分 服务端和客户端. 一.服务端侦听模式 1.创建套接字与 IPEndPoint绑定,并设置为侦听模式. 1//创建IPEndPoint实例 2 IPEndPoint ipep = new IPEn

kvm虚拟化学习笔记(四)之kvm虚拟机日常管理与配置

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://koumm.blog.51cto.com/703525/1290269 KVM虚拟化学习笔记系列文章列表 ---------------------------------------- kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51cto.com/703525/1288795 kvm虚拟化学习笔记(二)之linux kvm虚拟机安装 h

python网络编程学习笔记(二):socket建立网络客户端_python

1.建立socket 建立socket对象需要搞清通信类型和协议家族.通信类型指明了用什么协议来传输数据.协议的例子包括IPv4.IPv6.IPX\SPX.AFP.对于internet通信,通信类型基本上都是AF_INET(和IPv4对应).协议家族一般表示TCP通信的SOCK_STREAM或者表示UDP通信的SOCK_DGRAM.因此对于TCP通信,建立一个socket连接的语句为:s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)对于UDP通

我的opengl编程学习(一)(简介、绘制图像、三维观察、光照)

这是我第二次学习OPENGL,第一次学习是在大二的计算机图形学课堂上,那是对opengl只是走马观花,现在过了两年,我打算把opengl进行新一编完整而系统的学习,有三个目的:1.熟练掌握opengl编程,2从opegl的体系中加深对计算机图形渲染管线的整个体系的了解,作为深入学习GPU编程的进阶,3.制作好看的CG作品. 这里是我在学习<opengl programming guide fifth edition>过程的从头到尾的整个的学习笔记,放在这里,给自己做个以后的参考,也想与大家交流

Sqlite学习笔记(四)&amp;&amp;SQLite-WAL原理(转)

Sqlite学习笔记(三)&&WAL性能测试中列出了几种典型场景下WAL的性能数据,了解到WAL确实有性能优势,这篇文章将会详细分析WAL的原理,做到知其然,更要知其所以然. WAL是什么       WAL(Write ahead logging)是一种日志模式,它是一种思想,普遍应用于关系型数据库.每个事务执行变更时,修改数据页,同时会产生日志,这样在事务提交后,不需要将修改的脏页刷盘,只需要将事务产生的日志落盘即可返回.WAL保证日志一定先于对应的脏页落盘,就是所谓的WAL.SQLI

Linux服务器Shell编程学习笔记

Shell脚本编程学习入门是本文要介绍的内容,我们可以使用任意一种文字编辑器,比如gedit.kedit.emacs.vi等来编写shell脚本,它必须以如下行开始(必须放在文件的第一行):  代码如下 复制代码 #!/bin/sh ...注意:最好使用"!/bin/bash"而不是"!/bin/sh",如果使用tc shell改为tcsh,其他类似. 符号#!用来告诉系统执行该sell脚本的程序,本例使用/bin/sh.编辑结束并保存后,如果要执行该shell脚本

Caliburn.Micro学习笔记(四)----IHandle&lt;T&gt;实现多语言功能

Caliburn.Micro学习笔记目录 说一下IHandle<T>实现多语言功能 因为Caliburn.Micro是基于MvvM的UI与codebehind分离, binding可以是双向的所以我们想动态的实现多语言切换很是方便今天我做一个小demo给大家提供一个思路 先看一下效果                                           点击英文  变成英文状态点chinese就会变成中文                         源码的下载地址在文章的最下