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

Author Topic: Help with basic fragment-shadered full-screen sprite  (Read 4661 times)

0 Members and 1 Guest are viewing this topic.

exoloner

  • Newbie
  • *
  • Posts: 9
    • View Profile
    • JaK (Freebook)
    • Email
Help with basic fragment-shadered full-screen sprite
« on: February 12, 2019, 02:13:29 pm »
Hello!
I'm trying desperately to run a simply 2D fragment shader, just a starfield, using SFML 2.5 (2018-2019)

It's a pretty minimalistic scenario:

A class that uses fragment shader as an in-game background, and the main() using that class.

The class code implementing this special shadered-backgrounds is this :
#pragma once
#include <SFML/Graphics.hpp>
#include <list>
#include <iterator>
#include <string>
#include <fstream>
#include <streambuf>

#ifndef FONSFX_H
#define FONSFX_H

#include <SFML/Graphics.hpp>

namespace FonsFX
{
        class FonsEfecte
        {
        private:
                sf::Image img;
                sf::Texture tex;
               
                bool ShaderGeom_isOk = false;
                bool ShaderFrag_isOk = false;
        public:
                sf::Sprite sprite;
                sf::Shader sh;         

                FonsEfecte(unsigned int Ample, unsigned int Alt) {
                        img.create(Ample , Alt );
                        tex.loadFromImage(img);
                        sprite.setTexture(tex);
                       
                        std::string CodiSharedQUADFixe = "void main(void)       {       gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;                 }";
                        if (sh.loadFromMemory(CodiSharedQUADFixe, sf::Shader::Geometry))
                                ShaderGeom_isOk = true;
                       
                       
                                std::ifstream t("Data/gfx/CampDestels.glsl");
                                std::string CodiFragment((std::istreambuf_iterator<char>(t)),
                                std::istreambuf_iterator<char>());[/color]

                        if (sh.loadFromFile( CodiFragment, sf::Shader::Fragment))
                                ShaderFrag_isOk = true;
/*
[b][color=red]This might be a bug inside loadFromFile method, I assure that, because
 as the std::ifstream code demonstrates, it's not a path/permission rights file access issue:
then the loadFromFile is not working properly when a // // path is given.
[/color][/b] */

                }
                void UpdateFXvar(std::string FXVarName, sf::Vector2f FXValue)
                {
                        sf::Shader::bind(&sh);
                        sh.setUniform(FXVarName, FXValue);
                }
                void UpdateFXvar(std::string FXVarName,float FXValue)
                {
                        sf::Shader::bind(&sh);
                        sh.setUniform(FXVarName, FXValue);
                }
                void Render(sf::RenderWindow *window)
                {
                        sf::RenderStates r;
                        r.shader = &sh;
                        sf::Shader::bind(&sh);
                        window->draw(sprite, r);
                }
                ~FonsEfecte() {
                }
        };
}

#endif
 

Now the main() and the only thing I get is a black drawing, assuming it's the sprite.

int main()
{
sf::RenderWindow window;
FonsFX::FonsEfecte *ELFonsDestelsFx;
sf::Clock clock;

        while (window.isOpen())
        {
.
... other stuff,...events and so...
                ELFonsDestelsFx->UpdateFXvar("time", clock.getElapsedTime().asSeconds());
                ELFonsDestelsFx->UpdateFXvar("resolution", sf::Vector2f(window.getSize().x, window.getSize().y));
               
                window.clear(sf::Color(180, 180, 180, 255));

                ELFonsDestelsFx->Render(&window);
                window.display();
        }

        return 0;
}

and the code on the fragment shader is like this, assuming it compiles ok, because the sf::Shader loadFromFile returns a true :

CampdEstels.glsl

uniform float time;
uniform vec2 resolution;

float h(float i){
        return fract(pow(3., sqrt(i/2.)));
}

void main(void){
       
        vec2 p=gl_FragCoord.xy*2.-resolution;
       
        float a=floor(degrees(4.+atan(p.y,p.x))*2.)/4.;
       
        float d=pow(2.,-10.*fract(0.1*time*(h(a+.5)*-.1-.1)-h(a)*1000.));
       
        if(abs(length(p)-d*length(resolution)) < d*35.){
                gl_FragColor=vec4(d*(h(a+.5)*3.));
        }else{
                gl_FragColor=vec4(0.);
        }
}

So, I'm trying to report a bug in the loadFromFile at sf::Shader when the path contains slashes.
and also I'm trying to get help, because this code shows a 640x480 black sprite, although the both shaders are loading ok, and the uniforms are being updated regurarly.

Anyoen could find this an interesting phenomena. or help?...please?
« Last Edit: February 12, 2019, 04:31:12 pm by exoloner »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: A possible bug in sf::Shader and a thing that not works
« Reply #1 on: February 12, 2019, 02:53:12 pm »
I don't recommend mixing different topics in one thread unless they are really related. ;)

So, I'm trying to report a bug in the loadFromFile at sf::Shader when the path contains slashes.
I'm not sure what you mean exactly. Since you only show what you use right now and don't explain how you noticed the issue or what the original code was, it's impossible to say what's going on.
If by "is not working properly when a // // path is given." you meant that you were using // in a path, then that's not really surprising to not work, as // isn't really a valid path. Maybe you're confusing it with \\?

and also I'm trying to get help, because this code shows a 640x480 black sprite, although the both shaders are loading ok, and the uniforms are being updated regurarly.
Can you further break down your code, so that you have one main.cpp file with max 200 lines of code that causes the issue?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

exoloner

  • Newbie
  • *
  • Posts: 9
    • View Profile
    • JaK (Freebook)
    • Email
Re: A possible bug in sf::Shader and a thing that not works
« Reply #2 on: February 12, 2019, 04:30:09 pm »
OK, I recognize that was a bit rush exposition of my problems.
I've ended up with wrong load error handling, on my own.
So, yes, loadFromFile from sf::Shader works perfectly.

Fine but I still can't see the fullscreen sprite-shader because, I guess, using a totally bad vertex shader (it does even load with a TRUE return).

My question: is this Vertex shader ok with SFML internals in order to render a full screen sprite with a fragment shader as texture?

   std::string CodiSharedQUADFixe = "void main(void)    {   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;         }";         
        sh.loadFromMemory(CodiSharedQUADFixe, sf::Shader::Geometry);
 
Isolated GLSL :
void main(void)    {   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;         }

The Sprite-fragment shaded code, a class to render a full screen sized sprite with a fragment-shader texture :

#pragma once
#include <SFML/Graphics.hpp>
#include <list>
#include <iterator>
#include <string>
#include <fstream>
#include <streambuf>

#ifndef FONSFX_H
#define FONSFX_H

#include <SFML/Graphics.hpp>

namespace FonsFX
{
        class FonsEfecte
        {
        private:
                sf::Image img;
                sf::Texture tex;
               
                bool ShaderGeom_isOk = false;
                bool ShaderFrag_isOk = false;
        public:
                sf::Sprite sprite;
                sf::Shader sh;         

                FonsEfecte(unsigned int Ample, unsigned int Alt) {
                        img.create(Ample , Alt );
                        tex.loadFromImage(img);
                        sprite.setTexture(tex);
                       
                        //loadFromMemory
                        //if (sh.loadFromFile("Data/gfx/baseVertex.glsl", sf::Shader::Geometry))
                        std::string CodiSharedQUADFixe = "void main(void)       {       gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;                 }";                    
                        if (sh.loadFromMemory(CodiSharedQUADFixe, sf::Shader::Geometry))
                                ShaderGeom_isOk = true;

                        if (sh.loadFromFile("Data/gfx/CampDestels.glsl", sf::Shader::Fragment))                        
                                ShaderFrag_isOk = true;
                }
                void UpdateFXvar(std::string FXVarName, sf::Vector2f FXValue)
                {
                        sf::Shader::bind(&sh);
                        sh.setUniform(FXVarName, FXValue);
                }
                void UpdateFXvar(std::string FXVarName,float FXValue)
                {
                        sf::Shader::bind(&sh);
                        sh.setUniform(FXVarName, FXValue);
                }
                void Render(sf::RenderWindow *window)
                {
                        sf::RenderStates r;
                        r.shader = &sh;
                        sf::Shader::bind(&sh);
                        window->draw(sprite, r);
                }
                ~FonsEfecte() {
                }
        };
}

#endif

Thanks eXpl0it3r, for the "collaterals" idea. Now I've rebuild a simple alone main() c++, for testing, so now my problems are located in the improper vertex shader, I guess.

#include <SFML/Graphics.hpp>
#include <list>
#include <iterator>
#include <iomanip>
#include <sstream>
#include <string>

#include "FondosFX.h"
int main()
{
        sf::RenderWindow window;
        window.create(
                sf::VideoMode(
                        640,
                        480,
                        32), "PLanet Busters",
                sf::Style::None);

window.setVerticalSyncEnabled(true);
window.setFramerateLimit(30);
sf::WindowHandle handle = window.getSystemHandle();
window.setMouseCursorVisible(false);

FonsFX::FonsEfecte *ELFonsDestelsFx;

ELFonsDestelsFx = new FonsFX::FonsEfecte(
        window.getSize().x, window.getSize().y);

sf::Clock clock;
                       
while (window.isOpen())
{
        sf::Event event;
        while (window.pollEvent(event))
        {
                switch (event.type)
                {
                case sf::Event::Closed:
                        window.close();
                        break;
                case sf::Event::KeyPressed:
                        if (event.key.code == sf::Keyboard::Escape)
                        {
                                window.close();
                        }
                }
        }
        window.clear(sf::Color(180, 180, 180, 255));

        ELFonsDestelsFx->UpdateFXvar("time", clock.getElapsedTime().asSeconds());
        ELFonsDestelsFx->UpdateFXvar("resolution", sf::Vector2f(window.getSize().x, window.getSize().y));

        ELFonsDestelsFx->Render(&window);
       
        window.display();
}
        return 0;
}
 

and the CampDestels.glsl fragment shader file :
uniform float time;
uniform vec2 resolution;

float h(float i){
        return fract(pow(3., sqrt(i/2.)));
}

void main(void){
       
        vec2 p=gl_FragCoord.xy*2.-resolution;
       
        float a=floor(degrees(4.+atan(p.y,p.x))*2.)/4.;
       
        float d=pow(2.,-10.*fract(0.1*time*(h(a+.5)*-.1-.1)-h(a)*1000.));
       
        if(abs(length(p)-d*length(resolution)) < d*35.){
                gl_FragColor=vec4(d*(h(a+.5)*3.));
        }else{
                gl_FragColor=vec4(0.);
        }
}
 
« Last Edit: February 12, 2019, 04:36:16 pm by exoloner »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Help with basic fragment-shadered full-screen sprite
« Reply #3 on: February 12, 2019, 04:42:45 pm »
You seem to be mixing vertex shader and geometry shader; yours is a vertex shader, so don't use sf::Shader::Geometry in loadFromfile.

And to answer the question "is my shader ok with SFML", have a look at the minimal shaders in tutorial.

There's also a shader example in the SDK, don't hesitate to check it as well.
Laurent Gomila - SFML developer

exoloner

  • Newbie
  • *
  • Posts: 9
    • View Profile
    • JaK (Freebook)
    • Email
Re: Help with basic fragment-shadered full-screen sprite
« Reply #4 on: February 12, 2019, 06:01:09 pm »
Yaaay...  :-[ Thanks Laurent and eXpl0it3r!

Yes, I just need the fragment stuff, and let the full-screen sized sprite draw by himself.
 No Geometry shader needed the coords are totally ok as by default in sf::Sprite rasterization in this case.

So I must remove the Geometry shader, having a GLSL code wrong or not, It's useless and breaks things :

  std::string CodiSharedQUADFixe = "void main(void)       {       gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;                 }";                    
                        if (sh.loadFromMemory(CodiSharedQUADFixe, sf::Shader::Geometry))
                                ShaderGeom_isOk = true;

Thanks! Now my gamedev can go on!

Mortal

  • Sr. Member
  • ****
  • Posts: 284
    • View Profile
Re: Help with basic fragment-shadered full-screen sprite
« Reply #5 on: February 12, 2019, 06:25:58 pm »
hi

no need to use sprite and texture to draw fragment shader. just use sf::RectangleShape to get fullscreen to draw on it. also, no need to provide the vertex shader. like so:

#include <SFML/Graphics.hpp>


#define GLSL120(src) "#version 120 core\n" #src

static const char* frag = GLSL120(

uniform float time;
uniform vec2 resolution;

float h(float i) {
        return fract(pow(3., sqrt(i / 2.)));
}

void main(void) {

        vec2 p = gl_FragCoord.xy*2. - resolution;

        float a = floor(degrees(4. + atan(p.y, p.x))*2.) / 4.;

        float d = pow(2., -10.*fract(0.1*time*(h(a + .5)*-.1 - .1) - h(a)*1000.));

        if (abs(length(p) - d*length(resolution)) < d*35.) {
                gl_FragColor = vec4(d*(h(a + .5)*3.));
        }
        else {
                gl_FragColor = vec4(0.);
        }
}

);

int main()
{
        sf::RenderWindow window({ 800, 600 }, "SFML Shader Example");
        window.setMouseCursorVisible(false);

        sf::RectangleShape fullscreen({ 800, 600 });
        sf::Shader shader;
        if (!shader.loadFromMemory(frag, sf::Shader::Fragment))
                return -1;

        shader.setUniform("resolution", sf::Vector2f({ 800, 600 }));

        sf::Clock clock;
        while (window.isOpen()) {
                sf::Event event;
                while (window.pollEvent(event)) {
                        if (event.type == sf::Event::Closed)
                                window.close();
                }

                shader.setUniform("time", clock.getElapsedTime().asSeconds());

                window.clear();
                window.draw(fullscreen, &shader);
                window.display();
        }
}

exoloner

  • Newbie
  • *
  • Posts: 9
    • View Profile
    • JaK (Freebook)
    • Email
Re: Help with basic fragment-shadered full-screen sprite
« Reply #6 on: February 13, 2019, 08:55:34 am »
I see, just a minimal drawable and the address of a sf::Shader instanciated object does the trick.
Thanks too.

hi

no need to use sprite and texture to draw fragment shader. just use sf::RectangleShape to get fullscreen to draw on it. also, no need to provide the vertex shader. like so:

#include <SFML/Graphics.hpp>


#define GLSL120(src) "#version 120 core\n" #src

static const char* frag = GLSL120(

uniform float time;
uniform vec2 resolution;

float h(float i) {
        return fract(pow(3., sqrt(i / 2.)));
}

void main(void) {

        vec2 p = gl_FragCoord.xy*2. - resolution;

        float a = floor(degrees(4. + atan(p.y, p.x))*2.) / 4.;

        float d = pow(2., -10.*fract(0.1*time*(h(a + .5)*-.1 - .1) - h(a)*1000.));

        if (abs(length(p) - d*length(resolution)) < d*35.) {
                gl_FragColor = vec4(d*(h(a + .5)*3.));
        }
        else {
                gl_FragColor = vec4(0.);
        }
}

);

int main()
{
        sf::RenderWindow window({ 800, 600 }, "SFML Shader Example");
        window.setMouseCursorVisible(false);

        sf::RectangleShape fullscreen({ 800, 600 });
        sf::Shader shader;
        if (!shader.loadFromMemory(frag, sf::Shader::Fragment))
                return -1;

        shader.setUniform("resolution", sf::Vector2f({ 800, 600 }));

        sf::Clock clock;
        while (window.isOpen()) {
                sf::Event event;
                while (window.pollEvent(event)) {
                        if (event.type == sf::Event::Closed)
                                window.close();
                }

                shader.setUniform("time", clock.getElapsedTime().asSeconds());

                window.clear();
                window.draw(fullscreen, &shader);
                window.display();
        }
}