SFML community forums

Help => Graphics => Topic started by: Sumzary on January 17, 2014, 09:58:50 pm

Title: Trying to implement a shockwave shader using sf::Shader
Post by: Sumzary on January 17, 2014, 09:58:50 pm
This is the shockwave.frag file:
uniform sampler2D in_Texture; // 0
uniform vec2 in_Center; // Mouse position
uniform float in_Time; // effect elapsed time. Multiply this to affect speed.

// Amplitude?, Refraction?, Width? e.g. 10.0, 0.8, 0.1
uniform vec3 in_ShockParams;

uniform int in_WindowWidth;
uniform int in_WindowHeight;

varying vec2 var_TexCoord;

void main()
{
  vec2 uv = var_TexCoord;
  vec2 texCoord = uv;
  float x = in_Center.x / float(in_WindowWidth);
  float y = (float(in_WindowHeight) - in_Center.y) / float(in_WindowHeight);
  float distance = distance(uv, vec2(x, y));

  if ( (distance <= (in_Time + in_ShockParams.z)) &&
       (distance >= (in_Time - in_ShockParams.z)) )
  {
    float diff = (distance - in_Time);
    float powDiff = 1.0 - pow(abs(diff * in_ShockParams.x),
                                in_ShockParams.y);
    float diffTime = diff * powDiff;
    vec2 diffUV = normalize(uv - in_Center);
    texCoord = uv + (diffUV * diffTime);
  }

  gl_FragColor = texture2D(in_Texture, texCoord);
}

This is all the relevant code:
shader.loadFromFile("Vania/Shaders/shockwave.frag", sf::Shader::Fragment);
shader.setParameter("in_Center", 0.5f, 0.5f);
shader.setParameter("in_ShockParams", 10.f, 0.8f, 0.1f);
shader.setParameter("in_Time", 2.f);
shader.setParameter("in_WindowWidth", conf::res.x);
shader.setParameter("in_WindowHeight", conf::res.y);

...

window.draw(renderSprite, &shader);

Everything seems fine so far, but when i start the game, all I see is one solid color (would put screenshot here but it seems pointless), is there something wrong with my SFML code? Something obvious I'm missing here? Been stuck for a while trying to figure this out, some help would be very much appreciated ;]
Title: AW: Trying to implement a shockwave shader using sf::Shader
Post by: eXpl0it3r on January 17, 2014, 10:31:07 pm
You never clear or display the drawn thing - at least you didn't post it. Please provide a complete and minimal example, so we can directly test it. ;)
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: Laurent on January 17, 2014, 10:35:04 pm
You should start with a minimal shader and build on top of it until things stop working as expected. Writing the final thing directly and then wondering why it doesn't work often leads nowhere ;)

And where do you set the in_Texture parameter? It's not shown in your code.
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: Sumzary on January 17, 2014, 10:38:43 pm
Here you go lad :D
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>


int main() {

        sf::RenderWindow window(sf::VideoMode(640, 360), "Test 123");

        sf::RenderTexture texture;
        texture.create(640, 360);

        sf::Texture tex;
        tex.loadFromFile("Image.png");

        sf::Sprite sprite;
        sprite.setTexture(tex);

        sf::Shader shader;
        shader.loadFromFile("Shockwave.frag", sf::Shader::Fragment);
        shader.setParameter("in_Center", 0.5f, 0.5f);
        shader.setParameter("in_ShockParams", 10.f, 0.8f, 0.1f);
        shader.setParameter("in_Time", 1.f);
        shader.setParameter("in_WindowWidth", 640);
        shader.setParameter("in_WindowHeight", 360);

        // The main loop
        while (window.isOpen()) {

                // Event processing
                sf::Event event;
                while (window.pollEvent(event)) {

                        if (event.type == sf::Event::Closed)
                                window.close();
                }

                texture.clear(sf::Color::Red);
                texture.draw(sprite);
                texture.display();

                sf::Sprite rSprite(texture.getTexture());

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

Just have a random image around and copy the shader stuff to a file.

EDIT: Didn't actually write this myself, found it on the internet, thats why I'm struggling so much :|
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: cob59 on January 17, 2014, 11:34:10 pm
About shaders, I came across this topic once. It might help :
http://gmc.yoyogames.com/index.php?showtopic=586380
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: G. on January 17, 2014, 11:49:46 pm
var_TexCoord has no value. It's probably initialized in a vertex shader in the code you blindly copied. :p
Also, what Laurent asked.
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: Sumzary on January 18, 2014, 09:43:23 am
After some googling and testing this is what I got.

The C++ code in "main.cpp":
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>


int main() {

        sf::RenderWindow window(sf::VideoMode(640, 360), "Test 123");

        sf::RenderTexture texture;
        texture.create(640, 360);

        sf::Texture tex;
        tex.loadFromFile("Image.png");

        sf::Sprite sprite;
        sprite.setTexture(tex);

        sf::Shader shader;
        shader.loadFromFile("Shockwave.vert", "Shockwave.frag");
        shader.setParameter("in_Texture", sf::Shader::CurrentTexture);
        shader.setParameter("in_Center", 0.5f, 0.5f);
        shader.setParameter("in_ShockParams", 10.0f, 0.8f, 0.1f);
        shader.setParameter("in_WindowWidth", 640);
        shader.setParameter("in_WindowHeight", 360);

        sf::Clock clock;
        clock.restart();

        // The main loop
        while (window.isOpen()) {

                // Event processing
                sf::Event event;
                while (window.pollEvent(event)) {

                        if (event.type == sf::Event::Closed)
                                window.close();
                }

                shader.setParameter("in_Time", clock.getElapsedTime().asSeconds());

                texture.clear(sf::Color::Red);
                texture.draw(sprite);
                texture.display();

                sf::Sprite rSprite(texture.getTexture());

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

The "Shockwave.vert":
#version 110

attribute vec4 in_Color;

varying vec4 var_Color;
varying vec2 var_TexCoord;

void main()
{
  gl_Position = ftransform();
  var_Color = in_Color;
  var_TexCoord = gl_MultiTexCoord0.xy;
}

And the "Shockwave.frag":
#version 110

uniform sampler2D in_Texture; // 0
uniform vec2 in_Center; // Mouse position
uniform float in_Time; // effect elapsed time. Multiply this to affect speed.

// Amplitude?, Refraction?, Width? e.g. 10.0, 0.8, 0.1
uniform vec3 in_ShockParams;

uniform int in_WindowWidth;
uniform int in_WindowHeight;

varying vec2 var_TexCoord;

void main()
{
  vec2 uv = var_TexCoord;
  vec2 texCoord = uv;
  float x = in_Center.x / float(in_WindowWidth);
  float y = (float(in_WindowHeight) - in_Center.y) / float(in_WindowHeight);
  float distance = distance(uv, vec2(x, y));

  if ( (distance <= (in_Time + in_ShockParams.z)) &&
       (distance >= (in_Time - in_ShockParams.z)) )
  {
    float diff = (distance - in_Time);
    float powDiff = 1.0 - pow(abs(diff * in_ShockParams.x),
                                in_ShockParams.y);
    float diffTime = diff * powDiff;
    vec2 diffUV = normalize(uv - in_Center);
    texCoord = uv + (diffUV * diffTime);
  }

  gl_FragColor = texture2D(in_Texture, texCoord);
}

The program without the shader:
(http://s8.postimg.org/vev9087zp/image.png)

With shader:
(http://s8.postimg.org/kqri1dy0l/image.png)


It seems to just show this one pixel from the top-left corner, it's like I'm missing something very simple. Ideas?
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: the_mean_marine on January 18, 2014, 11:00:49 am
You've made a small mistake in your vertex shader.

The line:
var_TexCoord = gl_MultiTexCoord0.xy;
should be:
var_TexCoord = gl_TextureMatrix[0] * gl_MultiTexCoord0;
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: Sumzary on January 18, 2014, 03:04:51 pm
It draws the background image fine, but the effect is just not there, fiddling with different values didn't help.  :(
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: Sumzary on January 18, 2014, 08:28:48 pm
Actually, I'm getting some errors:
An internal OpenGL call failed in Shader.cpp (235) : GL_INVALID_OPERATION, the specified operation is not allowed in the current state
An internal OpenGL call failed in Shader.cpp (235) : GL_INVALID_OPERATION, the specified operation is not allowed in the current state

Help meh, i'm stumped :'(
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: Sumzary on January 18, 2014, 09:50:39 pm
Well I solved it, these variables were ints:
uniform int in_WindowWidth;
uniform int in_WindowHeight;

Turns out you cant "shader.setParamater(int);", so I had to change the code to make them floats instead:
uniform float in_WindowWidth;
uniform float in_WindowHeight;

A feature to be added mayhaps?  ;)
Title: Re: Trying to implement a shockwave shader using sf::Shader
Post by: Sqasher on January 18, 2014, 10:59:09 pm
You convert the int to float in the shockwave fragment shader anyway:

float x = in_Center.x / float(in_WindowWidth);
float y = (float(in_WindowHeight) - in_Center.y) / float(in_WindowHeight);
 

Also, graphics cards are made specifically for floating point calculations and can be slow in integer calculations. So I think this won't be added to SFML.