PVS
The Potentially Visible Set (or Potential Visibility Set) is a collection of visleaves which the player might be able to see. It is not an accurate measure of visibility but thanks to being pre-compiled into a map is a very fast one. It forms the basis for many run-time tests of visibility, including networking and rendering control.
See Visibility optimization for a more in-depth discussion of how leaves and the PVS work.
Console commands
r_novis
<boolean>- Bypasses the PVS system, causing the whole world to be rendered at once.
r_lockpvs
<boolean>- Prevents the PVS system from updating. Allows inspection "behind the scenes".
sv_strict_notarget
<boolean>- If set, notarget will cause entities to never think they are in the PVS.
test_randomizeinpvs
<void>- [Todo]
Programming
PVS is handled by the server only. Clients do not know anything about it (but see NotifyShouldTransmit()
).
Clusters
int engine->GetClusterForOrigin( Vector origin )
- Gets the cluster for the given origin.
int engine->GetClusterCount()
- The number of clusters in the map.
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_t
is a struct containing a min and maxVector
.
PVS
A PVS is stored in a byte buffer in which each bit represents the visibility of a leaf (
).

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
pvssize
bytes 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".
Example
This function bypasses the problem of an dynamic light entity being processed needlessly when its bounding box pokes through a wall. It is quite expensive!
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;
}
// transmit if we are in the shared PVS
if (!found_overlap)
return FL_EDICT_DONTSEND;
if (engine->CheckBoxInPVS( mins, maxs, pvs, pvsSize ))
return FL_EDICT_ALWAYS;
return FL_EDICT_DONTSEND;
}
Areas
Areas are created by areaportals. A map without areaportals is one large area.
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.
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
- Visleaf
- Visibility optimization
- Half-Life 2 Map Editing Optimization Guide: Visleafs
- VBSP, which generates leaves
- VVIS, which determines visibility between leaves
- PAS, the Potentially Audible Set
- Wikipedia:Potentially Visible Set