Я пытаюсь реализовать октет, и для этого мне нужен быстрый алгоритм пересечения AABB-лучей. После некоторых поисков я наткнулся на бумагу this, которая, казалось, предлагала это. Из исходного кода, доступны here, я перевел pluecker_cls_cff
функцию C#, как это:Отрицание правдивости булевой оценки, вызывающей 5-кратное замедление?
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;
}
Это, кажется, работает хорошо, но это казалось довольно медленно для меня (250мс сделать 10 млн пересекает), поэтому я попробовал некоторые микро-бенчмаркинг с различными разновидностями. В одном я удалил отрицание, которое было сразу после заявления return
, и отменил все сравнения (>
- <
и наоборот).
Это теперь:
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 раз быстрее (50 мс, чтобы сделать 10 миллионов пересечений)! Я уверен, что это не оптимизируется, мой тест выглядит следующим образом:
for (int i = 0; i < 10000000; i++)
{
if (!box.Intersect_3(ref ray))
{
throw new Exception();
}
}
Что может объяснить эту огромную разницу? Я запускаю .NET 4.0 на x86.
++ Элегантные наблюдения. –
Это, а также отрицание '>' is '<=', а не '<'. – Timwi
Да, ты прав. Благодаря! И тогда вы думали, что знаете логическую логику. Было слишком хорошо, чтобы быть правдой, я думаю, потому что алгоритм не кажется таким быстрым (40 м пересекает/s на одном ядре Core 2 Duo E8400), но это может просто быть восприятием. – JulianR