advancedLightBinManager.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "lighting/advanced/advancedLightBinManager.h"
  24. #include "lighting/advanced/advancedLightManager.h"
  25. #include "lighting/advanced/advancedLightBufferConditioner.h"
  26. #include "lighting/shadowMap/shadowMapManager.h"
  27. #include "lighting/shadowMap/shadowMapPass.h"
  28. #include "lighting/shadowMap/lightShadowMap.h"
  29. #include "lighting/common/lightMapParams.h"
  30. #include "renderInstance/renderDeferredMgr.h"
  31. #include "gfx/gfxTransformSaver.h"
  32. #include "scene/sceneManager.h"
  33. #include "scene/sceneRenderState.h"
  34. #include "materials/materialManager.h"
  35. #include "materials/sceneData.h"
  36. #include "core/util/safeDelete.h"
  37. #include "core/util/rgb2luv.h"
  38. #include "gfx/gfxDebugEvent.h"
  39. #include "math/util/matrixSet.h"
  40. #include "console/consoleTypes.h"
  41. #include "gfx/gfxTextureManager.h"
  42. const RenderInstType AdvancedLightBinManager::RIT_LightInfo( "specularLighting" );
  43. const String AdvancedLightBinManager::smBufferName( "specularLighting" );
  44. ShadowFilterMode AdvancedLightBinManager::smShadowFilterMode = ShadowFilterMode_SoftShadowHighQuality;
  45. bool AdvancedLightBinManager::smPSSMDebugRender = false;
  46. bool AdvancedLightBinManager::smUseSSAOMask = false;
  47. bool AdvancedLightBinManager::smDiffuseLightViz = false;
  48. bool AdvancedLightBinManager::smSpecularLightViz = false;
  49. bool AdvancedLightBinManager::smDetailLightingViz = false;
  50. S32 AdvancedLightBinManager::smMaximumNumOfLights = -1;
  51. bool AdvancedLightBinManager::smUseLightFade = false;
  52. F32 AdvancedLightBinManager::smLightFadeStart = 50;
  53. F32 AdvancedLightBinManager::smLightFadeEnd = 75;
  54. bool AdvancedLightBinManager::smAllowLocalLightShadows = true;
  55. ImplementEnumType( ShadowFilterMode,
  56. "The shadow filtering modes for Advanced Lighting shadows.\n"
  57. "@ingroup AdvancedLighting" )
  58. { ShadowFilterMode_None, "None",
  59. "@brief Simple point sampled filtering.\n"
  60. "This is the fastest and lowest quality mode." },
  61. { ShadowFilterMode_SoftShadow, "SoftShadow",
  62. "@brief A variable tap rotated poisson disk soft shadow filter.\n"
  63. "It performs 4 taps to classify the point as in shadow, out of shadow, or along a "
  64. "shadow edge. Samples on the edge get an additional 8 taps to soften them." },
  65. { ShadowFilterMode_SoftShadowHighQuality, "SoftShadowHighQuality",
  66. "@brief A 12 tap rotated poisson disk soft shadow filter.\n"
  67. "It performs all the taps for every point without any early rejection." },
  68. EndImplementEnumType;
  69. // NOTE: The order here matches that of the LightInfo::Type enum.
  70. const String AdvancedLightBinManager::smLightMatNames[] =
  71. {
  72. "AL_PointLightMaterial", // LightInfo::Point
  73. "AL_SpotLightMaterial", // LightInfo::Spot
  74. "AL_VectorLightMaterial", // LightInfo::Vector
  75. "", // LightInfo::Ambient
  76. };
  77. // NOTE: The order here matches that of the LightInfo::Type enum.
  78. const GFXVertexFormat* AdvancedLightBinManager::smLightMatVertex[] =
  79. {
  80. getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Point
  81. getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Spot
  82. getGFXVertexFormat<FarFrustumQuadVert>(), // LightInfo::Vector
  83. NULL, // LightInfo::Ambient
  84. };
  85. // NOTE: The order here matches that of the ShadowType enum.
  86. const String AdvancedLightBinManager::smShadowTypeMacro[] =
  87. {
  88. "", // ShadowType_Spot
  89. "", // ShadowType_PSSM,
  90. "", // ShadowType_Paraboloid,
  91. "SHADOW_DUALPARABOLOID_SINGLE_PASS", // ShadowType_DualParaboloidSinglePass,
  92. "SHADOW_DUALPARABOLOID", // ShadowType_DualParaboloid,
  93. "SHADOW_CUBE", // ShadowType_CubeMap,
  94. };
  95. AdvancedLightBinManager::RenderSignal &AdvancedLightBinManager::getRenderSignal()
  96. {
  97. static RenderSignal theSignal;
  98. return theSignal;
  99. }
  100. IMPLEMENT_CONOBJECT(AdvancedLightBinManager);
  101. ConsoleDocClass( AdvancedLightBinManager,
  102. "@brief Rendering Manager responsible for lighting, shadows, and global variables affecing both.\n\n"
  103. "Should not be exposed to TorqueScript as a game object, meant for internal use only\n\n"
  104. "@ingroup Lighting"
  105. );
  106. AdvancedLightBinManager::AdvancedLightBinManager( AdvancedLightManager *lm /* = NULL */,
  107. ShadowMapManager *sm /* = NULL */,
  108. GFXFormat lightBufferFormat /* = GFXFormatR8G8B8A8 */ )
  109. : RenderBinManager( RIT_LightInfo, 1.0f, 1.0f ),
  110. mNumLightsCulled(0),
  111. mLightManager(lm),
  112. mShadowManager(sm)
  113. {
  114. mMRTLightmapsDuringDeferred = true;
  115. Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials );
  116. Con::addVariableNotify( "$pref::Shadows::filterMode", callback );
  117. Con::addVariableNotify( "$AL::PSSMDebugRender", callback );
  118. Con::addVariableNotify( "$AL::UseSSAOMask", callback );
  119. Con::addVariableNotify( "$AL::DiffuseLightViz", callback);
  120. Con::addVariableNotify( "$AL::SpecularLightViz", callback);
  121. Con::addVariableNotify( "$AL::DetailLightingViz", callback);
  122. }
  123. AdvancedLightBinManager::~AdvancedLightBinManager()
  124. {
  125. _deleteLightMaterials();
  126. Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials );
  127. Con::removeVariableNotify( "$pref::shadows::filterMode", callback );
  128. Con::removeVariableNotify( "$AL::PSSMDebugRender", callback );
  129. Con::removeVariableNotify( "$AL::UseSSAOMask", callback );
  130. Con::removeVariableNotify( "$AL::DiffuseLightViz", callback);
  131. Con::removeVariableNotify( "$AL::SpecularLightViz", callback);
  132. Con::removeVariableNotify( "$AL::DetailLightingViz", callback);
  133. }
  134. void AdvancedLightBinManager::consoleInit()
  135. {
  136. Parent::consoleInit();
  137. Con::addVariable( "$pref::shadows::filterMode",
  138. TYPEID<ShadowFilterMode>(), &smShadowFilterMode,
  139. "The filter mode to use for shadows.\n"
  140. "@ingroup AdvancedLighting\n" );
  141. Con::addVariable( "$AL::UseSSAOMask", TypeBool, &smUseSSAOMask,
  142. "Used by the SSAO PostEffect to toggle the sampling of ssaomask "
  143. "texture by the light shaders.\n"
  144. "@ingroup AdvancedLighting\n" );
  145. Con::addVariable( "$AL::PSSMDebugRender", TypeBool, &smPSSMDebugRender,
  146. "Enables debug rendering of the PSSM shadows.\n"
  147. "@ingroup AdvancedLighting\n" );
  148. Con::addVariable("$AL::DiffuseLightViz", TypeBool, &smDiffuseLightViz,
  149. "Enables debug rendering of the PSSM shadows.\n"
  150. "@ingroup AdvancedLighting\n");
  151. Con::addVariable("$AL::SpecularLightViz", TypeBool, &smSpecularLightViz,
  152. "Enables debug rendering of the PSSM shadows.\n"
  153. "@ingroup AdvancedLighting\n");
  154. Con::addVariable("$AL::DetailLightingViz", TypeBool, &smDetailLightingViz,
  155. "Enables debug rendering of the PSSM shadows.\n"
  156. "@ingroup AdvancedLighting\n");
  157. Con::addVariable("$pref::maximumNumOfLights",
  158. TypeS32, &smMaximumNumOfLights,
  159. "The maximum number of local lights that can be rendered at a time. If set to -1, then no limit.\n");
  160. Con::addVariable("$pref::useLightFade", TypeBool, &smUseLightFade, "Indicates if local lights should utilize the distance-based object fadeout logic.\n");
  161. Con::addVariable("$pref::lightFadeStart", TypeF32, &smLightFadeStart, "Distance at which light fading begins if $pref::useLightFade is on.\n");
  162. Con::addVariable("$pref::lightFadeEnd", TypeF32, &smLightFadeEnd, "Distance at which light fading should have fully faded if $pref::useLightFade is on.\n");
  163. Con::addVariable("$pref::allowLocalLightShadows", TypeBool, &smAllowLocalLightShadows, "Indicates if local lights(point/spot) can cast shadows.\n");
  164. }
  165. bool AdvancedLightBinManager::setTargetSize(const Point2I &newTargetSize)
  166. {
  167. /*bool ret = Parent::setTargetSize( newTargetSize );
  168. // We require the viewport to match the default.
  169. mNamedTarget.setViewport( GFX->getViewport() );
  170. return ret;*/
  171. return true;
  172. }
  173. bool AdvancedLightBinManager::_updateTargets()
  174. {
  175. /* PROFILE_SCOPE(AdvancedLightBinManager_updateTargets);
  176. bool ret = Parent::_updateTargets();
  177. mDiffuseLightingTarget = NamedTexTarget::find("diffuseLighting");
  178. if (mDiffuseLightingTarget.isValid())
  179. {
  180. mDiffuseLightingTex = mDiffuseLightingTarget->getTexture();
  181. for (U32 i = 0; i < mTargetChainLength; i++)
  182. mTargetChain[i]->attachTexture(GFXTextureTarget::Color1, mDiffuseLightingTex);
  183. }
  184. GFX->finalizeReset();
  185. return ret;*/
  186. return true;
  187. }
  188. void AdvancedLightBinManager::addLight( LightInfo *light )
  189. {
  190. // Get the light type.
  191. const LightInfo::Type lightType = light->getType();
  192. AssertFatal( lightType == LightInfo::Point ||
  193. lightType == LightInfo::Spot, "Bogus light type." );
  194. // Find a shadow map for this light, if it has one
  195. ShadowMapParams *lsp = light->getExtended<ShadowMapParams>();
  196. LightShadowMap *lsm = lsp->getShadowMap();
  197. // Get the right shadow type.
  198. ShadowType shadowType = ShadowType_None;
  199. if ( light->getCastShadows() && smAllowLocalLightShadows &&
  200. lsm && lsm->hasShadowTex() &&
  201. !ShadowMapPass::smDisableShadows )
  202. shadowType = lsm->getShadowType();
  203. // Add the entry
  204. LightBinEntry lEntry;
  205. lEntry.lightInfo = light;
  206. lEntry.shadowMap = lsm;
  207. lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex(), lsp->hasIesProfile() );
  208. if( lightType == LightInfo::Spot )
  209. lEntry.vertBuffer = mLightManager->getConeMesh( lEntry.numPrims, lEntry.primBuffer );
  210. else
  211. lEntry.vertBuffer = mLightManager->getSphereMesh( lEntry.numPrims, lEntry.primBuffer );
  212. // If it's a point light, push front, spot
  213. // light, push back. This helps batches.
  214. Vector<LightBinEntry> &curBin = mLightBin;
  215. if ( light->getType() == LightInfo::Point )
  216. curBin.push_front( lEntry );
  217. else
  218. curBin.push_back( lEntry );
  219. }
  220. void AdvancedLightBinManager::clearAllLights()
  221. {
  222. Con::setIntVariable("lightMetrics::activeLights", mLightBin.size());
  223. Con::setIntVariable("lightMetrics::culledLights", mNumLightsCulled);
  224. mLightBin.clear();
  225. mNumLightsCulled = 0;
  226. }
  227. S32 QSORT_CALLBACK AdvancedLightBinManager::_lightScoreCmp(const LightBinEntry* a, const LightBinEntry* b)
  228. {
  229. F32 diff = a->lightInfo->getScore() - b->lightInfo->getScore();
  230. return diff > 0 ? 1 : diff < 0 ? -1 : 0;
  231. }
  232. void AdvancedLightBinManager::_scoreLights(const MatrixF& cameraTrans)
  233. {
  234. PROFILE_SCOPE(AdvancedLightBinManager_scoreLights);
  235. if (!LIGHTMGR)
  236. return;
  237. // Get all the lights.
  238. const Point3F lumDot(0.2125f, 0.7154f, 0.0721f);
  239. for (LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++)
  240. {
  241. // Get the light.
  242. LightBinEntry& light = *itr;
  243. F32 luminace = 0.0f;
  244. F32 weight = 0.0f;
  245. F32 score = 0.0f;
  246. const bool isSpot = light.lightInfo->getType() == LightInfo::Spot;
  247. const bool isPoint = light.lightInfo->getType() == LightInfo::Point;
  248. if (isPoint || isSpot)
  249. {
  250. Point3F distVec = light.lightInfo->getPosition() - cameraTrans.getPosition();
  251. F32 dist = distVec.len();
  252. score = dist;// light.lightInfo->getRange().x / mMax(dist, 1.0f);
  253. // Get the luminocity.
  254. luminace = mDot(light.lightInfo->getColor(), lumDot) * light.lightInfo->getBrightness();
  255. weight = light.lightInfo->getPriority();
  256. //Distance fading test
  257. if (smUseLightFade)
  258. {
  259. if (dist > smLightFadeStart)
  260. {
  261. float fadeOutAmt = (dist - smLightFadeStart) / (smLightFadeEnd - smLightFadeStart);
  262. fadeOutAmt = 1 - fadeOutAmt;
  263. light.lightInfo->setFadeAmount(fadeOutAmt);
  264. }
  265. }
  266. else
  267. {
  268. light.lightInfo->setFadeAmount(1.0);
  269. }
  270. }
  271. light.lightInfo->setScore(score * weight - luminace);
  272. }
  273. // Sort them!
  274. mLightBin.sort(_lightScoreCmp);
  275. }
  276. void AdvancedLightBinManager::render( SceneRenderState *state )
  277. {
  278. PROFILE_SCOPE( AdvancedLightManager_Render );
  279. // Take a look at the SceneRenderState and see if we should skip drawing the pre-pass
  280. if( state->disableAdvancedLightingBins() )
  281. return;
  282. // Automagically save & restore our viewport and transforms.
  283. GFXTransformSaver saver;
  284. if( !mLightManager )
  285. return;
  286. // Get the sunlight. If there's no sun, and no lights in the bins, no draw
  287. LightInfo *sunLight = mLightManager->getSpecialLight( LightManager::slSunLightType, false );
  288. GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render, ColorI::RED );
  289. // Tell the superclass we're about to render
  290. //if ( !_onPreRender( state ) )
  291. // return;
  292. NamedTexTargetRef sceneColorTargetRef = NamedTexTarget::find("AL_FormatToken");
  293. if (sceneColorTargetRef.isNull())
  294. return;
  295. if (mLightingTargetRef.isNull())
  296. mLightingTargetRef = GFX->allocRenderToTextureTarget();
  297. //Do a quick pass to update our probes if they're dirty
  298. //PROBEMGR->updateDirtyProbes();
  299. mLightingTargetRef->attachTexture(GFXTextureTarget::Color0, sceneColorTargetRef->getTexture());
  300. GFX->pushActiveRenderTarget();
  301. GFX->setActiveRenderTarget(mLightingTargetRef);
  302. GFX->setViewport(sceneColorTargetRef->getViewport());
  303. // Restore transforms
  304. MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
  305. matrixSet.restoreSceneViewProjection();
  306. // Set up the SG Data
  307. SceneData sgData;
  308. sgData.init( state );
  309. // There are cases where shadow rendering is disabled.
  310. const bool disableShadows = /*state->isReflectPass() || */ShadowMapPass::smDisableShadows;
  311. // Pick the right material for rendering the sunlight... we only
  312. // cast shadows when its enabled and we're not in a reflection.
  313. LightMaterialInfo *vectorMatInfo;
  314. if ( sunLight &&
  315. sunLight->getCastShadows() &&
  316. !disableShadows &&
  317. sunLight->getExtended<ShadowMapParams>() )
  318. vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM,false,false );
  319. else
  320. vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false, false);
  321. // Initialize and set the per-frame parameters after getting
  322. // the vector light material as we use lazy creation.
  323. _setupPerFrameParameters( state );
  324. // Draw sunlight/ambient
  325. if ( sunLight && vectorMatInfo )
  326. {
  327. GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Sunlight, ColorI::RED );
  328. // Set up SG data
  329. setupSGData( sgData, state, sunLight );
  330. vectorMatInfo->setLightParameters( sunLight, state );
  331. // Set light holds the active shadow map.
  332. mShadowManager->setLightShadowMapForLight( sunLight );
  333. // Set geometry
  334. GFX->setVertexBuffer( mFarFrustumQuadVerts );
  335. GFX->setPrimitiveBuffer( NULL );
  336. vectorMatInfo->matInstance->mSpecialLight = true;
  337. // Render the material passes
  338. while( vectorMatInfo->matInstance->setupPass( state, sgData ) )
  339. {
  340. vectorMatInfo->matInstance->setSceneInfo( state, sgData );
  341. vectorMatInfo->matInstance->setTransforms( matrixSet, state );
  342. GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
  343. }
  344. }
  345. const Frustum& frustum = state->getCameraFrustum();
  346. MatrixF invCam(frustum.getTransform());
  347. invCam.inverse();
  348. const MatrixF& cameraTrans = frustum.getTransform();
  349. if(smUseLightFade || smMaximumNumOfLights != -1)
  350. _scoreLights(cameraTrans);
  351. S32 lightCount = 0;
  352. // Blend the lights in the bin to the light buffer
  353. for( LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++ )
  354. {
  355. if (smMaximumNumOfLights != -1 && lightCount >= smMaximumNumOfLights)
  356. break;
  357. lightCount++;
  358. LightBinEntry& curEntry = *itr;
  359. LightInfo *curLightInfo = curEntry.lightInfo;
  360. if (curEntry.lightInfo->getType() >= LightInfo::Vector)
  361. continue;
  362. LightMaterialInfo *curLightMat = curEntry.lightMaterial;
  363. const U32 numPrims = curEntry.numPrims;
  364. const U32 numVerts = curEntry.vertBuffer->mNumVerts;
  365. ShadowMapParams *lsp = curLightInfo->getExtended<ShadowMapParams>();
  366. // Skip lights which won't affect the scene.
  367. if (!curLightMat || curLightInfo->getBrightness() * curLightInfo->getFadeAmount() <= 0.001f)
  368. continue;
  369. GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Light, ColorI::RED );
  370. setupSGData( sgData, state, curLightInfo );
  371. curLightMat->setLightParameters( curLightInfo, state );
  372. mShadowManager->setLightShadowMap( curEntry.shadowMap );
  373. // Set geometry
  374. GFX->setVertexBuffer( curEntry.vertBuffer );
  375. GFX->setPrimitiveBuffer( curEntry.primBuffer );
  376. lsp->getOcclusionQuery()->begin();
  377. curLightMat->matInstance->mSpecialLight = false;
  378. // Render the material passes
  379. while( curLightMat->matInstance->setupPass( state, sgData ) )
  380. {
  381. // Set transforms
  382. matrixSet.setWorld(*sgData.objTrans);
  383. curLightMat->matInstance->setTransforms(matrixSet, state);
  384. curLightMat->matInstance->setSceneInfo(state, sgData);
  385. if(curEntry.primBuffer)
  386. GFX->drawIndexedPrimitive(GFXTriangleList, 0, 0, numVerts, 0, numPrims);
  387. else
  388. GFX->drawPrimitive(GFXTriangleList, 0, numPrims);
  389. }
  390. lsp->getOcclusionQuery()->end();
  391. }
  392. // Set NULL for active shadow map (so nothing gets confused)
  393. mShadowManager->setLightShadowMap(NULL);
  394. GFX->setVertexBuffer( NULL );
  395. GFX->setPrimitiveBuffer( NULL );
  396. // Fire off a signal to let others know that light-bin rendering is ending now
  397. getRenderSignal().trigger(state, this);
  398. // Finish up the rendering
  399. //_onPostRender();
  400. GFX->popActiveRenderTarget();
  401. }
  402. AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMaterial( LightInfo::Type lightType,
  403. ShadowType shadowType,
  404. bool useCookieTex,
  405. bool isPhotometric)
  406. {
  407. PROFILE_SCOPE( AdvancedLightBinManager_GetLightMaterial );
  408. // Build the key.
  409. const LightMatKey key( lightType, shadowType, useCookieTex, isPhotometric );
  410. // See if we've already built this one.
  411. LightMatTable::Iterator iter = mLightMaterials.find( key );
  412. if ( iter != mLightMaterials.end() )
  413. return iter->value;
  414. // If we got here we need to build a material for
  415. // this light+shadow combination.
  416. LightMaterialInfo *info = NULL;
  417. // First get the light material name and make sure
  418. // this light has a material in the first place.
  419. const String &lightMatName = smLightMatNames[ lightType ];
  420. if ( lightMatName.isNotEmpty() )
  421. {
  422. Vector<GFXShaderMacro> shadowMacros;
  423. // Setup the shadow type macros for this material.
  424. if ( shadowType == ShadowType_None )
  425. shadowMacros.push_back( GFXShaderMacro( "NO_SHADOW" ) );
  426. else
  427. {
  428. shadowMacros.push_back( GFXShaderMacro( smShadowTypeMacro[ shadowType ] ) );
  429. // Do we need to do shadow filtering?
  430. if ( smShadowFilterMode != ShadowFilterMode_None )
  431. {
  432. shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW" ) );
  433. const F32 SM = GFX->getPixelShaderVersion();
  434. if ( SM >= 3.0f && smShadowFilterMode == ShadowFilterMode_SoftShadowHighQuality )
  435. shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW_HIGH_QUALITY" ) );
  436. }
  437. }
  438. if ( useCookieTex )
  439. shadowMacros.push_back( GFXShaderMacro( "USE_COOKIE_TEX" ) );
  440. if(isPhotometric)
  441. shadowMacros.push_back(GFXShaderMacro("UES_PHOTOMETRIC_MASK"));
  442. // Its safe to add the PSSM debug macro to all the materials.
  443. if ( smPSSMDebugRender )
  444. shadowMacros.push_back( GFXShaderMacro( "PSSM_DEBUG_RENDER" ) );
  445. if( smDiffuseLightViz )
  446. shadowMacros.push_back(GFXShaderMacro("DIFFUSE_LIGHT_VIZ"));
  447. else if (smSpecularLightViz)
  448. shadowMacros.push_back(GFXShaderMacro("SPECULAR_LIGHT_VIZ"));
  449. else if (smDetailLightingViz)
  450. shadowMacros.push_back(GFXShaderMacro("DETAIL_LIGHTING_VIZ"));
  451. // Now create the material info object.
  452. info = new LightMaterialInfo( lightMatName, smLightMatVertex[ lightType ], shadowMacros );
  453. }
  454. // Push this into the map and return it.
  455. mLightMaterials.insertUnique( key, info );
  456. return info;
  457. }
  458. void AdvancedLightBinManager::_deleteLightMaterials()
  459. {
  460. LightMatTable::Iterator iter = mLightMaterials.begin();
  461. for ( ; iter != mLightMaterials.end(); iter++ )
  462. delete iter->value;
  463. mLightMaterials.clear();
  464. }
  465. void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *state )
  466. {
  467. PROFILE_SCOPE( AdvancedLightBinManager_SetupPerFrameParameters );
  468. const Frustum &frustum = state->getCameraFrustum();
  469. MatrixF invCam( frustum.getTransform() );
  470. invCam.inverse();
  471. const Point3F *wsFrustumPoints = frustum.getPoints();
  472. const Point3F& cameraPos = frustum.getPosition();
  473. // Perform a camera offset. We need to manually perform this offset on the sun (or vector) light's
  474. // polygon, which is at the far plane.
  475. Point3F cameraOffsetPos = cameraPos;
  476. // Now build the quad for drawing full-screen vector light
  477. // passes.... this is a volatile VB and updates every frame.
  478. FarFrustumQuadVert verts[4];
  479. {
  480. verts[0].point.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraPos);
  481. invCam.mulP(wsFrustumPoints[Frustum::FarTopLeft], &verts[0].normal);
  482. verts[0].texCoord.set(-1.0, 1.0);
  483. verts[0].tangent.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraOffsetPos);
  484. verts[1].point.set(wsFrustumPoints[Frustum::FarTopRight] - cameraPos);
  485. invCam.mulP(wsFrustumPoints[Frustum::FarTopRight], &verts[1].normal);
  486. verts[1].texCoord.set(1.0, 1.0);
  487. verts[1].tangent.set(wsFrustumPoints[Frustum::FarTopRight] - cameraOffsetPos);
  488. verts[2].point.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraPos);
  489. invCam.mulP(wsFrustumPoints[Frustum::FarBottomLeft], &verts[2].normal);
  490. verts[2].texCoord.set(-1.0, -1.0);
  491. verts[2].tangent.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraOffsetPos);
  492. verts[3].point.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraPos);
  493. invCam.mulP(wsFrustumPoints[Frustum::FarBottomRight], &verts[3].normal);
  494. verts[3].texCoord.set(1.0, -1.0);
  495. verts[3].tangent.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraOffsetPos);
  496. }
  497. mFarFrustumQuadVerts.set( GFX, 4 );
  498. dMemcpy( mFarFrustumQuadVerts.lock(), verts, sizeof( verts ) );
  499. mFarFrustumQuadVerts.unlock();
  500. PlaneF farPlane(wsFrustumPoints[Frustum::FarBottomLeft], wsFrustumPoints[Frustum::FarTopLeft], wsFrustumPoints[Frustum::FarTopRight]);
  501. PlaneF vsFarPlane(verts[0].normal, verts[1].normal, verts[2].normal);
  502. // Parameters calculated, assign them to the materials
  503. LightMatTable::Iterator iter = mLightMaterials.begin();
  504. for ( ; iter != mLightMaterials.end(); iter++ )
  505. {
  506. if ( iter->value )
  507. iter->value->setViewParameters( frustum.getNearDist(),
  508. frustum.getFarDist(),
  509. frustum.getPosition(),
  510. farPlane,
  511. vsFarPlane);
  512. }
  513. }
  514. void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light )
  515. {
  516. PROFILE_SCOPE( AdvancedLightBinManager_setupSGData );
  517. data.lights[0] = light;
  518. data.ambientLightColor = state->getAmbientLightColor();
  519. data.objTrans = &MatrixF::Identity;
  520. if ( light )
  521. {
  522. if ( light->getType() == LightInfo::Point )
  523. {
  524. // The point light volume gets some flat spots along
  525. // the perimiter mostly visible in the constant and
  526. // quadradic falloff modes.
  527. //
  528. // To account for them slightly increase the scale
  529. // instead of greatly increasing the polycount.
  530. mLightMat = light->getTransform();
  531. mLightMat.scale( light->getRange() * 1.01f );
  532. data.objTrans = &mLightMat;
  533. }
  534. else if ( light->getType() == LightInfo::Spot )
  535. {
  536. mLightMat = light->getTransform();
  537. // Rotate it to face down the -y axis.
  538. MatrixF scaleRotateTranslate( EulerF( M_PI_F / -2.0f, 0.0f, 0.0f ) );
  539. // Calculate the radius based on the range and angle.
  540. F32 range = light->getRange().x;
  541. F32 radius = range * mSin( mDegToRad( light->getOuterConeAngle() ) * 0.5f );
  542. // NOTE: This fudge makes the cone a little bigger
  543. // to remove the facet egde of the cone geometry.
  544. radius *= 1.1f;
  545. // Use the scale to distort the cone to
  546. // match our radius and range.
  547. scaleRotateTranslate.scale( Point3F( radius, radius, range ) );
  548. // Apply the transform and set the position.
  549. mLightMat *= scaleRotateTranslate;
  550. mLightMat.setPosition( light->getPosition() );
  551. data.objTrans = &mLightMat;
  552. }
  553. }
  554. }
  555. void AdvancedLightBinManager::MRTLightmapsDuringDeferred( bool val )
  556. {
  557. // Do not enable if the GFX device can't do MRT's
  558. if ( GFX->getNumRenderTargets() < 2 )
  559. val = false;
  560. if ( mMRTLightmapsDuringDeferred != val )
  561. {
  562. mMRTLightmapsDuringDeferred = val;
  563. // Reload materials to cause a feature recalculation on deferred materials
  564. if(mLightManager->isActive())
  565. MATMGR->flushAndReInitInstances();
  566. RenderDeferredMgr *deferred;
  567. if ( Sim::findObject( "AL_DeferredBin", deferred ) && deferred->getTargetTexture( 0 ) )
  568. deferred->updateTargets();
  569. }
  570. }
  571. AdvancedLightBinManager::LightMaterialInfo::LightMaterialInfo( const String &matName,
  572. const GFXVertexFormat *vertexFormat,
  573. const Vector<GFXShaderMacro> &macros )
  574. : matInstance(NULL),
  575. zNearFarInvNearFar(NULL),
  576. farPlane(NULL),
  577. vsFarPlane(NULL),
  578. negFarPlaneDotEye(NULL),
  579. lightPosition(NULL),
  580. lightDirection(NULL),
  581. lightColor(NULL),
  582. lightRange(NULL),
  583. lightInvSqrRange(NULL),
  584. lightAmbient(NULL),
  585. lightSpotParams(NULL)
  586. {
  587. Material *mat = MATMGR->getMaterialDefinitionByName( matName );
  588. if ( !mat )
  589. return;
  590. matInstance = new LightMatInstance( *mat );
  591. for ( U32 i=0; i < macros.size(); i++ )
  592. matInstance->addShaderMacro( macros[i].name, macros[i].value );
  593. matInstance->init( MATMGR->getDefaultFeatures(), vertexFormat );
  594. lightDirection = matInstance->getMaterialParameterHandle("$lightDirection");
  595. lightAmbient = matInstance->getMaterialParameterHandle("$lightAmbient");
  596. lightSpotParams = matInstance->getMaterialParameterHandle("$lightSpotParams");
  597. lightRange = matInstance->getMaterialParameterHandle("$lightRange");
  598. lightInvSqrRange = matInstance->getMaterialParameterHandle("$lightInvSqrRange");
  599. lightPosition = matInstance->getMaterialParameterHandle("$lightPosition");
  600. farPlane = matInstance->getMaterialParameterHandle("$farPlane");
  601. vsFarPlane = matInstance->getMaterialParameterHandle("$vsFarPlane");
  602. negFarPlaneDotEye = matInstance->getMaterialParameterHandle("$negFarPlaneDotEye");
  603. zNearFarInvNearFar = matInstance->getMaterialParameterHandle("$zNearFarInvNearFar");
  604. lightColor = matInstance->getMaterialParameterHandle("$lightColor");
  605. lightBrightness = matInstance->getMaterialParameterHandle("$lightBrightness");
  606. }
  607. AdvancedLightBinManager::LightMaterialInfo::~LightMaterialInfo()
  608. {
  609. SAFE_DELETE(matInstance);
  610. }
  611. void AdvancedLightBinManager::LightMaterialInfo::setViewParameters( const F32 _zNear,
  612. const F32 _zFar,
  613. const Point3F &_eyePos,
  614. const PlaneF &_farPlane,
  615. const PlaneF &_vsFarPlane)
  616. {
  617. MaterialParameters *matParams = matInstance->getMaterialParameters();
  618. matParams->setSafe( farPlane, *((const Point4F *)&_farPlane) );
  619. matParams->setSafe( vsFarPlane, *((const Point4F *)&_vsFarPlane) );
  620. if ( negFarPlaneDotEye->isValid() )
  621. {
  622. // -dot( farPlane, eyePos )
  623. const F32 negFarPlaneDotEyeVal = -( mDot( *((const Point3F *)&_farPlane), _eyePos ) + _farPlane.d );
  624. matParams->set( negFarPlaneDotEye, negFarPlaneDotEyeVal );
  625. }
  626. matParams->setSafe( zNearFarInvNearFar, Point4F( _zNear, _zFar, 1.0f / _zNear, 1.0f / _zFar ) );
  627. }
  628. void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState )
  629. {
  630. MaterialParameters *matParams = matInstance->getMaterialParameters();
  631. matParams->setSafe( lightColor, lightInfo->getColor() );
  632. F32 luxTargMultiplier = 1;
  633. switch( lightInfo->getType() )
  634. {
  635. case LightInfo::Vector:
  636. {
  637. matParams->setSafe( lightDirection, lightInfo->getDirection());
  638. matParams->setSafe( lightAmbient, renderState->getAmbientLightColor());
  639. }
  640. break;
  641. case LightInfo::Spot:
  642. {
  643. const F32 outerCone = lightInfo->getOuterConeAngle();
  644. const F32 innerCone = getMin(lightInfo->getInnerConeAngle(), outerCone-0.0001f);
  645. const F32 outerCos = mCos(mDegToRad(outerCone / 2.0f));
  646. const F32 innerCos = mCos(mDegToRad(innerCone / 2.0f));
  647. Point2F spotParams(outerCos,mMax(innerCos - outerCos,0.001f));
  648. matParams->setSafe( lightSpotParams, spotParams );
  649. matParams->setSafe( lightDirection, lightInfo->getDirection());
  650. matParams->setSafe( lightPosition, lightInfo->getPosition());
  651. const F32 radius = lightInfo->getRange().x;
  652. const F32 invSqrRadius = 1.0f / mSquared(radius);
  653. matParams->setSafe(lightRange, radius);
  654. matParams->setSafe(lightInvSqrRange, invSqrRadius);
  655. F32 concentration = 360.0f/ outerCone;
  656. luxTargMultiplier = radius * concentration;
  657. }
  658. break;
  659. case LightInfo::Point:
  660. {
  661. matParams->setSafe(lightPosition, lightInfo->getPosition());
  662. const F32 radius = lightInfo->getRange().x;
  663. const F32 invSqrRadius = 1.0f / (radius * radius);
  664. matParams->setSafe( lightRange, radius);
  665. matParams->setSafe( lightDirection, -lightInfo->getTransform().getUpVector());
  666. matParams->setSafe( lightInvSqrRange, invSqrRadius);
  667. luxTargMultiplier =radius;
  668. }
  669. break;
  670. default:
  671. AssertFatal( false, "Bad light type!" );
  672. break;
  673. }
  674. matParams->setSafe(lightBrightness, lightInfo->getBrightness()* lightInfo->getFadeAmount() * luxTargMultiplier);
  675. }
  676. bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgData )
  677. {
  678. // Go no further if the material failed to initialize properly.
  679. if ( !mProcessedMaterial ||
  680. mProcessedMaterial->getNumPasses() == 0 )
  681. return false;
  682. U32 reflectStatus = Base;
  683. if (state->isReflectPass())
  684. reflectStatus = Reflecting;
  685. // Fetch the lightmap params
  686. const LightMapParams *lmParams = sgData.lights[0]->getExtended<LightMapParams>();
  687. // If no Lightmap params, let parent handle it
  688. if(lmParams == NULL)
  689. return Parent::setupPass(state, sgData);
  690. // Defaults
  691. bool bRetVal = true;
  692. // What render pass is this...
  693. if(mCurPass == -1)
  694. {
  695. // First pass, reset this flag
  696. mInternalPass = false;
  697. // Pass call to parent
  698. bRetVal = Parent::setupPass(state, sgData);
  699. }
  700. else
  701. {
  702. // If this light is represented in a lightmap, it has already done it's
  703. // job for non-lightmapped geometry. Now render the lightmapped geometry
  704. // pass (specular + shadow-darkening)
  705. if(!mInternalPass && lmParams->representedInLightmap)
  706. mInternalPass = true;
  707. else
  708. return Parent::setupPass(state, sgData);
  709. }
  710. // Set up the shader constants we need to...
  711. if(mLightMapParamsSC->isValid())
  712. {
  713. // If this is an internal pass, special case the parameters
  714. if(mInternalPass)
  715. {
  716. AssertFatal( lmParams->shadowDarkenColor.alpha == -1.0f, "Assumption failed, check unpack code!" );
  717. getMaterialParameters()->set( mLightMapParamsSC, lmParams->shadowDarkenColor );
  718. }
  719. else
  720. getMaterialParameters()->set( mLightMapParamsSC, LinearColorF::WHITE );
  721. }
  722. // Now override stateblock with our own
  723. if(!mInternalPass)
  724. {
  725. // If this is not an internal pass, and this light is represented in lightmaps
  726. // than only effect non-lightmapped geometry for this pass
  727. if (lmParams->representedInLightmap)
  728. {
  729. GFX->setStateBlock(mLitState[StaticLightNonLMGeometry][reflectStatus]);
  730. }
  731. else // This is a normal, dynamic light.
  732. {
  733. if (mSpecialLight)
  734. GFX->setStateBlock(mLitState[SunLight][reflectStatus]);
  735. else
  736. GFX->setStateBlock(mLitState[DynamicLight][reflectStatus]);
  737. }
  738. }
  739. else // Internal pass, this is the add-specular/multiply-darken-color pass
  740. GFX->setStateBlock(mLitState[StaticLightLMGeometry][reflectStatus]);
  741. return bRetVal;
  742. }
  743. bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat *vertexFormat )
  744. {
  745. bool success = Parent::init(features, vertexFormat);
  746. // If the initialization failed don't continue.
  747. if ( !success || !mProcessedMaterial || mProcessedMaterial->getNumPasses() == 0 )
  748. return false;
  749. mLightMapParamsSC = getMaterialParameterHandle("$lightMapParams");
  750. // Grab the state block for the first render pass (since this mat instance
  751. // inserts a pass after the first pass)
  752. AssertFatal(mProcessedMaterial->getNumPasses() > 0, "No passes created! Ohnoes");
  753. const RenderPassData *rpd = mProcessedMaterial->getPass(0);
  754. AssertFatal(rpd, "No render pass data!");
  755. AssertFatal(rpd->mRenderStates[0], "No render state 0!");
  756. // Get state block desc for normal (not wireframe, not translucent, not glow, etc)
  757. // render state
  758. GFXStateBlockDesc litState = rpd->mRenderStates[0]->getDesc();
  759. // Create state blocks for each of the 3 possible combos in setupPass
  760. //DynamicLight State: This will effect lightmapped and non-lightmapped geometry
  761. // in the same way.
  762. litState.separateAlphaBlendDefined = true;
  763. litState.separateAlphaBlendEnable = false;
  764. litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask;
  765. litState.setCullMode(GFXCullCW);
  766. mLitState[DynamicLight][Base] = GFX->createStateBlock(litState);
  767. litState.setCullMode(GFXCullCCW);
  768. mLitState[DynamicLight][Reflecting] = GFX->createStateBlock(litState);
  769. litState.separateAlphaBlendDefined = true;
  770. litState.separateAlphaBlendEnable = false;
  771. litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask;
  772. litState.setCullMode(GFXCullCCW);
  773. mLitState[SunLight][Base] = GFX->createStateBlock(litState);
  774. litState.setCullMode(GFXCullCCW);
  775. mLitState[SunLight][Reflecting] = GFX->createStateBlock(litState);
  776. // StaticLightNonLMGeometry State: This will treat non-lightmapped geometry
  777. // in the usual way, but will not effect lightmapped geometry.
  778. litState.separateAlphaBlendDefined = true;
  779. litState.separateAlphaBlendEnable = false;
  780. litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask;
  781. litState.setCullMode(GFXCullCW);
  782. mLitState[StaticLightNonLMGeometry][Base] = GFX->createStateBlock(litState);
  783. litState.setCullMode(GFXCullCCW);
  784. mLitState[StaticLightNonLMGeometry][Reflecting] = GFX->createStateBlock(litState);
  785. // StaticLightLMGeometry State: This will add specular information (alpha) but
  786. // multiply-darken color information.
  787. litState.blendDest = GFXBlendSrcColor;
  788. litState.blendSrc = GFXBlendZero;
  789. litState.stencilMask = RenderDeferredMgr::OpaqueStaticLitMask;
  790. litState.separateAlphaBlendDefined = true;
  791. litState.separateAlphaBlendEnable = true;
  792. litState.separateAlphaBlendSrc = GFXBlendOne;
  793. litState.separateAlphaBlendDest = GFXBlendOne;
  794. litState.separateAlphaBlendOp = GFXBlendOpAdd;
  795. litState.setCullMode(GFXCullCW);
  796. mLitState[StaticLightLMGeometry][Base] = GFX->createStateBlock(litState);
  797. litState.setCullMode(GFXCullCCW);
  798. mLitState[StaticLightLMGeometry][Reflecting] = GFX->createStateBlock(litState);
  799. return true;
  800. }