PVS

 
A Potentially Visible Set (or Potential Visibility Set) is a collection of visleaves which might be visible from a given location. It is not a precise measure of visibility, but thanks to being pre-compiled into a map, it is a very fast one. It forms the basis for many run-time tests, including networking filtering and rendering control.
Console Commands
- r_novis<boolean>
- Disables the PVS system, causing the whole world to be rendered at once.
- r_lockpvs<boolean>
- Prevents the PVS system from updating. Allows direct inspection "behind the scenes".
- mat_wireframe<choices>
- While not strictly PVS-related, wireframe modes 1 and 3 allow you to see leaves popping in and out of view.
- sv_strict_notarget<boolean>
- If set, notarget will cause entities to never think they are in the PVS.
- test_randomizeinpvs<void>
- [Todo]
Programming
Clusters
- int engine->GetClusterForOrigin( Vector origin )
- Gets the cluster for the given origin.
- int engine->GetClusterCount()
- The number of clusters in the map.  Tip: Tip:ceil(engine->GetClusterCount() / 8.0f)returns the appropriate length for a PVS buffer in the current map.
- int engine->GetAllClusterBounds( bbox_t *pBBoxList, int maxBBox )
- Gets a list of all clusters' bounds. Returns total number of clusters. bbox_tis a struct containing a min and max vector.
PVS
A PVS is stored in a byte buffer in which each bit represents the visibility of a cluster.
 Bug:Testing an empty PVS can have unreliable results in some situations.
Bug:Testing an empty PVS can have unreliable results in some situations.- 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?[confirm] Adds the PVS of the given origin to the "current accumulated pvs" with an "8 unit fudge factor".
Example
This function bypasses the problem of a dynamic light entity being processed needlessly when its bounding box pokes through a wall. The code is quite expensive, but not as expensive as a dynamic light!
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;
}
Areas
Areas are completely separate collections of leaves, either set in stone by brushwork or created dynamically by closed areaportals (the latter of which PVS alone cannot account for).
- int engine->GetArea( Vector origin )
- Determine which area the origin is within.
- void engine->GetAreaBits( int area, byte *bits, int buflen )
- Get a bit buffer of which areas the given area can flow into.
- int engine->CheckAreasConnected( int area1, int area2 )
- Check whether area1 flows into area2 and vice versa. Result depends on areaportal state.  Note:Areaportals will close of their own accord depending on the position of the player. Area testing is therefore not always a good idea! Note: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 )
- Given a view origin (which tells us the area to start looking in) and a portal key, fill in the plane that leads out of this area (it points into whatever area it leads to).
- void engine->SetAreaPortalState( int portalNumber, int isOpen )
- void engine->SetAreaPortalStates( int *portalNumbers, int *isOpen, int nPortals )
- Open or close one or many areaportals.
See also
- Visibility optimization for in-depth discussion of how leaves and the PVS work.
- Half-Life 2 Map Editing Optimization Guide: Visleafs [sic]
- VBSP, which generates leaves
- VVIS, which determines visibility between leaves
- PAS, the Potentially Audible Set
- Wikipedia:Potentially visible set























