00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025 #include "nel/3d/shadow_map_manager.h"
00026 #include "nel/misc/aabbox.h"
00027 #include "nel/3d/driver.h"
00028 #include "nel/3d/scene.h"
00029 #include "nel/3d/viewport.h"
00030 #include "nel/3d/scissor.h"
00031 #include "nel/3d/dru.h"
00032 #include "nel/3d/texture_mem.h"
00033 #include "nel/3d/visual_collision_manager.h"
00034 #include "nel/misc/hierarchical_timer.h"
00035 #include "nel/misc/fast_floor.h"
00036
00037
00038 using namespace NLMISC;
00039 using namespace std;
00040
00041 namespace NL3D {
00042
00043
00044
00045
00046 static inline float easeInEaseOut(float x)
00047 {
00048 float y;
00049
00050 float x2=x*x;
00051 float x3=x2*x;
00052 y= -2*x3 + 3*x2;
00053 return y;
00054 }
00055
00056
00057
00058 CShadowMapManager::CShadowMapManager()
00059 {
00060 uint i;
00061
00062
00063 _TextureCategory= new ITexture::CTextureCategory("SHADOW MANAGER");
00064
00065 setQuadGridSize(NL3D_SMM_QUADGRID_SIZE, NL3D_SMM_QUADCELL_SIZE);
00066 _ShadowCasters.reserve(256);
00067 _GenerateShadowCasters.reserve(256);
00068 _PolySmooth= true;
00069
00070
00071 _FillQuads.setVertexFormat(CVertexBuffer::PositionFlag);
00072 _FillMaterial.initUnlit();
00073 _FillMaterial.setColor(CRGBA(0,0,0,0));
00074 _FillMaterial.setZWrite(false);
00075 _FillMaterial.setZFunc(CMaterial::always);
00076 _FillMaterial.setDoubleSided(true);
00077 _FillQuads.setPreferredMemory(CVertexBuffer::RAMVolatile, true);
00078
00079
00080 _BlurQuads.setVertexFormat(CVertexBuffer::PositionFlag |
00081 CVertexBuffer::TexCoord0Flag |
00082 CVertexBuffer::TexCoord1Flag |
00083 CVertexBuffer::TexCoord2Flag |
00084 CVertexBuffer::TexCoord3Flag);
00085 _BlurQuads.setPreferredMemory(CVertexBuffer::RAMVolatile, true);
00086
00087
00088 _BlurQuads.setNumVertices(8);
00089 for (i=0;i<2;i++)
00090 {
00091 _BlurMaterial[i].initUnlit();
00092 _BlurMaterial[i].setColor(CRGBA::White);
00093 _BlurMaterial[i].setZWrite(false);
00094 _BlurMaterial[i].setZFunc(CMaterial::always);
00095 _BlurMaterial[i].setDoubleSided(true);
00096
00097
00098 uint j;
00099 for(j=1;j<4;j++)
00100 {
00101 _BlurMaterial[i].texEnvOpRGB(j, CMaterial::InterpolateConstant);
00102 _BlurMaterial[i].texEnvArg0RGB(j, CMaterial::Texture, CMaterial::SrcColor);
00103 _BlurMaterial[i].texEnvArg1RGB(j, CMaterial::Previous, CMaterial::SrcColor);
00104 _BlurMaterial[i].texEnvOpAlpha(j, CMaterial::InterpolateConstant);
00105 _BlurMaterial[i].texEnvArg0Alpha(j, CMaterial::Texture, CMaterial::SrcAlpha);
00106 _BlurMaterial[i].texEnvArg1Alpha(j, CMaterial::Previous, CMaterial::SrcAlpha);
00107 }
00108
00109 _BlurMaterial[i].texConstantColor(1, CRGBA(128,128,128,128));
00110 _BlurMaterial[i].texConstantColor(2, CRGBA(85,85,85,85));
00111 _BlurMaterial[i].texConstantColor(3, CRGBA(64,64,64,64));
00112 }
00113
00114 _BlurTextureW= 0;
00115 _BlurTextureH= 0;
00116
00117
00118 _CopyQuads.setVertexFormat (CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag);
00119 _CopyQuads.setNumVertices(4);
00120 _CopyQuads.setPreferredMemory(CVertexBuffer::RAMVolatile, true);
00121 CVertexBufferReadWrite vba;
00122 _CopyQuads.lock (vba);
00123 vba.setVertexCoord (0, CVector (0, 0, 0));
00124 vba.setVertexCoord (1, CVector (1, 0, 0));
00125 vba.setVertexCoord (2, CVector (1, 0, 1));
00126 vba.setVertexCoord (3, CVector (0, 0, 1));
00127
00128
00129 _CopyMaterial.initUnlit();
00130 _CopyMaterial.setColor(CRGBA::White);
00131 _CopyMaterial.setZWrite(false);
00132 _CopyMaterial.setZFunc(CMaterial::always);
00133 _CopyMaterial.setDoubleSided(true);
00134 _CopyMaterial.setBlend (false);
00135 _CopyMaterial.setAlphaTest (false);
00136 _CopyMaterial.setBlendFunc (CMaterial::one, CMaterial::zero);
00137
00138
00139
00140
00141 const uint clampTextSize= 512;
00142 const uint clampNearFadeSize= 32;
00143 const uint clampFarFadeSize= 128;
00144 uint textMemSize= 4*clampTextSize*1;
00145
00146 uint8 *tmpMem= new uint8[textMemSize];
00147 memset(tmpMem, 255, textMemSize);
00148 for(i=0;i<clampNearFadeSize;++i)
00149 {
00150 float f= (float)i/clampNearFadeSize;
00151 f= easeInEaseOut(f);
00152 tmpMem[4*i+3]= uint8(255.f*f);
00153 }
00154 for(i=0;i<clampFarFadeSize;++i)
00155 {
00156 float f= (float)i/clampFarFadeSize;
00157 f= easeInEaseOut(f);
00158 tmpMem[4*(clampTextSize-i-1)+3]= uint8(255.f*f);
00159 }
00160
00161 _ClampTexture = new CTextureMem (tmpMem, 4*clampTextSize*1, true, false, clampTextSize, 1);
00162 _ClampTexture->setWrapS (ITexture::Clamp);
00163 _ClampTexture->setWrapT (ITexture::Clamp);
00164 _ClampTexture->setFilterMode (ITexture::Linear, ITexture::LinearMipMapOff);
00165 _ClampTexture->generate();
00166 _ClampTexture->setReleasable (false);
00167
00168 _ClampTexture->setTextureCategory(_TextureCategory);
00169
00170
00171 _ReceiveShadowMaterial.initUnlit();
00172 _ReceiveShadowMaterial.setBlend(true);
00173 _ReceiveShadowMaterial.setBlendFunc(CMaterial::zero, CMaterial::invsrccolor);
00174 _ReceiveShadowMaterial.setZWrite(false);
00175
00176 _ReceiveShadowMaterial.setAlphaTest(true);
00177 _ReceiveShadowMaterial.setAlphaTestThreshold(0.01f);
00178
00179
00180
00181 _ReceiveShadowMaterial.enableUserTexMat(0, true);
00182 _ReceiveShadowMaterial.setTexCoordGen(0, true);
00183 _ReceiveShadowMaterial.setTexCoordGenMode(0, CMaterial::TexCoordGenObjectSpace);
00184
00185
00186
00187 _ReceiveShadowMaterial.texEnvOpRGB(0, CMaterial::Modulate);
00188 _ReceiveShadowMaterial.texEnvArg0RGB(0, CMaterial::Diffuse, CMaterial::InvSrcColor);
00189 _ReceiveShadowMaterial.texEnvArg1RGB(0, CMaterial::Texture, CMaterial::SrcAlpha);
00190
00191 _ReceiveShadowMaterial.texEnvOpAlpha(0, CMaterial::Replace);
00192 _ReceiveShadowMaterial.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
00193
00194
00195
00196 _ReceiveShadowMaterial.enableUserTexMat(1, true);
00197 _ReceiveShadowMaterial.setTexCoordGen(1, true);
00198 _ReceiveShadowMaterial.setTexCoordGenMode(1, CMaterial::TexCoordGenObjectSpace);
00199 _ReceiveShadowMaterial.setTexture(1, _ClampTexture);
00200
00201 _ReceiveShadowMaterial.texEnvOpRGB(1, CMaterial::Modulate);
00202 _ReceiveShadowMaterial.texEnvArg0RGB(1, CMaterial::Previous, CMaterial::SrcColor);
00203 _ReceiveShadowMaterial.texEnvArg1RGB(1, CMaterial::Texture, CMaterial::SrcAlpha);
00204
00205 _ReceiveShadowMaterial.texEnvOpAlpha(0, CMaterial::Replace);
00206 _ReceiveShadowMaterial.texEnvArg0Alpha(0, CMaterial::Previous, CMaterial::SrcAlpha);
00207
00208
00209 _CasterShadowMaterial.initUnlit();
00210 _CasterShadowMaterial.setColor(CRGBA::White);
00211 _CasterShadowMaterial.setZWrite(false);
00212 _CasterShadowMaterial.setZFunc(CMaterial::always);
00213 _CasterShadowMaterial.setDoubleSided(true);
00214
00215 _CasterShadowMaterial.setBlend(true);
00216 _CasterShadowMaterial.setBlendFunc(CMaterial::one, CMaterial::one);
00217
00218 _BlurQuads.setName("CShadowMapManager::_BlurQuads");
00219 _FillQuads.setName("CShadowMapManager::_FillQuads");
00220 _CopyQuads.setName("CShadowMapManager::_CopyQuads");
00221 }
00222
00223
00224 CShadowMapManager::~CShadowMapManager()
00225 {
00226 clearAllShadowCasters();
00227 }
00228
00229
00230 void CShadowMapManager::setQuadGridSize(uint size, float cellSize)
00231 {
00232 _ShadowReceiverGrid.create(size, cellSize);
00233 }
00234
00235
00236 void CShadowMapManager::addShadowCaster(CTransform *model)
00237 {
00238 _ShadowCasters.push_back(model);
00239 }
00240
00241
00242 void CShadowMapManager::addShadowReceiver(CTransform *model)
00243 {
00244 CAABBox bb;
00245 model->getReceiverBBox(bb);
00246
00247 _ShadowReceiverGrid.insert(bb.getMin(), bb.getMax(), model);
00248 }
00249
00250
00251 void CShadowMapManager::renderGenerate(CScene *scene)
00252 {
00253 H_AUTO( NL3D_ShadowManager_Generate );
00254
00255
00256 garbageShadowTextures(scene);
00257
00258 IDriver *driverForShadowGeneration= scene->getRenderTrav().getAuxDriver();
00259
00260
00261
00262 uint32 wndW= _BlurTextureW, wndH= _BlurTextureH;
00263
00264 if(driverForShadowGeneration)
00265 driverForShadowGeneration->getWindowSize(wndW, wndH);
00266 uint baseTextureSize= scene->getShadowMapTextureSize();
00267
00268 uint32 textDestW= min(wndW, (uint32)NL3D_SMM_MAX_TEXTDEST_SIZE);
00269 uint32 textDestH= min(wndH, (uint32)NL3D_SMM_MAX_TEXTDEST_SIZE);
00270
00271
00272 if( _ShadowCasters.empty() ||
00273 textDestW<baseTextureSize || textDestH<baseTextureSize)
00274 {
00275 clearAllShadowCasters();
00276 return;
00277 }
00278
00279
00280 if( _GenerateShadowCasters.empty() )
00281 {
00282
00283 return;
00284 }
00285
00286
00287 uint numTextW= textDestW/baseTextureSize;
00288 uint numTextH= textDestH/baseTextureSize;
00289 if(!isPowerOf2(numTextW))
00290 numTextW= raiseToNextPowerOf2(numTextW)/2;
00291 if(!isPowerOf2(numTextH))
00292 numTextH= raiseToNextPowerOf2(numTextH)/2;
00293
00294 uint maxSCPerPass= numTextW * numTextH;
00295
00296
00297 float vpWidth= (float)baseTextureSize / (float)(numTextW*baseTextureSize);
00298 float vpHeight= (float)baseTextureSize / (float)(numTextH*baseTextureSize);
00299
00300
00301
00302 updateBlurTexture(*driverForShadowGeneration, numTextW * baseTextureSize, numTextH * baseTextureSize);
00303
00304
00305
00306
00307
00308
00309 CViewport bkupViewport;
00310 driverForShadowGeneration->getViewport(bkupViewport);
00311 bool bkupFog= driverForShadowGeneration->fogEnabled();
00312
00313
00314 driverForShadowGeneration->enableFog(false);
00315
00316 driverForShadowGeneration->setColorMask(false, false, false, true);
00317
00318 uint numSC= _GenerateShadowCasters.size();
00319 uint baseSC= 0;
00320 while(numSC>0)
00321 {
00322 uint numPassSC= min(maxSCPerPass, numSC);
00323
00324 uint numTotalLine= (numPassSC+numTextW-1)/numTextW;
00325
00326 uint numTotalCol= (numPassSC<numTextW)?numPassSC:numTextW;
00327
00328
00329 driverForShadowGeneration->setRenderTarget (_BlurTexture[0], 0, 0, numTotalCol*baseTextureSize, numTotalLine*baseTextureSize);
00330
00331 uint textX, textY;
00332 uint i;
00333
00334
00335
00336
00337
00338 if(_PolySmooth)
00339 driverForShadowGeneration->enablePolygonSmoothing(true);
00340
00341 textX=0;
00342 textY=0;
00343 for(i=0;i<numPassSC;i++)
00344 {
00345
00346 CTransform *sc= _GenerateShadowCasters[baseSC+i];
00347
00348
00349 CVector lightDir;
00350 computeShadowDirection(scene, sc, lightDir);
00351
00352
00353 CViewport vp;
00354 vp.init(textX*baseTextureSize/(float)_BlurTextureW, textY*baseTextureSize/(float)_BlurTextureH, vpWidth, vpHeight);
00355 driverForShadowGeneration->setupViewport(vp);
00356
00357
00358
00359 CScissor sic;
00360 sic.init(textX*baseTextureSize/(float)_BlurTextureW, textY*baseTextureSize/(float)_BlurTextureH, vpWidth, vpHeight);
00361 driverForShadowGeneration->setupScissor(sic);
00362 driverForShadowGeneration->clear2D(CRGBA(0,0,0,0));
00363
00364
00365 sc->generateShadowMap(lightDir);
00366
00367
00368 textX++;
00369 if(textX==numTextW)
00370 {
00371 textX= 0;
00372 textY++;
00373 }
00374 }
00375
00376
00377 if(_PolySmooth)
00378 driverForShadowGeneration->enablePolygonSmoothing(false);
00379
00380
00381 CScissor sic;
00382 sic.initFullScreen();
00383
00384 driverForShadowGeneration->setupScissor(sic);
00385 CViewport vp;
00386 vp.initFullScreen();
00387 driverForShadowGeneration->setupViewport(vp);
00388 driverForShadowGeneration->setFrustum(0, (float)_BlurTextureW, 0, (float)_BlurTextureH, -1,1,false);
00389 driverForShadowGeneration->setupViewMatrix(CMatrix::Identity);
00390 driverForShadowGeneration->setupModelMatrix(CMatrix::Identity);
00391
00392
00393 fillBlackBorder(driverForShadowGeneration, numPassSC, numTextW, numTextH, baseTextureSize);
00394
00395
00396
00397 uint numBlur= scene->getShadowMapBlurSize();
00398 clamp(numBlur, 0U, 3U);
00399 uint blurTarget = 0;
00400 for(i=0;i<numBlur;i++)
00401 {
00402
00403 blurTarget = (i+1)&1;
00404 const uint blurSource = i&1;
00405 driverForShadowGeneration->setRenderTarget (_BlurTexture[blurTarget], 0, 0, numTotalCol*baseTextureSize, numTotalLine*baseTextureSize);
00406
00407
00408 applyFakeGaussianBlur(driverForShadowGeneration, numPassSC, numTextW, numTextH, baseTextureSize, blurSource);
00409
00410
00411 fillBlackBorder(driverForShadowGeneration, numPassSC, numTextW, numTextH, baseTextureSize);
00412 }
00413
00414
00415 _CopyMaterial.setTexture(0, _BlurTexture[blurTarget]);
00416
00417
00418
00419 textX=0;
00420 textY=0;
00421 for(i=0;i<numPassSC;i++)
00422 {
00423
00424 CTransform *sc= _GenerateShadowCasters[baseSC+i];
00425 CShadowMap *sm= sc->getShadowMap();
00426 if(sm)
00427 {
00428 ITexture *text= sm->getTexture();
00429 if(text)
00430 {
00431 uint bts= baseTextureSize;
00432
00433
00434
00435 {
00436
00437 driverForShadowGeneration->setRenderTarget (text, 0, 0, bts, bts);
00438 driverForShadowGeneration->clear2D (CRGBA(0,0,0,0));
00439
00440
00441 driverForShadowGeneration->setFrustum(0, 1, 0, 1, -1,1,false);
00442
00443
00444 {
00445 CVertexBufferReadWrite vba;
00446 _CopyQuads.lock (vba);
00447 const float u= (float)(textX*bts)*_BlurTextureOOW;
00448 const float v= (float)(textY*bts)*_BlurTextureOOH;
00449 const float width= (float)bts*_BlurTextureOOW;
00450 const float height= (float)bts*_BlurTextureOOH;
00451 vba.setTexCoord (0, 0, u, v);
00452 vba.setTexCoord (1, 0, u+width, v);
00453 vba.setTexCoord (2, 0, u+width, v+height);
00454 vba.setTexCoord (3, 0, u, v+height);
00455 }
00456
00457
00458 driverForShadowGeneration->activeVertexBuffer (_CopyQuads);
00459
00460 CScissor sic;
00461 sic.initFullScreen();
00462
00463 driverForShadowGeneration->setupScissor(sic);
00464
00465 driverForShadowGeneration->setupViewMatrix(CMatrix::Identity);
00466 driverForShadowGeneration->setupModelMatrix(CMatrix::Identity);
00467
00468
00469 vp.init (0, 0, 1, 1);
00470 driverForShadowGeneration->setupViewport(vp);
00471 driverForShadowGeneration->renderRawQuads (_CopyMaterial, 0, 1);
00472
00473
00474 driverForShadowGeneration->setRenderTarget (NULL);
00475 }
00476
00477
00478 sm->LastGenerationFrame= scene->getNumRender();
00479 }
00480 }
00481
00482
00483 textX++;
00484 if(textX==numTextW)
00485 {
00486 textX= 0;
00487 textY++;
00488 }
00489 }
00490
00491
00492
00493 baseSC+= numPassSC;
00494 numSC-= numPassSC;
00495 }
00496
00497
00498 driverForShadowGeneration->setRenderTarget (NULL);
00499
00500
00501 driverForShadowGeneration->setColorMask(true, true, true, true);
00502
00503 driverForShadowGeneration->setupViewport(bkupViewport);
00504 driverForShadowGeneration->enableFog(bkupFog);
00505
00506 CScissor sic;
00507 sic.initFullScreen();
00508 driverForShadowGeneration->setupScissor(sic);
00509
00510
00511 scene->getRenderTrav().setupDriverCamera();
00512
00513
00514
00515 clearGenerateShadowCasters();
00516 }
00517
00518
00519 void CShadowMapManager::renderProject(CScene *scene)
00520 {
00521
00522 if( _ShadowCasters.empty() )
00523 {
00524 return;
00525 }
00526
00527
00528
00529
00530
00531 H_AUTO( NL3D_ShadowManager_Project );
00532
00533
00534
00535
00536
00537
00538 IDriver *driver= scene->getRenderTrav().getDriver();
00539 CRGBA bkupFogColor= driver->getFogColor();
00540
00541
00542 driver->setupFog(driver->getFogStart(), driver->getFogEnd(), CRGBA::Black);
00543
00544
00545
00546
00547
00548 scene->getRenderTrav().resetLightSetup();
00549 driver->enableLight(0, true);
00550
00551
00552
00553 for(uint i=0;i<_ShadowCasters.size();i++)
00554 {
00555 CTransform *caster= _ShadowCasters[i];
00556 CShadowMap *sm= caster->getShadowMap();
00557 nlassert(sm);
00558
00559
00560 if( sm->getTexture() && sm->getFinalFade()<1 )
00561 {
00562 CVector casterPos= caster->getWorldMatrix().getPos();
00563
00564
00565 CAABBox worldBB= sm->LocalBoundingBox;
00566 worldBB.setCenter(worldBB.getCenter() + casterPos);
00567
00568
00569 CMatrix worldProjMat= sm->LocalProjectionMatrix;
00570 worldProjMat.setPos(worldProjMat.getPos()+casterPos);
00571
00572
00573 CMatrix wsTextMat;
00574 wsTextMat= worldProjMat;
00575 wsTextMat.invert();
00576
00577
00578 _ReceiveShadowMaterial.setTexture(0, sm->getTexture());
00580 CRGBA ambient, diffuse;
00581 computeShadowColors(scene, caster, ambient, diffuse);
00582
00583
00584 ambient.R= max(uint8(10), ambient.R);
00585 ambient.G= max(uint8(10), ambient.G);
00586 ambient.B= max(uint8(10), ambient.B);
00587
00588 uint R= ambient.R + (diffuse.R>>1);
00589 uint G= ambient.G + (diffuse.G>>1);
00590 uint B= ambient.B + (diffuse.B>>1);
00591 clamp(R, 1U, 256U);
00592 clamp(G, 1U, 256U);
00593 clamp(B, 1U, 256U);
00594
00595
00596
00597 R= (uint)(256 * ambient.R / (float)R);
00598 G= (uint)(256 * ambient.G / (float)G);
00599 B= (uint)(256 * ambient.B / (float)B);
00600 clamp(R,0U,255U);
00601 clamp(G,0U,255U);
00602 clamp(B,0U,255U);
00604 if(sm->getFinalFade()>0)
00605 {
00606 sint factor= OptFastFloor( 256 * sm->getFinalFade() );
00607 clamp(factor, 0, 256);
00608 R= 255*factor + R*(256-factor); R>>=8;
00609 G= 255*factor + G*(256-factor); G>>=8;
00610 B= 255*factor + B*(256-factor); B>>=8;
00611 }
00612 _ReceiveShadowMaterial.setColor(CRGBA(uint8(R),uint8(G),uint8(B),255));
00613
00614
00615 _ShadowMapProjector.setWorldSpaceTextMat(wsTextMat);
00616
00617
00618 _ShadowReceiverGrid.select(worldBB.getMin(), worldBB.getMax());
00619
00620 TShadowReceiverGrid::CIterator it;
00621 for(it= _ShadowReceiverGrid.begin();it!=_ShadowReceiverGrid.end();it++)
00622 {
00623 CTransform *receiver= *it;
00624
00625 if(receiver==caster)
00626 continue;
00627
00628
00629
00630 _ShadowMapProjector.applyToMaterial(receiver->getReceiverRenderWorldMatrix(), _ReceiveShadowMaterial);
00631
00632
00633 receiver->receiveShadowMap(sm, casterPos, _ReceiveShadowMaterial);
00634 }
00635
00636
00637 CVisualCollisionManager *shadowVcm= scene->getVisualCollisionManagerForShadow();
00638 if(shadowVcm)
00639 {
00640 shadowVcm->receiveShadowMap(driver, sm, casterPos, _ReceiveShadowMaterial, _ShadowMapProjector);
00641 }
00642 }
00643 }
00644
00645
00646 driver->setupFog(driver->getFogStart(), driver->getFogEnd(), bkupFogColor);
00647
00648
00649 scene->getRenderTrav().resetLightSetup();
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730 clearAllShadowCasters();
00731 }
00732
00733
00734
00735 void CShadowMapManager::computeShadowDirection(CScene *scene, CTransform *sc, CVector &lightDir)
00736 {
00737
00738 lightDir= scene->getSunDirection();
00739 const CLightContribution &lc= sc->getLightContribution();
00740
00741 CRGBA color= scene->getSunDiffuse();
00742 lightDir*= (float)lc.SunContribution * (color.R + color.G + color.B);
00743
00744
00745 const CVector &modelPos= sc->getWorldMatrix().getPos();
00746 for(uint i=0;i<NL3D_MAX_LIGHT_CONTRIBUTION;i++)
00747 {
00748 CPointLight *pl= lc.PointLight[i];
00749
00750 if(!pl)
00751 break;
00752
00753 CVector plDir= modelPos - pl->getPosition();
00754 plDir.normalize();
00755
00756 color= pl->getDiffuse();
00757 lightDir+= plDir * (float)lc.AttFactor[i] * (float)(color.R + color.G + color.B);
00758 }
00759
00760
00761 lightDir.normalize();
00762
00763
00764 float zThre= sc->getShadowMapDirectionZThreshold();
00765 if(lightDir.z>zThre)
00766 {
00767
00768
00769
00770
00771
00772 float scale= 0.f;
00773 if(lightDir.x!=0.f || lightDir.y!=0.f)
00774 scale= sqrtf( (1-sqr(zThre)) / (sqr(lightDir.x)+sqr(lightDir.y)) );
00775 lightDir.x*= scale;
00776 lightDir.y*= scale;
00777
00778 lightDir.z= zThre;
00779
00780
00781 lightDir.normalize();
00782 }
00783 }
00784
00785
00786
00787 void CShadowMapManager::computeShadowColors(CScene *scene, CTransform *sc, CRGBA &ambient, CRGBA &diffuse)
00788 {
00789 const CLightContribution &lc= sc->getLightContribution();
00790
00791
00792 ambient= lc.computeCurrentAmbient(scene->getSunAmbient());
00793
00794
00795 uint r, g, b;
00796 CRGBA color= scene->getSunDiffuse();
00797 r= color.R * lc.SunContribution;
00798 g= color.G * lc.SunContribution;
00799 b= color.B * lc.SunContribution;
00800
00801
00802 for(uint i=0;i<NL3D_MAX_LIGHT_CONTRIBUTION;i++)
00803 {
00804 CPointLight *pl= lc.PointLight[i];
00805
00806 if(!pl)
00807 break;
00808
00809
00810 color= pl->getDiffuse();
00811 r+= color.R * lc.AttFactor[i];
00812 g+= color.G * lc.AttFactor[i];
00813 b+= color.B * lc.AttFactor[i];
00814 }
00815
00816
00817 r>>=8;
00818 g>>=8;
00819 b>>=8;
00820
00821
00822
00823 diffuse.R= uint8(min(r, 255U));
00824 diffuse.G= uint8(min(g, 255U));
00825 diffuse.B= uint8(min(b, 255U));
00826 }
00827
00828
00829
00830 void CShadowMapManager::fillBlackBorder(IDriver *drv, uint numPassText, uint numTextW, uint numTextH, uint baseTextureSize)
00831 {
00832 if(numPassText==0)
00833 return;
00834
00835
00836 uint numFullLine= numPassText/numTextW;
00837
00838 uint lastLineNumCol= numPassText - (numFullLine*numTextW);
00839
00840 uint numTotalLine= numFullLine + (lastLineNumCol?1:0);
00841
00842
00843 uint numHQuads= numTotalLine * 2;
00844 uint numTotalCol;
00845 uint numVQuads;
00846 if(numFullLine)
00847 numTotalCol= numTextW;
00848 else
00849 numTotalCol= lastLineNumCol;
00850 numVQuads= numTotalCol * 2;
00851
00852 _FillQuads.setNumVertices((numVQuads + numHQuads)*4);
00853
00854
00855 uint i;
00856 for(i=0;i<numTotalLine;i++)
00857 {
00858 uint w;
00859 if(i<numFullLine)
00860 w= numTextW*baseTextureSize;
00861 else
00862 w= lastLineNumCol*baseTextureSize;
00863
00864 setBlackQuad(i*2+0, 0, i*baseTextureSize, w, 1);
00865
00866 setBlackQuad(i*2+1, 0, (i+1)*baseTextureSize-1, w, 1);
00867 }
00868
00869
00870 uint baseId= numTotalLine*2;
00871 for(i=0;i<numTotalCol;i++)
00872 {
00873 uint h;
00874 if(i<lastLineNumCol)
00875 h= numTotalLine*baseTextureSize;
00876 else
00877 h= numFullLine*baseTextureSize;
00878
00879 setBlackQuad(baseId + i*2+0, i*baseTextureSize, 0, 1, h);
00880
00881 setBlackQuad(baseId + i*2+1, (i+1)*baseTextureSize-1, 0, 1, h);
00882 }
00883
00884
00885 _FillMaterial.setColor(CRGBA(0,0,0,0));
00886 drv->activeVertexBuffer(_FillQuads);
00887 drv->renderRawQuads(_FillMaterial, 0, numHQuads+numVQuads);
00888 }
00889
00890
00891
00892 void CShadowMapManager::setBlackQuad(uint index, sint x, sint y, sint w, sint h)
00893 {
00894 float x0= (float)x;
00895 float y0= (float)y;
00896 float x1= (float)x+(float)w;
00897 float y1= (float)y+(float)h;
00898 index*= 4;
00899 CVertexBufferReadWrite vba;
00900 _FillQuads.lock(vba);
00901 vba.setVertexCoord (index+0, CVector (x0, 0, y0));
00902 vba.setVertexCoord (index+1, CVector (x1, 0, y0));
00903 vba.setVertexCoord (index+2, CVector (x1, 0, y1));
00904 vba.setVertexCoord (index+3, CVector (x0, 0, y1));
00905 }
00906
00907
00908 void CShadowMapManager::updateBlurTexture(IDriver &drv, uint w, uint h)
00909 {
00910 w= max(w, 2U);
00911 h= max(h, 2U);
00912
00913 if(_BlurTextureW==w && _BlurTextureH==h)
00914 return;
00915
00916
00917 uint i, j;
00918 for (i=0; i<2; i++)
00919 {
00920 _BlurMaterial[i].setTexture(0, NULL);
00921 _BlurMaterial[i].setTexture(1, NULL);
00922 _BlurMaterial[i].setTexture(2, NULL);
00923 _BlurMaterial[i].setTexture(3, NULL);
00924 }
00925 _BlurTexture[0]= NULL;
00926 _BlurTexture[1]= NULL;
00927 _BlurTextureW= w;
00928 _BlurTextureH= h;
00929
00930 for (i=0; i<2; i++)
00931 {
00932 uint8 *tmpMem= new uint8[4*_BlurTextureW*_BlurTextureH];
00933 _BlurTexture[i] = new CTextureMem (tmpMem, 4*_BlurTextureW*_BlurTextureH, true, false, _BlurTextureW, _BlurTextureH);
00934 _BlurTexture[i]->setWrapS (ITexture::Clamp);
00935 _BlurTexture[i]->setWrapT (ITexture::Clamp);
00936 _BlurTexture[i]->setFilterMode (ITexture::Linear, ITexture::LinearMipMapOff);
00937 _BlurTexture[i]->generate();
00938 _BlurTexture[i]->setReleasable (false);
00939 _BlurTexture[i]->setRenderTarget (true);
00940
00941 _BlurTexture[i]->setTextureCategory(_TextureCategory);
00942 }
00943
00944 uint maxNumCstLighted;
00945 uint maxNumCstUnlighted;
00946 drv.getNumPerStageConstant(maxNumCstLighted, maxNumCstUnlighted);
00947
00948
00949 for (i=0; i<2; i++)
00950 {
00951 for (j=0; j<maxNumCstUnlighted; j++)
00952 {
00953 _BlurMaterial[i].setTexture(j, _BlurTexture[i]);
00954 }
00955 }
00956
00957
00958 _BlurTextureOOW= 1.f / _BlurTextureW;
00959 _BlurTextureOOH= 1.f / _BlurTextureH;
00960
00961 _BlurTextureD05W= 0.5f*_BlurTextureOOW;
00962 _BlurTextureD05H= 0.5f*_BlurTextureOOH;
00963 }
00964
00965
00966
00967 void CShadowMapManager::copyScreenToBlurTexture(IDriver *drv, uint numPassText, uint numTextW, uint numTextH, uint baseTextureSize)
00968 {
00969 if(numPassText==0)
00970 return;
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981 }
00982
00983
00984 void CShadowMapManager::applyFakeGaussianBlur(IDriver *drv, uint numPassText, uint numTextW, uint numTextH, uint baseTextureSize, uint blurSource)
00985 {
00986 if(numPassText==0)
00987 return;
00988
00989
00990 uint numFullLine= numPassText/numTextW;
00991
00992 uint lastLineNumCol= numPassText - (numFullLine*numTextW);
00993
00994
00995 uint index= 0;
00996 if(numFullLine)
00997 setBlurQuadFakeGaussian(index++, 0, 0, numTextW*baseTextureSize, numFullLine*baseTextureSize);
00998 if(lastLineNumCol)
00999 setBlurQuadFakeGaussian(index++, 0, numFullLine*baseTextureSize, lastLineNumCol*baseTextureSize, baseTextureSize);
01000
01001
01002 drv->activeVertexBuffer(_BlurQuads);
01003 drv->renderRawQuads(_BlurMaterial[blurSource], 0, index);
01004 }
01005
01006
01007
01008 void CShadowMapManager::setBlurQuadFakeGaussian(uint index, sint x, sint y, sint w, sint h)
01009 {
01010 float x0= (float)x;
01011 float y0= (float)y;
01012 float x1= (float)x+(float)w;
01013 float y1= (float)y+(float)h;
01014 float u0= x0*_BlurTextureOOW;
01015 float v0= y0*_BlurTextureOOH;
01016 float u1= x1*_BlurTextureOOW;
01017 float v1= y1*_BlurTextureOOH;
01018 index*= 4;
01019
01020
01021
01022
01023 CVertexBufferReadWrite vba;
01024 _BlurQuads.lock(vba);
01025 vba.setVertexCoord (index+0, CVector (x0, 0, y0));
01026 vba.setTexCoord(index+0, 0, u0-_BlurTextureD05W, v0-_BlurTextureD05H);
01027 vba.setTexCoord(index+0, 1, u0+_BlurTextureD05W, v0+_BlurTextureD05H);
01028 vba.setTexCoord(index+0, 2, u0-_BlurTextureD05W, v0+_BlurTextureD05H);
01029 vba.setTexCoord(index+0, 3, u0+_BlurTextureD05W, v0-_BlurTextureD05H);
01030
01031 vba.setVertexCoord (index+1, CVector (x1, 0, y0));
01032 vba.setTexCoord(index+1, 0, u1-_BlurTextureD05W, v0-_BlurTextureD05H);
01033 vba.setTexCoord(index+1, 1, u1+_BlurTextureD05W, v0+_BlurTextureD05H);
01034 vba.setTexCoord(index+1, 2, u1-_BlurTextureD05W, v0+_BlurTextureD05H);
01035 vba.setTexCoord(index+1, 3, u1+_BlurTextureD05W, v0-_BlurTextureD05H);
01036
01037 vba.setVertexCoord (index+2, CVector (x1, 0, y1));
01038 vba.setTexCoord(index+2, 0, u1-_BlurTextureD05W, v1-_BlurTextureD05H);
01039 vba.setTexCoord(index+2, 1, u1+_BlurTextureD05W, v1+_BlurTextureD05H);
01040 vba.setTexCoord(index+2, 2, u1-_BlurTextureD05W, v1+_BlurTextureD05H);
01041 vba.setTexCoord(index+2, 3, u1+_BlurTextureD05W, v1-_BlurTextureD05H);
01042
01043 vba.setVertexCoord (index+3, CVector (x0, 0, y1));
01044 vba.setTexCoord(index+3, 0, u0-_BlurTextureD05W, v1-_BlurTextureD05H);
01045 vba.setTexCoord(index+3, 1, u0+_BlurTextureD05W, v1+_BlurTextureD05H);
01046 vba.setTexCoord(index+3, 2, u0-_BlurTextureD05W, v1+_BlurTextureD05H);
01047 vba.setTexCoord(index+3, 3, u0+_BlurTextureD05W, v1-_BlurTextureD05H);
01048 }
01049
01050
01051
01052 struct CShadowMapSort
01053 {
01054 CTransform *Caster;
01055 float Weight;
01056
01057 bool operator<(const CShadowMapSort &o) const
01058 {
01059 return Weight<o.Weight;
01060 }
01061 };
01062
01063
01064 void CShadowMapManager::selectShadowMapsToGenerate(CScene *scene)
01065 {
01066
01067 const uint maxPerFrame= 8;
01068 const float minCamDist= 10;
01069 const CVector &camPos= scene->getRenderTrav().CamPos;
01070 uint i;
01071
01072
01073 clearGenerateShadowCasters();
01074
01075
01076 if(! (scene->getFilterRenderFlags() & UScene::FilterSkeleton) )
01077 return;
01078
01079
01080
01081 static vector<CShadowMapSort> sortList;
01082 sortList.clear();
01083 sortList.reserve(_ShadowCasters.size());
01084 for(i=0;i<_ShadowCasters.size();i++)
01085 {
01086 CTransform *caster= _ShadowCasters[i];
01087
01088
01089
01090
01091 if(caster->getShadowMap() && caster->getShadowMap()->getFinalFade()<1 )
01092 {
01093 CShadowMapSort sms;
01094 sms.Caster= caster;
01095
01096 sms.Weight= (float)(scene->getNumRender() - caster->getShadowMap()->LastGenerationFrame);
01097
01098 float distToCam= (caster->getWorldMatrix().getPos() - camPos).norm();
01099 distToCam= max(distToCam, minCamDist);
01100
01101 sms.Weight/= distToCam;
01102
01103
01104 sortList.push_back(sms);
01105 }
01106 }
01107
01108
01109 sort(sortList.begin(), sortList.end());
01110
01111
01112 uint numSel= min((uint)sortList.size(), maxPerFrame);
01113 _GenerateShadowCasters.resize(numSel);
01114 for(i= 0;i<numSel;i++)
01115 {
01116 _GenerateShadowCasters[i]= sortList[sortList.size()-1-i].Caster;
01117 }
01118
01119
01120
01121 for(i=0;i<_GenerateShadowCasters.size();i++)
01122 {
01123 _GenerateShadowCasters[i]->setGeneratingShadowMap(true);
01124 }
01125 }
01126
01127
01128
01129 void CShadowMapManager::clearAllShadowCasters()
01130 {
01131 _ShadowReceiverGrid.clear();
01132 _ShadowCasters.clear();
01133 clearGenerateShadowCasters();
01134 }
01135
01136
01137
01138 void CShadowMapManager::clearGenerateShadowCasters()
01139 {
01140
01141 for(uint i=0;i<_GenerateShadowCasters.size();i++)
01142 {
01143 _GenerateShadowCasters[i]->setGeneratingShadowMap(false);
01144 }
01145
01146 _GenerateShadowCasters.clear();
01147 }
01148
01149
01150 ITexture *CShadowMapManager::allocateTexture(uint textSize)
01151 {
01152 nlassert( isPowerOf2(textSize) );
01153
01154
01155 if(!_FreeShadowTextures.empty())
01156 {
01157 ITexture *freeText= _FreeShadowTextures.back()->second;
01158
01159 if(freeText->getWidth() == textSize)
01160 {
01161
01162 _FreeShadowTextures.pop_back();
01163 return freeText;
01164 }
01165
01166 else
01167 {
01168
01169 _ShadowTextureMap.erase(_FreeShadowTextures.back());
01170
01171 _FreeShadowTextures.pop_back();
01172 }
01173 }
01174
01175
01176
01177 uint8 *tmpMem= new uint8[4*textSize*textSize];
01178 ITexture *text;
01179 text = new CTextureMem (tmpMem, 4*textSize*textSize, true, false, textSize, textSize);
01180 text->setWrapS (ITexture::Clamp);
01181 text->setWrapT (ITexture::Clamp);
01182 text->setFilterMode (ITexture::Linear, ITexture::LinearMipMapOff);
01183 text->generate();
01184 text->setReleasable (false);
01185 text->setRenderTarget (true);
01186
01187 text->setTextureCategory(_TextureCategory);
01188
01189
01190 _ShadowTextureMap[text]= text;
01191
01192 return text;
01193 }
01194
01195
01196 void CShadowMapManager::releaseTexture(ITexture *text)
01197 {
01198 if(!text)
01199 return;
01200
01201 ItTextureMap it= _ShadowTextureMap.find(text);
01202 nlassert(it!=_ShadowTextureMap.end());
01203
01204
01205 _FreeShadowTextures.push_back(it);
01206 }
01207
01208
01209 void CShadowMapManager::garbageShadowTextures(CScene *scene)
01210 {
01211 uint defSize= scene->getShadowMapTextureSize();
01212
01213
01214 std::vector<ItTextureMap>::iterator itVec= _FreeShadowTextures.begin();
01215 for(;itVec!=_FreeShadowTextures.end();)
01216 {
01217 if((*itVec)->second->getWidth() != defSize)
01218 {
01219
01220 _ShadowTextureMap.erase(*itVec);
01221
01222 itVec= _FreeShadowTextures.erase(itVec);
01223 }
01224 else
01225 {
01226 itVec++;
01227 }
01228 }
01229
01230
01231 if(_FreeShadowTextures.size()>NL3D_SMM_MAX_FREETEXT)
01232 {
01233
01234 uint startToFree= NL3D_SMM_MAX_FREETEXT/2;
01235 for(uint i=startToFree;i<_FreeShadowTextures.size();i++)
01236 {
01237
01238 _ShadowTextureMap.erase(_FreeShadowTextures[i]);
01239 }
01240
01241 _FreeShadowTextures.resize(startToFree);
01242 }
01243 }
01244
01245
01246 }
01247