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

Author Topic: Transparency of glowing Point (Fragment-Shader)  (Read 5017 times)

0 Members and 1 Guest are viewing this topic.

Grundkurs

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
Transparency of glowing Point (Fragment-Shader)
« on: November 18, 2015, 01:57:17 pm »
Hey Folks,
currently im working on getting laser-shots in my game to glow.
My approach is to pass a vec2 containing the position of the laser to a fragment-shader.
At that position i create a glowing Point, so on the screen it looks like there's a glowing laser-shot at the particular position.
This looks ok for now and works fine: The point gets drawn at the correct positions and moves as expected.


The fragment-shader for this is:

uniform vec2 resolution;
uniform vec2 laserPos;

float R = 0.97;
float G = 0.77;
float B = 0.40;

void main() {

    vec2 q = gl_FragCoord.xy / resolution.xy;
    vec2 laserPos = laserPos / resolution;

    // "-1" transfers mouse.y to SFML-coordinate-system aligned position
    vec2 r = vec2(q.x - laserPos.x , q.y + laserPos.y - 1.);

    //size of radius    
        float col = 0.002 / length(r);


    gl_FragColor = vec4(col * R, col * G, col * B, 1.);

}

However my problem is, that if i create a sf::RectangleShape with the size of the window to draw the fragmentShader to, its drawn all black except the glowing point itsself.
So if i have a background-image that is drawn just before the rectangleShape, you can't see it because the rectangleShape paints the whole screen black except the glowing point.
How could i just draw the glowing point without all the blackness around it?
is my fragment-Shader flawed because it paints everything black or do i use the wrong "tool" on SFML-side to get the yellow-painted Glow drawn without anything else?
Unfortunately i ran out of ideas on this and hope someone may has some hint for me.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Transparency of glowing Point (Fragment-Shader)
« Reply #1 on: November 18, 2015, 02:10:39 pm »
Short answer: clamping "col" to 0 and using it as the alpha of gl_FragColor (with fixed RGB components) should do the trick.

But... you're drawing the full screen for a small laser shot. Looks like overkill. Why don't you simply use a sprite that you move around? What's the advantage of using a fragment shader here?
Laurent Gomila - SFML developer

Grundkurs

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
Re: Transparency of glowing Point (Fragment-Shader)
« Reply #2 on: November 18, 2015, 02:39:24 pm »
i changed the last line in the fragment-shader to:
gl_FragColor = vec4(col * R, col * G, col * B, clamp(col, 0.,col));
and it instantly worked, the black background dissapeared but the glow stays the same, thanks a lot Laurent, you saved my day!
 
I took this approach for two reasons: The first is "personal", i just discovered the world of shaders in SFML and im fiddeling with it and checking stuff out how it may improve the graphics of my game, so i was curious about getting the glowing done with shaders instead using an already prepared texture bound to a sprite.

the other reason is that there will be a lot of "projectiles" involved, so i was thinking about just book-keeping the position of each shot instead the whole sprite  and let the graphics card visualize every position. I don't know if this will gain performance, i just want to try if i can get it done. Maybe with a sf::VertexArray holding the position of every lasershot and drawing them all at once. I have to check out which approach is suitable, however i made a small step forward today, thanks again.

Grundkurs

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
Re: Transparency of glowing Point (Fragment-Shader)
« Reply #3 on: November 19, 2015, 11:07:33 pm »
today i tried to get the fragment shader to draw multiple lasershots at different positions at the same time.
this is how it looks like:

i just love it!
However i noticed a heavy fps-drop when shooting some more of those little lasers.
so i refactored the program using sprites and textures (as suggested by Laurent).
I created a small laser-texture and tried to get is as close as possible to the shader-variant i already got.
It looks like this:

The performance-difference is quite drastic:
shader-version: 61 fps at 0 shots
shader-version: 37 fps  at 100 shots

texture-version: 61 fps at 0 shots
texture-version: 61 fps at 1860 shots

Basically after 100 Shots i lost almost half of the performance :-(
i implemented the shader-based solution basically this way:
main.cpp
int main(){
    sf::RenderWindow window(sf::VideoMode(800, 600), "Radial Gradient", sf::Style::Default);

    //the rect thats used for drawing the shader
    sf::VertexArray renderRect{sf::PrimitiveType::Quads, 4 };
    renderRect.append(sf::Vertex{sf::Vector2f{0.f,0.f}});
    renderRect.append(sf::Vertex{sf::Vector2f{0.f,600.f}});
    renderRect.append(sf::Vertex{sf::Vector2f{800.f,600.f}});
    renderRect.append(sf::Vertex{sf::Vector2f{800.f,0.f}});
   
    sf::Sprite playerSpaceship;
    std::vector<Projectile> projectiles;
//...
//...some setup-code
//...
   
   
    if(keyPressed()) projectiles.push_back(Projectile{sf::Vector2f{playerSpaceship.getPosition()},renderRect, shader});

    for(auto& i: projectiles) {
        i.update(sf::seconds(fixedFrameTime));
    }


    window.clear(sf::Color{0,40,60,255});
    for(auto& i: projectiles) {
            window.draw(i);
        }
        window.draw(sprite);
        window.display();
    }

    return EXIT_SUCCESS;
}
Projectile.hpp
class Projectile : public sf::Drawable{
    public:
    Projectile(sf::Vector2f position, sf::VertexArray& rect, sf::Shader& shader);
    void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
    void update(const sf::Time& dt);
private:
    sf::VertexArray&                mRectShape;
    sf::Shader&                     mShader;
    sf::Vector2f                    mPosition;
};
Projectile.cpp
Projectile::Projectile(sf::Vector2f position, sf::VertexArray& rect, sf::Shader& shader)
    : mPosition(position), mRectShape(rect),mShader(shader)   {}

void Projectile::draw(sf::RenderTarget& target, sf::RenderStates states) const {
    states.shader = &mShader;

    mShader.setParameter("laserPos", mPosition);
    mShader.setParameter("resolution", sf::Vector2f{800.f,600.f});
    target.draw(mRectShape, states);
}

void Projectile::update(const sf::Time &dt) {
    mPosition.y -= 50.f * dt.asSeconds();
}

the bottleneck seems to be drawing the sf::VertexArray for each projectile. Exchanging the sf::VertexArray with a sf::RectangleShape has the same effect on performance. Drawing the sf::VertexArray or sf::RectangleShape without any Shader-Calculations (like: target.draw(rectShape) omitting "states" as an Argument) has the same performance-consuming effect, so im pretty sure the performance drop is due to the overall design using one sf::RectangleShape /sf::VertexShape for drawing alle the projectiles :-/
« Last Edit: November 20, 2015, 09:17:27 am by Grundkurs »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Transparency of glowing Point (Fragment-Shader)
« Reply #4 on: November 20, 2015, 07:44:54 am »
You're drawing one full-screen quad with fragment shader for each little projectile. This is really the most inefficient implementation that you could find ;)
Laurent Gomila - SFML developer

Grundkurs

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
Re: Transparency of glowing Point (Fragment-Shader)
« Reply #5 on: November 20, 2015, 09:15:07 am »
your post got me the idea to check out a just smaller "quad". So instead of one giant 800 x 600 Rect i pass around and draw for every single shot i tried another approach, exchanging the Rect with a small CircleShape (100 x 100 px). Every Projectile has now its own sf::CircleShape entity that is beeing used for drawing the laser-Glow.
I pass the position of the circleShape to the shader, so the laser is beeing drawn to the correct position of the circleShape.
Performance finally drastically improved :-)
glsl-version: 61 fps at 0 shots
glsl-version: 61 fps at 1870 shots.
thanks again for the good hints Laurent!
 
« Last Edit: November 20, 2015, 11:22:04 am by Grundkurs »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Transparency of glowing Point (Fragment-Shader)
« Reply #6 on: November 20, 2015, 09:25:22 am »
You'd have better performances with a rectangle (circles are made of tenths of triangles, a rectangle is made of two). And then... yeah, it still doesn't make much sense to use a fragment shader instead of a texture in this case, but I guess you're just trying things and having fun ;)
Laurent Gomila - SFML developer