lightQuery.cpp

Engine/source/lighting/lightQuery.cpp

More...

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