PVS: Difference between revisions
No edit summary |
No edit summary |
||
Line 86: | Line 86: | ||
=== Areas === | === Areas === | ||
''Areas are completely separate collections of leaves, either set in stone by [[brush]]work or created dynamically by closed [[areaportal]]s. | ''Areas are completely separate collections of leaves, either set in stone by [[brush]]work or created dynamically by closed [[areaportal]]s (which PVS alone cannot account for).'' | ||
; <code>[[int]] engine->GetArea( [[Vector]] origin )</code> | ; <code>[[int]] engine->GetArea( [[Vector]] origin )</code> |
Revision as of 05:06, 6 August 2011
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 is a very fast one. It forms the basis for many run-time tests, including networking filtering and rendering control.
See Visibility optimization for in-depth discussion of how leaves and the PVS work.
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 mode does 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
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 cluster.

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 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;
}
// transmit if we are in the shared PVS
if (found_overlap && engine->CheckBoxInPVS( mins, maxs, pvs, pvsSize ))
return FL_EDICT_ALWAYS;
return FL_EDICT_DONTSEND;
}
Areas
Areas are completely separate collections of leaves, either set in stone by brushwork or created dynamically by closed areaportals (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!
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