advancedLightBinManager.cpp 34 KB

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