Lf.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include "anki/renderer/Lf.h"
  2. #include "anki/renderer/Renderer.h"
  3. #include "anki/scene/SceneGraph.h"
  4. #include "anki/scene/Movable.h"
  5. #include "anki/scene/Camera.h"
  6. #include "anki/scene/Light.h"
  7. namespace anki {
  8. //==============================================================================
  9. // Misc =
  10. //==============================================================================
  11. // Some constants
  12. #define ANKI_MAX_LIGHTS_WITH_FLARE 16
  13. #define ANKI_MAX_FLARES_PER_LIGHT 8
  14. #define ANKI_MAX_FLARES (ANKI_MAX_LIGHTS_WITH_FLARE * ANKI_MAX_FLARES_PER_LIGHT)
  15. //==============================================================================
  16. struct Flare
  17. {
  18. Vec2 pos; ///< Position in NDC
  19. Vec2 scale; ///< Scale of the quad
  20. F32 alpha; ///< Alpha value
  21. F32 depth; ///< Texture depth
  22. U32 padding[2];
  23. };
  24. //==============================================================================
  25. struct LightSortFunctor
  26. {
  27. Bool operator()(const Light* lightA, const Light* lightB)
  28. {
  29. ANKI_ASSERT(lightA && lightB);
  30. ANKI_ASSERT(lightA->hasLensFlare() && lightB->hasLensFlare());
  31. return lightA->getLensFlareTexture().getGlId() <
  32. lightB->getLensFlareTexture().getGlId();
  33. }
  34. };
  35. //==============================================================================
  36. // Lf =
  37. //==============================================================================
  38. //==============================================================================
  39. Lf::~Lf()
  40. {}
  41. //==============================================================================
  42. void Lf::init(const RendererInitializer& initializer)
  43. {
  44. try
  45. {
  46. initInternal(initializer);
  47. }
  48. catch(const std::exception& e)
  49. {
  50. throw ANKI_EXCEPTION("Failed to init LF") << e;
  51. }
  52. }
  53. //==============================================================================
  54. void Lf::initInternal(const RendererInitializer& initializer)
  55. {
  56. enabled = initializer.get("pps.lf.enabled")
  57. && initializer.get("pps.hdr.enabled");
  58. if(!enabled)
  59. {
  60. return;
  61. }
  62. maxFlaresPerLight = initializer.get("pps.lf.maxFlaresPerLight");
  63. maxLightsWithFlares = initializer.get("pps.lf.maxLightsWithFlares");
  64. // Load program 1
  65. std::string pps = "#define TEX_DIMENSIONS vec2("
  66. + std::to_string(r->getPps().getHdr().getFai().getWidth()) + ".0, "
  67. + std::to_string(r->getPps().getHdr().getFai().getHeight()) + ".0)\n";
  68. pseudoProg.load(ShaderProgramResource::createSrcCodeToCache(
  69. "shaders/PpsLfPseudoPass.glsl", pps.c_str(), "r_").c_str());
  70. // Load program 2
  71. pps = "#define MAX_FLARES "
  72. + std::to_string(maxFlaresPerLight * maxLightsWithFlares) + "\n";
  73. std::string fname = ShaderProgramResource::createSrcCodeToCache(
  74. "shaders/PpsLfSpritePass.glsl", pps.c_str(), "r_");
  75. realProg.load(fname.c_str());
  76. ublock = &realProg->findUniformBlock("flaresBlock");
  77. ublock->setBinding(0);
  78. PtrSize blockSize = sizeof(Flare) * maxFlaresPerLight * maxLightsWithFlares;
  79. if(ublock->getSize() != blockSize)
  80. {
  81. throw ANKI_EXCEPTION("Incorrect block size");
  82. }
  83. // Init UBO
  84. flareDataUbo.create(blockSize, nullptr);
  85. // Create the FAI
  86. fai.create2dFai(r->getPps().getHdr().getFai().getWidth(),
  87. r->getPps().getHdr().getFai().getHeight(),
  88. GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
  89. fbo.create();
  90. fbo.setColorAttachments({&fai});
  91. if(!fbo.isComplete())
  92. {
  93. throw ANKI_EXCEPTION("Fbo not complete");
  94. }
  95. // Textures
  96. lensDirtTex.load("engine_data/lens_dirt.ankitex");
  97. }
  98. //==============================================================================
  99. void Lf::run()
  100. {
  101. ANKI_ASSERT(enabled);
  102. //
  103. // First pass
  104. //
  105. // Set the common state
  106. const Texture& inTex = r->getPps().getHdr().getFai();
  107. fbo.bind();
  108. pseudoProg->bind();
  109. pseudoProg->findUniformVariable("tex").set(inTex);
  110. pseudoProg->findUniformVariable("lensDirtTex").set(*lensDirtTex);
  111. GlStateSingleton::get().setViewport(
  112. 0, 0, inTex.getWidth(), inTex.getHeight());
  113. GlStateSingleton::get().disable(GL_DEPTH_TEST);
  114. GlStateSingleton::get().disable(GL_BLEND);
  115. r->drawQuad();
  116. //
  117. // Rest of the passes
  118. //
  119. // Retrieve some things
  120. SceneGraph& scene = r->getSceneGraph();
  121. Camera& cam = scene.getActiveCamera();
  122. VisibilityTestResults& vi = *cam.getVisibilityTestResults();
  123. // Iterate the visible light and get those that have lens flare
  124. Array<Light*, ANKI_MAX_LIGHTS_WITH_FLARE> lights;
  125. U lightsCount = 0;
  126. for(auto it = vi.getLightsBegin(); it != vi.getLightsEnd(); ++it)
  127. {
  128. SceneNode& sn = *(*it).node;
  129. ANKI_ASSERT(sn.getLight());
  130. Light* light = sn.getLight();
  131. if(light->hasLensFlare())
  132. {
  133. lights[lightsCount % maxLightsWithFlares] = light;
  134. ++lightsCount;
  135. }
  136. }
  137. // Early exit
  138. if(lightsCount == 0)
  139. {
  140. return;
  141. }
  142. lightsCount = lightsCount % (maxLightsWithFlares + 1);
  143. // Sort the lights using their lens flare texture
  144. std::sort(lights.begin(), lights.begin() + lightsCount, LightSortFunctor());
  145. // Write the UBO and get the groups
  146. //
  147. Array<Flare, ANKI_MAX_FLARES> flares;
  148. U flaresCount = 0;
  149. // Contains the number of flares per flare texture
  150. Array<U, ANKI_MAX_LIGHTS_WITH_FLARE> groups;
  151. Array<const Texture*, ANKI_MAX_LIGHTS_WITH_FLARE> texes;
  152. U groupsCount = 0;
  153. GLuint lastTexId = 0;
  154. // Iterate all lights and update the flares as well as the groups
  155. while(lightsCount-- != 0)
  156. {
  157. Light& light = *lights[lightsCount];
  158. const Texture& tex = light.getLensFlareTexture();
  159. const U depth = tex.getDepth();
  160. // Transform
  161. Vec3 posWorld = light.getWorldTransform().getOrigin();
  162. Vec4 posClip = cam.getViewProjectionMatrix() * Vec4(posWorld, 1.0);
  163. if(posClip.x() > posClip.w() || posClip.x() < -posClip.w()
  164. || posClip.y() > posClip.w() || posClip.y() < -posClip.w())
  165. {
  166. continue;
  167. }
  168. Vec2 posNdc = posClip.xy() / posClip.w();
  169. Vec2 dir = -posNdc;
  170. F32 len = dir.getLength();
  171. dir /= len; // Normalize dir
  172. // New group?
  173. if(lastTexId != tex.getGlId())
  174. {
  175. texes[groupsCount] = &tex;
  176. groups[groupsCount] = 0;
  177. lastTexId = tex.getGlId();
  178. ++groupsCount;
  179. }
  180. // First flare
  181. F32 stretchFactor = 1.0 - posNdc.getLength();
  182. stretchFactor *= stretchFactor;
  183. Vec2 stretch = light.getLensFlaresStretchMultiplier() * stretchFactor;
  184. flares[flaresCount].pos = posNdc;
  185. flares[flaresCount].scale =
  186. light.getLensFlaresSize() * Vec2(1.0, r->getAspectRatio())
  187. * stretch;
  188. flares[flaresCount].depth = 0.0;
  189. flares[flaresCount].alpha = light.getLensFlaresAlpha() * stretchFactor;
  190. ++flaresCount;
  191. ++groups[groupsCount - 1];
  192. // The rest of the flares
  193. for(U d = 1; d < depth; d++)
  194. {
  195. // Write the "flares"
  196. F32 factor = d / ((F32)depth - 1.0);
  197. F32 flen = len * 2.0 * factor;
  198. flares[flaresCount].pos = posNdc + dir * flen;
  199. flares[flaresCount].scale =
  200. light.getLensFlaresSize() * Vec2(1.0, r->getAspectRatio())
  201. * ((len - flen) * 2.0);
  202. flares[flaresCount].depth = d;
  203. flares[flaresCount].alpha = light.getLensFlaresAlpha();
  204. // Advance
  205. ++flaresCount;
  206. ++groups[groupsCount - 1];
  207. }
  208. }
  209. // Time to render
  210. //
  211. // Write the buffer
  212. flareDataUbo.write(&flares[0], 0, sizeof(Flare) * flaresCount);
  213. // Set the common state
  214. realProg->bind();
  215. GlStateSingleton::get().disable(GL_DEPTH_TEST);
  216. GlStateSingleton::get().enable(GL_BLEND);
  217. GlStateSingleton::get().setBlendFunctions(GL_ONE, GL_ONE);
  218. PtrSize offset = 0;
  219. for(U i = 0; i < groupsCount; i++)
  220. {
  221. const Texture& tex = *texes[i];
  222. U instances = groups[i];
  223. PtrSize buffSize = sizeof(Flare) * instances;
  224. realProg->findUniformVariable("images").set(tex);
  225. flareDataUbo.setBindingRange(0, offset, buffSize);
  226. r->drawQuadInstanced(instances);
  227. offset += buffSize;
  228. }
  229. }
  230. } // end namespace anki