advancedLightBinManager.cpp 34 KB

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