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

Author Topic: Shaders  (Read 2756 times)

0 Members and 1 Guest are viewing this topic.

LedLoaf

  • Newbie
  • *
  • Posts: 16
    • View Profile
    • Email
Shaders
« on: January 23, 2021, 08:19:12 am »
Hello,

So I'm checking out someone's Tron code from YouTube, which is basically like 2 player Snake. Towards the end he adds in a shader for the 2 players.

#include <SFML/Graphics.hpp>
#include <time.h>
#include <SFML/OpenGL.hpp>
#include <iostream>
using namespace sf;

const int W=600;
const int H=480;
int speed = 4;
bool field[W][H]={0};

struct player
{ int x,y,dir;
  Color color;
  player(Color c)
  {
    x=rand() % W;
    y=rand() % H;
    color=c;
    dir=rand() % 4;
  }
  void tick()
  {
    if (dir==0) y+=1;
    if (dir==1) x-=1;
    if (dir==2) x+=1;
    if (dir==3) y-=1;

    if (x>=W) x=0;  if (x<0) x=W-1;
    if (y>=H) y=0;  if (y<0) y=H-1;
  }

  Vector3f getColor()
  {return Vector3f(color.r,color.g,color.b);}
};

int main()
{
    srand(time(0));

    RenderWindow window(VideoMode(W, H), "The Tron Game!");
    window.setFramerateLimit(60);

    Texture texture;
    texture.loadFromFile("media/Tron/background.jpg");
    Sprite sBackground(texture);

    player p1(Color::Red), p2(Color::Green);

    Sprite sprite;
    RenderTexture t;
    t.create(W, H);
    t.setSmooth(true);
    sprite.setTexture(t.getTexture());
    t.clear();  t.draw(sBackground);

    Font font; font.loadFromFile("F:/Fonts/Sansation.ttf");
    sf::Text text("YOU WIN", font, 35);
    text.setPosition(W / 2 - 80, 20);

    bool Game=true;
    auto shader = new Shader;
    if (!shader->loadFromFile("shader.frag", sf::Shader::Fragment)) std::cout << "Failed to load Shader\n";
    shader->setUniform("frag_ScreenResolution", sf::Vector2f(W, H));
    shader->setUniform("frag_LightAttenuation",100);
    sf::RenderStates states; states.shader = shader;

    while (window.isOpen())
    {
        Event e;
        while (window.pollEvent(e))
        {
            if (e.type == Event::Closed)
                window.close();
        }

        if (Keyboard::isKeyPressed(Keyboard::Left)) if (p1.dir!=2) p1.dir=1;
        if (Keyboard::isKeyPressed(Keyboard::Right)) if (p1.dir!=1)  p1.dir=2;
        if (Keyboard::isKeyPressed(Keyboard::Up)) if (p1.dir!=0) p1.dir=3;
        if (Keyboard::isKeyPressed(Keyboard::Down)) if (p1.dir!=3) p1.dir=0;

        if (Keyboard::isKeyPressed(Keyboard::A)) if (p2.dir!=2) p2.dir=1;
        if (Keyboard::isKeyPressed(Keyboard::D)) if (p2.dir!=1)  p2.dir=2;
        if (Keyboard::isKeyPressed(Keyboard::W)) if (p2.dir!=0) p2.dir=3;
        if (Keyboard::isKeyPressed(Keyboard::S)) if (p2.dir!=3) p2.dir=0;

        if (!Game) {
            window.draw(text);
            window.display();
                continue;
        }

       
        for (int i = 0; i < speed; i++) {
            p1.tick(); p2.tick();
            if (field[p1.x][p1.y] == 1) { Game = false; text.setFillColor(p2.color); }
            if (field[p2.x][p2.y] == 1) { Game = false; text.setFillColor(p1 .color);}
            field[p1.x][p1.y] = 1;
            field[p2.x][p2.y] = 1;

          /*  CircleShape c(3);
            c.setPosition(p1.x, p1.y); c.setFillColor(p1.color);    t.draw(c);
            c.setPosition(p2.x, p2.y); c.setFillColor(p2.color);    t.draw(c);  */

            t.display();
         
            shader->setUniform("frag_LightOrigin", sf::Vector2f{ (float)p1.x,(float)p1.y });
            shader->setUniform("frag_LightColor", p1.getColor());
            t.draw(sprite, states);
            shader->setUniform("frag_LightOrigin", sf::Vector2f{(float) p2.x,(float)p2.y });
            shader->setUniform("frag_LightColor", p2.getColor());
            t.draw(sprite, states);

        }

       ////// draw  ///////
        window.clear();
        window.draw(sprite);
       // window.draw(sf::Sprite{ t.getTexture() });
        window.display();
    }

    return 0;
}
 

And here is the shader itself
uniform vec2 frag_LightOrigin; 
uniform vec3 frag_LightColor;  
uniform float frag_LightAttenuation;   
uniform vec2 frag_ScreenResolution;
uniform sampler2D texture;
void main()
{              
    vec2 baseDistance =  gl_FragCoord.xy;
    baseDistance.y = frag_ScreenResolution.y - baseDistance.y;
    float d = length(frag_LightOrigin - baseDistance);
    float a = 1.0/(frag_LightAttenuation * d); 
    vec4 color = vec4(a,a,a,1.0) * vec4(frag_LightColor, 1.0);  
    vec4 t = texture2D(texture, gl_TexCoord[0].xy);
    if (t[0]>color[0]) color[0]=t[0];
    if (t[1]>color[1]) color[1]=t[1];
    if (t[2]>color[2]) color[2]=t[2];
    gl_FragColor=color;
}
 

He originally was using setParameter and I know that was deprecated so I'm thinking something here is no longer correct? What happens is the screen is just completely green, much like it would be if you used window.clear(sf::Color::Green).

Along with that this was in my console output:
An internal OpenGL call failed in shader.cpp(466).
Expression:
   GLEXT_glUniform1i(binder.location, x)
Error description:
   GL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

One last thing, I changed the casted floats to sf::Vector2i and it was the same, except now it just continued to spam this error in the console box.

Thanks, everyone, hope the beginning of your year has been great.

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: Shaders
« Reply #1 on: January 23, 2021, 11:59:35 am »
uniform float frag_LightAttenuation;

is a float

shader->setUniform("frag_LightAttenuation",100);

is attempting to set an int. (You can tell from the error by looking up glUniform1i())

You probably want
shader->setUniform("frag_LightAttenuation",100.f);

It pays to be specific with your constants, instead of relying on implicit conversion. In this case it's not being converted because an overload for setUniform() is available for integers.

Also as a side note: there's no reason to 'new' your shader, especially as you don't even delete it. Place it on the stack with your other resources and it'll be fine.  ;)

LedLoaf

  • Newbie
  • *
  • Posts: 16
    • View Profile
    • Email
Re: Shaders
« Reply #2 on: January 25, 2021, 01:42:59 am »
Hey!

Thanks, fallahn, I can't believe it was that simple of a mistake!

Unfortunately, I have come across some bugs. One of the player's snake-like character has weird artifacts surrounding it. I've attached a picture. Nothing code-wise has changed except assigning that as a float.

Lastly, could you explain why in this case I don't need to create a sprite and get the RenderTexture's texture and draw it?

Thanks for the help, greatly appreciate it!

PS: I like to learn about these shaders. Do you know of any tutorials to get more familiar with them using SFML as a 2D environment?

EDIT: I noticed moving around the 't.display()' (the render texture) make its work better or worse. At its current spot, it only has artifacts on the right side. So I think it's just placing this in the correct spot?
« Last Edit: January 25, 2021, 01:57:39 am by LedLoaf »

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: Shaders
« Reply #3 on: January 25, 2021, 05:19:03 pm »
Try turning off the smoothing on the render texture, it may be causing it to get sampled outside the texture's area, which would create artifacts.

My personal favourite for learning not just shaders, but almost all aspects of SFML, was SFML Game Development:

https://www.packtpub.com/product/sfml-game-development/9781849696845


 

anything