Havok 物理引擎教程.docx

上传人:b****8 文档编号:30559526 上传时间:2023-08-16 格式:DOCX 页数:22 大小:29.36KB
下载 相关 举报
Havok 物理引擎教程.docx_第1页
第1页 / 共22页
Havok 物理引擎教程.docx_第2页
第2页 / 共22页
Havok 物理引擎教程.docx_第3页
第3页 / 共22页
Havok 物理引擎教程.docx_第4页
第4页 / 共22页
Havok 物理引擎教程.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

Havok 物理引擎教程.docx

《Havok 物理引擎教程.docx》由会员分享,可在线阅读,更多相关《Havok 物理引擎教程.docx(22页珍藏版)》请在冰豆网上搜索。

Havok 物理引擎教程.docx

Havok物理引擎教程

物理引擎Havok教程

(一)

搭建开发环境

网上关于Havok的教程实在不多,而且Havok学习起来还是有一定难度的,所以这里写了一个系列教程,希望能够帮到读者。

这是第一期。

一、Havok物理引擎简介

Havok引擎,全称为Havok游戏动力开发工具包(HavokGameDynamicsSDK),一般称为Havok,是一个用于物理系统方面的游戏引擎,为电子游戏所设计,注重在游戏中对于真实世界的模拟。

使用碰撞功能的Havok引擎可以让更多真实世界的情况以最大的拟真度反映在游戏中。

开发商Havok成立于1998年,目前Havok物理引擎被超过200款游戏使用,许多电影也应用了这家公司的软件技术。

2007年9月Havok被Intel收购,为了和NVIDIA的PhysX竞争,Intel在去年的(08年)免费开放了Havok的Physics和Animation组件,内容包括HavokSDK库、样例、技术文档以及支持Maya、3dsMax和AvidXSI等3D建模软件的格式转换工具。

按照Havok的授权文档,即使使用它开发商业游戏也是不需要付费的,这对国内的爱好者应该是一个好消息。

同PhysX相比,个人觉得,Havok无论在稳定性还是功能上,都要略胜一筹。

NVIDIA的PhysX在硬件加速上,暂时领先,但随着AMD加入到Havok硬件加速的开发,未来Havok的功能肯定会更加的强大。

二、Havok开发环境的搭建

1.安装SDK

首先,到Havok的官网下载SDK,

ContentTools是内容工具,包括一些3D建模软件的导出工具。

BehaviorTool是给游戏美工或设计师用的角色编辑工具,具有所见即所得的功能。

对程序员来讲最重要的就是SDK了,我下载的是6.0.0这个版本。

因为Intel只开放了物理和动画两个组件,所以下载的SDK是只包含这两个组件,其他的如布料(Cloth)和破坏(Destruction)还是需要付费才能使用。

HavokSDK使用的是C++语言,开发环境是VisualStudio,我用的版本是2005。

Demo目录下面是SDK的样例程序和源代码,Docs是文档,包括chm和pdf两种格式。

Lib是链接库,库分为Debug和release及动态链接和静态链接。

Source下面是SDK的包含文件。

Tools下面是工具,包括了VisualDebugger这个可视化调试器。

2.设置VisualStudio

这里以我使用的VisualStudio2005为例。

头文件包含目录的设置。

打开VisualStudio2005,依次选择工具-》选项-》项目与解决方案-》VC++目录

选择包含文件,添加新的一行,路径指向HavokSDK安装目录的Source目录。

建议建立一个叫HAVOK_HOME的环境变量,这样可以避免使用绝对路径。

库目录不能在这里设置,而应该为debug和release版本设置不同的库包含目录。

因为不论是debug还是release,它们的库名都是相同的。

你可以打开Demo/Demos下面的工程,看看它是如何设置为不同版本设置链接包含目录的。

三、第一个Havok程序

这里以SDK自带的一个控制台演示程序为例,使用VisualDebugger来观察Havok的具体效果。

首先运行Tools\VisualDebugger目录下的VisualDebugger程序,使用它我们可以观察到Havok实际运行的效果,而省去渲染步骤,而且可以把场景记录下来,供以后观看。

演示程序在Demo\StandAloneDemos\ConsoleExampleMt目录下,这个程序模拟一个快速运动的刚体,撞击墙壁的效果。

运行它,然后就可以在VisualDebugger中看到实际的效果了。

好了,第一期教程就是这样。

下期会接触到具体的编码问题。

如果你有任何问题,欢迎和我交流,我的邮箱songnianhu@,博客

物理引擎Havok教程

(二)

Havok基础库简介

Havok的SDK可以说比较复杂,并不是适合用来学习。

拿它用来演示效果的Demo程序的框架来说,它的实现实在是非常的神秘,初学者一开始就接触海量的代码,估计会很大的挫伤积极性。

所以为了降低大家学习的难度,我在做教程的时候会主要使用实际的代码来介绍SDK的各种特性,代码编写时我会尽量的简洁和通俗一点。

示例代码我会整理好,提供链接,供大家下载。

觉得好的话,大家要支持啊!

HavokSDK可以分为三大部分,Havok基础库、Havok物理组件、Havok动画组件。

基础库,为Havok的其他组件提供了通用功能的支持,Havok物理组件负责实时的刚体模拟,Havok动画组件负责处理骨骼和角色动画,与物理组件配合,可以实现强大的角色动画控制功能。

关于HavokSDK的代码习惯,这里要说明一下,HavokSDK所有的类名基本上都以hk*开头,然后后面跟一个字符表示它所属的组件,例如,hkpWorld,说明它属于物理组件(HavokPhysics),hkaBone,说明它属于动画组件(HavokAnimation),hk后不跟一个表示组件的字符,则表明它是Havok基础库的一部份。

Havok基础库

Havok基础库定义了一些基本的数据类型和容器类,它还包括与平台无关的接口,用于访问操作系统的资源,比如内存管理、时钟等。

基础库中的许多类都可以修改或者替换,这样通过提供的源代码,你可以灵活地扩展基础库的功能。

不过有些部分,因为编译进了Havok库,所以不能被替换,包括那些有内联函数的容器类,还有config目录下面的构造配置选项(它保存了在编译Havok库时的配置,对它进行任何更改,都需要重新构建整个Havok库)。

使用基础库,只需要简单的包含hkBase.h即可。

hkBase.h内,还定义了一些最基本的数据类型,比如浮点型(hkReal),有符号和无符号整形等等。

1.Havok基本系统

1.1Havok的初始化

hkBaseSystem类负责创建所有Havok子系统。

这些子系统中大部分都是单态类(singleton),各自都有特定的功能,比如内存管理、错误处理、流处理。

这些类的主要接口是init和quit方法。

调用init方法来初始化Havok子系统。

statichkResultHK_CALLinit(hkMemory*memoryManager,

hkThreadMemory*threadMemory,

hkErrorReportFunctionerrorReportFunction

void*errorReportObject=HK_NULL);

参数memoryManager,是一个将被Havok在内部使用的内存管理器的实现。

这个参数允许你在初始化的过程中指定内存管理器而不必重新构建hkBase。

Havok本身提供了许多默认的内存管理器的实现,如果没有特殊要求的话,就可以使用它们。

当然,你也可以实现自己的一个内存管理器,Havok推荐使用hkPoolMemory类。

这个内存管理器的实现以及其他的可用的实现可以在目录下面找到。

参数threadMemory,是当前线程的内存管理器,它可以用于优化内存分配和释放的性能。

如果你传入了HK_NULL作为参数,默认的,hkBaseSystem:

:

init()会为你创建一个hkThreadMemory实例。

errorReportFunction和errorReportObject参数被Havok的错误处理器使用,错误处理器主要负责处理断言、错误、警告,或者在引擎内部报告这些事件的发生。

默认的错误处理器是,它只是简单的调用errorReportFunction打印错误消息。

下面举一个使用hkPoolMemory初始化hkBaseSystem的代码示例:

#include//includeforhkBaseSystem

#include//hkPoolMemory

extern"C"intprintf(constchar*fmt,...);//Forprintf,usedbytheerrorhandler

//Stubfunctiontoprintanyerrorreportfunctionalitytostdout

//std:

:

puts(...)couldbeusedherealternatively

staticvoiderrorReportFunction(constchar*str,void*errorOutputObject)

{

printf("%s",str);

}

{

...

hkBaseSystem:

:

init(newhkPoolMemory(),HK_NULL,errorReportFunction);

...

}

hkBaseSystem还有一个quit方法,它退出内存系统并销毁所有的hkSingleton实例。

1.2Havok多线程模式的初始化

和PhysX不同,Havok现阶段采用的是CPU计算,所以Havok采用了多线程来提高性能。

Havok使用的每一个线程,都有它自己的hkThreadMemory内存管理器,必须在线程开始时初始化,线程结束时销毁。

hkThreadMemory可以用于在销毁和重分配内存时缓存内存块。

下面的代码演示在主线程中的初始化。

hkMemory*memoryManager=newhkPoolMemory();

hkThreadMemorythreadMemory(memoryManager,16);

hkBaseSystem:

:

init(memoryManager,&threadMemory,errorReportFunction);

memoryManager->removeReference();

1.2管理Havok对象

Havok使用引用计数来管理对象。

hkBaseObject是所有Havok类的基类,只有虚函数。

hkReferencedObject是hkBaseObject的子类,他是Havok对象管理的最基本单元,刚体(Rigidbodies)、约束(constraints)和动作(actions)都是hkReferencedObject。

hkReferencedObject刚创建时,引用计数是1,每当它被引用一次时,引用计数加一,删除引用时,引用计数减一。

当不使用hkReferencedObject时,调用removeReference()引用计数减一。

m_world->addEntity(rigidBody);

rigidBody->removeReference();

2.Havok容器类

Havok提供了两种容器类,Arrays和Maps。

hkArray是Havok默认的数组类。

它和STL的数组类非常相似,但有一些关键的不同之处。

首先它只支持那些简单的数据类型,如果你要建立一个对象的数组,那么你应该使用hkObjectArray,而不是hkArray。

还有就是hkArray的方法的命名和STL也是不同的,例如STL中是push_back(),而在hkArray中就变成了pushBack()。

而且,hkArray不保存元素的次序,例如当调用removeAt()删除了一个元素,为了提高性能,会用最后一个元素替换这个被删除的元素,而方法removeAtAndCopy()则可以提供和STL一样的实现,依然保存元素的次序。

另外还有hkInplaceArray,它是hkArray的子类,在性能上要优于hkArray。

关于数组类的其它方法你可以查看SDK文档,这里就不一一介绍了。

3.Havok数学库

Havok数学库提供了线性代数的一些相关的数据类型,如向量(vector)、矩阵(matrix)、4元数。

hkMath的数据类型在不同的平台上实现是不同的,Havok针对不同的平台作出了相应的优化。

首先来看hkMath提供的基本数据类型,有

hkReal默认的浮点类型,即float

hkQuadReal这个类型使用了CPU的SIMD寄存器,占用4个hkReal的空间。

hkSimdReal当SIMD启用时,一个单独的hkReal保存在SIMD寄存器内,x部分是一个hkQuadReal。

SIMD被禁用时,他就仅仅是个简单的hkReal类型。

其他的hkMath函数还有hkMath:

:

sqrt(),hkMath:

:

sin()等等,可以查看SDK文档。

SDK中称与线性代数相关的数据类型为混合类型(CompundTypes)。

它们有:

hkVector4这个Havok内通用的向量类。

它针对大多数平台进行了相应的优化,而且其他的数学类多数由它组成。

每个hkVector4有四个hkReal元素,为了方便进行运算,一般只使用前三个元素x,y,z,后面的w部分,默认值是零。

hkQuaternion四原数类,可以用来表示旋转。

多数情况下,认为它是一个单位化的四元数。

hkMatrix3hkReal组成的3X3的矩阵。

hkRotation这个类保存正交的旋转矩阵。

Havok中,有两种方法保存旋转:

hkQuaternion和hkRotation。

如果你处理的旋转是hkVector4,旋转hkVector4的操作要比旋转hkQuaternion快。

而在需要大量保存旋转的情况下,使用hkQuaternion效率要更高一些。

hkTransform这个类表示一个旋转和平移(rotation,translation)。

它分别由一个hkRotation和hkVector4组成。

hkQsTransform一个分解的Transform(平移向量+四原数+缩放向量)。

Havok的动画系统会经常使用它。

数学库,就简单的介绍到这里,它们的使用以及需要注意的地方,我在讲分析具体代码的时候会说。

4.串行化(Serialization)

所谓串行化就是通过一定的处理将数据转换为一种可写的格式。

串行化之后,原始数据还应该能够被精确的还原。

就是说串行化之后的数据可以安全的保存到磁盘或通过网络传输。

在游戏开发领域,串行化通常用于保存和装载资源。

Packfiles(这个不知如何翻译)

使用Havok的串行化工具,可以串行化任意的数据对象。

一个对象被串行化了之后,它的所有信息和状态都会被精确地保存。

在需要的时候,这个对象还可以被再次装载。

串行化后的数据都被保存在一个称作packfiles的结构中。

它既可以保存为XML或者二进制的形式。

使用Havok的导出插件,可以从Maya和3DStudioMax中将数据保存到packfiles,然后就可以在Havok的SDK中转载了。

向游戏装载packfiles使用类hkXmlPackfileReader和hkBinaryPackfileReader。

XML形式的packfile与平台无关,可以在任意平台上创建和装载。

而二进制形式的packfiles则特定于对应的平台,所以它只能在指定的目标平台上装载。

Packfiles也可以从一种形式转换成另一种形式。

使用hkXmlPackfileReader读取XML,再用hkBinaryPackfileWriter转换成二进制形式。

反之,二进制形式的packfile,用hkBinaryPackfileReader读取数据,hkXmlPackfileWriter转换数据成XML形式。

4.1装载游戏数据

装载游戏数据的功能,由命名空间hkSerializeUtil和hkLoader工具类提供。

它们检测数据的格式是XML还是二进制形式。

并且如果提供的数据是是另一个版本的SDK中建立的,它们还会在装载的时候将内容更新为最新的版本。

下面的代码演示了hkLoader工具类的用法:

hkResource*loadedData=hkSerializeUtil:

:

load("filename.hkx");

hkRootLevelContainer*container=loadedData->getContent();

//装载后的数据属于hkResource。

必须确保在访问container的时候,hkResource没有被销毁

hkLoaderloader;

hkRootLevelContainer*container=loader.load("filename.hkx");

//装载后的数据属于hkLoader,同上,也必须确保在访问container的时候,hkLoader没有被销毁

packfile被装载之后,还需要做一些附加的处理。

例如,需要设置多态对象的虚函数表,未串行化数据的缓存数据或指针也要被初始化。

任何需要做最后处理的类都通过被hkTypeInfoRegistry注册,来完成最后处理。

一旦数据装载完成,packfile读取器为每个需要做最后处理的的对象调用注册函数。

4.2保存游戏数据

游戏中的含有元数据的对象,也可以被串行化并保存为packfile,使用的类是hkXmlPackfileWriter和hkBinaryPackfileWriter。

如果碰到指针指向的对象不包含任何元数据这样的情况,操作会被跳过,并写入一个空指针。

hkOstreamostream(FILENAME);

kXmlPackfileWriterwriter;

writer.setContents(&simpleobject,SimpleObjectClass);

kPackfileWriter:

:

Optionsoptions;//usedefaultoptions

writer.save(ostream.getStreamWriter(),options);

使用hkBinaryPackfileWriter可以为不同的平台导出不同二进制形式的packfile。

要实现这样的操作,设置hkPackfileWriter:

:

Options:

:

m_layout为想要的平台即可。

hkStructureLayout包含了若干支持的平台/编译环境。

要读取的导出的数据,在目标平台上使用hkBinaryPackfileReader,用和上面一样的方法来读取数据。

hkOstreamostream(FILENAME);

hkBinaryPackfileWriterwriter;

writer.setContents(&simpleobject,SimpleObjectClass);

hkPackfileWriter:

:

Optionsoptions;

//将数据导出为PlayStation®2gcc3.2格式

options.m_layout=hkStructureLayout:

:

Gcc32Ps2LayoutRules;

writer.save(ostream.getStreamWriter(),options);

5.快照工具集

Havok还提供了快照工具集(snapshotutility),它可以方便的保存world,很好地隐藏了底层的细节。

下面的代码演示如何保存world:

//Savetheworldintothefileat"path"

statichkResultsaveWorld(hkpWorld*world,constchar*path,boolbinary)

{

hkOstreamoutfile(path);

returnhkpHavokSnapshot:

:

save(world,outfile.getStreamWriter(),binary);

}

注意,在保存文件的过程中,如果碰到不明白的对象,会在控制台上打印警告消息。

装载快照,和保存差不多,代码如下:

//Loadssnapshotat"path".

statichkpWorld*loadWorld(constchar*path,hkPackfileReader:

:

AllocatedData**allocsOut)

{

hkIstreaminfile(path);

hkpPhysicsData*physicsData=hkpHavokSnapshot:

:

load(infile.getStreamReader(),allocsOut);

returnphysicsData->createWorld();

}

6.多线程

Havok被专门设计成运行于多线程环境。

这一小节将简单的介绍Havok的多线程的工作原理,以及如何在物理模拟时使用多线程。

要实现Havok的多线程运行,需要两个类,hkJobQueue和hkJobThreadPool类。

hkJobQueue类。

工作队列是所需完成job的核心容器。

job是一项可以被任意线程处理的工作的单元。

一个线程可以向队列添加job,也可以向队列请求job。

hkJobQueue:

:

processAllJobs()可以被多个线程同时调用,然后每个线程都会开始处理job知道队列中没有任何job为止。

hkJobThreadPool是一个抽象类,它允许多线程从工作队列处理job。

典型的,在整个应用程序的生命周期内,只创建一个hkJobThreadPool的实例。

这样就保证了始终有一组线程在运行。

调用hkJobThreadPool:

:

processAllJobs()方法,会导致它简单的在所有的工作线程上调用hkJobQueue:

:

processAllJobs()方法。

这个函数直到所有工作都完成之后才会返回。

Havok的物理、动画、碰撞查询、布料、Bihavior都支持在多线程环境下执行。

理论上,向hkJobQueue添加job,调用processAllJobs(),可以并行的进行以上所有的计算。

但仅仅是理论上而,其中还有许多同步的问题,导致完全并行是不可能的。

我们这里只介绍如何在多线程环境下运行Havok的物理模拟。

其他组件与之类似。

6.1物理模拟的多线程

HavokSDK随带了一个单独的示例,演示了如何进行物理模拟的多线程计算。

代码在Demo\StandAloneDemos\ConsoleExampleMt目录下。

要启用多线程物理模拟,你在创建world的时候需要将hkpWorldCinfo:

:

m_simulationType设置成hkpWorldCinfo:

:

SIMULATION_TYPE_

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 动态背景

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1