Trying to create a "water" shader

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Trying to create a "water" shader

Post by Jasoco »

I'm a bit stumped on how to go about this. Basically I want to create a water effect shader for the reflections in my game. But I can't figure out how to just shift a row of pixels.

I mean you know how it ripples. Not quite a sine wave pattern but more an abnormal pattern of jaggy offsets moving in a smooth wave pattern. But I just don't know how I would shift a row of pixels or something.

I mean right now I just have this pretty looking thing:
Image

It's not that big a deal. I'm drawing each reflectable entity onto a separate field that gets placed below the world and the water is a transparent blue texture. But I'd like to do something cool with the reflection layer just to make it look neater.
User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Trying to create a "water" shader

Post by raidho36 »

Use timer external variable and UV position of the pixel, sample by coordinates shifted sideways by sine function that takes timer as an input and vertical pixel coordinate as a static offset. Just get sinewave cycle to be smaller than one pixel. Then it will still be cyclical while not appearing as sinewave visually.
alloyed
Citizen
Posts: 80
Joined: Thu May 28, 2015 8:45 pm
Contact:

Re: Trying to create a "water" shader

Post by alloyed »

Here's a writeup that's been sitting in my bookmarks:
https://forums.tigsource.com/index.php? ... msg1104986
It's pretty similar to what raidho suggested, except instead of using a sine wave to decide displacement it looks at a texture, and then it does some perspective correction stuff that shouldn't matter for a top down game. So you can probably safely stop at step 1 :p
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Trying to create a "water" shader

Post by ivan »

How about a simple solution using blend modes?
All you'd need is an animated ripples texture (seamlessly tiled).
First you draw the blue backdrop, then you draw the reflections and finally you draw the ripples on top.
The ripples texture needs to be noisy, possibly using additive blending - which will make reflected objects appear fuzzy and washed out.
With a little bit of tweaking I think you can get a decent-looking water effect.
I've used a similar approach for the analog filters in this game.
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: Trying to create a "water" shader

Post by Jasoco »

All I really want is to give a slight waving effect to the reflection layer. I just don't know what code to use in the shader to grab a pixel at an offset instead of the current one.

I'm reading that Kingdom writeup alloyed posted above and maybe it'll give me some ideas. But I don't know what code to use. Shaders are so.. not Lua at all. But I find them intriguing. I even read through the entire "Share a shader" thread and couldn't really find anything that helps give me simple code to displace a pixel.

Small chance I might not even keep reflections. I don't know yet. I'm experimenting. But right now my method requires that I draw a bunch of images a second time. Some entities can just use the same images flipped upside down, but others I need to actually draw the reflected version. Like the pots (Seen above) which can't just be mirrored since then it would look stupid as heck, so I drew a quick "underside" style view to use for them. And walls will need to be drawn without the "top" part of the wall since obviously you wouldn't be able to see the top of the wall in the reflection. Same with the waterfall which would need a separate version without the top of the waterfall. Though I would like to figure out a way to just fade the reflection after 24 or 32 pixels so I don't have to worry about tall things.

Still a work in progress and an experiment that I might not even use. Though I do plan on making ice floors eventually and would like to have reflections there. Maybe also shiny tile floors for fancy buildings.
User avatar
veethree
Inner party member
Posts: 875
Joined: Sat Dec 10, 2011 7:18 pm

Re: Trying to create a "water" shader

Post by veethree »

I just don't know what code to use in the shader to grab a pixel at an offset instead of the current one
I recently implemented conway's game of life in glsl, And game of life logic requires grabbing adjacent pixels.
I used something like this

Code: Select all

vec4 Pixel = Texel(tex, vec2(tc.x, tc.y - (1.0 / size.y)));
"Pixel" would be the pixel above the current one. And size is a vec2 with the width/height of the window.

Not sure if this helps, I may have misunderstood what you mean by "grab a pixel"
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: Trying to create a "water" shader

Post by Jasoco »

Well I don't know what I'm doing wrong. What am I missing here?
Image

It's only grabbing like one line of pixels or something. I don't know because it doesn't look right at all. (The blackness is because there's only a water underlay tile under the water tiles. The black is regular ground, or rather transparency on the canvas since the ground doesn't draw an underlay.)

This is my shader so far:

Code: Select all

extern vec2 size;

vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
	vec4 pixel = Texel(texture, vec2(texture_coords.x - (1.0 / size.x)), texture_coords.y);
	return pixel;
}

Code: Select all

	lgr.setShader(waterShader)
	waterShader:send("size", {RENDERWIDTH, RENDERHEIGHT})
	lgr.setColor(255,255,255)
	lgr.draw(self.reflectionCanvas, 0, 0)
	lgr.setShader()
RENDERWIDTH, RENDERHEIGHT are the size of the canvas itself. It doesn't seem to matter at all if I replace them with love.graphics.getWidth() and getHeight(). I get the same result.

Where am I going wrong?
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: Trying to create a "water" shader

Post by Nixola »

There's a subtle mistake in one line:

Code: Select all

 vec4 pixel = Texel(texture, vec2(texture_coords.x - (1.0 / size.x)), texture_coords.y);
//should be
vec4 pixel = Texel(texture, vec2(texture_coords.x - (1.0 / size.x), texture_coords.y));
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: Trying to create a "water" shader

Post by Jasoco »

Haha, that works. Or at least I now have a shifted pixel so it's a starting point. I'm surprised and not surprised because I should have seen it coming as I remember moving that piece of code from the Y part to the X part and grabbing the whole thing. Funny, I guess I expected it to error me out if it was typed wrong instead of just accepting it and compiling it as is.

Okay, now to get to work figuring out how to make it look neat.
User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Trying to create a "water" shader

Post by raidho36 »

Code: Select all

extern time;
vec4 pixel = Texel(texture, vec2(texture_coords.x - sin(time + texture_coords.y * 10), texture_coords.y));
Post Reply

Who is online

Users browsing this forum: No registered users and 217 guests