Greetings!
I know that this forum is not for general programming issues, but for SFML specific stuff. I'm stuck with a problem that I can't solve and I'm not sure if it's something general I'm doing wrong or if it's something SFML specific I'm doing wrong, so I just thought I ask
I am trying to implement the 2D water effect described here:
http://freespace.virgin.net/hugo.elias/graphics/x_water.htmI want to implement it using shaders and rendertextures, because it seems more efficient to me, than using arrays of pixels and then upload those to the GPU each frame. Right now I trying to implement the creation of the Heightmap.
Here is what I'm doing: I have 3 rendertextures (3 because you can't read and write to a rendertexture at the same time) firstBuffer contains the Heightmap 2 frames ago, secondBuffer contains the heightmap form the last frame and finalBuffer is where the heightmap is drawn to. Releasing space puts a new "ripple" at the mouse position.
Here is my code:
#include <SFML/Graphics.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(600, 600), "SFML works!");
window.setFramerateLimit(60);
sf::RenderTexture buffers[3];
buffers[0].create(500, 500);
buffers[1].create(500, 500);
buffers[2].create(500, 500);
sf::RenderTexture* firstBuffer = buffers;
sf::RenderTexture* secondBuffer = &buffers[1];
sf::RenderTexture* finalBuffer = &buffers[2];
sf::Shader waterHeightmapShader;
waterHeightmapShader.loadFromFile("waterHeightmapShader.glsl", sf::Shader::Fragment);
sf::Sprite sprite;
sprite.setPosition(50, 50);
sprite.setTexture(finalBuffer->getTexture());
while (window.isOpen())
{
waterHeightmapShader.setParameter("mousePosition", sf::Vector2f(-1, -1));
sf::Event event;
while (window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
if(event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::Escape)
window.close();
// when the spacebar is pressed, add a new ripple at the mouse position
if(event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::Space)
{
sf::Vector2i mousePosition = sf::Mouse::getPosition(window);
if(mousePosition.x > 50 && mousePosition.y > 50 && mousePosition.x < 600 - 50 && mousePosition.y < 600 - 50)
{
// this is an ugly hack
mousePosition.x -= 50;
mousePosition.y -= 50;
sf::Vector2f mouse(mousePosition);
mouse.x /= 500.f;
mouse.y /= 500.f;
std::cout << mouse.x << " " << mouse.y << std::endl;
waterHeightmapShader.setParameter("mousePosition", mouse);
}
}
}
waterHeightmapShader.setParameter("textureTwoFramesAgo", firstBuffer->getTexture());
waterHeightmapShader.setParameter("textureOneFrameAgo", secondBuffer->getTexture());
// create the heightmap
finalBuffer->clear(sf::Color::Transparent);
finalBuffer->draw(sf::Sprite(secondBuffer->getTexture()), &waterHeightmapShader);
finalBuffer->display();
sprite.setTexture(finalBuffer->getTexture());
window.clear();
window.draw(sprite);
window.display();
// swap the buffers around, first becomes second, second becomes third and third becomes first
sf::RenderTexture* swapper = firstBuffer;
firstBuffer = secondBuffer;
secondBuffer = finalBuffer;
finalBuffer = swapper;
}
return 0;
}
And the shader:
// Scene buffer
uniform sampler2D textureTwoFramesAgo;
uniform sampler2D textureOneFrameAgo;
uniform vec2 mousePosition;
const float textureSize = 500.0;
const float pixelSize = 1.0 / textureSize;
void main()
{
// pixels position
vec2 position = gl_TexCoord[0].st;
vec4 finalColor = (texture2D(textureTwoFramesAgo, vec2(position.x - pixelSize, position.y)) +
texture2D(textureTwoFramesAgo, vec2(position.x + pixelSize, position.y)) +
texture2D(textureTwoFramesAgo, vec2(position.x, position.y + pixelSize)) +
texture2D(textureTwoFramesAgo, vec2(position.x, position.y - pixelSize)) ) / 2.0 -
texture2D(textureOneFrameAgo, position);
// damping
// finalColor *= 0.5;
// add new ripples
if(mousePosition.x > 0.0)
if(distance(position, mousePosition) < pixelSize * 5.0)
{
finalColor = vec4(1.0, 1.0, 1.0, 1.0);
}
gl_FragColor = finalColor;
}
If you give the code a try you'll see my problem. The problem is that whenever I create a new "ripple" it appears, but the next frame it appears to be flipped around the x-axis and the frame after that the rendertexture seems to be empty... Also the circle spreads, but it doesn't do the up and down/ripple/wavy effect.
I know the explanation is shitty, but I don't know how to describe it any better. I tried to make a video of it, but my computer refuses to do so (really I tried everything)
Sorry again for abusing this forum, but there is a lot of smart people here and I thought maybe someone is able to help me or point me in the right direction.
Thanks in advance
Foaly