lightQuery.cpp
Engine/source/lighting/lightQuery.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "lighting/lightQuery.h" 26 27#include "lighting/lightManager.h" 28#include "platform/profiler.h" 29 30 31LightQuery::LightQuery( U32 maxLights ) 32 : mMaxLights( maxLights ) 33{ 34} 35 36LightQuery::~LightQuery() 37{ 38} 39 40void LightQuery::init( const Point3F &cameraPos, 41 const Point3F &cameraDir, 42 F32 viewDist ) 43{ 44 mVolume.center = cameraPos; 45 mVolume.radius = viewDist; 46 mLights.clear(); 47} 48 49void LightQuery::init( const SphereF &bounds ) 50{ 51 mVolume = bounds; 52 mLights.clear(); 53} 54 55void LightQuery::init( const Box3F &bounds ) 56{ 57 bounds.getCenter( &mVolume.center ); 58 mVolume.radius = ( bounds.maxExtents - mVolume.center ).len(); 59 mLights.clear(); 60} 61 62void LightQuery::getLights( LightInfo** outLights, U32 maxLights ) 63{ 64 PROFILE_SCOPE( LightQuery_getLights ); 65 66 // Gather lights if we haven't already. 67 if ( mLights.empty() ) 68 _scoreLights(); 69 70 U32 lightCount = getMin( (U32)mLights.size(), getMin( mMaxLights, maxLights ) ); 71 72 // Copy them over. 73 for ( U32 i = 0; i < lightCount; i++ ) 74 { 75 LightInfo *light = mLights[i]; 76 77 // If the score reaches zero then we got to 78 // the end of the valid lights for this object. 79 if ( light->getScore() <= 0.0f ) 80 break; 81 82 outLights[i] = light; 83 } 84} 85 86void LightQuery::_scoreLights() 87{ 88 PROFILE_SCOPE( LightQuery_scoreLights ); 89 90 if ( !LIGHTMGR ) 91 return; 92 93 // Get all the lights. 94 LIGHTMGR->getAllUnsortedLights( &mLights ); 95 LightInfo *sun = LIGHTMGR->getSpecialLight( LightManager::slSunLightType ); 96 97 const Point3F lumDot( 0.2125f, 0.7154f, 0.0721f ); 98 99 Vector<LightInfo*>::iterator iter = mLights.begin(); 100 for ( ; iter != mLights.end(); iter++ ) 101 { 102 // Get the light. 103 LightInfo *light = (*iter); 104 105 F32 luminace = 0.0f; 106 F32 dist = 0.0f; 107 F32 weight = 0.0f; 108 109 const bool isSpot = light->getType() == LightInfo::Spot; 110 const bool isPoint = light->getType() == LightInfo::Point; 111 112 if ( isPoint || isSpot ) 113 { 114 // Get the luminocity. 115 luminace = mDot( light->getColor(), lumDot ) * light->getBrightness(); 116 117 // Get the distance to the light... score it 1 to 0 near to far. 118 F32 lenSq = ( mVolume.center - light->getPosition() ).lenSquared(); 119 120 F32 radiusSq = mSquared( light->getRange().x + mVolume.radius ); 121 F32 distSq = radiusSq - lenSq; 122 123 if ( distSq > 0.0f ) 124 dist = mClampF( distSq / ( 1000.0f * 1000.0f ), 0.0f, 1.0f ); 125 126 // TODO: This culling is broken... it culls spotlights 127 // that are actually visible. 128 if ( false && isSpot && dist > 0.0f ) 129 { 130 // TODO: I cannot test to see if we're within 131 // the cone without a more detailed test... so 132 // just reject if we're behind the spot direction. 133 134 Point3F toCenter = mVolume.center - light->getPosition(); 135 F32 angDot = mDot( toCenter, light->getDirection() ); 136 if ( angDot < 0.0f ) 137 dist = 0.0f; 138 } 139 140 weight = light->getPriority(); 141 } 142 else 143 { 144 // The sun always goes first 145 // regardless of the settings. 146 if ( light == sun ) 147 { 148 weight = F32_MAX; 149 dist = 1.0f; 150 luminace = 1.0f; 151 } 152 else 153 { 154 // TODO: When we have multiple directional 155 // lights we should score them here. 156 } 157 } 158 159 // TODO: Manager ambient lights here too! 160 161 light->setScore( luminace * weight * dist ); 162 } 163 164 // Sort them! 165 mLights.sort( _lightScoreCmp ); 166} 167 168S32 LightQuery::_lightScoreCmp( LightInfo* const *a, LightInfo* const *b ) 169{ 170 F32 diff = (*a)->getScore() - (*b)->getScore(); 171 return diff < 0 ? 1 : diff > 0 ? -1 : 0; 172} 173