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

Author Topic: SFML 2 Water Shader Problem  (Read 8981 times)

0 Members and 1 Guest are viewing this topic.

lolz123

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
SFML 2 Water Shader Problem
« on: August 19, 2011, 05:24:41 am »
Hello,

I am pretty new to GLSL, but I was able to create a full screen water distortion effect by setting the pixel colors to that of pixels whose positions are dictated by offsets which are derived from a tiling noise texture. Here is how it looks:



Here is the shader. Time is wrapped to be in the range [0, 256) in order to have the water "flow" without any stutter as the noise texture repeats.

Code: [Select]
uniform sampler2D screenTex;

uniform sampler2D noiseTex;

uniform float time;

void main()
{
// Get the color of the noise texture at a position the current fragment position offset by the time
vec4 noiseTexCol = texture2D(noiseTex, vec2(gl_TexCoord[0].x + time, gl_TexCoord[0].y + time));

// Reduce the offset
float reducedOffset = noiseTexCol.x / 70;

// Get the color of the screen at the offset location
    vec4 col = texture2D(screenTex,  gl_TexCoord[0].xy + vec2(reducedOffset, reducedOffset));

// Set the fragment color
gl_FragColor = col;
}


But now I would like to apply that only to a specific region in order to create a body of water. I would like to simply distort a region and apply a blue overlay. I tried binding the shader while I drew a simple blue box, but when I run it what was once a blue box flickers seemingly random colors from the screen texture. I am not sure that I understand the GLSL texture coordinate system properly. Perhaps the lack of texture coordinates on the primitives is causing the color flicker.

Here is the code I am using to draw the body of water:

Code: [Select]
  // Render the water shape with the shader applied
sf::Image screen;
screen.CopyScreen(appWindow);
waterShader.SetTexture("screenTex", screen);
waterShader.SetParameter("time", time / 256.0f);

glColor4f(0.2f, 0.2f, 1.0f, 0.4f);

glDisable(GL_TEXTURE_2D);

waterShader.Bind();

Renderb2Body(body, 80.0f);

waterShader.Unbind();

glEnable(GL_TEXTURE_2D);

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);


Renderb2Body just draws a box. It works fine without the shader.

Any help on this matter is appreciated.
Have you heard about the new Cray super computer?  It’s so fast, it executes an infinite loop in 6 seconds.

easy

  • Full Member
  • ***
  • Posts: 146
    • MSN Messenger - easy82.contact@gmail.com
    • View Profile
    • Email
SFML 2 Water Shader Problem
« Reply #1 on: August 21, 2011, 12:52:19 pm »
Hey lolz123!

I don't know the answer, but I wanted to add that this sreenshot looks awsome! Would you give me some info on your project? Also, are you using some skeletal animation system there? Anyway, it looks fantastic!

Cheers,
easy

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFML 2 Water Shader Problem
« Reply #2 on: August 21, 2011, 12:55:05 pm »
Might help if you would post a screenshot when the effect fails?
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

lolz123

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
SFML 2 Water Shader Problem
« Reply #3 on: August 21, 2011, 02:58:52 pm »
@ Easy: The name of the project is Gore Factor (I could not come up with something better). It uses a form of vector animation in combination with sprite animation. Here is a YouTube video, download link is in the description:



@ Groogy: Well, you don't see much. but here it is:



That white box is the place where the distortion effect is supposed to take place. It flickers seemingly random shades from the rest of the screen.
Have you heard about the new Cray super computer?  It’s so fast, it executes an infinite loop in 6 seconds.

ekun

  • Newbie
  • *
  • Posts: 28
    • View Profile
    • Vagante
    • Email
SFML 2 Water Shader Problem
« Reply #4 on: August 21, 2011, 09:01:26 pm »
Is the white box a sprite?

If not, have you tried applying it to a Sprite instead of a Shape?
@ekunenuke

easy

  • Full Member
  • ***
  • Posts: 146
    • MSN Messenger - easy82.contact@gmail.com
    • View Profile
    • Email
SFML 2 Water Shader Problem
« Reply #5 on: August 22, 2011, 12:18:35 am »
Quote from: "lolz123"
@ Easy: The name of the project is Gore Factor (I could not come up with something better). It uses a form of vector animation in combination with sprite animation. Here is a YouTube video, download link is in the description:



Thanks for the video! I haven't downloaded it yet, I guess it's for Windows, and I'm on Linux... But it look very smooth and detailed, I can see you've put a great amount of time into this project. Congratulations - and keep it up!

I hope you're gonna make a multiplayer game of this!

lolz123

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
SFML 2 Water Shader Problem
« Reply #6 on: August 22, 2011, 12:42:08 am »
@ Easy: That was the idea!

@ epaik: I am using OpenGL directly, so it is neither. Otherwise the whole binding the effect thing wouldn't work.
Have you heard about the new Cray super computer?  It’s so fast, it executes an infinite loop in 6 seconds.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFML 2 Water Shader Problem
« Reply #7 on: August 22, 2011, 01:08:11 am »
I'm not experienced enough with GLSL or fragment shading at all to come with anything constructive. Best I can come up with is to experiment on the white box and try to achieve any kind of effect at all.

But also remember it is fragment shader and not vertex. You do not distort the geometry in any way only the pixels inside the geometry. So when you disable the texture and only have a single colour you have only  single colour to distort and if I get it right you only move the colours around right? So that means you move white colour around so no effect is apparent.

So what you want to do to simulate the effect of water is taking the small area behind the water and distort those colours.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

lolz123

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
SFML 2 Water Shader Problem
« Reply #8 on: August 22, 2011, 02:35:09 am »
Well, the distortion effect works full-screen, just not on that small box. It doesn't use what is being drawn as the source for the distortion texture, it uses what has currently been draw on screen (in my game engine shaders get drawn last). I think the coordinates for the textures in GLSL are messed up somehow, I just don't know how exactly.
Have you heard about the new Cray super computer?  It’s so fast, it executes an infinite loop in 6 seconds.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFML 2 Water Shader Problem
« Reply #9 on: August 22, 2011, 02:41:56 am »
Are you sure that's what is actually happening? Because the difference between the fullscreen and the local versions is that the local one does not have a texture to distort(You disable them and plus it is all white). The coordinate system between them is the same except that the available range is different.

Except for that all I can recommend is to experiment and try get a grip of what is happening on each line.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

lolz123

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
SFML 2 Water Shader Problem
« Reply #10 on: August 22, 2011, 03:02:56 am »
Well, has a texture to work with, since it remains not only white but changes colors to the colors of pixels on screen (sometimes red when it is reading the texture at the player's shirt, for example). Also, disabling textures in the main program does not disable them for the shader. That is why I think the texture coordinates in the shader are wrong, but since I do not really understand GLSL texture coordinates, I do not know what to change in the code.
Have you heard about the new Cray super computer?  It’s so fast, it executes an infinite loop in 6 seconds.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFML 2 Water Shader Problem
« Reply #11 on: August 22, 2011, 03:19:14 am »
Found this one: http://www.lighthouse3d.com/tutorials/glsl-tutorial/simple-texture/

About at the end he starts covering about accessing colours in another texture using the current interpolated texture coordinate. Might be able to find out there what's wrong or at least how to do it right. But I think you'll have to read several pages.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

easy

  • Full Member
  • ***
  • Posts: 146
    • MSN Messenger - easy82.contact@gmail.com
    • View Profile
    • Email
SFML 2 Water Shader Problem
« Reply #12 on: August 22, 2011, 10:03:51 am »
I don't know how it works, but I'd do this:

1. Render the scene to a texture
2. Pass this texture (or a part of it) to the shader
3. Draw the shaded surface

I'm most definately telling you obvious things about shader programming which I absolutely don't know, so I just shut up from now :)

Strobe

  • Newbie
  • *
  • Posts: 15
    • View Profile
SFML 2 Water Shader Problem
« Reply #13 on: August 26, 2011, 11:59:21 pm »
Quote from: "easy"

1. Render the scene to a texture
2. Pass this texture (or a part of it) to the shader
3. Draw the shaded surface


^This will most definitely work, provided the last step involves the texture being drawn to another target: either a composite layer or the window, but never to the same texture or to a texture recycled back into the source.

I think the OP might be seeing a runaway feedback effect(*), which probably accounts for the flickering. Even worse, when you apply a shader to a texture using the same texture as a source, you get that "undefined behavior" as mentioned here: http://www.opengl.org/wiki/GLSL_:_common_mistakes#Sampling_and_Rendering_to_the_Same_Texture

(*Feedback is often a desired property. Milkdrop, for instance, uses feedback in almost all of its presets. To use it properly, you need two textures that you can ping-pong between.)

lolz123

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
SFML 2 Water Shader Problem
« Reply #14 on: August 27, 2011, 04:26:44 am »
I figured it out, it was the texture coordinates as I originally predicted. I also changed some stuff in the code that draws the water so that the "waves" move with the scene and not with the camera (with the camera meaning not at all).

@ Groogy: Thanks for the site, it was very helpful!

 Here is the finished effect:



If anyone else ever wants to use this effect, here is the shader (didn't change much):

Code: [Select]
uniform sampler2D screenTex;

uniform sampler2D noiseTex;

uniform float time;

uniform float waterTexX;
uniform float waterTexY;

void main()
{
// Get the color of the noise texture at a position the current fragment position offset by the time
vec4 noiseTexCol = texture2D(noiseTex, vec2(gl_TexCoord[0].x + waterTexX + time, gl_TexCoord[0].y + waterTexY + time));

// Reduce the offset
float reducedOffset = (.5 - noiseTexCol.x) / 70;

// Get the color of the screen at the offset location and set it as the fragment color
gl_FragColor = texture2D(screenTex,  gl_TexCoord[0].xy + vec2(reducedOffset, reducedOffset));
}


And here is the code that rendered it (this part changed):

Code: [Select]
// First render the water texture
waterTexture.Bind();

glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex3f(renderPos.x - renderDims.x, renderPos.y - renderDims.y, 0.0f);
glTexCoord2f(tilingWaterTextCoordUpper.x, 0); glVertex3f(renderPos.x + renderDims.x, renderPos.y - renderDims.y, 0.0f);
glTexCoord2f(tilingWaterTextCoordUpper.x, tilingWaterTextCoordUpper.y); glVertex3f(renderPos.x + renderDims.x, renderPos.y + renderDims.y, 0.0f);
glTexCoord2f(0, tilingWaterTextCoordUpper.y); glVertex3f(renderPos.x - renderDims.x, renderPos.y + renderDims.y, 0.0f);
glEnd();

// Render the water shape with the shader applied
sf::Image screen;
screen.CopyScreen(appWindow);
waterShader.SetTexture("screenTex", screen);
waterShader.SetParameter("time", time / 256.0f);
waterShader.SetParameter("waterTexX", Wrap(camera->x / window_width, 256.0f));
waterShader.SetParameter("waterTexY", Wrap(camera->y / window_height, 256.0f));

glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);

renderPos = Vec2f(physicsPos.x * physicsDrawScale, physicsPos.y * physicsDrawScale);

waterShader.Bind();

Vec2f difference = renderPos - *camera - renderDims;
Vec2f lower(difference.x / window_width, difference.y / window_height);
Vec2f higher = lower + shaderTextCoordDims;

glBegin(GL_QUADS);
glTexCoord2f(lower.x, lower.y); glVertex3f(renderPos.x - renderDims.x, renderPos.y - renderDims.y, 0.0f);
glTexCoord2f(higher.x, lower.y); glVertex3f(renderPos.x + renderDims.x, renderPos.y - renderDims.y, 0.0f);
glTexCoord2f(higher.x, higher.y); glVertex3f(renderPos.x + renderDims.x, renderPos.y + renderDims.y, 0.0f);
glTexCoord2f(lower.x, higher.y); glVertex3f(renderPos.x - renderDims.x, renderPos.y + renderDims.y, 0.0f);
glEnd();

waterShader.Unbind();

glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);


Thanks for the help!
Have you heard about the new Cray super computer?  It’s so fast, it executes an infinite loop in 6 seconds.