Массив потенциальной видимости (PVS), областей видимости

From Valve Developer Community
< Ru
Jump to navigation Jump to search
English (en)Русский (ru)Translate (Translate)

PVS (сокращение от Potentially Visible Set или Potential Visibility Set) - это набор областей видимости(en), которые могут быть видны из заданного местоположения. Это не точная система определения видимости, но очень быстрая благодаря сохранению в файл карты при компиляции. Он используется для многих проверок в процессе игры, включая сетевую фильтрацию и управление отображением.

Команды управления

r_novis  <булева переменная(en)>
Отключает систему PVS, в результате чего весь мир игры отображается постоянно.
Warning.pngВозможна путаница:Если на карте есть прикрытия(en) и/или порталы областей(en), модели всё равно будут исчезать, если не отключена переменная r_occlusion и не включена переменная r_portalsopenall, соответственно.
r_lockpvs  <булева переменная(en)>
Предотвращает обновление системы PVS. Позволяет непосредственно исследовать "скрываемые объекты".
mat_wireframe(en)  <варианты выбора>
Хотя это и не используется PVS, но режимы отображения каркаса 1 и 3 позволяют видеть, как области видимости появляются и исчезают из поля зрения.
sv_strict_notarget  <булева переменная(en)>
Если переменная notarget(en) включена, то объекты не смогут распознать, что они находятся в PVS.
test_randomizeinpvs  <пусто>
[Нужно сделать]

Программирование

Кластеры (области видимости)

Нужно сделать: Difference between a cluster and a leaf.

int(en) engine->GetClusterForOrigin( vector(en) origin )
Определяет кластер в которой располагаются указанные координаты.
int(en) engine->GetClusterCount()
Количество кластеров на карте.
Tip.pngСовет: ceil(engine->GetClusterCount() / 8.0f) возвращает соответствующую длину буфера PVS для активной карты.
int(en) engine->GetAllClusterBounds( bbox_t *pBBoxList, int(en) maxBBox )
Возвращает список границ всех кластеров. Возвращает общее количество кластеров. bbox_t is a struct containing a min and max Vector(en).

Массив PVS

Массив потенциальной видимости хранится в виде байтового(en) буфера, где каждый бит представляет видимость областей видимости.

Icon-Bug.pngБаг:Testing an empty PVS can have unreliable results in some situations.
int(en) engine->GetPVSForCluster( int(en) cluster, int(en) outputpvslength, byte(en)* 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(en) engine->CheckOriginInPVS( vector(en) origin, byte(en) *checkpvs, int(en) checkpvssize )
Determines whether the given location is within the given PVS.
bool(en) engine->CheckBoxInPVS( vector(en) mins, vector(en) maxs, byte(en) *checkpvs, int(en) checkpvssize )
Determines whether the given box is within the given PVS at any point.
void(en) engine->ResetPVS( byte(en) *pvs, int(en) pvssize )
Resets pvssize bytes to 0, starting at pvs.
void(en) engine->AddOriginToPVS( vector(en) origin )
Deprecated?[подтвердить] Adds the PVS of the given origin to the "current accumulated pvs" with an "8 unit fudge factor".

Пример

Эта функция позволяет обойти проблему ненужной обработки динамичного источника света, когда его ограничивающий короб(en) проходит сквозь стену. Код довольно затратный(en), но не более чем сам динамичный источник света!

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;
}

Области карты

Области карты - это обособленные области видимости, либо полностью изолированные элементами карты(en), либо отделённые динамически закрытыми порталами областей(en) (последее PVS самостоятельно определить не может).

int(en) engine->GetArea( vector(en) origin )
Определяет, в какой области карты находится начало отсчёта.
void engine->GetAreaBits( int(en) area, byte(en) *bits, int(en) buflen )
Задаёт битовый буфер областей, которые будут сообщающимися с указанной.
int(en) engine->CheckAreasConnected( int(en) area1, int(en) area2 )
Проверяет, сообщается ли область area1 с областью area2 в прямом и обратном направлениях. Результат зависит от состояния портала областей.
Note.pngПримечание: Areaportals will close of their own accord depending on the position of the player(en). Area testing is therefore not always a good idea!
bool(en) engine->GetAreaPortalPlane( vector(en) vViewOrigin, int(en) portalKey, VPlane(en) *pPlane )
По указанному началу отсчёта (которое определяет область для начала поиска) и ключу портала, определяет плоскость, которая отделяет эту область (указывает область, в которую ведёт).
void(en) engine->SetAreaPortalState( int(en) portalNumber, int(en) isOpen )
void(en) engine->SetAreaPortalStates( int(en) *portalNumbers, int(en) *isOpen, int(en) nPortals )
Открыть или закрыть один или несколько порталов областей.

Смотреть также

Эта статья(раздел) является наброском(en). Вы можете помочь, дополнив её.