2009年2月3日星期二

改变数学库

在编写图形和场景子系统时我意识到哪些数学代码是需要的。我原先的计划是编写一个看起来像HLSL的底层功能的学库并使用SSE提升效率。我开始编写并且很快清晰显示出这是一个非常正确的实现。那时仅仅作为一个SSE实现,还有SSE2..4,3DNow需要实现,并且在Xbox360和其它平台上在本质上完全不同。可以肯定,只要增加人力就可以解决这个问题。但用这种方法解决程序问题永远不是一个好办法。因此我开始寻找一个更有效的解决办法,很快从D3DX数学库中找到了答案。D3DX数学库的功能是非常全面的,尤其对于游戏,支持所有当前向量指令集,并且360的数学库基本上提供了相同的特性集。

这有两个缺点:

1.因为D3DX方法不是内联增加调用开销。
2.除了DirectX和Xbox360不能移植到其它平台。

但我可以容忍这一些因为它“现在”帮我减少了很多工作,移植一个数学库到其它平台并根据特定平台优化的工作包装方法和自己编写方法一样多。

其它一些考虑的方面:

1.使用c++数学代码,性能不能影响使用的方便。例如,一个operator+()操作因为需要构建一个临时的对象总是会损失掉一些性能。但在一般游戏代码中使用c++操作符重载比传统的方法更方便,更具有可读性。有一点要特别注意的是在内部循环使用底层代码是有它实际道理的。

2.在Nebula中只有很少的地方需要在CPU上执行大量的数学运算(在Nebula2中:粒子系统,动画代码,为skinned characters计算阴影。在Nebula3这些计算都交给GPU来完成,或者将被放弃掉)。一般来讲,CPU将不需要执行几何运算。

当我重写整个数学库的时候,我又做了一个我在所有时间都想做的改变,但这在Nebula2中是不可能的因为会破坏很多已经存在的代码:默认构造函数将不再初始化底层数学对象。我知道会有争论。但我想看看它如何在实践中证明。

另个一个基本改变是区分点和向量之间的不同。现在有一个Math::point和一个Math::vector类都是继承Math::float4类。一个点说明在3d空间中的一个位置,一个向量说明在3d空间中的一个方向和大小,以此推广到4维空间(如果是点的话W分量总是1.0,如果是向量的话W分量总0.0)。

(point + point) is 错误的
(point * scalar) is 错误的
point = point + vector
vector = point - point
vector = vector + vector
vector = vector - vector
vector = vector * scalar
etc...

并且,类的接口也变得清晰因为程序员可以立刻知道参数是期望传入一个点或者是一个向量。

因此新的数学库看起来像这样:

以下底层类直接调用D3DX方法:

* matrix44 (D3DXMatrix functions)
* float4 (D3DXVec4 functions)
* quaternion (D3DXQuaternion functions)
* plane (D3DXPlane functions)

所有其它通用类(像bbox,sphere,line等等)都是使用底层类提供的功能。这有一个新的scalar类型(其实就是float的预定义),可以帮助移植到其它平台。我一直都为数学库编写一套完整的测试类和性能测试类,但现在我非常地开心因为经过大约两天的实现我就可以减少一大块工作了。

原文: Math lib changes

[声明]:限于译者水平,文中难免错漏之处,欢迎各位网友批评指正;

没有评论:

发表评论