//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #ifdef _WIN32 #include <windows.h> #endif #include "vrad.h" #include "leaf_ambient_lighting.h" #include "bsplib.h" #include "vraddetailprops.h" #include "anorms.h" #include "pacifier.h" static TableVector g_BoxDirections[6] = { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 }, { 0, 0, 1 }, { 0, 0, -1 }, }; static void ComputeAmbientFromSurface( dface_t *surfID, dworldlight_t* pSkylight, Vector& radcolor ) { if ( !surfID ) return; texinfo_t *pTexInfo = &texinfo[surfID->texinfo]; // If we hit the sky, use the sky ambient if ( pTexInfo->flags & SURF_SKY ) { if ( pSkylight ) { // add in sky ambient VectorCopy( pSkylight->intensity, radcolor ); } } else { Vector reflectivity = dtexdata[pTexInfo->texdata].reflectivity; VectorMultiply( radcolor, reflectivity, radcolor ); } } // TODO: it's CRAZY how much lighting code we share with the engine. It should all be shared code. float Engine_WorldLightAngle( const dworldlight_t *wl, const Vector& lnormal, const Vector& snormal, const Vector& delta ) { float dot, dot2; Assert( wl->type == emit_surface ); dot = DotProduct( snormal, delta ); if (dot < 0) return 0; dot2 = -DotProduct (delta, lnormal); if (dot2 <= ON_EPSILON/10) return 0; // behind light surface return dot * dot2; } // TODO: it's CRAZY how much lighting code we share with the engine. It should all be shared code. float Engine_WorldLightDistanceFalloff( const dworldlight_t *wl, const Vector& delta ) { Assert( wl->type == emit_surface ); // Cull out stuff that's too far if (wl->radius != 0) { if ( DotProduct( delta, delta ) > (wl->radius * wl->radius)) return 0.0f; } return InvRSquared(delta); } void AddEmitSurfaceLights( const Vector &vStart, Vector lightBoxColor[6] ) { int iThread = 0; for ( int iLight=0; iLight < *pNumworldlights; iLight++ ) { dworldlight_t *wl = &dworldlights[iLight]; // Should this light even go in the ambient cubes? if ( !( wl->flags & DWL_FLAGS_INAMBIENTCUBE ) ) continue; Assert( wl->type == emit_surface ); // Can this light see the point? if ( TestLine( vStart, wl->origin, 0, iThread ) != CONTENTS_EMPTY ) continue; // Add this light's contribution. Vector vDelta = wl->origin - vStart; float flDistanceScale = Engine_WorldLightDistanceFalloff( wl, vDelta ); Vector vDeltaNorm = vDelta; VectorNormalize( vDeltaNorm ); float flAngleScale = Engine_WorldLightAngle( wl, wl->normal, vDeltaNorm, vDeltaNorm ); float ratio = flDistanceScale * flAngleScale; if ( ratio == 0 ) continue; for ( int i=0; i < 6; i++ ) { float t = DotProduct( g_BoxDirections[i], vDeltaNorm ); if ( t > 0 ) { lightBoxColor[i] += wl->intensity * (t * ratio); } } } } void ComputeAmbientFromSphericalSamples( const Vector &vStart, Vector lightBoxColor[6] ) { // Figure out the color that rays hit when shot out from this position. Vector radcolor[NUMVERTEXNORMALS]; for ( int i = 0; i < NUMVERTEXNORMALS; i++ ) { Vector vEnd = vStart + g_anorms[i] * (COORD_EXTENT * 1.74); // Now that we've got a ray, see what surface we've hit Vector lightStyleColors[MAX_LIGHTSTYLES]; lightStyleColors[0].Init(); // We only care about light style 0 here. Vector colorSum; CalcRayAmbientLighting( vStart, vEnd, lightStyleColors, colorSum ); radcolor[i] = lightStyleColors[0]; } // accumulate samples into radiant box for ( int j = 6; --j >= 0; ) { float t = 0; lightBoxColor[j].Init(); for (int i = 0; i < NUMVERTEXNORMALS; i++) { float c = DotProduct( g_anorms[i], g_BoxDirections[j] ); if (c > 0) { t += c; lightBoxColor[j] += radcolor[i] * c; } } lightBoxColor[j] *= 1/t; } // Now add direct light from the emit_surface lights. These go in the ambient cube because // there are a ton of them and they are often so dim that they get filtered out by r_worldlightmin. AddEmitSurfaceLights( vStart, lightBoxColor ); } bool IsLeafAmbientSurfaceLight( dworldlight_t *wl ) { static const float g_flWorldLightMinEmitSurface = 0.005f; static const float g_flWorldLightMinEmitSurfaceDistanceRatio = ( InvRSquared( Vector( 0, 0, 512 ) ) ); if ( wl->type != emit_surface ) return false; if ( wl->style != 0 ) return false; float intensity = max( wl->intensity[0], wl->intensity[1] ); intensity = max( intensity, wl->intensity[2] ); return (intensity * g_flWorldLightMinEmitSurfaceDistanceRatio) < g_flWorldLightMinEmitSurface; } // There are problems with water lighting that make bobbing objects look bad. the same problems // show up for other poorly sampled areas of the world, but floating in water makes it look the // worst because of oscillating back and forth and because water always acts as a bsp splitting // plane. The hack turned on if this #define is set makes all per leaf ambient for water exactly // match the per leaf above the water, and does solve the specific problems seen with d1_canals_11. // It was decided to punt it for hl2 because of effecting the underwater lighting of every object // in all levels at the last minute. This solution isn't good anyway - what is needed is either // some sort of adaptive sampling strategy, or distance-based interpolation or some other sort of // smoothly spacially varying lighting. #define MAKE_LIGHT_BELOW_WATER_MATCH_LIGHT_ABOVE_WATER 0 void ComputePerLeafAmbientLighting() { // Figure out which lights should go in the per-leaf ambient cubes. int nInAmbientCube = 0; int nSurfaceLights = 0; for ( int i=0; i < *pNumworldlights; i++ ) { dworldlight_t *wl = &dworldlights[i]; if ( IsLeafAmbientSurfaceLight( wl ) ) wl->flags |= DWL_FLAGS_INAMBIENTCUBE; else wl->flags &= ~DWL_FLAGS_INAMBIENTCUBE; if ( wl->type == emit_surface ) ++nSurfaceLights; if ( wl->flags & DWL_FLAGS_INAMBIENTCUBE ) ++nInAmbientCube; } Msg( "%d of %d (%d%% of) surface lights went in leaf ambient cubes.\n", nInAmbientCube, nSurfaceLights, nSurfaceLights ? ((nInAmbientCube*100) / nSurfaceLights) : 0 ); g_pLeafAmbientLighting->SetCount( numleafs ); StartPacifier( "ComputePerLeafAmbientLighting: " ); for ( int leafID = 0; leafID < numleafs; leafID++ ) { dleaf_t *pLeaf = &dleafs[leafID]; Vector cube[6]; Vector center = ( Vector( pLeaf->mins[0], pLeaf->mins[1], pLeaf->mins[2] ) + Vector( pLeaf->maxs[0], pLeaf->maxs[1], pLeaf->maxs[2] ) ) * 0.5f; #if MAKE_LIGHT_BELOW_WATER_MATCH_LIGHT_ABOVE_WATER if (pLeaf->contents & CONTENTS_WATER) { center.z=pLeaf->maxs[2]+1; int above_leaf=PointLeafnum( center); dleaf_t *pLeaf = &dleafs[above_leaf]; center = ( Vector( pLeaf->mins[0], pLeaf->mins[1], pLeaf->mins[2] ) + Vector( pLeaf->maxs[0], pLeaf->maxs[1], pLeaf->maxs[2] ) ) * 0.5f; } #endif ComputeAmbientFromSphericalSamples( center, cube ); for ( int i = 0; i < 6; i++ ) { VectorToColorRGBExp32( cube[i], (*g_pLeafAmbientLighting)[leafID].m_Color[i] ); } UpdatePacifier( (float)leafID / numleafs ); } EndPacifier( true ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 5821 | Knut Wikstrom |
Added Valve Source code. This is NOT to be commited to other than new code from Valve. |