`
mmdev
  • 浏览: 12893526 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

【GPU编程】《The Cg Tutorial》学习之环境贴图(Environment Mapping)

 
阅读更多

本例实现了一个基于GPU加速的OpenGL+Cg实现的环境贴图例子。


环境贴图(Environment Mapping)也叫做反射贴图,这项技术由Blinn和Newell于1976年提出,可以用于模拟光滑表面对周围场景的映射效果。生活中有很多这样的例子,比如一个光滑的球体,我们可以在它表面看到周围的环境。图一是维基百科给出的例子:


图一 环境贴图实例

环境贴图基于这样一种假设:物体周围的场景一切都位于无穷远处,这样能够编码到一个被称为环境贴图的全向图像里。而且,模型只能反射环境,不能反射本身。这样也不要期望多个反射,比如两个模型相互反射的情况。

一、立方体纹理

环境贴图最常用的纹理是立方体纹理。它包括六幅正方形的纹理图像,即组成了我们用来生成环境贴图的全向图像。图二是一个环境贴图的例子。


图二 一个环境贴图例子


图三 立方体环境贴图示意图

访问立方体纹理需要一个三维的纹理坐标,它代表了一个三维的向量,这个向量从立方体的中心出发,向外射出,立方体的一个面相交。

需要注意的是:访问立方体所得到的纹理颜色只与这个向量的方向有关,而与大小没有关系。正因为环境映射依赖于方向而不依赖于位置,它在平的反射表面上表现得很差。例如镜子,在镜子上反射主要依赖于位置,相反,环境映射在曲面上表现得很好。

产生立方体纹理:需要得到两个方向的图像,可以把照相机摆在物体中心的位置,然后向六个方向以90度视角拍照。必须要是90度,这样6幅图像才能刚好组合成一个全向图像。

从磁盘加载图像生成纹理可参考:GLAUX纹理生成


二、环境贴图的算法步骤如下:

1、根据视线方向和法向量计算反射向量;

2、使用反射向量检索环境贴图得到纹理信息;

3、将纹理信息融合到当前像素中。


反射向量计算

图四绘制了反射向量的计算示意图。


图四 反射向量计算

计算公式:

R = I - 2 * N * (N * I)

I是入射光线,N是法向量。

Cg语言提供了计算反射光线的库函数:

reflect(I,N)

注意:N必须被单位化,且向量必须是3维的。

计算得到的反射光线向量长度和入射光线向量长度相等。


在本次实现中,我把反射向量的计算放在顶点程序中,虽然这样效果不如把它放在片断程序中效果好,但是用片段程序计算反射向量并不被一些基本片断profile支持。

顶点Cg程序vertex.cg:

环境贴图通常是基于世界空间来确定方向的,因此我们在世界坐标系中进行计算反射向量。要实现这一点,必须把其余的顶点数据变化到世界空间。我们也需要提供一个uniform的模型变换矩阵把顶点和房法向量变换到世界空间。

模型变换矩阵的计算可能稍微有点复杂。他需要根据模型变换包括旋转平移进行计算。

在这个实例中,在绘制模型猴头之前,进行的模型变换是:先旋转、再平移。

我们先依据旋转的参数计算出旋转矩阵rotateMatrix,计算函数:

其数学推导:

图五 旋转变换矩阵计算

然后进行平移变换矩阵translateMatrix的计算:

其数学依据:

图六 平移变换矩阵计算

然后得到模型变换矩阵modelMatrix = tranlateMatrix * rotateMatrix(注意顺序:先旋转变换,再平移变换)。


片断Cg程序fragment.cg:

注意:我们最后需要将环境贴图所得颜色与模型本身颜色进行混合,这样做的原因是更加贴近现实,因为没有完全反射的物体。

模型本身的颜色是通过访问一个二维纹理得到的,这个二维纹理也是从磁盘加载一幅图像生成。


程序所载入的模型是一个猴头,其数据放在一个.h头文件中,由定点坐标、法向量以及三角形定点索引等数组组成。

程序运行效果:

我所使用的用来构建环境贴图的6幅图:

用于模型本身纹理映射的图:


折射效果的实现

折射的物理依据:

我们一般假设光线只进行一次这是,即忽略光线从介质射出时发生的折射,这样是为了简化计算,而且人眼也不会感觉到和现实有明显的区别。


折射光线计算

Cg提供了计算折射光线的函数refract:

这样,和上述反射环境贴图的区别就是:用折射光线向量去访问立方体环境贴图。

顶点Cg程序:veretx.cg:


片断Cg程序fragment.cg:


运行效果:




分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics