Is.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. #include "anki/renderer/Is.h"
  2. #include "anki/renderer/Renderer.h"
  3. #include "anki/scene/SceneGraph.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 planes;
  57. Vec4 sceneAmbientColor;
  58. Vec4 groundLightDir;
  59. };
  60. //==============================================================================
  61. // Threading jobs
  62. /// Job to update point lights
  63. struct WritePointLightsUbo: ThreadJob
  64. {
  65. ShaderPointLight* shaderLights = nullptr; ///< Mapped UBO
  66. PointLight** visibleLights = nullptr;
  67. U32 visibleLightsCount = 0;
  68. Is* is = nullptr;
  69. void operator()(U threadId, U threadsCount)
  70. {
  71. U64 start, end;
  72. choseStartEnd(threadId, threadsCount, visibleLightsCount, start, end);
  73. const Camera* cam = is->cam;
  74. for(U64 i = start; i < end; i++)
  75. {
  76. ANKI_ASSERT(i < Is::MAX_POINT_LIGHTS);
  77. ANKI_ASSERT(i < visibleLightsCount);
  78. ShaderPointLight& pl = shaderLights[i];
  79. const PointLight& light = *visibleLights[i];
  80. Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
  81. cam->getViewMatrix());
  82. pl.posAndRadius = Vec4(pos, light.getRadius());
  83. pl.diffuseColorShadowmapId = light.getDiffuseColor();
  84. pl.specularColor = light.getSpecularColor();
  85. }
  86. }
  87. };
  88. /// Job to update spot lights
  89. struct WriteSpotLightsUbo: ThreadJob
  90. {
  91. ShaderSpotLight* shaderLights = nullptr; ///< Mapped UBO
  92. SpotLight** visibleLights = nullptr;
  93. U32 visibleLightsCount = 0;
  94. Is* is = nullptr;
  95. void operator()(U threadId, U threadsCount)
  96. {
  97. U64 start, end;
  98. choseStartEnd(threadId, threadsCount, visibleLightsCount, start, end);
  99. const Camera* cam = is->cam;
  100. for(U64 i = start; i < end; i++)
  101. {
  102. ANKI_ASSERT(i < Is::MAX_SPOT_LIGHTS);
  103. ANKI_ASSERT(i < visibleLightsCount);
  104. ShaderSpotLight& slight = shaderLights[i];
  105. const SpotLight& light = *visibleLights[i];
  106. Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
  107. cam->getViewMatrix());
  108. slight.posAndRadius = Vec4(pos, light.getDistance());
  109. slight.diffuseColorShadowmapId = Vec4(light.getDiffuseColor().xyz(),
  110. 0);
  111. slight.specularColor = light.getSpecularColor();
  112. Vec3 lightDir = -light.getWorldTransform().getRotation().getZAxis();
  113. lightDir = cam->getViewMatrix().getRotationPart() * lightDir;
  114. slight.lightDirection = Vec4(lightDir, 0.0);
  115. slight.outerCosInnerCos = Vec4(light.getOuterAngleCos(),
  116. light.getInnerAngleCos(), 1.0, 1.0);
  117. static const Mat4 biasMat4(
  118. 0.5, 0.0, 0.0, 0.5,
  119. 0.0, 0.5, 0.0, 0.5,
  120. 0.0, 0.0, 0.5, 0.5,
  121. 0.0, 0.0, 0.0, 1.0);
  122. // bias * proj_l * view_l * world_c
  123. slight.texProjectionMat = biasMat4 * light.getProjectionMatrix() *
  124. Mat4::combineTransformations(light.getViewMatrix(),
  125. Mat4(cam->getWorldTransform()));
  126. // Transpose because of driver bug
  127. slight.texProjectionMat.transpose();
  128. }
  129. }
  130. };
  131. /// A job to write the tiles UBO
  132. struct WriteTilesUboJob: ThreadJob
  133. {
  134. PointLight** visiblePointLights = nullptr;
  135. U32 visiblePointLightsCount = 0;
  136. SpotLight** visibleSpotLights = nullptr;
  137. U32 visibleSpotLightsCount = 0; ///< Both shadow and not
  138. ShaderTile* shaderTiles = nullptr; ///< Mapped UBO
  139. U32 maxLightsPerTile = 0;
  140. Is* is = nullptr;
  141. void operator()(U threadId, U threadsCount)
  142. {
  143. U64 start, end;
  144. choseStartEnd(threadId, threadsCount,
  145. Tiler::TILES_X_COUNT * Tiler::TILES_Y_COUNT, start, end);
  146. for(U32 i = start; i < end; i++)
  147. {
  148. ShaderTile& stile = shaderTiles[i];
  149. doTile(i, stile);
  150. }
  151. }
  152. /// Do a tile
  153. void doTile(U tileId, ShaderTile& stile)
  154. {
  155. auto& lightIndices = stile.lightIndices;
  156. const Tiler& tiler = is->r->getTiler();
  157. // Point lights
  158. //
  159. U pointLightsInTileCount = 0;
  160. for(U i = 0; i < visiblePointLightsCount; i++)
  161. {
  162. const PointLight& light = *visiblePointLights[i];
  163. if(tiler.test(light.getSphere(), tileId))
  164. {
  165. // Use % to avoid overflows
  166. const U id = pointLightsInTileCount % Is::MAX_LIGHTS_PER_TILE;
  167. lightIndices[id] = i;
  168. ++pointLightsInTileCount;
  169. }
  170. }
  171. stile.lightsCount[0] = pointLightsInTileCount;
  172. // Spot lights
  173. //
  174. U spotLightsInTileCount = 0;
  175. U spotLightsShadowInTileCount = 0;
  176. for(U i = 0; i < visibleSpotLightsCount; i++)
  177. {
  178. const SpotLight& light = *visibleSpotLights[i];
  179. if(tiler.test(light.getFrustum(), tileId))
  180. {
  181. const U id = (pointLightsInTileCount + spotLightsInTileCount
  182. + spotLightsShadowInTileCount)
  183. % Is::MAX_LIGHTS_PER_TILE;
  184. // Use % to avoid overflows
  185. lightIndices[id] = i;
  186. if(light.getShadowEnabled())
  187. {
  188. ++spotLightsShadowInTileCount;
  189. }
  190. else
  191. {
  192. ++spotLightsInTileCount;
  193. }
  194. }
  195. }
  196. stile.lightsCount[1] = spotLightsInTileCount;
  197. stile.lightsCount[2] = spotLightsShadowInTileCount;
  198. #if 0
  199. U totalLightsInTileCount = std::min(
  200. pointLightsInTileCount + spotLightsInTileCount
  201. + spotLightsShadowInTileCount,
  202. Is::MAX_LIGHTS_PER_TILE);
  203. if(pointLightsInTileCount + spotLightsInTileCount > maxLightsPerTile)
  204. {
  205. ANKI_LOGW("Too many lights per tile: " << lightsInTileCount);
  206. }
  207. #endif
  208. }
  209. };
  210. //==============================================================================
  211. Is::Is(Renderer* r_)
  212. : RenderingPass(r_), sm(r_)
  213. {}
  214. //==============================================================================
  215. Is::~Is()
  216. {}
  217. //==============================================================================
  218. void Is::init(const RendererInitializer& initializer)
  219. {
  220. try
  221. {
  222. initInternal(initializer);
  223. }
  224. catch(const std::exception& e)
  225. {
  226. throw ANKI_EXCEPTION("Failed to init IS") << e;
  227. }
  228. }
  229. //==============================================================================
  230. void Is::initInternal(const RendererInitializer& initializer)
  231. {
  232. groundLightEnabled = initializer.is.groundLightEnabled;
  233. //
  234. // Init the passes
  235. //
  236. sm.init(initializer);
  237. //
  238. // Load the programs
  239. //
  240. std::string pps =
  241. "#define TILES_X_COUNT " + std::to_string(Tiler::TILES_X_COUNT) + "\n"
  242. "#define TILES_Y_COUNT " + std::to_string(Tiler::TILES_Y_COUNT) + "\n"
  243. "#define RENDERER_WIDTH " + std::to_string(r->getWidth()) + "\n"
  244. "#define RENDERER_HEIGHT " + std::to_string(r->getHeight()) + "\n"
  245. "#define MAX_LIGHTS_PER_TILE " + std::to_string(MAX_LIGHTS_PER_TILE)
  246. + "\n"
  247. "#define MAX_POINT_LIGHTS " + std::to_string(MAX_POINT_LIGHTS) + "\n"
  248. "#define MAX_SPOT_LIGHTS " + std::to_string(MAX_SPOT_LIGHTS) + "\n"
  249. "#define GROUND_LIGHT " + std::to_string(groundLightEnabled) + "\n";
  250. if(sm.getPcfEnabled())
  251. {
  252. pps += "#define PCF 1\n";
  253. }
  254. // point light
  255. lightPassProg.load(ShaderProgramResource::createSrcCodeToCache(
  256. "shaders/IsLpGeneric.glsl", pps.c_str()).c_str());
  257. //
  258. // Create FBOs
  259. //
  260. // IS FBO
  261. Renderer::createFai(r->getWidth(), r->getHeight(), GL_RGB8,
  262. GL_RGB, GL_UNSIGNED_INT, fai);
  263. fbo.create();
  264. fbo.setColorAttachments({&fai});
  265. fbo.setOtherAttachment(GL_DEPTH_ATTACHMENT, r->getMs().getDepthFai());
  266. if(!fbo.isComplete())
  267. {
  268. throw ANKI_EXCEPTION("Fbo not complete");
  269. }
  270. //
  271. // Init the quad
  272. //
  273. static const F32 quadVertCoords[][2] = {{1.0, 1.0}, {0.0, 1.0},
  274. {0.0, 0.0}, {1.0, 0.0}};
  275. quadPositionsVbo.create(GL_ARRAY_BUFFER, sizeof(quadVertCoords),
  276. quadVertCoords, GL_STATIC_DRAW);
  277. static const U16 quadVertIndeces[2][3] =
  278. {{0, 1, 3}, {1, 2, 3}}; // 2 triangles
  279. quadVertIndecesVbo.create(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadVertIndeces),
  280. quadVertIndeces, GL_STATIC_DRAW);
  281. quadVao.create();
  282. quadVao.attachArrayBufferVbo(
  283. &quadPositionsVbo, 0, 2, GL_FLOAT, false, 0, 0);
  284. quadVao.attachElementArrayBufferVbo(&quadVertIndecesVbo);
  285. //
  286. // Create UBOs
  287. //
  288. // Common UBO
  289. commonUbo.create(sizeof(ShaderCommonUniforms), nullptr);
  290. // lights UBO
  291. pointLightsUbo.create(sizeof(ShaderPointLights), nullptr);
  292. spotLightsUbo.create(sizeof(ShaderSpotLights), nullptr);
  293. // lightIndices UBO
  294. tilesUbo.create(sizeof(ShaderTiles), nullptr);
  295. // Sanity checks
  296. const ShaderProgramUniformBlock* ublock;
  297. ublock = &lightPassProg->findUniformBlock("commonBlock");
  298. if(ublock->getSize() != sizeof(ShaderCommonUniforms)
  299. || ublock->getBinding() != COMMON_UNIFORMS_BLOCK_BINDING)
  300. {
  301. throw ANKI_EXCEPTION("Problem with the commonBlock");
  302. }
  303. ublock = &lightPassProg->findUniformBlock("pointLightsBlock");
  304. if(ublock->getSize() != sizeof(ShaderPointLights)
  305. || ublock->getBinding() != POINT_LIGHTS_BLOCK_BINDING)
  306. {
  307. throw ANKI_EXCEPTION("Problem with the pointLightsBlock");
  308. }
  309. ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
  310. if(ublock->getSize() != sizeof(ShaderSpotLights)
  311. || ublock->getBinding() != SPOT_LIGHTS_BLOCK_BINDING)
  312. {
  313. throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
  314. }
  315. ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
  316. if(ublock->getSize() != sizeof(ShaderSpotLights)
  317. || ublock->getBinding() != SPOT_LIGHTS_BLOCK_BINDING)
  318. {
  319. throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
  320. }
  321. ublock = &lightPassProg->findUniformBlock("tilesBlock");
  322. if(ublock->getSize() != sizeof(ShaderTiles)
  323. || ublock->getBinding() != TILES_BLOCK_BINDING)
  324. {
  325. throw ANKI_EXCEPTION("Problem with the tilesBlock");
  326. }
  327. }
  328. //==============================================================================
  329. void Is::lightPass()
  330. {
  331. ThreadPool& threadPool = ThreadPoolSingleton::get();
  332. VisibilityTestResults& vi =
  333. *cam->getFrustumable()->getVisibilityTestResults();
  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. lightPassProg->findUniformVariable("limitsOfNearPlane").set(
  479. Vec4(r->getLimitsOfNearPlane(), r->getLimitsOfNearPlane2()));
  480. commonUbo.setBinding(COMMON_UNIFORMS_BLOCK_BINDING);
  481. pointLightsUbo.setBinding(POINT_LIGHTS_BLOCK_BINDING);
  482. spotLightsUbo.setBinding(SPOT_LIGHTS_BLOCK_BINDING);
  483. tilesUbo.setBinding(TILES_BLOCK_BINDING);
  484. lightPassProg->findUniformVariable("msFai0").set(r->getMs().getFai0());
  485. lightPassProg->findUniformVariable("msDepthFai").set(
  486. r->getMs().getDepthFai());
  487. lightPassProg->findUniformVariable("shadowMapArr").set(sm.sm2DArrayTex);
  488. quadVao.bind();
  489. glDrawElementsInstanced(GL_TRIANGLES, 2 * 3, GL_UNSIGNED_SHORT, 0,
  490. Tiler::TILES_Y_COUNT * Tiler::TILES_X_COUNT);
  491. }
  492. //==============================================================================
  493. void Is::run()
  494. {
  495. SceneGraph& scene = r->getSceneGraph();
  496. cam = &scene.getActiveCamera();
  497. GlStateSingleton::get().disable(GL_BLEND);
  498. // Ground light direction
  499. Vec3 groundLightDir;
  500. if(groundLightEnabled)
  501. {
  502. groundLightDir = cam->getViewMatrix().getColumn(1).xyz();
  503. }
  504. // Write common block
  505. if(commonUboUpdateTimestamp < r->getPlanesUpdateTimestamp()
  506. || commonUboUpdateTimestamp < scene.getAmbientColorUpdateTimestamp()
  507. || commonUboUpdateTimestamp == 1
  508. || (groundLightEnabled
  509. && !groundVectorsEqual(groundLightDir, prevGroundLightDir)))
  510. {
  511. ShaderCommonUniforms blk;
  512. blk.planes = Vec4(r->getPlanes().x(), r->getPlanes().y(), 0.0, 0.0);
  513. blk.sceneAmbientColor = Vec4(scene.getAmbientColor(), 0.0);
  514. if(groundLightEnabled)
  515. {
  516. blk.groundLightDir = Vec4(groundLightDir, 1.0);
  517. prevGroundLightDir = groundLightDir;
  518. }
  519. commonUbo.write(&blk);
  520. commonUboUpdateTimestamp = Timestamp::getTimestamp();
  521. }
  522. // Do the light pass including the shadow passes
  523. lightPass();
  524. }
  525. } // end namespace anki