Frustum Culling
Автор: Анатолий Герлиц
Одной из важных оптимизаций в компьютерных играх является отсечение геометрии, не видимой на экране (Frustum Culling, далее фрустум кулинг). Раз мы все равно не увидим объект, то и не зачем тратить ресурсы компьютера на его подготовку и отрисовку.
В этой статье я затрону следующие темы:
- кулинг сфер (Bounding Sphere), AABB (axis-aligned bounding box), OBB (oriented Bounding Box).
- кулинг большого количества объектов.
- применение SSE.
- многопоточный кулинг.
- кулинг на стороне GPU.
- сравнение по скорости всех методов.
Что не буду затрагивать:
- использование иерархий, деревьев. Можно объединить объекты в достаточно большие группы по территориальному признаку и сперва определить их видимость.
- различные оптимизации для одного объекта, вроде запоминание 'удачной' плоскости отсечения.
- тест с учетом буфера глубины. Объект может попадать во фрустум, но при этом быть полностью загороженным другим более близким к камере объектом. Следовательно его тоже можно было бы не рисовать.
- cофтверный кулинг. Можно определять загороженность объектов другими объектами на стороне CPU.
- кулинг для теней.
Простейший кулинг.
Имеем область видимости, заданную фрустумом или пирамидой видимости. Объекты, не попавшие в него следует отбросить и не посылать на рендер. Фрустум удобно задавать 6 плоскостями (frustum_planes).
Имеем объекты на сцене. Каждый объект можно аппроксимировать простейшей геометрией. Например сферой, боксом (BoundingSphere, BoundingBox). Вся геометрия объекта лежит внутри этого примитива.
Окружающие примитивы
Тест на видимость такой простейшей геометрии проходит очень быстро. Нашей задачей является — понять находится ли указанный примитив вне фрустума.
Рассмотрим определение видимости: сфер, боксов. Боксы бывают разными: ориентированные по мировым осям AABB (axis-aligned bounding box) и ориентированные по локальным осям объекта OBB (oriented Bounding Box). Видно, что OBB лучше апроксимирует объект, но при этом тест на видимость сложнее чем ABB.
Сфера-фрустум.
Алгоритм: для центра объекта находим его расстояние до каждой плоскости фрустума. Если точка находится сзади плоскости, дальше чем радиус сферы, то очевидно что сфера не попадает в область видимости. Данная плоскость становится отсекающей.
__forceinline bool SphereInFrustum(vec3 &pos, float &radius, vec4 *frustum_planes) { bool res = true; //тестируем 6 плоскостей фрустума for ( int i = 0; i < 6; i++) { //считаем расстояние от центра сферы до плоскости //если центр сферы находится за плоскостью и расстояние больше чем радиус сферы, //то объект не попадает во фрустум if ( frustum_planes[i].x * pos.x + frustum_planes[i].y * pos.y + frustum_planes[i].z * pos.z + frustum_planes[i].w <= -radius) res = false; //return false; //флаг работает быстрее } return res; //return true; }
AABB-фрустум.
Окружающая сфера не всегда точно апроксимирует объект. Для более точного теста чаще используют апроксимирующие боксы. Боксы бывают разными. Ориентированные по мировым осям AABB и ориентированные по локальным осям объекта OBB.
Общая идея теста боксов: если все 8 точек бокса находятся за какой-либо плоскостью фрустума, то бокс не попадает во фрустум. В следующем примере приводится тест ABB-фрустум, но если подставить world-space точки в уравнения, то получим тест OBB-фрустум.