| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- #include "anki/renderer/Lf.h"
- #include "anki/renderer/Renderer.h"
- #include "anki/scene/SceneGraph.h"
- #include "anki/scene/Movable.h"
- #include "anki/scene/Camera.h"
- #include "anki/scene/Light.h"
- namespace anki {
- //==============================================================================
- // Misc =
- //==============================================================================
- // Some constants
- #define ANKI_MAX_LIGHTS_WITH_FLARE 16
- #define ANKI_MAX_FLARES_PER_LIGHT 8
- #define ANKI_MAX_FLARES (ANKI_MAX_LIGHTS_WITH_FLARE * ANKI_MAX_FLARES_PER_LIGHT)
- //==============================================================================
- struct Flare
- {
- Vec2 pos; ///< Position in NDC
- Vec2 scale; ///< Scale of the quad
- F32 alpha; ///< Alpha value
- F32 depth; ///< Texture depth
- U32 padding[2];
- };
- //==============================================================================
- struct LightSortFunctor
- {
- Bool operator()(const Light* lightA, const Light* lightB)
- {
- ANKI_ASSERT(lightA && lightB);
- ANKI_ASSERT(lightA->hasLensFlare() && lightB->hasLensFlare());
- return lightA->getLensFlareTexture().getGlId() <
- lightB->getLensFlareTexture().getGlId();
- }
- };
- //==============================================================================
- // Lf =
- //==============================================================================
- //==============================================================================
- Lf::~Lf()
- {}
- //==============================================================================
- void Lf::init(const RendererInitializer& initializer)
- {
- try
- {
- initInternal(initializer);
- }
- catch(const std::exception& e)
- {
- throw ANKI_EXCEPTION("Failed to init LF") << e;
- }
- }
- //==============================================================================
- void Lf::initInternal(const RendererInitializer& initializer)
- {
- enabled = initializer.get("pps.lf.enabled")
- && initializer.get("pps.hdr.enabled");
- if(!enabled)
- {
- return;
- }
- maxFlaresPerLight = initializer.get("pps.lf.maxFlaresPerLight");
- maxLightsWithFlares = initializer.get("pps.lf.maxLightsWithFlares");
- // Load program 1
- std::string pps = "#define TEX_DIMENSIONS vec2("
- + std::to_string(r->getPps().getHdr().getFai().getWidth()) + ".0, "
- + std::to_string(r->getPps().getHdr().getFai().getHeight()) + ".0)\n";
- pseudoProg.load(ShaderProgramResource::createSrcCodeToCache(
- "shaders/PpsLfPseudoPass.glsl", pps.c_str(), "r_").c_str());
- // Load program 2
- pps = "#define MAX_FLARES "
- + std::to_string(maxFlaresPerLight * maxLightsWithFlares) + "\n";
- std::string fname = ShaderProgramResource::createSrcCodeToCache(
- "shaders/PpsLfSpritePass.glsl", pps.c_str(), "r_");
- realProg.load(fname.c_str());
- ublock = &realProg->findUniformBlock("flaresBlock");
- ublock->setBinding(0);
- PtrSize blockSize = sizeof(Flare) * maxFlaresPerLight * maxLightsWithFlares;
- if(ublock->getSize() != blockSize)
- {
- throw ANKI_EXCEPTION("Incorrect block size");
- }
- // Init UBO
- flareDataUbo.create(blockSize, nullptr);
- // Create the FAI
- fai.create2dFai(r->getPps().getHdr().getFai().getWidth(),
- r->getPps().getHdr().getFai().getHeight(),
- GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
- fbo.create();
- fbo.setColorAttachments({&fai});
- if(!fbo.isComplete())
- {
- throw ANKI_EXCEPTION("Fbo not complete");
- }
- // Textures
- lensDirtTex.load("engine_data/lens_dirt.ankitex");
- }
- //==============================================================================
- void Lf::run()
- {
- ANKI_ASSERT(enabled);
- //
- // First pass
- //
- // Set the common state
- const Texture& inTex = r->getPps().getHdr().getFai();
- fbo.bind();
- pseudoProg->bind();
- pseudoProg->findUniformVariable("tex").set(inTex);
- pseudoProg->findUniformVariable("lensDirtTex").set(*lensDirtTex);
- GlStateSingleton::get().setViewport(
- 0, 0, inTex.getWidth(), inTex.getHeight());
- GlStateSingleton::get().disable(GL_DEPTH_TEST);
- GlStateSingleton::get().disable(GL_BLEND);
- r->drawQuad();
- //
- // Rest of the passes
- //
- // Retrieve some things
- SceneGraph& scene = r->getSceneGraph();
- Camera& cam = scene.getActiveCamera();
- VisibilityTestResults& vi = *cam.getVisibilityTestResults();
- // Iterate the visible light and get those that have lens flare
- Array<Light*, ANKI_MAX_LIGHTS_WITH_FLARE> lights;
- U lightsCount = 0;
- for(auto it = vi.getLightsBegin(); it != vi.getLightsEnd(); ++it)
- {
- SceneNode& sn = *(*it).node;
- ANKI_ASSERT(sn.getLight());
- Light* light = sn.getLight();
- if(light->hasLensFlare())
- {
- lights[lightsCount % maxLightsWithFlares] = light;
- ++lightsCount;
- }
- }
- // Early exit
- if(lightsCount == 0)
- {
- return;
- }
- lightsCount = lightsCount % (maxLightsWithFlares + 1);
- // Sort the lights using their lens flare texture
- std::sort(lights.begin(), lights.begin() + lightsCount, LightSortFunctor());
- // Write the UBO and get the groups
- //
- Array<Flare, ANKI_MAX_FLARES> flares;
- U flaresCount = 0;
- // Contains the number of flares per flare texture
- Array<U, ANKI_MAX_LIGHTS_WITH_FLARE> groups;
- Array<const Texture*, ANKI_MAX_LIGHTS_WITH_FLARE> texes;
- U groupsCount = 0;
- GLuint lastTexId = 0;
- // Iterate all lights and update the flares as well as the groups
- while(lightsCount-- != 0)
- {
- Light& light = *lights[lightsCount];
- const Texture& tex = light.getLensFlareTexture();
- const U depth = tex.getDepth();
- // Transform
- Vec3 posWorld = light.getWorldTransform().getOrigin();
- Vec4 posClip = cam.getViewProjectionMatrix() * Vec4(posWorld, 1.0);
- if(posClip.x() > posClip.w() || posClip.x() < -posClip.w()
- || posClip.y() > posClip.w() || posClip.y() < -posClip.w())
- {
- continue;
- }
- Vec2 posNdc = posClip.xy() / posClip.w();
- Vec2 dir = -posNdc;
- F32 len = dir.getLength();
- dir /= len; // Normalize dir
- // New group?
- if(lastTexId != tex.getGlId())
- {
- texes[groupsCount] = &tex;
- groups[groupsCount] = 0;
- lastTexId = tex.getGlId();
- ++groupsCount;
- }
- // First flare
- F32 stretchFactor = 1.0 - posNdc.getLength();
- stretchFactor *= stretchFactor;
- Vec2 stretch = light.getLensFlaresStretchMultiplier() * stretchFactor;
- flares[flaresCount].pos = posNdc;
- flares[flaresCount].scale =
- light.getLensFlaresSize() * Vec2(1.0, r->getAspectRatio())
- * stretch;
- flares[flaresCount].depth = 0.0;
- flares[flaresCount].alpha = light.getLensFlaresAlpha() * stretchFactor;
- ++flaresCount;
- ++groups[groupsCount - 1];
- // The rest of the flares
- for(U d = 1; d < depth; d++)
- {
- // Write the "flares"
- F32 factor = d / ((F32)depth - 1.0);
- F32 flen = len * 2.0 * factor;
- flares[flaresCount].pos = posNdc + dir * flen;
- flares[flaresCount].scale =
- light.getLensFlaresSize() * Vec2(1.0, r->getAspectRatio())
- * ((len - flen) * 2.0);
- flares[flaresCount].depth = d;
- flares[flaresCount].alpha = light.getLensFlaresAlpha();
- // Advance
- ++flaresCount;
- ++groups[groupsCount - 1];
- }
- }
- // Time to render
- //
- // Write the buffer
- flareDataUbo.write(&flares[0], 0, sizeof(Flare) * flaresCount);
- // Set the common state
- realProg->bind();
- GlStateSingleton::get().disable(GL_DEPTH_TEST);
- GlStateSingleton::get().enable(GL_BLEND);
- GlStateSingleton::get().setBlendFunctions(GL_ONE, GL_ONE);
- PtrSize offset = 0;
- for(U i = 0; i < groupsCount; i++)
- {
- const Texture& tex = *texes[i];
- U instances = groups[i];
- PtrSize buffSize = sizeof(Flare) * instances;
- realProg->findUniformVariable("images").set(tex);
- flareDataUbo.setBindingRange(0, offset, buffSize);
-
- r->drawQuadInstanced(instances);
- offset += buffSize;
- }
- }
- } // end namespace anki
|