Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: SFML Light System - Let There Be Light  (Read 229313 times)

0 Members and 1 Guest are viewing this topic.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: SFML Light System - Let There Be Light
« Reply #345 on: November 20, 2014, 04:35:59 pm »
Is this the example code?

/*
        Let There Be Light
        Copyright (C) 2012 Eric Laukien

        This software is provided 'as-is', without any express or implied
        warranty.  In no event will the authors be held liable for any damages
        arising from the use of this software.

        Permission is granted to anyone to use this software for any purpose,
        including commercial applications, and to alter it and redistribute it
        freely, subject to the following restrictions:

        1. The origin of this software must not be misrepresented; you must not
                claim that you wrote the original software. If you use this software
                in a product, an acknowledgment in the product documentation would be
                appreciated but is not required.
        2. Altered source versions must be plainly marked as such, and must not be
                misrepresented as being the original software.
        3. This notice may not be removed or altered from any source distribution.
*/


#include <LTBL/Light/LightSystem.h>
#include <LTBL/Light/Light_Point.h>
#include <LTBL/Utils.h>

#include <assert.h>

#include <SFML/Graphics.hpp>

#include <sstream>

int main(int argc, char* args[])
{
        sf::VideoMode vidMode;
        vidMode.width = 800;
        vidMode.height = 600;
        vidMode.bitsPerPixel = 32;
        assert(vidMode.isValid());

        sf::RenderWindow win;
        win.create(vidMode, "Let there be Light - Demo");

        sf::View view;
        sf::Vector2u windowSize(win.getSize());
        view.setSize(sf::Vector2f(static_cast<float>(windowSize.x), static_cast<float>(windowSize.y)));
        view.setCenter(view.getSize() / 2.0f);

        // ---------------------- Background Image ---------------------

        sf::Texture backgroundImage;

        assert(backgroundImage.loadFromFile("data/background.png"));

        // Tiling background
        backgroundImage.setRepeated(true);

        sf::Sprite backgroundSprite(backgroundImage);
        backgroundSprite.setTextureRect(sf::IntRect(0, 0, vidMode.width * 2, vidMode.height * 2));
        backgroundSprite.setPosition(-400.0f, -400.0f);

        // --------------------- Light System Setup ---------------------

        ltbl::LightSystem ls(AABB(Vec2f(0.0f, 0.0f), Vec2f(static_cast<float>(vidMode.width), static_cast<float>(vidMode.height))), &win, "data/lightFin.png", "data/shaders/lightAttenuationShader.frag");

        // Create a light
        ltbl::Light_Point* testLight = new ltbl::Light_Point();
        testLight->m_intensity = 2.0f;
        testLight->m_center = Vec2f(200.0f, 200.0f);
        testLight->m_radius = 600.0f;
        testLight->m_size = 15.0f;
        testLight->m_spreadAngle = ltbl::pifTimes2;
        testLight->m_softSpreadAngle = 0.0f;
        testLight->CalculateAABB();

        testLight->m_bleed = 0.4f;
        testLight->m_linearizeFactor = 0.2f;

        ls.AddLight(testLight);

        testLight->SetAlwaysUpdate(true);

        // Create a light
        ltbl::Light_Point* testLight2 = new ltbl::Light_Point();
        testLight2->m_center = Vec2f(200.0f, 200.0f);
        testLight2->m_radius = 500.0f;
        testLight2->m_size = 30.0f;
        testLight2->m_color.r = 0.5f;
        testLight2->m_intensity = 1.5f;
        testLight2->m_spreadAngle = ltbl::pifTimes2;
        testLight2->m_softSpreadAngle = 0.0f;
        testLight2->CalculateAABB();

        ls.AddLight(testLight2);

        testLight2->SetAlwaysUpdate(false);

        // Create an emissive light
        ltbl::EmissiveLight* emissiveLight = new ltbl::EmissiveLight();

        sf::Texture text;

        if(!text.loadFromFile("data/emissive.png"))
                abort();

        emissiveLight->SetTexture(&text);

        emissiveLight->SetRotation(45.0f);

        emissiveLight->m_intensity = 1.3f;

        ls.AddEmissiveLight(emissiveLight);

        emissiveLight->SetCenter(Vec2f(500.0f, 500.0f));

        // Create a hull by loading it from a file
        ltbl::ConvexHull* testHull = new ltbl::ConvexHull();

        if(!testHull->LoadShape("data/testShape.txt"))
                abort();

        // Pre-calculate certain aspects
        testHull->CalculateNormals();
        testHull->CalculateAABB();

        testHull->SetWorldCenter(Vec2f(300.0f, 300.0f));

        testHull->m_renderLightOverHull = true;

        ls.AddConvexHull(testHull);

        // ------------------------- Game Loop --------------------------

        sf::Event eventStructure;

        bool quit = false;

        ls.m_useBloom = true;

        while(!quit)
        {
                while(win.pollEvent(eventStructure))
                        if(eventStructure.type == sf::Event::Closed)
                        {
                                quit = true;
                                break;
                        }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                        view.move(sf::Vector2f(-1.0f, 0.0f));
                else if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                        view.move(sf::Vector2f(1.0f, 0.0f));

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                        view.move(sf::Vector2f(0.0f, -1.0f));
                else if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                        view.move(sf::Vector2f(0.0f, 1.0f));

                sf::Vector2i mousePos = sf::Mouse::getPosition(win);
                //testLight2->IncCenter(ltbl::Vec2f(0.1f, 0.0f));
                // Update light
                testLight->SetCenter(Vec2f(static_cast<float>(mousePos.x), static_cast<float>(vidMode.height) - static_cast<float>(mousePos.y)));

                win.clear();

                win.setView(view);
                ls.SetView(view);

                // Draw the background
                win.draw(backgroundSprite);

                // Calculate the lights
                ls.RenderLights();

                // Draw the lights
                ls.RenderLightTexture();

                //ls.DebugRender();

                win.display();
        }

        win.close();
}
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: SFML Light System - Let There Be Light
« Reply #346 on: November 20, 2014, 11:58:32 pm »
Thanks eXpl0it3r.
I'm not sure how I missed that before.

I don't think it solves the fundamental problem of the 1.5.1 LTBL / 2.x SFML compatibility issue.  But it should be helpful to myself and others who are trying to get things working.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: SFML Light System - Let There Be Light
« Reply #347 on: November 22, 2014, 11:46:05 am »
I've setup my own repository now. It contains all the "historical" source files from SourceForge and I've updated the code base to make it work with SFML 2.x. Besides making sure the CMake script works and the original example builds and runs fine, I haven't done much more on the code base, so if there were other issues, they'll still exist. Let me know which ones and I can fix them, or you can send in a PR.

Based off the LTBL 1.5.1 code base: https://github.com/eXpl0it3r/LTBL
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: SFML Light System - Let There Be Light
« Reply #348 on: November 22, 2014, 05:03:28 pm »
That's very nice of you. ;)
With no offence to lolz, the LTBL code feels very legacy/weird/unclear:
1. AABB is friend with itself.
2. Redundancy - example closes the window just before end of main, RenderLightTexture resets the blend func before calling resetGLStates etc.
3. Members are often public and named m_...
4. LightSystem calls std::abort if loading something fails.
5. Gratuitous use of GL, especially glBegin/glEnd.
6. Some of constructs (Vec2f and Point2i notably) are kind of useless, yes - lolz said he might want to reuse his quad tree but that would be better done by typedef in the headers instead of making a new incompatible class while this is meant to be an SFML library.

Do you intend to fix stuff like that?
Back to C++ gamedev with SFML in May 2023

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: SFML Light System - Let There Be Light
« Reply #349 on: November 22, 2014, 05:19:52 pm »
Yeah, I've noticed some odd things as well. I'm not really sure, how far I'll go in cleaning things up. I think, I'll try to implement a better error handling that std::abort and fix some other C++ related things, but I don't know, if I'll be touching the OpenGL code. On one hand I've no experience with it and on the other it's legacy OpenGL, not something I want to learn and work with too much. ;)

But I guess if there are others making suggestions and helping out, I'll certainly try to fix things.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: SFML Light System - Let There Be Light
« Reply #350 on: November 22, 2014, 05:39:24 pm »
When cloning your link I immediately get CRLF issue - working directory is not clear:
        modified:   bin/data/background.png
        modified:   bin/data/emissive.png
        modified:   bin/data/lightFin.png
        modified:   doc/manual.pdf
        modified:   license.txt
 
Can you just yourself convert license.txt to LF endings and remove the .gitattributes file?
(Or maybe I will make a pull request for it -- done.)
« Last Edit: November 22, 2014, 05:53:51 pm by FRex »
Back to C++ gamedev with SFML in May 2023

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: SFML Light System - Let There Be Light
« Reply #351 on: November 22, 2014, 06:19:18 pm »
Keep in mind that there is also GLLight2D, the "sequel" to LTBL according to lolz123. GLLight2D seems to take a different approach rather than representing a refactored LTBL, but you might still take it into consideration when extending the work.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: SFML Light System - Let There Be Light
« Reply #352 on: November 23, 2014, 12:57:33 am »
I've setup my own repository now. It contains all the "historical" source files from SourceForge and I've updated the code base to make it work with SFML 2.x. Besides making sure the CMake script works and the original example builds and runs fine, I haven't done much more on the code base, so if there were other issues, they'll still exist. Let me know which ones and I can fix them, or you can send in a PR.

Based off the LTBL 1.5.1 code base: https://github.com/eXpl0it3r/LTBL

THANK YOU!!!

Keep in mind that there is also GLLight2D, the "sequel" to LTBL according to lolz123. GLLight2D seems to take a different approach rather than representing a refactored LTBL, but you might still take it into consideration when extending the work.

LTBL provides significantly different functionality than GLLight2D. 
I can safely say that most users are looking for what LTBL offers, and not GLLight2D.

GLLight2D is a much more technical approach that allows things like global illumination.  But this is generally not the approach you want to take for a real-time application like a video game.  Especially a graphically "simple" 2D game which would otherwise run on lower level hardware.

Basically, it's just not worth the performance hit.

Quote from the GLLight2D post:

For now, GLLight2D is real time @60fps / resolution of 900x600 on a moderate rig and remains dynamic but looks grainy unless you let it sit there and accumulate samples for a bit. If this is unacceptable, you could then just use it for computing static lighting on level load (a 2D light map). That, or you could just use a blur shader and blur away the graininess (although it doesn't look quite as good then).

That performance is very likely unacceptable for many applications.  Remember, that's just GLLight2D, with no other physics/graphics/AI/game logic/etc running.  He specifically points out 900x600 (tiny) because anything larger is going to have even worse performance.

Lightmaps are generally unacceptable for any kind of dynamic lighting scenario, and add a significant complication to your content pipeline.

« Last Edit: November 23, 2014, 01:06:12 am by Jabberwocky »

lolz123

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
Re: SFML Light System - Let There Be Light
« Reply #353 on: November 29, 2014, 07:48:55 am »
Hello everyone,

Due to the apparent demand for a 2D lighting system, I have started finally remaking LTBL, calling it LTBL2. With clean code, vastly superior performance, easier to use, CMake support, directional lights, dynamic quad tree root, and zoomable views that actually work. It also relies exclusively on SFML now. Furthermore, custom light types are super easy to do now (requires no code).

It should be done in 2 to 4 days. I will post here again when it goes up.

Edit: I forgot to add: It can render antumbras now. Here is an image of what that means :)

« Last Edit: November 29, 2014, 07:54:16 am by lolz123 »
Have you heard about the new Cray super computer?  It’s so fast, it executes an infinite loop in 6 seconds.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
AW: SFML Light System - Let There Be Light
« Reply #354 on: November 29, 2014, 11:47:58 am »
Nice! Looking forward to it! :)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: SFML Light System - Let There Be Light
« Reply #355 on: November 29, 2014, 11:54:02 am »
Hi lolz123 -

That's wonderful news!  Thanks for revisiting LTBL, and thanks again to eXpl0it3r for helping out as well.

A couple quick notes I have from working with LTBL1, in case it helps with LTBL2.

1.  Transparent hulls visible seam:
When you use transparent hulls, you can see a visible seam between the main umbra and the shadow fins.  I'm pretty sure I tracked this down to being a problem of the fin tris (created by function MaskShadow) overlapping with the main umbra created in that same function.  The overlap results in the dark seam due to rendering the overlapping alpha-blended geometry.

Transparent hulls are a pretty important feature, as without them the shadows appear completely black, rather than using the ambient color.  So I ended up using hull transparency to work around this.

2.  Static QuadTree crash:
There was a crash associated with the Static QuadTree related to these functions:
Code: [Select]
StaticQuadTree::StaticQuadTree(const AABB &rootRegion)
: m_created(false)
{
m_pRootNode.reset(new QuadTreeNode(rootRegion, 0));

m_created = true;
}

void StaticQuadTree::Create(const AABB &rootRegion)
{
m_pRootNode.reset(new QuadTreeNode(rootRegion, 0));

m_created = true;
}

There are two versions of the QuadTreeNode constructor.  The one used above does not pass in a QuadTree pointer.  So the root node of the StaticQuadTree has an uninitialized m_pQuadTree pointer.

This causes a crash later when Update is called on the StaticQuadTree's root node.

My solution was to change the above code to:

Code: [Select]
StaticQuadTree::StaticQuadTree(const AABB &rootRegion)
: m_created(false)
{
m_pRootNode.reset(new QuadTreeNode(rootRegion, 0, NULL, this));

m_created = true;
}

void StaticQuadTree::Create(const AABB &rootRegion)
{
m_pRootNode.reset(new QuadTreeNode(rootRegion, 0, NULL, this));

m_created = true;
}

3.  Offset shadows
If the view dims don't match the screen dims, the shadows are drawn in the wrong place.
This is solved by making this change in LightSystem::SetUp

Code: [Select]
void LightSystem::SetUp(const AABB &region)
{
// Create the quad trees
m_lightTree.Create(region);
m_hullTree.Create(region);
m_emissiveTree.Create(region);

// Base RT size off of window resolution
// *** CHANGE THIS LINE
// sf::Vector2u viewSizeui(m_pWin->getSize());

// *** TO THIS
sf::Vector2u viewSizeui;
// - adding 0.1f for float imprecision so we don't round down to the lower unsigned int.
viewSizeui.x = (unsigned int)(m_viewAABB.GetDims().x + 0.1f);
viewSizeui.y = (unsigned int)(m_viewAABB.GetDims().y + 0.1f);

For this to work, you must also set the m_viewAABB before setup is called.

4.  Window resizing support

LTBL doesn't handle window resizing.  It would need to hook into the resize event, and recreate the m_compositionTexture at the appropriate size.  I believe this is also necessary for view size changes.

______

I very much appreciate the work you've done with LTBL.
« Last Edit: November 29, 2014, 11:59:44 am by Jabberwocky »

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: SFML Light System - Let There Be Light
« Reply #356 on: November 29, 2014, 12:14:12 pm »
I also have one other issue I've been trying to resolve.
I wanted to ask your advice, if you have time.

My game is top-down.  I want the shadows to draw on the ground, but not overtop other "tall" entities/sprites.

For example, let's say there are two trees by a light.  Currently, LTBL would draw the shadow of the first tree overtop the second tree.  I don't want it to.  I only want the shadow on the ground.

Conceptually, what I'm trying to do is this:

Render loop
1.  Draw the ground, and any "low" entities/sprites which should be shadowed
2.  Render LTBL's shadows
3.  Render any "tall" entities/sprites

That works... but not quite.
The ground properly receives shadows.  Good
The tall entities do not receive shadows.  Good
The tall entities are completely bright, and not affected by the light at all.  Bad.

I think what I need to do is something like this:
1.  Draw the ground, and any "low" entities/sprites which should be shadowed
2.  Render LTBL's light with shadows
3.  Activate a new fullscreen render texture, with a clear alpha transparency
4.  Render any "tall" entities/sprites on this 2nd fullscreen render texture
5.  Render LTBL again on the fullscreen render texture, disabling any hull shadows in this LTBL pass
6.  Render the fullscreen render texture onto the main render window.

This way, the tall entities receive light, but now shadow.
I certainly don't expect you to support this feature for me.  But does this seem like a reasonable approach for me to take?
« Last Edit: November 29, 2014, 12:17:06 pm by Jabberwocky »

lolz123

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
Re: SFML Light System - Let There Be Light
« Reply #357 on: November 29, 2014, 07:19:09 pm »
Hello Jabberwocky,

A similar feature already exists in the original LTBL. It will exist in LTBL2 as well.
On a hull, set m_renderLightOverHull to true. It will make hulls not become shadowed by their own shadow, but can receive shadows from other hulls.

This may not be quite what you are looking for, but I can add what you describe to LTBL2, it shouldn't be too hard.
Have you heard about the new Cray super computer?  It’s so fast, it executes an infinite loop in 6 seconds.

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re: SFML Light System - Let There Be Light
« Reply #358 on: November 30, 2014, 12:47:47 am »
On a hull, set m_renderLightOverHull to true. It will make hulls not become shadowed by their own shadow, but can receive shadows from other hulls.

Thanks lolz123.

Unfortunately that doesn't quite solve the problem, because the hull geometry is always an approximation of the graphics, and doesn't account for any sprite transparency.  In the tree example I gave, the tree canopy has lots of transparency (between the leaves) through which the shadow would need to display on the ground below.

Quote
I can add what you describe to LTBL2, it shouldn't be too hard.

I appreciate the offer!  I'll wait for LTBL2 and see what I can do with that.
« Last Edit: November 30, 2014, 12:58:49 am by Jabberwocky »

 

anything