Массив потенциальной видимости (PVS), областей видимости
PVS (сокращение от Potentially Visible Set или Potential Visibility Set) - это набор областей видимости, которые могут быть видны из заданного местоположения. Это не точная система определения видимости, но очень быстрая благодаря сохранению в файл карты при компиляции. Он используется для многих проверок в процессе игры, включая сетевую фильтрацию и управление отображением.
Команды управления
r_novis<булева переменная>- Отключает систему PVS, в результате чего весь мир игры отображается постоянно.
Возможна путаница:Если на карте есть прикрытия и/или порталы областей, модели всё равно будут исчезать, если не отключена переменная r_occlusionи не включена переменнаяr_portalsopenall, соответственно.r_lockpvs<булева переменная>- Предотвращает обновление системы PVS. Позволяет непосредственно исследовать "скрываемые объекты".
mat_wireframe<варианты выбора>- Хотя это и не используется PVS, но режимы отображения каркаса 1 и 3 позволяют видеть, как области видимости появляются и исчезают из поля зрения.
sv_strict_notarget<булева переменная>- Если переменная notarget включена, то объекты не смогут распознать, что они находятся в PVS.
test_randomizeinpvs<пусто>- [Нужно сделать]
Программирование
Кластеры (области видимости)
int engine->GetClusterForOrigin( vector origin )- Определяет кластер в которой располагаются указанные координаты.
int engine->GetClusterCount()- Количество кластеров на карте.
Совет: ceil(engine->GetClusterCount() / 8.0f)возвращает соответствующую длину буфера PVS для активной карты. int engine->GetAllClusterBounds( bbox_t *pBBoxList, int maxBBox )- Возвращает список границ всех кластеров. Возвращает общее количество кластеров.
bbox_tis a struct containing a min and max Vector.
Массив PVS
Массив потенциальной видимости хранится в виде байтового буфера, где каждый бит представляет видимость областей видимости.
int engine->GetPVSForCluster( int cluster, int outputpvslength, byte* outputpvs )- Places the PVS for the given cluster in
outputpvs. The return value is the number of bytes that were written; values in the rest of the buffer are undefined. bool engine->CheckOriginInPVS( vector origin, byte *checkpvs, int checkpvssize )- Determines whether the given location is within the given PVS.
bool engine->CheckBoxInPVS( vector mins, vector maxs, byte *checkpvs, int checkpvssize )- Determines whether the given box is within the given PVS at any point.
void engine->ResetPVS( byte *pvs, int pvssize )- Resets
pvssizebytes to 0, starting atpvs. void engine->AddOriginToPVS( vector origin )- Deprecated?[подтвердить] Adds the PVS of the given origin to the "current accumulated pvs" with an "8 unit fudge factor".
Пример
Эта функция позволяет обойти проблему ненужной обработки динамичного источника света, когда его ограничивающий короб проходит сквозь стену. Код довольно затратный, но не более чем сам динамичный источник света!
int CMyEnt::ShouldTransmit(const CCheckTransmitInfo *pInfo)
{
Vector vecSurroundMins, vecSurroundMaxs;
CollisionProp()->WorldSpaceSurroundingBounds( &vecSurroundMins, &vecSurroundMaxs );
// Are our surrounding bounds in PVS?
if ( !engine->CheckBoxInPVS(vecSurroundMins, vecSurroundMaxs, pInfo->m_PVS, pInfo->m_nPVSSize) )
return FL_EDICT_DONTSEND;
// Get our own PVS (cache the buffer if you use this code)
int pvsSize = ceil(engine->GetClusterCount() / 8.0f); // bits to bytes
byte* pvs = new byte[pvsSize];
int cluster = engine->GetClusterForOrigin(GetAbsOrigin());
engine->GetPVSForCluster(cluster, pvsSize, pvs);
// Find the intersection of our PVS and the player's
byte* pvs_shared = new byte[pvsSize];
bool found_overlap = false;
for (int i=0; i < pvsSize; i++)
{
pvs_shared[i] = pvs[i] & pInfo->PVS[i]; // bitwise AND
if (!found_overlap && pvs_shared[i] != 0)
found_overlap = true;
}
bool in_pvs = false;
if (found_overlap)
in_pvs = engine->CheckBoxInPVS( vecSurroundMins, vecSurroundMaxs, pvs_shared, pvsSize );
// Free the memory we just allocated
delete[] pvs;
delete[] pvs_shared;
// transmit if we are in the shared PVS
return in_pvs ? FL_EDICT_ALWAYS : FL_EDICT_DONTSEND;
}
Области карты
Области карты - это обособленные области видимости, либо полностью изолированные элементами карты, либо отделённые динамически закрытыми порталами областей (последее PVS самостоятельно определить не может).
int engine->GetArea( vector origin )- Определяет, в какой области карты находится начало отсчёта.
void engine->GetAreaBits( int area, byte *bits, int buflen )- Задаёт битовый буфер областей, которые будут сообщающимися с указанной.
int engine->CheckAreasConnected( int area1, int area2 )- Проверяет, сообщается ли область area1 с областью area2 в прямом и обратном направлениях. Результат зависит от состояния портала областей.
Примечание: Areaportals will close of their own accord depending on the position of the player. Area testing is therefore not always a good idea! bool engine->GetAreaPortalPlane( vector vViewOrigin, int portalKey, VPlane *pPlane )- По указанному началу отсчёта (которое определяет область для начала поиска) и ключу портала, определяет плоскость, которая отделяет эту область (указывает область, в которую ведёт).
void engine->SetAreaPortalState( int portalNumber, int isOpen )void engine->SetAreaPortalStates( int *portalNumbers, int *isOpen, int nPortals )- Открыть или закрыть один или несколько порталов областей.
Смотреть также
- Оптимизация видимости объяснения подробноcтей работы областей видимости и массива потенциальной видимости.
- Half-Life 2 Map Editing Optimization Guide: Visleafs [sic]
- VBSP компилятор, разбивающий пространство карты на области видмости
- VVIS компилятор, определяющй видимость между области видмости
- PAS - массив потенциальной слышимости
Potentially visible set