实时阴影绘制技术研究

C++博客 首页 新随笔 联系 聚合 管理
  48 Posts :: 20 Stories :: 57 Comments :: 0 Trackbacks

转载自:http://17de.com/library/HL2/SourceEngine.html

原文地址:http://17de.com/library/HL2/D3DTutorial10_Half-Life2_Shading.pdf

  在Half-Life 完成之后不久,Valve开始筹备他们的下一个主打游戏--Half-Life 2。在商讨游戏引擎的采用问题上,开发小组明白到原版游戏所采用的改良Quake 1引擎对于Half-Life 2来说显得过于破旧,而且在很多的方面都不符合这一代游戏发展的要求。于是,vlave的开发小组决定从美工设计以及游戏代码开始,设计出一个全新的游戏框架,并在其中加入了一套来自havok的定制物理引擎。

  对于一个游戏来说,“引擎”就是一个系统,就像是一辆汽车的发动机一样,他能输入来自加速器的动能,并输出到轮子的转动。软件(在这里为游戏)的引擎实现的东西和汽车的发动机一样,输入来自框架(某些程序或者文件的片段),然后输出程序员们想要的结果。再次拿汽车的发动机为例,一个软件的引擎不能自行运作,他必须依靠另外一个系统,就好像,你只能开着“一台汽车”而非“一台发动机”去上班。在Source中,一个纯粹的引擎只能是一堆代码,完全不具有可玩性。所以不难对引擎下这样的定义:引擎就是一套让游戏元素发生互动关系并将其编译成可玩程序的代码或程式,依靠框架进行操作。



 

Source引擎总览

  Source并不是一套简单的3D引擎,也可以是说,他并非只是一套渲染器。Source引擎包含了很多不同的模组,程序员可以在引擎的程序包中方便地取出以及添加进其他的元素。

  在这篇文章里面,我将会为大家展示这些模组是什么回事并且对游戏产生怎样的影响。在下面将要陈述的问题主要讲解在Source引擎中一些令人惊奇的模组是怎样对整个游戏的画面以及游戏效果产生影响,而不是去解释Source引擎的代码怎样去运作。对于此,可能大家会觉得比较枯燥,毕竟,这些在程序实现上的问题针对的是对游戏有一定研究的玩家。我们并没有打算深入到Source的程序代码进行研究,因为这些已经不属于我们一般老百姓可以研究的范畴了。在这里必须要给读者澄清一下,由于目前Source引擎的非公开性,我们并不能准确地将Source引擎中每一个模组的特性都准确地表示出来,如果你一定要深入研究的话,请参考Half-Life 2发布之后的 SDK 参考文档以及Valve以后的白皮书。本文的章节细分以笔者对Source引擎的了解为依据。请根据实际情况印证并参考其他专著以及文献。

  • 3D 引擎
    • 渲染器
      • Pixel 、vertex shaders
      • 光影效果
      • HDR (High Dynamic Range)
    • 动画以及角色面部表情
    • 几何构成
    • VGUI游戏界面
  • 物理引擎,基于Havok 定制的物理引擎
    • 刚体的动力学模型以及关节约束机制
    • 弹性机构、绳索机构、布纹处理、车辆系统
    • 水以及火光
    • 粒子系统
    • 怪物/NPC/程序 上的物理学系统
  • 材质系统
  • AI 系统


 

在这里,我尚且用3D engine来描述造Source引擎中,生成引擎输出图像及其几何体的模组。

渲染器

  这部分最能体现显卡的功力,也是玩家最为注重的一个重点。渲染器的作用主要主要功能就是采集画面几何体和材质的数据,通过一系列繁杂的过程,生成一个三维的图像。Valve并没有重新创造Source引擎的渲染器而采用了Microsoft DirectX 9.0 的 API,并借助Half-Life SL高阶编程语言编写引擎,在很大程度上节省了宝贵的时间,这归功于 DirectX9良好的硬件兼容性以及先进的代码设计流程。原有的Half-Life 1引擎被设计成支持 OpenGL and Direct3D的双模式,但正如各位所见,这个引擎在Direct3D模式下的渲染十分糟糕,特别是在目前主流的显卡上工作时,其效率以及画质远不及OpenGL模式下的表现。在设计Source引擎的时候,Valve放弃了ogl的渲染模式进而采用DirectX架构,以增强其硬件兼容性以及对未来特效的支持,比如是Shader2.0b甚至是Shader3.0 Model的支持。

Pixel and Vertex shaders

  Shader就是一些能够在GPU/VPU上执行的程序句段。目前市面上流行的游戏中,采用实时渲染的画面均大量运用了Shader,你的显卡无时无刻在处理着这些Shader信息。现代显卡主要的改进就是用Shader代码替代沿用自GeForce GTS时代固定的硬件T&L (Transform and Lighting)。Shader允许程序员创建他们喜欢的Shader特效程序片段以取代有限个数的固化在显卡核心中的预设特效。经过Shader编程之后,如果有一个关于bump mapping的技术推出,程序员只需改写或者加入该部分的Shader代码便能使这些特效运行在现今的显卡上,而不需等待下一代的显卡出现。于是,显卡的处理特性便得以最大程度地延伸。在程序接口方面,由Microsoft推出的HLSL、nVIDIA推出的Cg、以及OpenGL小组推出的GLSL都是编写Shader的工具。能和目前个人PC、工业用电脑上的DirectX以及OpenGL很好地对应。

  Source对directx中的pixel/vertex shaders version 2.0提供了完整的支持,Valve最近的声明指出Source引擎将在未来硬件成熟的时候提供对Shader3.0的支持。目前的Source引擎中,所有的directX 9 Shader均在 (high level shader language)下完成,对代码的运用上只需简单地插入片段,省却了在底层使用汇编语言重编译的麻烦,增加了Source引擎的弹性。在引擎代码方面,所有的代码均用C/C++ using Visual Studio 6.0进行开发,有很大的开放度以及可扩展性,目前已经有数家公司得到Valve授权采用Source引擎进行下一代游戏的开发,除传统的FPS游戏之外,还有aRPG,SPD等模式,相信在明年开初将会见到很多采用Source引擎制作的佳作。

  对于玩家,Shader就能实现依靠驱动程序实现更加多以及更富弹性的特效,在Half-Life 2中最为凸出的Shader2.0特效就是那些吸引眼球的充满反射和折射的水纹效果。在目前推出的基于Source引擎的CS:Source选项设置中单独对水纹效果提供了一个现实效果设置选项。

光影效果:

在 Source 引擎中使用了两类的方法处理光影:辐射度光影贴图和环境光立方体贴图。

  • 辐射度光影贴图主要用于静态的大型的物体,比如地形模型。
  • 环境光立方体贴图用于动态 的模型或模型库中可重复调用的模型,比如各种游戏中的人物角色、家具陈设、各种在游戏中可拿起的具有物理特性的物体。

辐射度光影贴图

  整个引擎的光影效果实现占据了Source引擎的绝大比重,这里只略略讲述Half-Life 2画面成功的秘诀--辐射度光影贴图。在 Source 引擎的渲染器中,辐射度光影贴图扮演着一个最为重要的角色。先给大家一个辐射度光影贴图所能实现的大概效果:

方向性光照
辐射度光照

  在Source以及整个Half-Life 2架构中,光能传递贴图起到的作用就是将光影贴图和法线贴图的优点有机地结合,笼统地说,就是将更加真实精确的光影效果(辐射度光照)以及更加细腻的模型细节(法线贴图)通过算法整合到最后的效果图中。

 

辐射度法线贴图基本方程

  在传统的法线贴图中,每次工作只会累积一个光源的效果,多重漫射光将会由NL在多通道中进行合成,在对Light Map进行辐射度处理的时候只能处理一个颜色值。辐射度法线贴图能在一个通道中实现任意多光线的处理,基本处理方程会转化为每个切面的向量计算。在DirectX中,法线是可以转换的,并不局限于形体,可以扩展到光线、颜色……。在辐射度贴图中,使用下面的方程将法线从法线贴图中转换为上述辐射度法线贴图基本方程:

lightmapColor[0]*dot( bumpBasis[0], normal )+lightmapColor[1]*dot( bumpBasis[1], normal )+lightmapColor[2]*dot( bumpBasis[2], normal )

  在3D物体创建上,一般都会使用cube map制作镜面反射光线,在Source引擎中,cube map会在引擎的渲染器中预先处理,根据嗅探器的作用,在编辑器中创建的环境会选用最近、最贴切的cube map创造反射光线,为解决材质的边界问题,可以手动为某个表面手动添加cube map

  在Hammar这个Half-Life 2地图编辑器中,设计者在材质表面安设了环境探测用的实体以作为镜面反射的参照物。

  接下来将会为大家讲解在Half-Life 2中整个静态环境的生成。首先将会为大家介绍一下我们想得到的效果,并以一个小范围为例说明整个Shader序列的创建过程:

实现的效果可以用下面的流程图进行说明:

  左下脚的Normal法线贴图和三张Lightmap混合后的辐射度贴图再加上漫反射系数的控制就可以创建出以上所说的辐射度法线贴图;再以加法加上传统的表面光滑度以及反射度的贴图结果,就可以生成最终的贴图效果。在Source中创建一个静态的环境时还需要用到三张Lightmap,主要是考虑到为了适应任意光源的作用。在下面的分组图中,大家会看得更加明白:

LightMap #1
LightMap #2
LightMap #3

 三张直接辐射能贴图整合之后的效果,由于缺乏了法线贴图的支撑,整体没有细节可言。

由于这个过程处于贴图的预处理程序,需要考虑到整体执行的效率,因此只采用了分辨率较低的lightmaps贴图(因为diffuse材质的irradiance十分平滑的,只需很小的分辨率,渲染结果是通过filter还原),在这一步骤中,渲染的贴图可以说丢失了所有的细节。如果盲目增大lightmaps的分辨率,处理时间会成倍增加,显存带宽也会被大量占据。

因此,Source引擎将lightmaps分成三个成分,每个贴图都有其对应的基本方程,最后根据法线贴图储存的法线进行混合得出第一步的处理结果,在很大程度上利用了低分辨率的好处,并且能将法线贴图所最擅长的细节表达发挥出来。

另一方面,程序设计员可以采用不同的法线贴图与之结合,在debug模式下实时检查渲染结果变得比以前方便得多。

接下来,Source会将上面由Lightmaps生成的辐射贴图附上法线贴图,

辐射度贴图
法线贴图
被细节化的辐射度贴图

  物体的表面有凹凸的细节,形状方面需要依靠法线贴图实现,至于光线的表现方面,则需要依靠漫反射系数来确定。下面的流程就是继续细化并加上法线贴图的辐射度贴图。

辐射度法线贴图
漫反射系数
被加上漫反射系数的辐射度法线贴图

同时,考虑物体表面反光程度的镜面反射贴图也在进行之中,第一步也是采用立方体反射贴图和法线贴图的混合:

立方体反射贴图
法线贴图
法线贴图加载到镜面反射贴图上
上一步生成的镜面反射法线贴图
镜面反射系数
镜面反射法线贴图和镜面反射系数的混合

最后的步骤,由加上了漫反射系数的辐射度法线贴图和加上了镜面反射系数的镜面反射贴图进行加法运算,得出最后结果

加上了漫反射系数的辐射度法线贴图
加上了镜面反射系数的镜面反射贴图

最后结果

在整个渲染流程中,法线贴图起着引导性作用,ATI目前的顶级产品Radeon X800系列已经完整支持新一代的法线贴图处理方式,并对大材质的贴图采用了全新的3Dc纹理压缩技术。虽然我们目前未收到任何关于Source引擎采用3Dc纹理压缩的消息,但从ATI发布的白皮书来看,X800系列显卡在处理法线贴图的算法技术上会和Valve有更好的沟通,实操效果会占据一定的优势。

环境光立方体贴图
 

    《半条命2》动态物件和人物模型的光影效果

    前面介绍了静态场景的光影效果,下面我们来看看在《半条命2》中的动态模型是如何绘制的。

    核心技术-基于环境光立方体 (Ambient cube)的光能传递凹凸贴图技术

    由于动态模型的位置和形状都有可能发生变化,所以就不能像静态场景那样处理了。动态模型所受到的光照也是由直接光照和间接光照组成的。在Source引擎中,只能从照射一个模型的所有直接光源中选出有两个最主要的来使用比较复杂的光照公式进行实时计算,而其他比较次要的直接光源以及场景中的间接光源都会被预先保存到一个称为“环境光立方体”的东西中。

环境光立方体

    首先Valve的技术人员在关卡场景中放置一个虚拟的立方体,然后地图编辑器就分别对立方体的每个面计算出垂直通过这个面的环境光的颜色和强度。场景里那些比较次要(远或暗)的直接光源,也被计算在内。

    对于每个面都计算一个光照颜色,可以得到六个颜色,基本上代表了从四面八方射来的穿过这个体积中的所有比较次要的光线的信息。这六个颜色是可以预先计算出来保存在关卡场景数据里的。

    通过模型表面的法线来决定取这六个颜色的比重并将它们混合,就可以得到一种类似于光能传递的效果。在环境光立方体的六个面中,必然有至少三个面会在法线的相反方向,这些面的颜色忽略不计。所以一般只有另外三个面的颜色会用到。法线方向越正对哪个面,这个面对应颜色所占的比重就越大。

    用环境光立方体技术渲染的蚁狮模型,虽然没有加入凹凸贴图,但是已经有一种类似光能传递的效果。

从立方体环境贴图中获取光照的着色器代码:

float3 AmbientLight( const float3 worldNormal)
{

   float3
nSquared = worldNormal * worldNormal;
   int3
isNegative = ( worldNormal< 0.0 );
   float3
linearColor;
   linearColor = nSquared.x * cAmbientCube[isNegative.x] +
                 nSquared.y * cAmbientCube[isNegative.y+2] +
                 nSquared.z * cAmbientCube[isNegative.z+4];

   return
linearColor;
}

 
    在前面说道为了结合使用法线贴图,对于静态场景,一个面对应着三张光照贴图。而在这里也是类似的,一个动态模型对应着三个环境光立方体。这三个环境光立方体面上的颜色是分别根据各面局部坐标系的三个基向量来计算出来的。

 a.b.c分别使用相对于三个基向量的环境光照图和环境光立方体的效果

    我们把法线贴图贴到场景中看一看:

 法线贴图

    按照和静态场景类似的方法用法线贴图来寻址环境光立方体的颜色,就可以得到下面的效果了:

    和前面没有凹凸细节的图对比一下吧:

    不要忘了,模型本身也是有材质贴图的。我们把它贴上去看一看:

模型自身的材质贴图,没有光照

    如果把光照效果和它混合,就成了这个样子:

混合操作依然是颜色各通道相乘。角色表面具有凹凸细节。

    和没有使用法线贴图的效果对比一下:

没有凹凸贴图

    漫反射的部分完成后,就该加入高光了。对于角色的高光,Source引擎仍然使用高光环境反射贴图。

完全的高光环境反射,也没有加入凹凸贴图,好一只光滑的金属蚁狮

加了凹凸贴图

高光强度贴图,也是越白的地方高光越强,
我们可以看出蚁狮表面的高光并不是很强的

用高光强度贴图去过滤高光

把高光叠加到漫反射部分上去,得到最后的效果

折射效果:

折射效果用于场景中的玻璃或者水面之类的特效。如果我们把场景中的一个多边形面所挡住的东西画到贴图上,再贴到这个面上去,那么这个面看起来就是透明的了。Source 引擎中使用 StretchRect() 从场景渲染后暂存的帧缓存中复制出一个纹理,就是我们常说的实时渲染到纹理。如果我们在贴这个贴图时做一个扰动,比如加一些水波或者凹凸的扰动,那么这个面看起来就像是水面或者凹凸不平的玻璃的折射的效果了。这个纹理将参照 dudv 凹凸贴图或法线贴图在屏幕空间中做适当的偏移,然后再投射到几何体上。借助法线贴图和最新的DirectX 9.0 Pixel Shader技术,加入这个扰动的过程十分容易实现。

部分着色器代码:

sampler RefractSampler:          register( s2 );
sampler NormalSampler:           register( s3 );
sampler RefractTintSampler:      register( s5 );
const float3 g_EnvmapTint:       register( c0 );
const float3 g_RefractTint:      register( c1 );
const float3 g_EnvmapContrast:   register( c2 );
const float3 g_EnvmapSaturation: register( c3 );
const float2 g_RefractScale:     register( c5 );

struct PS_INPUT
{
float2 vBumpTexCoord: TEXCOORD0;
float3 vWorldVertToEyeVector: TEXCOORD1;
float3 x3tangentSpaceTranspose: TEXCOORD2;
float3 vRefractXYW: TEXCOORD5;
float3 projNormal: TEXCOORD6;
};

float4 main( PS_INPUT i ) : COLOR
{
// Load normal and expand range
float4 vNormalSample = tex2D( NormalSampler, i.vBumpTexCoord);
float3 tangentSpaceNormal= vNormalSample * 2.0 -1.0;
float3 refractTintColor= 2.0 * g_RefractTint * tex2D( RefractTintSampler, i.vBumpTexCoord);
// Perform division by W only once
float ooW= 1.0f / i.vRefractXYW.z;
// Compute coordinates for sampling refraction
float2 vRefractTexCoordNoWarp= i.vRefractXYW.xy * ooW;
float2 vRefractTexCoord= tangentSpaceNormal.xy;
float scale = vNormalSample.a * g_RefractScale;
vRefractTexCoord = vRefractTexCoord * scale;
vRefractTexCoord += vRefractTexCoordNoWarp;
float3 result = refractTintColor * tex2D( RefractSampler, vRefractTexCoord.xy);
return float4( result, vNormalSample.a);
}

水面的视觉效果:

    首先我们来看反射。Source 引擎首先将水面上要反射的景物上下颠倒地渲染到一张贴图上。然后是折射,将水下的景物渲染到另一张贴图上。然后将这两张贴图贴到水面的多边形上,同时根据凹凸贴图,使用 Pixel Shader 对纹理坐标进行调整,以加入扰动,得到水的最终效果!简单吧。 然后将这两张贴图贴到水面的多边形上,同时根据凹凸贴图,使用 Pixel Shader 分别加入扰动,得到水的最终效果!简单吧。如果没有DirectX 9.0中的Pixel Shader技术,想对反射和折射贴图进行象素级的扰动来实现这样的水面效果是十分困难的。在Source引擎中对水面的视觉模拟范例 只采用了30行左右的代码:

最终的效果
反射贴图
折射贴图

float4 main( PS_INPUT i ) : COLOR
{
// Load normal and expand range
float4 vNormalSample= tex2D( NormalSampler, i.vBumpTexCoord);
float3 vNormal= vNormalSample * 2.0 -1.0;
float ooW= 1.0f / i.W; // Perform division by W only once
float2 vReflectTexCoord, vRefractTexCoord;
float4 vN; // vectorize the dependent UV calculations (reflect = .xy, refract = .wz)
vN.xy = vNormal.xy;
vN.w = vNormal.x;
vN.z = vNormal.y;
float4 vDependentTexCoords = vN* vNormalSample.a * g_ReflectRefractScale;
vDependentTexCoords += ( i.vReflectXY_vRefractYX * ooW);
vReflectTexCoord = vDependentTexCoords.xy;
vRefractTexCoord = vDependentTexCoords.wz;
float4 vReflectColor = tex2D( ReflectSampler, vReflectTexCoord) * vReflectTint; // Sample reflection
float4 vRefractColor = tex2D( RefractSampler, vRefractTexCoord) * vRefractTint; // and refraction
float3 vEyeVect= texCUBE( NormalizeSampler, i.vTangentEyeVect) * 2.0 -1.0;
float fNdotV= saturate( dot( vEyeVect, vNormal) ); // Fresnel term
float fFresnel= pow( 1.0 - fNdotV, 5 );
if( g_bReflect && g_bRefract) {
  return lerp( vRefractColor, vReflectColor, fFresnel);
 }
else if( g_bReflect) {
  return vReflectColor;
 } else if( g_bRefract) {
  return vRefractColor;
 } else{
  return float4( 0.0f, 0.0f, 0.0f, 0.0f );
 }
}

HDR (High Dynamic Range)

以下图的例子说明:

  如果你有一间只有一角被照亮的,灰暗的房子,那么在这个角落里的物体旁边的光线会比房间其他地方要光。这就是一个”泛光”的现象。如果你将整个房间照亮的话,在这个角落上的物体也会在视觉上出现高于正常的亮度。在这个黑暗的房子的顶棚开一个洞,比如是天窗或者是破旧的穿洞什么的,让外面的阳光直射进屋,这时在天窗或者孔洞的周围就会出现泛光的现象,这一圈的范围会出现很多鲜明生动的色彩,


 

  这些效果主要是因为眼睛会对你看到的亮度作出调节,虹膜会不断地受到周遭光源环境的影响,而促使瞳孔扩张和收缩活动,眼镜会让瞳孔处在一个能接受所见景物最高亮度和最低亮度之间的一个平衡点上,并会不断随环境变换而作出调节,视觉区域中,和这个平衡点相距甚远的色彩区域则不会表现该点的细节,而且会和背景以及光线在大气中的折射产生丰富的色彩范围,于是,泛光的区域便会出现。

  在没有HDR的游戏里面,这些看似很简单的东西绝对是不可能发生。这时因为在这些游戏中,每个像素储存的只是颜色的信息,或者只是在游戏中会出现的一些表面、或者网格信息,几何体被光源照亮的程度只会由渲染器简单抬高或者减低像素的色彩亮度以表达这个像素是否处在光照环境,和周围的环境是没有任何联系的,真实的高光以及泛光效果自然不会被真实地反映出来。在HDR技术中,像素被赋予亮度参数,色调的计算采用了浮点精度,因此,光源强度不再仅仅限于黑白两色和灯光颜色的混合,Alpha通道的运用丰富了色彩的输出层次。当然,在渲染器引擎中,色彩范围的增减还是要依 靠像素被照亮的程度来进行模拟。目前ATI的8500以上显卡均已经支持浮点着色以及缓冲区的多对象着色,nVIDIA的显卡也已经从NV40开始支持该功能,能通过硬件实现 HDR 效果,在游戏中,很多近似于现实的物理效果能被模拟出来。

HDR渲染包含多种不同的技术,而Lombardi详细透露了Valve对于LC的计划,他们将努力在这一前沿领域再次远远领先其他开发者/公司。

比如,Lombardi提到了Bloom特效:“这一特效已经在许多其他游戏中得以应用并且往往被误认为是HDR的完全实现。”

有趣的是,以下的特效集被Valve描述为“我们在Lost Coast中对HDR的定义”,以及“在Source引擎开发中HDR的初步实现”,这暗示着我们不但可以期待着在其他基于Source引擎的游戏中看到HDR,而且未来这些HDR特效将会更多更好。

以下是目前 Valve 计划实现的HDR特效:

Bloom:
用于生成在场景亮处边缘的“模糊效果”,模仿相机的曝光过度。


半条命2,Lost Coast,HDR,《半条命2》新关卡



半条命2,Lost Coast,HDR,《半条命2》新关卡


HDR Skybox:
渲染天空的多次曝光,允许实时曝光调整。对于LC来说有16种的HDR Skybox变化。

半条命2,Lost Coast,HDR,《半条命2》新关卡



半条命2,Lost Coast,HDR,《半条命2》新关卡


HDR Cube Map(HDR立方体贴图):
由引擎生成,使用HDR skybox和HDR light source及HDR light map合力产生。HDR Cube Map让一个物体的反射光线更符合光源的亮度。

半条命2,Lost Coast,HDR,《半条命2》新关卡



半条命2,Lost Coast,HDR,《半条命2》新关卡

HDR Water Reflection/Refraction(HDR水反射/折射):
无论光源的反射有多亮,水面的 “白热”点总是和Bloom效果一起出现。当在水底看着太阳时可能会出现类似的效果。

半条命2,Lost Coast,HDR,《半条命2》新关卡



半条命2,Lost Coast,HDR,《半条命2》新关卡

HDR Refraction Effect(HDR折射效果):
HDR光照穿过可折射材料传输时产生的符合这些材料性质的效果(比如阳光照射在LC中修道院的彩色玻璃时产生绚丽的五彩光芒)。

半条命2,Lost Coast,HDR,《半条命2》新关卡



半条命2,Lost Coast,HDR,《半条命2》新关卡


HDR Light Map(HDR光照贴图):
通过radiosity(计算光线形态及阴影来生成3D图象)过程产生,将光弹跳/全局照明也考虑在内。我们可以在LC的修道院内正对着窗户的墙上看到这种特效。

半条命2,Lost Coast,HDR,《半条命2》新关卡



半条命2,Lost Coast,HDR,《半条命2》新关卡


HDR Light Source(HDR光源):
未经压缩的光线数据值令设计人员能够从任何给定的场景中使用更大范围的光线数据值。

Exposure Control(曝光控制):
运用“眼睛调整”令我们在暗部场景看到比在过亮场景中更多的不同程度的细节。
 

动画、几何体以及游戏界面

动画以及角色面部造型

  就如目前很多的现代游戏引擎一样,角色的动作效果由一个骨骼系统控制。事实上,Half-Life 1 是这个骨骼系统使用的先行者。通过这骨骼系统,多种的动画以及细腻的动作可以被绑定到同一个角色上,由绑定在不同骨架部位的动画互相作用而生成整个角色的动作。Source引擎还在这个骨架系统中整合进Havok先进的物理引擎。

  对于玩家来说,使用附加有物理特性的骨骼系统会让我们看到更加真实的角色动作以及怪物的运动动作。因为在这些骨骼上会混合地播放角色动画,举个例子,一个角色在跑动的时候向对手开枪,然后被对手还击的子弹击中手部,手中的枪脱手飞出……这一系列的动作都能在一个角色上同时上演,加入了物理特性的骨骼系统能对受伤的手部作出反应,比如是承受冲击力时的晃动以及身体的扭转。

面部动画系统

  也许Source中最为神奇的特效来自于引擎中对面部表情的动画,Valve觉得,Half-Life 2里面的角色应该拥有与现实无异的表情,为了达到这个目的,Valve建立了一个包含面部肌肉模拟系统以及一个基于文本文件的半自动声音识别系统。

  在文本识别系统中,Source采用了“Keyshape”的动画,类似于Valve里面资深动画师Bill Buren所描述的渐变以及顶点动画。这套系统中包含了一系列预先设定的表情脚本,能控制角色面肌肉群产生相应的面部动画,并进行相加/混合/插值运算以创建现实生活中所见的自然真实的角色表情。

  为了缩短整个角色动画的构建过程,Valve在Source中创建了一套VRS (Voice Recognition Software,声音识别软件),有了准确自然的角色面部表情,就需要有精密的发音口形与之搭配,于是,一个文本文件会在语音对话中起到指挥的作用,关卡的设计师只需简单地将一个声效文件以及对应的脚本放进Source中,便能让一个角色在适当的时候说话。所有的角色动作会由VRS作出发音单词的判定然后调用该单词的口形,这些基本的口型就被称为Keyshape,通过骨骼系统和顶点渐变过程实现Keyshape之间的动画,于是便产生了精确的发音口形。更为神奇的是这些Keyshape能绑定角色的情感因素,Keyshape根据权重来确定在面部产生表情的正确部位,Valve将其称之为面部肌肉的仿真模拟。

Geometry

  几何模型的体现主要来自网格(例如表现一个物体或者角色的整体),静态网格(非生成整个物体),BSP序列以及一些几何建模实体。在Source中,所有的几何体均被储存在BSP序列中,当你查阅该序列的时候,你可以看到几何体均在 Hammer 地图编辑器中的光影关系,正如上面所说的场景合成一样,所有的辐射度、漫反射系数、镜面反射系数等均在编辑器中生成。

  BSP序列 (Binary Space Partitioning tree) 用以储存在Source里面大量的固态几何体(或许还有一些非固态的),不过,关于BSP序列的创建以及具体的操作将不在本文的讨论范围,各位有兴趣的玩家可以在google上搜索有关地图制作的知识,特别是关于Hammar地图编辑器的使用帮助。

  当我提及“mesh”网格的时候,具体指的是一些将几何体储存在地图文件之外一些独立的文件中,Source采用了.mdl文件来储存mesh网格。mesh多数用在创建能移动的物体或者一些复合的静态物体,主要是因为这种格式的文件能被XSI以及3DMax这些常用作三维建模以及动画设计的软件所导入。此外,.mdl文件还能多次地在场景中出现而避免重复地将几何体插进地图文件,采用了.mdl之后,你就不会再为已经够复杂的BSP序列添加进更多的冗余信息。
 

VGUI

  值得欣喜的是,Valve的图形控制界面将在Source中获得全新的定义。大家都知道,GUI (Graphic User Interface,用户图形界面) 就是和命令行(拼命地打字输入命令)相对的概念,意味着你根本不需要输入任何的命令,因为你有形象的图形操作界面能实现交互的人机操作。VGUI更是让开发者使用Source进行GUI的渲染,能在游戏中任何的地方显示并交互执行命令。这时,VGUI已经不再只限于一套菜单系统,他提供了程序接入窗口、按钮、弹出窗口、内核控制命令行等等控件。所有的这一切能按照程序员甚至玩家的意愿显示或者放置。另一方面,由于Source的VGUI采用了兼容的Unicode编码,能很方便地实现游戏语言以及文字的本地化,在CS:Source中任何地方的中文输入甚至全世界的语言文字输入已经让我们见识到了下一代VGUI的威力。

  在Source中,VGUI能在游戏中以及游戏外面进行显示,Steam的菜单就是一个很好的例子。在CS:Source出版之前,我们还不清楚,STEAM看似革命性的菜单是否就是采用了全新的VGUI编写。到了今天,CS:Source正式公开测试,可以这样下一个判断,CS:S中的,才是真正的VGUI,因为他采用了游戏的渲染引擎进行菜单的润色渲染,并能通过菜单操作所有的界面命令以及内核命令(半透明以及淡出淡入的效果、Debug Option菜单、附着完整信息的Console控制台),而Steam的窗口菜单只是GUI菜单的一个比较完善的改进罢了。据称,Valve将为Source制定的VGUI命名为VGUI2

物理系统

  有一样东西是Valve想在Half-Life 2中需要解决的首要问题,那就是一个能让角色和场景中任何物体都能发生互动关系增加整个游戏可玩性的物理引擎。Valve一直在找这样一个引擎,能让物品能和主角发生互动关系而不再是一个摆设,最后,他们将目光定格到 Havok 的物理引擎上。

  当和Havok整合之后,Source的一切得到了重生般的感觉,引擎里面所描述的所有东西都有了他们独到的物理特性,包括了声音、外观、材质、AI以及角色动画。当Valve被问道,是否会将Havok 1 引擎升级到Havok 2 的时候,Valve指出目前并不会作出此等举动,因为二代的引擎并没有比目前他们所拥有的引擎有更多的性能提升。

刚体动力学 以及 约束、关节链

  正如名称一样,刚性物体不能在游戏中被打碎、弯曲或者其他形式的扭曲。刚体的动力学是目前游戏中最常见的一个物理引擎表现部分--仅仅是非形体变形上的物理模仿,通常会以小盒子、铁桶、临时的木板等形式出现,不过有时候也会以小玩偶的形式出现(通过关节链将刚体组成一个简单的整体)

  关节节点就是常说的活动连接,这种连接允许你将两个物体有机地连接在一齐,你可以为这个关节添加约束,使他们只能在你规定的范围之内活动而不会走远。这就是在游戏中NPC被创建出来的关键。在众多角色中数不清的关节里面,有一些是能够被打断的,而有一些不能,在这些能够被打断的关节上,在被折断前就存在着一个受力的极限值。

  楼房被怪物击中,整个墙壁以及上面挂着的招牌被怪物强劲的冲击波衔翻,在Half-Life 2中似乎到处都充满这种可以被破坏的墙体。

柔性体:

  和刚性体相对的就是柔性以及弹性体,就和Source中的物理特性--作用力与反作用力一致,具体来说就是受力物体对施力物体的一种反作用,起到两者的排斥反应,只不过在弹性力中,这种排斥力是柔和的,加速度相对较小。在和橡胶轮胎的碰撞中,我们就能体验到这种弹性的反作用力。绳索的定义只需在地图编辑器中简单地连接两点并指定其属性即可,最重要的一个属性就是取样点的多少。当然,取样点越多绳结看上去越真实,但会对显示性能造成负面的影响。布料的模拟就类似于绳索,取样点点的多少将直接对布料在物理环境(大风、皱褶等)中的真实程度。当然,布料的模拟将消耗比绳索更加多的CPU资源而且按照目前的3D设计来说,要真实地模拟出一块布料在各种环境中的形态还是未能做到精确。

车辆系统

  车辆系统在Source中就是物理系统和建模系统的有机结合,加入了属于专有的脚本系统以便能让玩家操纵车辆。在Source引擎中的车辆系统由另外一群主要的专业设计师担任设计,以在达到最真实效果之余在最大限度上节省创作时间。毕竟Half-Life 2不是一个专业的赛车游戏,玩家只会用方向键对车辆进行操控,因此,在游戏中出现的航船、气垫船等可操控的交通工具均保持了最高的易用度:和读者想像中最简单的操作方法一样,WSAD控制方向,鼠标控制视觉以及枪械的瞄准。当然,车辆拥有属于自己的一套独立的脚本系统。

水、火

  Source中另外一个令人迷惑的东西就是水的模拟系统。当Valve说,水的效果会在物理的层面被模拟的时候,各界均推断在Source中将会引入流体动力学并加入物体的浮力特性到其物理指标中。但到了后来,Valve在声明中指出,在Source中并没有内建流体动力学的模型,water区域只是一个加入了特别的物理特性的场地。当其他的物体进入到这个区域后,会作出与之正常行为不同的动作,比如是行动变得缓慢、并且会出现重力上的变化(浮力)。当然,如果是真正的流体动力学模拟的话,将会是完全的自身物体特性引起的行为动作而非单纯的两者之间的互相作用。

  火,在Source系统中并非一个独立的系统,但作为一个FPS游戏中不可或缺的部分(特别是Half-Life 2这种充满毁灭性镜头的大作),火的效果是最能吸引玩家的眼球的。在Source中,火混合了粒子系统和材质系统,按照道理来说,在游戏关卡中的火苗如果在旁边出现易燃的物体的话,火将会向这些物体蔓延出去,不过并没有确切的消息肯定这个推断。

粒子系统和材质系统

 

  在Source中,粒子可以理解为“点状物”,常在一些单面的几何面上出现,这种粒子没有区域,没有体积,只能依靠坐标系或者某些参照物来描述其存在的位置,在字面上解,他们就是在空间上的点,是Source中比较容易进行模拟的物体。Source中的粒子除了长宽高的几何尺寸和明显的扭转系统之外,拥有和刚体完全一致的物理特性,毕竟,例子系统并不需要和刚体系统那样丰富的互动性。在游戏中,使用粒子系统创建的最常见的物体就是烟雾、沙尘、火、雨、雪、血雾、火花以及飞溅的碎片。

 

材质系统

  在Source引擎中的材质系统被赋予了物理特性以及贴图外观的特性。例如,给一块板赋予木材的材质,这块板便具有了木材的所有物理以及外观特征,重力、韧性、声学特性等均被附加到这块板上。材质特性方面保留了诸如密度、表面材质、耐压度、以及当折断或者敲击时发出的声响,虽然这些在众人眼中看是一些很简单很必然的事情,但在游戏中,这些细节将会是游戏增加其感染力的最佳途径。此外,AI系统还能就材质系统提供的信息,反馈给NPC以使其对战术作出相应的调整。当然,玩家也可以充分利用材质的特性从而得到更多的通关方法。

木板被赋予了物理刚节点之后,破裂之后的断层不再如一般游戏那样刀切般平整。

AI系统

  AI,Artificial Intelligence,近年来在电脑领域是一个突飞猛进的科研领域,一个优秀的AI系统,能对其周围的环境智能地作出非线性的反应并采取相应的行动。最重要的是具有依据周围环境参数的变更而决定系统行动的能力,否则,就不能称之为真正的AI。一个惯常的AI系统,会使角色根据当前任务的可行性、对主要任务影响的重要性以及目前的周遭环境作出判断以选择达到预定目的的最佳途径,而怎样选择最佳的动作以达到这个目的,就是一个AI系统优秀与否的体现。

聪明的NPC借助矮墙以及队友在对角线火力的掩护下弓身前进。

  老实地说句,笔者并不完全明暸Source的AI系统所能够完成的任务,Valve关于Half-Life 2的白皮书中就说过很多的东西表明Source里面的AI系统是多么的强大,大意就是下面的几点(已经足够让目前每一个游戏汗颜的了)。
 

  • 允许关卡设计师以I/O接口联系游戏中的实体以控制AI系统。
  • 成熟的导航系统,可以实现角色的跑动、飞行、跳跃、下蹲、上楼梯和爬手扶梯甚至在地下的挖掘动作。我们在cz中的机器人已经见识过新一代的导航系统是如何地高超。
  • AI系统能依靠视觉、听觉以及嗅觉感知到物体 的存在
  • AI的关系决定敌友以及其他实体的关系
  • 战斗AI允许AI角色进行团队攻防,他们知道何时推进、何时撤退、何时伏倒寻找掩护等等的战斗动作
  • 如果一个NPC看到你向一个关键的物体跑去的时候,他会判断你对该物体要作出的动作而采取相应的行动
  • 大规模的NPC进攻将一道桥弄垮这些细节将会脱离Valve的剧本随时地,在不可预见的情况下发生
  • AI知道移动重型物体是难以被快速移动的。
  • AI能清楚地知道他看到你的最后位置,并会对你逃跑的路线作出判断,以采取相应行动。
  • NPC会拒绝执行来自玩家的愚蠢的命令
  • AI能使用物理存在的物体。

  在游戏中NPC的AI着实让笔者大吃一惊,比如在TrainStation的一幕,主角刚刚到达City17,被NPC带到一个阴暗的长廊上准备接受洗脑,途中听到一间房间内发出人类疼苦的哀嚎,好奇的主角把头凑过去那个房门上打开的小窗户想了解里面发生什么事情,这时,屋内的NPC会判定屋子里面发生的事情不是主角所应该看到的,于是,NPC会走过来,唰地一声将小窗户关上……类似这种行为判定的例子在游戏中往往会是通关的关键。Source引擎做到了主角和NPC之间很好的互动以及沟通。

posted on 2005-12-26 23:51 苦行僧 阅读(7958) 评论(8)  编辑 收藏 引用 所属分类: 转载

Feedback

# re: 最牛的游戏引擎之一--Source剖析 2006-01-13 18:36 seraph
just a reply test,sorry……  回复  更多评论
  

# re: 最牛的游戏引擎之一--Source剖析 2006-01-13 18:46 seraph
原来不注册也能回复。
hl2游戏还算可以,图像引擎还真不怎么样。

文中还提到valve在hdr相关方面远远领先于其他公司,原作者要么是外行,要么是valve的枪手。farcry1.3补丁就加入hdr,而且其效果至今都几乎是无可超越的,scct也早在3月份就加入了堪称完美的hdr效果。hl2:lc去年4季度(还是3季度末?)才出,效果也没见比别人高明到哪儿去,真不知道valve领先到哪儿了。  回复  更多评论
  

# re: 最牛的游戏引擎之一--Source剖析 2006-01-16 15:38 苦行僧
因为以前也没有看过HDR方面的东西,所以看到评论就google了一下。找到下面两篇文章:
http://www.bit-tech.net/gaming/2005/06/14/hl2_hdr_overview/1.html
中文的翻译:http://hardware.mydrivers.com/pages/200506241438_43550.htm
是说valve source的Lost Coast中的HDR的。

还有一个就是:http://media.qingdaonews.com/printthread.php?t=17483,我转载了一下,是对几个游戏引擎的HDR效果的一个图片对比。

看了半天也没有看明白,HDR比较标准有哪些?怎么说一个HDR做的比另外一个好呢?

因为我的方向主要在阴影这边,没有研究过HDR,不过跟光照有点关系的我都比较感兴趣,有空多向seraph请教( 也没有留个交流方式:( )。  回复  更多评论
  

# re: 最牛的游戏引擎之一--Source剖析 2006-02-21 10:41 m17
驱动之家写得文章很业余的啦!
最近刚照着那份 PDF 自己把所有的 shader 都做了一遍,大概是理解了那些 shader 的原理了. 驱动之家关于 hdr 的那段写的不是很好,所以我又改写了一段,欢迎大家讨论  回复  更多评论
  

# re: 最牛的游戏引擎之一--Source剖析 2006-02-21 12:40 实时阴影绘制技术研究
牛人,向你学习  回复  更多评论
  

# re: 最牛的游戏引擎之一--Source剖析 2006-08-12 19:05 QQ52438974
的确好牛


不知道波斯王子1代有没有上面所说的HDR,BLOOM什么的 但是就画面来说 的确非常完美

引擎复杂程度是一回事
引擎效率是另一回事


  回复  更多评论
  

# re: 最牛的游戏引擎之一--Source剖析 2007-10-18 21:00 test
<font color=red>test</font>  回复  更多评论
  

# re: 最牛的游戏引擎之一--Source剖析 2012-04-04 22:01 路过
我晕。。。  回复  更多评论
  


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理