00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/lighting_manager.h"
00029 #include "3d/point_light.h"
00030 #include "3d/transform.h"
00031 #include "3d/fast_floor.h"
00032 #include "nel/3d/logic_info.h"
00033 #include "nel/misc/aabbox.h"
00034
00035
00036 using namespace NLMISC;
00037 using namespace std;
00038
00039
00040 namespace NL3D {
00041
00042
00043
00044
00045
00046
00047 #define NL3D_LIGHT_QUAD_GRID_SIZE 256
00048 #define NL3D_LIGHT_QUAD_GRID_ELTSIZE 10.f
00049 #define NL3D_LIGHT_QUAD_GRID_RADIUS_LIMIT 20.f
00050
00051 #define NL3D_LIGHT_QUAD_GRID_FACTOR 4
00052
00053
00054
00055 #define NL3D_DEFAULT_NOATT_LIGHT_RADIUS 1000.f
00056
00057 #define NL3D_DEFAULT_OUT_OF_ATT_LIGHT_INF_FACTOR 0.1f
00058
00059 #define NL3D_DEFAULT_LIGHT_TRANSITION_THRESHOLD 0.1f
00060
00061
00062
00063 CLightingManager::CLightingManager()
00064 {
00065
00066
00067 uint qgSize= NL3D_LIGHT_QUAD_GRID_SIZE;
00068 float eltSize= NL3D_LIGHT_QUAD_GRID_ELTSIZE;
00069 float radiusLimit= NL3D_LIGHT_QUAD_GRID_RADIUS_LIMIT;
00070
00071 for(uint i=0;i<NL3D_QUADGRID_LIGHT_NUM_LEVEL;i++)
00072 {
00073
00074 _LightQuadGrid[i].create(qgSize, eltSize);
00075 _StaticLightedModelQuadGrid[i].create(qgSize, eltSize);
00076 _LightQuadGridRadiusLimit[i]= radiusLimit;
00077
00078
00079 qgSize/= NL3D_LIGHT_QUAD_GRID_FACTOR;
00080 qgSize= max(qgSize, 1U);
00081 eltSize*= NL3D_LIGHT_QUAD_GRID_FACTOR;
00082 radiusLimit*= NL3D_LIGHT_QUAD_GRID_FACTOR;
00083 }
00084
00085
00086
00087 _NoAttLightRadius= NL3D_DEFAULT_NOATT_LIGHT_RADIUS;
00088 _OutOfAttLightInfFactor= NL3D_DEFAULT_OUT_OF_ATT_LIGHT_INF_FACTOR;
00089 _LightTransitionThreshold= NL3D_DEFAULT_LIGHT_TRANSITION_THRESHOLD;
00090
00091
00092
00093 setMaxLightContribution(3);
00094 }
00095
00096
00097
00098 void CLightingManager::setMaxLightContribution(uint nlights)
00099 {
00100 _MaxLightContribution= min(nlights, (uint)NL3D_MAX_LIGHT_CONTRIBUTION);
00101 }
00102
00103
00104
00105 void CLightingManager::setNoAttLightRadius(float noAttLightRadius)
00106 {
00107 nlassert(noAttLightRadius>0);
00108 _NoAttLightRadius= noAttLightRadius;
00109 }
00110
00111
00112
00113 void CLightingManager::setOutOfAttLightInfFactor(float outOfAttLightInfFactor)
00114 {
00115 outOfAttLightInfFactor= max(0.f, outOfAttLightInfFactor);
00116 _OutOfAttLightInfFactor= outOfAttLightInfFactor;
00117 }
00118
00119
00120
00121 void CLightingManager::setLightTransitionThreshold(float lightTransitionThreshold)
00122 {
00123 clamp(lightTransitionThreshold, 0.f, 1.f);
00124 _LightTransitionThreshold= lightTransitionThreshold;
00125 }
00126
00127
00128
00129
00130 void CLightingManager::clearDynamicLights()
00131 {
00132
00133 for(uint i=0;i<NL3D_QUADGRID_LIGHT_NUM_LEVEL;i++)
00134 {
00135
00136 _LightQuadGrid[i].clear();
00137 }
00138
00139
00140 _DynamicLightList.clear();
00141 }
00142
00143
00144 void CLightingManager::addDynamicLight(CPointLight *light)
00145 {
00146
00147
00148
00149 CPointLightInfo plInfo;
00150 plInfo.Light= light;
00151
00152
00153 float radius=light->getAttenuationEnd();
00154
00155 if(radius==0)
00156 radius= _NoAttLightRadius;
00157 plInfo.Sphere.Center= light->getPosition();
00158 plInfo.Sphere.Radius= radius;
00159
00160
00161 CVector bbmin= light->getPosition();
00162 bbmin-= CVector(radius, radius, radius);
00163 CVector bbmax= light->getPosition();
00164 bbmax+= CVector(radius, radius, radius);
00165
00166
00167 uint qgId;
00168 for(qgId= 0; qgId<NL3D_QUADGRID_LIGHT_NUM_LEVEL-1; qgId++)
00169 {
00170
00171 if(radius<_LightQuadGridRadiusLimit[qgId])
00172 break;
00173 }
00174
00175 _LightQuadGrid[qgId].insert(bbmin, bbmax, plInfo);
00176
00177
00178
00179
00180
00181
00182
00183 _StaticLightedModelQuadGrid[qgId].select(bbmin, bbmax);
00184
00185 CQuadGrid<CTransform*>::CIterator itModel= _StaticLightedModelQuadGrid[qgId].begin();
00186 while(itModel != _StaticLightedModelQuadGrid[qgId].end() )
00187 {
00188 CTransform *model= *itModel;
00189 const CVector &modelPos= model->getWorldMatrix().getPos();
00190
00191
00192 if( plInfo.Sphere.include(modelPos) )
00193 {
00194
00195 model->resetLighting();
00196 }
00197
00198
00199 itModel++;
00200 }
00201
00202
00203
00204
00205 _DynamicLightList.push_back(light);
00206
00207 }
00208
00209
00210 CLightingManager::CQGItLightedModel CLightingManager::eraseStaticLightedModel(CQGItLightedModel ite)
00211 {
00212
00213 for(uint i=0;i<NL3D_QUADGRID_LIGHT_NUM_LEVEL;i++)
00214 {
00215
00216 _StaticLightedModelQuadGrid[i].erase(ite.QgItes[i]);
00217 }
00218
00219
00220 return CQGItLightedModel();
00221 }
00222
00223
00224 CLightingManager::CQGItLightedModel CLightingManager::insertStaticLightedModel(CTransform *model)
00225 {
00226 CQGItLightedModel ite;
00227 const CVector &worldPos= model->getWorldMatrix().getPos();
00228
00229
00230 for(uint i=0;i<NL3D_QUADGRID_LIGHT_NUM_LEVEL;i++)
00231 {
00232 ite.QgItes[i]= _StaticLightedModelQuadGrid[i].insert(worldPos, worldPos, model);
00233 }
00234
00235
00236 return ite;
00237 }
00238
00239
00240
00241 struct CSortLight
00242 {
00243 CPointLight *PointLight;
00244 float Influence;
00245
00246 };
00247
00248
00249 void CLightingManager::computeModelLightContributions(CTransform *model, CLightContribution &lightContrib,
00250 ILogicInfo *logicInfo)
00251 {
00252 sint i;
00253
00254
00255 static std::vector<CPointLightInfluence> lightList;
00256
00257 lightList.clear();
00258
00259
00260 CVector modelPos;
00261 float modelRadius;
00262
00263
00264 CAABBox bbox;
00265 model->getAABBox(bbox);
00266
00267 modelPos= model->getWorldMatrix() * bbox.getCenter();
00268
00269 if(model->isBigLightable())
00270 {
00271
00272 modelRadius= bbox.getRadius();
00273 }
00274 else
00275 {
00276
00277 modelRadius= 0;
00278 }
00279
00280
00281
00282
00283
00284 getDynamicPointLightList(modelPos, lightList);
00285
00286
00287 if( !lightContrib.FrozenStaticLightSetup )
00288 {
00289
00290 if(!logicInfo)
00291 {
00292
00293 lightContrib.SunContribution= 255;
00294
00295 lightContrib.LocalAmbient.set(0,0,0,0);
00296
00297 }
00298 else
00299 {
00300
00301 logicInfo->getStaticLightSetup(lightList, lightContrib.SunContribution, lightContrib.LocalAmbient);
00302 }
00303 }
00304
00305
00306
00307
00308
00309 for(i=0; i<(sint)lightList.size();i++)
00310 {
00311 CPointLight *pl= lightList[i].PointLight;
00312
00313
00314 float dist= (pl->getPosition() - modelPos).norm();
00315 float distMinusRadius= dist - modelRadius;
00316
00317
00318 float inf;
00319 float attBegin= pl->getAttenuationBegin();
00320 float attEnd= pl->getAttenuationEnd();
00321
00322 if( attEnd==0 )
00323 {
00324
00325 inf= 1;
00326
00327
00328 if(pl->getType() == CPointLight::SpotLight)
00329 inf*= pl->computeLinearAttenuation(modelPos, dist, modelRadius);
00330 }
00331 else
00332 {
00333
00334 if(distMinusRadius<attBegin)
00335 {
00336
00337
00338
00339 inf= 1 + _OutOfAttLightInfFactor * (attBegin - distMinusRadius);
00340
00341
00342
00343 if(pl->getType() == CPointLight::SpotLight)
00344 inf*= pl->computeLinearAttenuation(modelPos, dist, modelRadius);
00345 }
00346 else if(distMinusRadius<attEnd)
00347 {
00348
00349
00350 inf= pl->computeLinearAttenuation(modelPos, dist, modelRadius);
00351 }
00352 else
00353 {
00354
00355
00356 inf= _OutOfAttLightInfFactor * (attEnd - distMinusRadius);
00357 }
00358 }
00359
00360
00361 lightList[i].BkupInfluence= lightList[i].Influence;
00362 lightList[i].Influence*= inf;
00363
00364
00365 lightList[i].DistanceToModel= dist;
00366 }
00367
00368
00369 sort(lightList.begin(), lightList.end());
00370
00371
00372
00373 uint startId= 0;
00374 uint ligthSrcId= 0;
00375
00376 if(lightContrib.FrozenStaticLightSetup)
00377 startId= lightContrib.NumFrozenStaticLight;
00378
00379
00380 if(startId < _MaxLightContribution)
00381 {
00382
00383 float deltaMinInfluence= _LightTransitionThreshold;
00384 float minInfluence= 0;
00385
00386 if(lightList.size() > _MaxLightContribution-startId)
00387 {
00388
00389 minInfluence= lightList[_MaxLightContribution-startId].Influence;
00390
00391 minInfluence= max(minInfluence, 0.f);
00392 }
00393
00394 float minInfluenceStart = minInfluence + deltaMinInfluence;
00395 float OOdeltaMinInfluencex255= 255.f / deltaMinInfluence;
00396
00397
00398 for(i=startId;i<(sint)_MaxLightContribution; i++)
00399 {
00400
00401 if(ligthSrcId>=lightList.size())
00402 break;
00403 else
00404 {
00405 CPointLight *pl= lightList[ligthSrcId].PointLight;
00406 float inf= lightList[ligthSrcId].Influence;
00407 float bkupInf= lightList[ligthSrcId].BkupInfluence;
00408 float distToModel= lightList[ligthSrcId].DistanceToModel;
00409
00410 lightContrib.PointLight[i]= pl;
00411
00412
00413 if(inf >= minInfluenceStart)
00414 {
00415
00416
00417 lightContrib.Factor[i]= (uint8)OptFastFloor(bkupInf*255);
00418 }
00419 else
00420 {
00421 float f= (inf-minInfluence) * OOdeltaMinInfluencex255;
00422 sint fi;
00423
00424
00425 fi= OptFastFloor( bkupInf*f );
00426 clamp(fi, 0, 255);
00427 lightContrib.Factor[i]= fi;
00428 }
00429
00430
00431
00432
00433 sint attFactor= OptFastFloor( lightContrib.Factor[i] * pl->computeLinearAttenuation(modelPos, distToModel) );
00434 lightContrib.AttFactor[i]= (uint8)attFactor;
00435
00436
00437 lightContrib.TransformIterator[i]= pl->appendLightedModel(model);
00438
00439
00440 ligthSrcId++;
00441 }
00442 }
00443 }
00444 else
00445 {
00446
00447 i= startId;
00448 }
00449
00450
00451 if(i<NL3D_MAX_LIGHT_CONTRIBUTION)
00452 {
00453 lightContrib.PointLight[i]= NULL;
00454 }
00455
00456 }
00457
00458
00459
00460 void CLightingManager::getDynamicPointLightList(const CVector &worldPos, std::vector<CPointLightInfluence> &lightList)
00461 {
00462
00463 for(uint qgId=0; qgId<NL3D_QUADGRID_LIGHT_NUM_LEVEL; qgId++)
00464 {
00465 CQuadGrid<CPointLightInfo> &quadGrid= _LightQuadGrid[qgId];
00466
00467
00468 quadGrid.select(worldPos, worldPos);
00469
00470
00471 CQuadGrid<CPointLightInfo>::CIterator itLight;
00472 for(itLight= quadGrid.begin(); itLight!=quadGrid.end(); itLight++)
00473 {
00474
00475 if( (*itLight).Sphere.include(worldPos) )
00476 {
00477
00478 CPointLightInfluence pli;
00479 pli.PointLight= (*itLight).Light;
00480
00481 pli.Influence= 1;
00482 lightList.push_back( pli );
00483 }
00484 }
00485 }
00486 }
00487
00488
00489
00490 }