Direct3DXの甘い罠。浮動小数点結果が環境依存

Direct3DXは素晴らしいライブラリです。
私がいきなり「電装天使ヴァルフォース」という3Dゲームを作れたのも、ひとえにD3DXの助けがあってこそです。
 
ですが、陥りやすい罠もいくつか見られます。
まず紹介しておきたいのは、Direct3DXを使って行った行列やベクトル演算は、PC環境によって結果が異なるということです。
 
これにはかなりハマりました。
・リプレイ互換性が保てない
・通信対戦の際、お互いの整合性が保証できない
 
ヴァルフォースの通信対戦は、ユーザーのキー入力を送りあうことで実現しています。
これは「お互いに同じキー入力データが送信されれば、お互いのゲーム状況は同じになるはず」というのが前提です。
このDirect3DXの罠にハマり、危うくヴァルフォースの発売が半年は延びるところでした。
 
原因としては、Direct3DXは「そのPCで実装されている、最速の浮動小数点演算機構を使う」というところにあります。
もともと描画ライブラリなので、計算結果の誤差よりも速度を優先しているのです。
 
ある環境ではD3DXVec3Lengthの中でSSE2が使われ、ある環境では3DNow!が使われるといった感じです。
この現象は、私のPen4マシンと、友人のAthlonマシンで通信対戦していた時に発覚しました。
 
回避方法としては、この「最速の浮動小数点演算機構を使う」という機能をOFFにするという手段があります。
詳しくはこちらのNyaRuRuさんの記事を参照してください。
id:NyaRuRu:20040819
 
ただ、この方法はあくまで緊急処置です。
私も次回作では、ゲームのロジック部分でD3DXを使うのはやめ、独自の行列・ベクトル演算ライブラリを使うつもりです。
 
そのライブラリも作りかけのものがありますので、ある程度体裁が整ったらみなさんに提供しようと思っています。
名前などがD3DX互換になるため、単純に代替していただければ動くかと思います。
(私のものをまたずとも、1日あれば作れますけどね)
 
もうひとつ。
C++のsqrtやsinなどの関数も、SSE2が使える環境と使えない環境で誤差が出るそうです。(未確認)
いまさらSSE2が使えない環境をターゲットにゲームを作ることはないでしょうが、念のため_set_SSE2_enable関数を使い、SSE2が未対応な環境ではゲームが起動しないようにしておくと良いでしょう。