MSDNによるとD3DXMatrixPerspectiveFovLH()関数の中身は以下の通り。
ここで問題になるのがcot(fovY/2)の部分。コタンジェントは tanθの逆数らしいので、つまるところcosθ/sinθ。w 0 0 0 0 h 0 0 0 0 zf/(zf-zn) 1 0 0 -zn*zf/(zf-zn) 0 where: h is the view space height. It is calculated from h = cot(fovY/2); w is the view space width. It is calculated from w = h / Aspect.
毎フレーム呼びたい関数にsin()とcos()関数が両方とも入っちゃってるわけです。実際、素直に書き起こしたコードとD3DXMatrixPerspectiveFovLH()関数の速度を比較してみたら、1000万回のループでおおよそ1.5~2倍くらいの時間差が! ボトルネックは予想通り、sin()とcos()でした。
そこでsin()とcos()の部分だけインラインアセンブラで高速化に挑戦してみることにしました。 使った命令は8087命令セット?なので、まあ今日のx86プロセッサなら問題なく使えると思います。
ただ、この8087命令は使用するレジスタがちと特殊なようで、汎用レジスタからではfsincos命令の引数も戻り値も受け取ることはできないっぽい。長々と書くのもアレなんで、ズバリ答えが載ってるサイトを発見しました。ありがたく利用させていただくことに。
float angle, cosx, sinx;//引用元はdoubleでしたがfloatに変更させていただきました _asm { fld angle ;レジスタスタックに角度をプッシュ fsincos ;fsincos命令で一気にsin(angle)とcos(angle)を計算。答えはST(0)にcos,ST(1)にsinが入っている。 fstp cosx ;ST(0)スタックトップからcosをポップ。ST(1)がST(0)にスライドする。 fstp sinx ;同じくスタックトップからsinをポップ。 }
たったこれだけのコードで、sinθとcosθの値が同時に求められるんですね。これは便利だ。速度もd3dxをぶっちぎりで上回る200%以上の効果。ここまで速いと、エラーチェックとか要るのかなぁとかえって不安になってしまいますが…。まぁ気にしない気にしない…。
とっても参考になったサイト
SSE2を用いたPOV-Rayの最適化に関する考察
Intel x86 Instruction Reference
SIMPLY FPU