私は八分木を実装しようとしています。そのためには、高速なAABB線交差アルゴリズムが必要です。いくつか検索した後、私はそれを提供しているように見えるこの論文に出くわしました。ここで入手できるソースコードから、pluecker_cls_cff
関数を次のようにC#に変換しました。
public bool Intersect_2(ref RayPluecker r)
{
switch (r.Classification)
{
// 7 same-ish cases snipped
case Classification.PPP:
return !((r.Position.X > this.Max.X) || (r.Position.Y > this.Max.Y) || (r.Position.Z > this.Max.Z) ||
(r.PlueckerCoefficient.X + r.Direction.X * this.Max.Y - r.Direction.Y * this.Min.X < 0) ||
(r.PlueckerCoefficient.X + r.Direction.X * this.Min.Y - r.Direction.Y * this.Max.X > 0) ||
(r.PlueckerCoefficient.Y + r.Direction.X * this.Min.Z - r.Direction.Z * this.Max.X > 0) ||
(r.PlueckerCoefficient.Y + r.Direction.X * this.Max.Z - r.Direction.Z * this.Min.X < 0) ||
(r.PlueckerCoefficient.Z - r.Direction.Z * this.Min.Y + r.Direction.Y * this.Max.Z < 0) ||
(r.PlueckerCoefficient.Z - r.Direction.Z * this.Max.Y + r.Direction.Y * this.Min.Z > 0));
}
return false;
}
これは問題なく機能しているように見えますが、私にはかなり遅いように見えたので(1,000万回の交差を行うには250ミリ秒)、さまざまな種類のマイクロベンチマークを試しました。return
1つは、ステートメントの直後にある否定を削除し、すべての比較を逆>
にしました(<
またはその逆)。
雪が降る:
case Classification.PPP:
return ((r.Position.X < this.Max.X) || (r.Position.Y < this.Max.Y) || (r.Position.Z < this.Max.Z) ||
(r.PlueckerCoefficient.X + r.Direction.X * this.Max.Y - r.Direction.Y * this.Min.X > 0) ||
(r.PlueckerCoefficient.X + r.Direction.X * this.Min.Y - r.Direction.Y * this.Max.X < 0) ||
(r.PlueckerCoefficient.Y + r.Direction.X * this.Min.Z - r.Direction.Z * this.Max.X < 0) ||
(r.PlueckerCoefficient.Y + r.Direction.X * this.Max.Z - r.Direction.Z * this.Min.X > 0) ||
(r.PlueckerCoefficient.Z - r.Direction.Z * this.Min.Y + r.Direction.Y * this.Max.Z > 0) ||
(r.PlueckerCoefficient.Z - r.Direction.Z * this.Max.Y + r.Direction.Y * this.Min.Z < 0));
これでも同じ結果になるはずですよね?いくつかのテストケースを含む否定バージョンと同じ結果が返されるため、そう見えました。ただし、ベンチマークでは、5倍高速でした(1,000万回の交差を実行するには50ミリ秒)。最適化されていなかったと確信しています。私のベンチマークは次のようになります。
for (int i = 0; i < 10000000; i++)
{
if (!box.Intersect_3(ref ray))
{
throw new Exception();
}
}
この大きな違いを説明できるのは何ですか?x86で.NET4.0を実行しています。