以下内容综合了维基百科,百度百科,各游戏开发论坛,博客等,有些地方并未详述来源;
BMEM技术(凹凸映射Bump Mapping)
BMEM技术通过一张叫做高度图(Height map)的灰度图来储存每一点的高度信息然后直接由API处理。
凹凸映射和纹理映射(Texture Mapping是将纹理空间中的纹理像素映射到屏幕空间中的像素的过程)非常相似。然而,纹理映射是把颜色加到多边形上,而凹凸映射是把粗糙信息加到多边形上。这在多边形的视觉上会产生很吸引人的效果。我们只需要添加一点信息到本来需要使用大量多边形的物体上。需要注意的是这个物体是平的,但是它看起来却是粗糙不平的。让我们来看看上边的那个立方体。如果你很近地观察它时,你会发现它上面的很多细节。它看起来好像是由成千上万个多边形构成的,其实它只是由6个矩形构成。你或许会问:“这和纹理映射有什么不同?”它们的不同之处在于——凹凸映射是一种负责光方向的纹理映射。
凹凸贴图(bump mapping),又称为皱面贴图,是一项计算机图形学技术,在这项技术中每个待渲染的像素在计算照明之前都要加上一个从高度图中找到的扰动。这样得到的结果表面表现更加丰富、细致,更加接近物体在自然界本身的模样。法线贴图是一项常用的凹凸贴图技术,另外还有许多其它的实现技术,如视差映射等等。
凹凸贴图是指计算机图形学中在三维环境中通过纹理方法来产生表面凹凸不平的视觉效果。它主要的原理是通过改变表面光照方程的法线,而不是表面的几何法线来模拟凹凸不平的视觉特征,如褶皱、波浪等等。凹凸贴图的实现方法主要有:偏移向量凹凸纹理和改变高度场。
这是一种在3D场景中模拟粗糙表面的技术,将带有深度变化的凹凸材质贴图赋予3D物体,经过光线渲染处理后,这个物体的表面就会呈现出凹凸不平的感觉,而无需改变物体的几何结构或增加额外的点面。例如,把一张碎石的贴图赋予一个平面,经过处理后这个平面就会变成一片铺满碎石、高低不平的荒原。当然,使用凹凸贴图产生的凹凸效果其光影的方向角度是不会改变的,而且不可能产生物理上的起伏效果。
在游戏中,所使用的算法确切的说应该叫做fake bump mapping ,假凹凸贴图。因为在游戏中BumpMap并没有改变物体的表面而只是影响光照的结果,欺骗眼睛而已。最简单的做法是,直接把BumpMap叠加在已经渲染好的表面上,造成亮度上的扰动,从而让人以为是凹凸的--这个很容易理解,把一面白色的墙面有技巧的部分划成灰色就会变成蚀痕,这些诸位会比小的更擅长。而计算复杂度是基本加减法。这个所谓的 FakeBumpMapping 从Geforce2就开始硬件支持,但是从来没有大范围的应用过。
不过有趣的是,BumpMap这个东西却从未过时,在后来的渲染算法中,其储存表面高度域的特性仍然发挥着巨大的作用。
什么是凹凸图 Bump Map:
凹凸图和纹理图很相似。但是不同的是,凹凸图包含的不是颜色信息,而是凹凸信息。最通常的方法是通过存储高度值实现。我们要用到一个灰色的纹理图,灰色的亮度体现出每个点分别凸出多少(见上图)。这就是一个非常方便的保存凹凸图的方法,而且这种图很容易制作。这副图具体又是怎样被渲染器使用的呢?你接着往下看就会明白了。
当然,你并不一定要把自己局限于这些简单的图形,你可以扩展,用它来做木材,做石头,做脱了漆的墙面,做任何你想做的物体。
凹凸映射背后的原理 :
让我们来看看一个粗糙的表面。
从远处看,你判断这个物体是粗糙的的唯一证据是在它表面上下的亮度有改变。你的大脑能够获得这些亮暗不一的图案信息,然后判断出它们是表面中有凹凸的部位。上边的一幅图就说明了这一点。你可以发现它是一个浮雕式的表面。
凹凸贴图工作原理:
凹凸映射是补色渲染技术(Phong Shading Technique)的一项扩展,只是在补色渲染里,多边形表面上的法线将被改变,这个向量用来计算该点的亮度。当你加入了凹凸映射,法线向量会略微地改变,怎么改变则基于凹凸图。改变法线向量就会改变多边形的点的颜色值。就这么简单。
现在我们需要将凹凸图中的高度信息转换成补色渲染用到的法线的调节信息。
我们现在将凹凸位图的信息转换成一些小向量——一个向量对应于一个点。请看下边一副放大的凹凸图。相对亮的点比相对暗的点更为凸出。看清楚了吗?
现在计算每个点的向量,这些向量表征了每个点的倾斜情况,请看下图的描绘,图中红色小圆点表示向量是向下的。
有很多计算向量的方法,不同的方法精确度不同,但是选择什么方法要取决于你所要求的精确度是个什么层次。最通常的方法是分别计算每个点上X和Y的倾斜度:
- x_gradient = pixel(x-1, y) - pixel(x+1, y)
. - y_gradient = pixel(x, y-1) - pixel(x, y+1)
在得出了这两个倾斜度后,你就可以计算多边形点的法线了。
现在你可以看到被调节后的新法线向量了。这个调节公式很简单:
New_Normal = Normal + (U * x_gradient) + (V * y_gradient)
有了新法线向量后,你就可以通过补色渲染技术计算出多边形每个点的亮度了。
法线贴图(Normal Map)
但事实上游戏编程员却通常并不喜欢使用BMEM技术,因为他执行速度慢,因此他们通常使用DP3技术:直接把高度图(Height map)转换成一张法线图(Normal Map),其图的RGB分别是原高度图该点的法线指向:Nx、Ny、Nz,这张图可由Direct3D的专门函数帮助我们计算。最后在渲染的时候直接将该高度图的每个像素与光源的向量点乘,即可得到表示每一点的明暗系数的图:根据高度图,越突出的地方,法线与光源夹角越小,该点的数值越大。接着将这张图乘到渲染线中即可,这样就使模型在背光的凹处有阴影而在面向光源处更亮的效果,这样的3D模型看起来就像真的凹凸不平一样!这些都可以直接在渲染流水线中由机器完成。具体可以使用以下简单的语句来实现:
//将光源位置转换成ARGB
DWORD Vector2ARGB(D3DXVECTOR3 *v,float height)
{
DWORD r=(DWORD)(127.0f*v->x+128.0f);
DWORD g=(DWORD)(127.0f*v->y+128.0f);
DWORD b=(DWORD)(127.0f*v->z+128.0f);
DWORD a=(DWORD)(255.0f*height);
return((a<<24L)+(r<<16L)+(g<<8L)+b);
}
//生成法线图
D3DXComputeNormalMap(pNormalMap,pHeightMap,NULL,0,D3D_CHANNEL_RED,1.0f);//pHeightMap为原高度图的指针,pNormalMap为一张空纹理,用于存放法线图
//在渲染程序段中可以这样写:
DWORD F=Vector2ARGB(&light,0.0f); //light是单位化的光源向量
pD->SetRenderState(D3DRS_TEXTUREFACTOR,F);//pD是D3D的设备指针,这句将光源法线参数输入
pD->SetTexture(1,TEXTURE);//设置原纹理,如上面的球,如有需要可以贴上纹理样式
pD->SetTexture(0,normalmap);//使用上面生成好的法线图
pD->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);//设置“来源1”为法线图
pD->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3);//将“来源1”(法线图)与“来源2”(光源法线)进行点乘
pD->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_TFACTOR);//设置“来源2”为光线的光源法线参数
pD->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_TEXTURE);//这步和下面几步将图片的原纹理加上
pD->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_MODULATE);
pD->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_CURRENT);
以下转载至 :http://www.cnblogs.com/lancidie/archive/2010/11/02/1866914.html
一个平面——这个平面在现实中并不是一个“平”面,例如砖墙的表面带有石质浮雕等等。这样的情况如果要求游戏开发人员将复杂的3D细节都做出来是不现实的,因为即使不计较在建模时候的复杂度,过多的3D细节也同样会大量消耗显示芯片的性能,让游戏根本没有可玩性。
可行的方法就是将这个平面用一个贴图覆盖,用贴图的纹理实现一定的凹凸效果。但是这种方法实现的效果并不是很好,因为如果视角一变化,看起来就会像一张简单的画有图案的平面了。
后来,聪明的游戏开发者想出了一种方法,就是在贴图过程中对贴图进行一定的处理,从而保证了在视角变换以后仍然保证有较为明显的凹凸效果。
光与影,法线贴图技术的物理学基础
我们知道,人之所以能够对景物看出立体感的主要原因是因为人有两只眼睛。两只眼睛看的景象是不同的,所以人们才能分辨出立体感来。但是,由于电脑的屏幕是一个平面,分辨3D效果就只能靠光影效果来实现了。
举个简单的例子,这就像我们画素描的时候,为了不让一个球体看起来像是一个圆圈,必须让球体的一些区域是亮的,一些区域是暗的。而且从亮部转向暗部的时候是一个均匀的按照物理模型特点的过渡,这样画出来的球体才像个球体,电脑为我们绘制的过程也是一样。
基于这个道理,我们就不难理解可以通过贴图局部的亮暗变化来实现假的3D效果。换一种说法就是说我们可以通过在贴图上的局部做一些亮暗的变化来做到一种假的3D效果。
光照因角度不同而呈现不同的明暗
那么如何实时的对贴图进行转换呢?如果要实现虚拟的光影变换,我们最起码需要知道在一个平面上真正的凹凸的情况,这样才能让显示芯片进行运算,生成一种假的凹凸的效果。
显然,记录真实的凹凸模型是得不偿失的——如果那样的话就没有任何意义了,我们需要用一种非常简单的方法来记录一个贴图的凹凸情况,于是就诞生了一种全新的方法,法线贴图技术。
接下来,我们再回到我们刚才谈到的法线贴图的话题上。
法线贴图就是记录了一个需要进行光影变换的贴图上的各个点的凹凸情况的贴图,显示芯片根据这个贴图的内容,来实时的生成新的有过光影变化的贴图,从而实现立体效果。
那么,究竟是怎样利用法线贴图记录一个平面或者说是一个贴图的凹凸情况呢?我们知道,物体表面产生明暗变化的直接原因,就是光线照射角度的不同,光线垂直于平面的地方就亮,光线斜射到平面的地方就暗,光线照不到的地方就更暗(应该是黑色,但是由于环境光照所以不会有阴影是真正的黑色)。
借色彩之值存法线之向,巧妙的存储
学过初中物理的朋友一定还都记得,表示光线射向平面的角度时通常使用光线和该点法线角度来表示。这也就意味着,如果我们将一个贴图上所有点的法线记录起来的话,就不难再利用这些信息实现后期的假的凹凸效果了。
记录这些法线的载体就被我们称为法线贴图。为什么称之为贴图呢?我们知道,一条法线是一个三维向量,一个三维向量由X、Y、Z等3个分量组成,于是人们想出了一个聪明的方法,就是以这3个分量当作红绿蓝3个颜色的值存储,这样的话就生成一张新的贴图了,这就是法线贴图的来历。
采用色彩通道存储法线向量
法线贴图其实并不是真正的贴图,所以也不会直接贴到物体的表面,它所起的作用就是记录每个点上的法线的方向。所以这个贴图如果看起来也会比较诡异,经常呈现一种偏蓝紫色的样子。
法线贴图的生成过程
Doom3中的一张纹理贴图和这张贴图对应的法线贴图
『小提示-05:事实上,真正的法线贴图并不是记录贴图上每个点的法线的绝对角度,而是记录的是相对于平面的一个差值。这样的话,随着平面的3D变换都能够实现即时的法线运算了。』
传统纹理压缩,法线贴图不再适用
采用法线贴图技术的优势就是利用很少的资源实现了效果非常好的凹凸效果
高光贴图(specular map)
高光贴图在定义上是针对某特定的角度范围反光,而不是全范围的漫射光。基本上高光的亮度是取决于面的法线方向、摄像机和光源的平均方向,除此之外,高光贴图还可以反映不同的材质,例如金属的反光范围较小,比较接近全漫射光,而且高光还可以体现结构的光滑程度。
物体上某一点的光照后的颜色是由环境光,漫反射光,以及高光决定的,而除了环境光,其他两个都是分光源的diffuse,specular和材质本身的diffuse,specular,而高光图一般是存储材质的specular属性以及应用phong光照时的材质的高光系数,这样就可以利用光照公式计算了。