Is.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. #include "anki/renderer/Is.h"
  2. #include "anki/renderer/Renderer.h"
  3. #include "anki/scene/Scene.h"
  4. #include "anki/scene/Camera.h"
  5. #include "anki/scene/Light.h"
  6. #include "anki/core/ThreadPool.h"
  7. namespace anki {
  8. //==============================================================================
  9. static Bool groundVectorsEqual(const Vec3& prev, const Vec3& crnt)
  10. {
  11. Bool out = true;
  12. for(U i = 0; i < 3; i++)
  13. {
  14. Bool subout = fabs(prev[i] - crnt[i]) < (getEpsilon<F32>() * 10.0);
  15. out = out && subout;
  16. }
  17. return out;
  18. }
  19. //==============================================================================
  20. // Shader structs and block representations
  21. struct ShaderLight
  22. {
  23. Vec4 posAndRadius; ///< xyz: Light pos in eye space. w: The radius
  24. Vec4 diffuseColorShadowmapId;
  25. Vec4 specularColor;
  26. };
  27. struct ShaderPointLight: ShaderLight
  28. {};
  29. struct ShaderSpotLight: ShaderLight
  30. {
  31. Vec4 lightDirection; ///< xyz: Dir vector
  32. Vec4 outerCosInnerCos; ///< x: outer angle cos, y: inner
  33. Mat4 texProjectionMat;
  34. };
  35. struct ShaderPointLights
  36. {
  37. ShaderPointLight lights[Is::MAX_POINT_LIGHTS];
  38. };
  39. struct ShaderSpotLights
  40. {
  41. ShaderSpotLight lights[Is::MAX_SPOT_LIGHTS];
  42. };
  43. struct ShaderTile
  44. {
  45. U32 lightsCount[3]; ///< 0: Point lights number, 1: Spot lights number
  46. U32 padding[1];
  47. // When change this change the writeTilesUbo as well
  48. Array<U32, Is::MAX_LIGHTS_PER_TILE> lightIndices;
  49. };
  50. struct ShaderTiles
  51. {
  52. Array<ShaderTile, Tiler::TILES_X_COUNT * Tiler::TILES_Y_COUNT> tiles;
  53. };
  54. struct ShaderCommonUniforms
  55. {
  56. Vec4 nearPlanes;
  57. Vec4 limitsOfNearPlane;
  58. Vec4 sceneAmbientColor;
  59. Vec4 groundLightDir;
  60. };
  61. //==============================================================================
  62. // Threading jobs
  63. /// Job to update point lights
  64. struct WritePointLightsUbo: ThreadJob
  65. {
  66. ShaderPointLight* shaderLights = nullptr; ///< Mapped UBO
  67. PointLight** visibleLights = nullptr;
  68. U32 visibleLightsCount = 0;
  69. Is* is = nullptr;
  70. void operator()(U threadId, U threadsCount)
  71. {
  72. U64 start, end;
  73. choseStartEnd(threadId, threadsCount, visibleLightsCount, start, end);
  74. const Camera* cam = is->cam;
  75. for(U64 i = start; i < end; i++)
  76. {
  77. ANKI_ASSERT(i < Is::MAX_POINT_LIGHTS);
  78. ANKI_ASSERT(i < visibleLightsCount);
  79. ShaderPointLight& pl = shaderLights[i];
  80. const PointLight& light = *visibleLights[i];
  81. Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
  82. cam->getViewMatrix());
  83. pl.posAndRadius = Vec4(pos, light.getRadius());
  84. pl.diffuseColorShadowmapId = light.getDiffuseColor();
  85. pl.specularColor = light.getSpecularColor();
  86. }
  87. }
  88. };
  89. /// Job to update spot lights
  90. struct WriteSpotLightsUbo: ThreadJob
  91. {
  92. ShaderSpotLight* shaderLights = nullptr; ///< Mapped UBO
  93. SpotLight** visibleLights = nullptr;
  94. U32 visibleLightsCount = 0;
  95. Is* is = nullptr;
  96. void operator()(U threadId, U threadsCount)
  97. {
  98. U64 start, end;
  99. choseStartEnd(threadId, threadsCount, visibleLightsCount, start, end);
  100. const Camera* cam = is->cam;
  101. for(U64 i = start; i < end; i++)
  102. {
  103. ANKI_ASSERT(i < Is::MAX_SPOT_LIGHTS);
  104. ANKI_ASSERT(i < visibleLightsCount);
  105. ShaderSpotLight& slight = shaderLights[i];
  106. const SpotLight& light = *visibleLights[i];
  107. Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
  108. cam->getViewMatrix());
  109. slight.posAndRadius = Vec4(pos, light.getDistance());
  110. slight.diffuseColorShadowmapId = Vec4(light.getDiffuseColor().xyz(),
  111. 0);
  112. slight.specularColor = light.getSpecularColor();
  113. Vec3 lightDir = -light.getWorldTransform().getRotation().getZAxis();
  114. lightDir = cam->getViewMatrix().getRotationPart() * lightDir;
  115. slight.lightDirection = Vec4(lightDir, 0.0);
  116. slight.outerCosInnerCos = Vec4(light.getOuterAngleCos(),
  117. light.getInnerAngleCos(), 1.0, 1.0);
  118. static const Mat4 biasMat4(
  119. 0.5, 0.0, 0.0, 0.5,
  120. 0.0, 0.5, 0.0, 0.5,
  121. 0.0, 0.0, 0.5, 0.5,
  122. 0.0, 0.0, 0.0, 1.0);
  123. // bias * proj_l * view_l * world_c
  124. slight.texProjectionMat = biasMat4 * light.getProjectionMatrix() *
  125. Mat4::combineTransformations(light.getViewMatrix(),
  126. Mat4(cam->getWorldTransform()));
  127. // Transpose because of driver bug
  128. slight.texProjectionMat.transpose();
  129. }
  130. }
  131. };
  132. /// A job to write the tiles UBO
  133. struct WriteTilesUboJob: ThreadJob
  134. {
  135. PointLight** visiblePointLights = nullptr;
  136. U32 visiblePointLightsCount = 0;
  137. SpotLight** visibleSpotLights = nullptr;
  138. U32 visibleSpotLightsCount = 0; ///< Both shadow and not
  139. ShaderTile* shaderTiles = nullptr; ///< Mapped UBO
  140. U32 maxLightsPerTile = 0;
  141. Is* is = nullptr;
  142. void operator()(U threadId, U threadsCount)
  143. {
  144. U64 start, end;
  145. choseStartEnd(threadId, threadsCount,
  146. Tiler::TILES_X_COUNT * Tiler::TILES_Y_COUNT, start, end);
  147. for(U32 i = start; i < end; i++)
  148. {
  149. ShaderTile& stile = shaderTiles[i];
  150. doTile(i, stile);
  151. }
  152. }
  153. /// Do a tile
  154. void doTile(U tileId, ShaderTile& stile)
  155. {
  156. auto& lightIndices = stile.lightIndices;
  157. const Tiler& tiler = is->r->getTiler();
  158. // Point lights
  159. //
  160. U pointLightsInTileCount = 0;
  161. for(U i = 0; i < visiblePointLightsCount; i++)
  162. {
  163. const PointLight& light = *visiblePointLights[i];
  164. if(tiler.test(light.getSphere(), tileId))
  165. {
  166. // Use % to avoid overflows
  167. const U id = pointLightsInTileCount % Is::MAX_LIGHTS_PER_TILE;
  168. lightIndices[id] = i;
  169. ++pointLightsInTileCount;
  170. }
  171. }
  172. stile.lightsCount[0] = pointLightsInTileCount;
  173. // Spot lights
  174. //
  175. U spotLightsInTileCount = 0;
  176. U spotLightsShadowInTileCount = 0;
  177. for(U i = 0; i < visibleSpotLightsCount; i++)
  178. {
  179. const SpotLight& light = *visibleSpotLights[i];
  180. if(tiler.test(light.getFrustum(), tileId))
  181. {
  182. const U id = (pointLightsInTileCount + spotLightsInTileCount
  183. + spotLightsShadowInTileCount)
  184. % Is::MAX_LIGHTS_PER_TILE;
  185. // Use % to avoid overflows
  186. lightIndices[id] = i;
  187. if(light.getShadowEnabled())
  188. {
  189. ++spotLightsShadowInTileCount;
  190. }
  191. else
  192. {
  193. ++spotLightsInTileCount;
  194. }
  195. }
  196. }
  197. stile.lightsCount[1] = spotLightsInTileCount;
  198. stile.lightsCount[2] = spotLightsShadowInTileCount;
  199. #if 0
  200. U totalLightsInTileCount = std::min(
  201. pointLightsInTileCount + spotLightsInTileCount
  202. + spotLightsShadowInTileCount,
  203. Is::MAX_LIGHTS_PER_TILE);
  204. if(pointLightsInTileCount + spotLightsInTileCount > maxLightsPerTile)
  205. {
  206. ANKI_LOGW("Too many lights per tile: " << lightsInTileCount);
  207. }
  208. #endif
  209. }
  210. };
  211. //==============================================================================
  212. Is::Is(Renderer* r_)
  213. : RenderingPass(r_), sm(r_)
  214. {}
  215. //==============================================================================
  216. Is::~Is()
  217. {}
  218. //==============================================================================
  219. void Is::init(const RendererInitializer& initializer)
  220. {
  221. try
  222. {
  223. initInternal(initializer);
  224. }
  225. catch(const std::exception& e)
  226. {
  227. throw ANKI_EXCEPTION("Failed to init IS") << e;
  228. }
  229. }
  230. //==============================================================================
  231. void Is::initInternal(const RendererInitializer& initializer)
  232. {
  233. groundLightEnabled = initializer.is.groundLightEnabled;
  234. //
  235. // Init the passes
  236. //
  237. sm.init(initializer);
  238. //
  239. // Load the programs
  240. //
  241. std::string pps =
  242. "#define TILES_X_COUNT " + std::to_string(Tiler::TILES_X_COUNT) + "\n"
  243. "#define TILES_Y_COUNT " + std::to_string(Tiler::TILES_Y_COUNT) + "\n"
  244. "#define RENDERER_WIDTH " + std::to_string(r->getWidth()) + "\n"
  245. "#define RENDERER_HEIGHT " + std::to_string(r->getHeight()) + "\n"
  246. "#define MAX_LIGHTS_PER_TILE " + std::to_string(MAX_LIGHTS_PER_TILE)
  247. + "\n"
  248. "#define MAX_POINT_LIGHTS " + std::to_string(MAX_POINT_LIGHTS) + "\n"
  249. "#define MAX_SPOT_LIGHTS " + std::to_string(MAX_SPOT_LIGHTS) + "\n"
  250. "#define GROUND_LIGHT " + std::to_string(groundLightEnabled) + "\n";
  251. if(sm.getPcfEnabled())
  252. {
  253. pps += "#define PCF 1\n";
  254. }
  255. // point light
  256. lightPassProg.load(ShaderProgramResource::createSrcCodeToCache(
  257. "shaders/IsLpGeneric.glsl", pps.c_str()).c_str());
  258. //
  259. // Create FBOs
  260. //
  261. // IS FBO
  262. Renderer::createFai(r->getWidth(), r->getHeight(), GL_RGB8,
  263. GL_RGB, GL_UNSIGNED_INT, fai);
  264. fbo.create();
  265. fbo.setColorAttachments({&fai});
  266. fbo.setOtherAttachment(GL_DEPTH_ATTACHMENT, r->getMs().getDepthFai());
  267. if(!fbo.isComplete())
  268. {
  269. throw ANKI_EXCEPTION("Fbo not complete");
  270. }
  271. //
  272. // Init the quad
  273. //
  274. static const F32 quadVertCoords[][2] = {{1.0, 1.0}, {0.0, 1.0},
  275. {0.0, 0.0}, {1.0, 0.0}};
  276. quadPositionsVbo.create(GL_ARRAY_BUFFER, sizeof(quadVertCoords),
  277. quadVertCoords, GL_STATIC_DRAW);
  278. static const U16 quadVertIndeces[2][3] =
  279. {{0, 1, 3}, {1, 2, 3}}; // 2 triangles
  280. quadVertIndecesVbo.create(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadVertIndeces),
  281. quadVertIndeces, GL_STATIC_DRAW);
  282. quadVao.create();
  283. quadVao.attachArrayBufferVbo(
  284. &quadPositionsVbo, 0, 2, GL_FLOAT, false, 0, 0);
  285. quadVao.attachElementArrayBufferVbo(&quadVertIndecesVbo);
  286. //
  287. // Create UBOs
  288. //
  289. // Common UBO
  290. commonUbo.create(sizeof(ShaderCommonUniforms), nullptr);
  291. // lights UBO
  292. pointLightsUbo.create(sizeof(ShaderPointLights), nullptr);
  293. spotLightsUbo.create(sizeof(ShaderSpotLights), nullptr);
  294. // lightIndices UBO
  295. tilesUbo.create(sizeof(ShaderTiles), nullptr);
  296. // Sanity checks
  297. const ShaderProgramUniformBlock* ublock;
  298. ublock = &lightPassProg->findUniformBlock("commonBlock");
  299. if(ublock->getSize() != sizeof(ShaderCommonUniforms)
  300. || ublock->getBinding() != COMMON_UNIFORMS_BLOCK_BINDING)
  301. {
  302. throw ANKI_EXCEPTION("Problem with the commonBlock");
  303. }
  304. ublock = &lightPassProg->findUniformBlock("pointLightsBlock");
  305. if(ublock->getSize() != sizeof(ShaderPointLights)
  306. || ublock->getBinding() != POINT_LIGHTS_BLOCK_BINDING)
  307. {
  308. throw ANKI_EXCEPTION("Problem with the pointLightsBlock");
  309. }
  310. ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
  311. if(ublock->getSize() != sizeof(ShaderSpotLights)
  312. || ublock->getBinding() != SPOT_LIGHTS_BLOCK_BINDING)
  313. {
  314. throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
  315. }
  316. ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
  317. if(ublock->getSize() != sizeof(ShaderSpotLights)
  318. || ublock->getBinding() != SPOT_LIGHTS_BLOCK_BINDING)
  319. {
  320. throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
  321. }
  322. ublock = &lightPassProg->findUniformBlock("tilesBlock");
  323. if(ublock->getSize() != sizeof(ShaderTiles)
  324. || ublock->getBinding() != TILES_BLOCK_BINDING)
  325. {
  326. throw ANKI_EXCEPTION("Problem with the tilesBlock");
  327. }
  328. }
  329. //==============================================================================
  330. void Is::lightPass()
  331. {
  332. ThreadPool& threadPool = ThreadPoolSingleton::get();
  333. VisibilityInfo& vi = cam->getFrustumable()->getVisibilityInfo();
  334. Array<PointLight*, MAX_POINT_LIGHTS> visiblePointLights;
  335. U visiblePointLightsCount = 0;
  336. Array<SpotLight*, MAX_SPOT_LIGHTS> visibleSpotLights;
  337. U visibleSpotLightsCount = 0;
  338. U spotsNoShadowCount = 0, spotsShadowCount = 0;
  339. Array<SpotLight*, MAX_SPOT_LIGHTS> visibleSpotNoShadowLights,
  340. visibleSpotShadowLights;
  341. //
  342. // Quickly get the lights
  343. //
  344. for(auto it = vi.getLightsBegin(); it != vi.getLightsEnd(); ++it)
  345. {
  346. Light* light = (*it)->getLight();
  347. switch(light->getLightType())
  348. {
  349. case Light::LT_POINT:
  350. // Use % to avoid overflows
  351. visiblePointLights[visiblePointLightsCount % MAX_POINT_LIGHTS] =
  352. static_cast<PointLight*>(light);
  353. ++visiblePointLightsCount;
  354. break;
  355. case Light::LT_SPOT:
  356. {
  357. SpotLight* slight = static_cast<SpotLight*>(light);
  358. if(slight->getShadowEnabled())
  359. {
  360. visibleSpotShadowLights[
  361. spotsShadowCount % MAX_SPOT_LIGHTS] = slight;
  362. ++spotsShadowCount;
  363. }
  364. else
  365. {
  366. visibleSpotNoShadowLights[
  367. spotsNoShadowCount % MAX_SPOT_LIGHTS] = slight;
  368. ++spotsNoShadowCount;
  369. }
  370. break;
  371. }
  372. case Light::LT_NUM:
  373. break;
  374. }
  375. }
  376. visibleSpotLightsCount = spotsShadowCount + spotsNoShadowCount;
  377. if(visiblePointLightsCount > MAX_POINT_LIGHTS
  378. || visibleSpotLightsCount > MAX_SPOT_LIGHTS)
  379. {
  380. throw ANKI_EXCEPTION("Too many visible lights");
  381. }
  382. for(U i = 0; i < spotsNoShadowCount; i++)
  383. {
  384. visibleSpotLights[i] = visibleSpotNoShadowLights[i];
  385. }
  386. for(U i = 0; i < spotsShadowCount; i++)
  387. {
  388. visibleSpotLights[i + spotsNoShadowCount] = visibleSpotShadowLights[i];
  389. }
  390. //
  391. // Do shadows pass
  392. //
  393. Array<Light*, Sm::MAX_SHADOW_CASTERS> shadowCasters;
  394. for(U i = 0; i < spotsShadowCount; i++)
  395. {
  396. shadowCasters[i] = visibleSpotShadowLights[i];
  397. }
  398. Array<U32, Sm::MAX_SHADOW_CASTERS> shadowmapLayers;
  399. sm.run(&shadowCasters[0], spotsShadowCount, shadowmapLayers);
  400. // Prepare state
  401. fbo.bind();
  402. r->clearAfterBindingFbo(
  403. GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  404. GlStateSingleton::get().setViewport(
  405. 0, 0, r->getWidth(), r->getHeight());
  406. GlStateSingleton::get().disable(GL_DEPTH_TEST);
  407. GlStateSingleton::get().disable(GL_BLEND);
  408. //
  409. // Write the lights UBOs
  410. //
  411. // Map points
  412. ShaderPointLight* lightsMappedBuff =
  413. (ShaderPointLight*)pointLightsUbo.map(
  414. 0,
  415. sizeof(ShaderPointLight) * visiblePointLightsCount,
  416. GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
  417. WritePointLightsUbo jobs[ThreadPool::MAX_THREADS];
  418. for(U i = 0; i < threadPool.getThreadsCount(); i++)
  419. {
  420. jobs[i].shaderLights = lightsMappedBuff;
  421. jobs[i].visibleLights = &visiblePointLights[0];
  422. jobs[i].visibleLightsCount = visiblePointLightsCount;
  423. jobs[i].is = this;
  424. threadPool.assignNewJob(i, &jobs[i]);
  425. }
  426. // Done
  427. threadPool.waitForAllJobsToFinish();
  428. pointLightsUbo.unmap();
  429. // Map spots
  430. ShaderSpotLight* shaderSpotLights = (ShaderSpotLight*)spotLightsUbo.map(
  431. 0,
  432. sizeof(ShaderSpotLight) * visibleSpotLightsCount,
  433. GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
  434. WriteSpotLightsUbo jobs2[ThreadPool::MAX_THREADS];
  435. for(U i = 0; i < threadPool.getThreadsCount(); i++)
  436. {
  437. jobs2[i].shaderLights = shaderSpotLights;
  438. jobs2[i].visibleLights = &visibleSpotLights[0];
  439. jobs2[i].visibleLightsCount = visibleSpotLightsCount;
  440. jobs2[i].is = this;
  441. threadPool.assignNewJob(i, &jobs2[i]);
  442. }
  443. // Done
  444. threadPool.waitForAllJobsToFinish();
  445. // Set shadow layer IDs
  446. U32 i = 0;
  447. ShaderSpotLight* shaderSpotLight = shaderSpotLights + spotsNoShadowCount;
  448. for(; shaderSpotLight != shaderSpotLights + visibleSpotLightsCount;
  449. ++shaderSpotLight)
  450. {
  451. shaderSpotLight->diffuseColorShadowmapId.w() = (F32)shadowmapLayers[i];
  452. ++i;
  453. }
  454. spotLightsUbo.unmap();
  455. //
  456. // Update the tiles UBO
  457. //
  458. ShaderTile* stiles = (ShaderTile*)tilesUbo.map(
  459. GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
  460. WriteTilesUboJob tjobs[ThreadPool::MAX_THREADS];
  461. for(U i = 0; i < threadPool.getThreadsCount(); i++)
  462. {
  463. tjobs[i].visiblePointLights = &visiblePointLights[0];
  464. tjobs[i].visiblePointLightsCount = visiblePointLightsCount;
  465. tjobs[i].visibleSpotLights = &visibleSpotLights[0];
  466. tjobs[i].visibleSpotLightsCount = visibleSpotLightsCount;
  467. tjobs[i].shaderTiles = stiles;
  468. tjobs[i].is = this;
  469. threadPool.assignNewJob(i, &tjobs[i]);
  470. }
  471. threadPool.waitForAllJobsToFinish();
  472. tilesUbo.unmap();
  473. //
  474. // Setup shader and draw
  475. //
  476. // shader prog
  477. lightPassProg->bind();
  478. commonUbo.setBinding(COMMON_UNIFORMS_BLOCK_BINDING);
  479. pointLightsUbo.setBinding(POINT_LIGHTS_BLOCK_BINDING);
  480. spotLightsUbo.setBinding(SPOT_LIGHTS_BLOCK_BINDING);
  481. tilesUbo.setBinding(TILES_BLOCK_BINDING);
  482. lightPassProg->findUniformVariable("msFai0").set(r->getMs().getFai0());
  483. lightPassProg->findUniformVariable("msDepthFai").set(
  484. r->getMs().getDepthFai());
  485. lightPassProg->findUniformVariable("shadowMapArr").set(sm.sm2DArrayTex);
  486. quadVao.bind();
  487. glDrawElementsInstanced(GL_TRIANGLES, 2 * 3, GL_UNSIGNED_SHORT, 0,
  488. Tiler::TILES_Y_COUNT * Tiler::TILES_X_COUNT);
  489. }
  490. //==============================================================================
  491. void Is::run()
  492. {
  493. Scene& scene = r->getScene();
  494. cam = &scene.getActiveCamera();
  495. GlStateSingleton::get().disable(GL_BLEND);
  496. // Ground light direction
  497. Vec3 groundLightDir;
  498. if(groundLightEnabled)
  499. {
  500. groundLightDir = cam->getViewMatrix().getColumn(1).xyz();
  501. }
  502. // Write common block
  503. if(commonUboUpdateTimestamp < r->getPlanesUpdateTimestamp()
  504. || commonUboUpdateTimestamp < scene.getAmbientColorUpdateTimestamp()
  505. || commonUboUpdateTimestamp == 1
  506. || (groundLightEnabled
  507. && !groundVectorsEqual(groundLightDir, prevGroundLightDir)))
  508. {
  509. const Camera& cam = scene.getActiveCamera();
  510. ShaderCommonUniforms blk;
  511. blk.nearPlanes = Vec4(cam.getNear(), 0.0, r->getPlanes().x(),
  512. r->getPlanes().y());
  513. blk.limitsOfNearPlane = Vec4(r->getLimitsOfNearPlane(),
  514. r->getLimitsOfNearPlane2());
  515. blk.sceneAmbientColor = Vec4(scene.getAmbientColor(), 0.0);
  516. if(groundLightEnabled)
  517. {
  518. blk.groundLightDir = Vec4(groundLightDir, 1.0);
  519. prevGroundLightDir = groundLightDir;
  520. }
  521. commonUbo.write(&blk);
  522. commonUboUpdateTimestamp = Timestamp::getTimestamp();
  523. }
  524. // Do the light pass including the shadow passes
  525. lightPass();
  526. }
  527. } // end namespace anki