If you need help/did not understand something, feel free to ask in the comments! ATTENTION: As pointed out by GDQuest it's better to use *get_viewport_transform()* instead of *global_canvas_transform()* .
Couple more Godot 4 notes: `tool` needs to be `@tool` SCREEN_TEXTURE is deprecated, but the error in the editor explains how to fix it :) Thank you for this tutorial!
For anyone else who runs into this issue. This looked ok for me in the editor, but it looked all messed up when launching the game. I fixed it by using this instead: material.set_shader_param("y_zoom", get_viewport_transform().get_scale().y) Hope that helps
Cool tutorial! A note about using the global_canvas_transform: it will give you inconsistent results between the editor and the game view, and when you change the window's size - because the global canvas transform changes with the viewport size. You should use the relative canvas_transform of the viewport instead. You can use get_viewport_transform() to get it directly from any CanvasItem.
Thanks for the tip! I haven't had issues with global_canvas_transform so far, maybe when I change the stretch mode? Anyways I'd love to have something like this in Godot : github.com/godotengine/godot-proposals/issues/1078#issuecomment-645490060
Although I only fully grasped like 30 percent of what was being done, what I got in the end was fully functional. I am a beginner programmer and this level of programming is still a bit beyond what I can comprehend. A week ago I learned what a variable was haha. Thank you for the tutorial, I am going to definitely check out your other work.
I've been programming for a long time, and shaders are still quite mysterious to me. :D When they start _"add this multiplied by that, times the sin of this divided by the cosine of that, times two divided by the other...",_ it's like getting lost in a maze. No idea how they came up with some of this stuff. :) One of these days I'll read The Book Of Shaders. Heard good things about it. Maybe it demystifies it.
@@Nolkaloid In part, yes. But I'll have to watch it again, because I didn't assimilate some stuff. The thing is, and I realized this a few hours ago, for the longest time I've been having this barrier with some terminology still being abstract to my brain. For example, when you used the term _"sample"_ (as a verb) there was an immediate disconnect in my understanding. I just didn't know what you meant by it. After thinking about it, (and correct me if I'm wrong) I realized sampling just means picking a color from a source. This should probably be obvious, given that essentially all a frag shader does is working with colors, but my brain was still not putting all these basic things together. Another barrier I've been having is not knowing what values are going through the pipe, sometimes. For example, I read a few pages in the Book Of Shaders a few hours ago, and my initial assumption with _gl_FragCoord_ was that it was a normalized position. After playing around with it, I'm thinking maybe it isn't. Unfortunately, the book isn't explicit about this (unless I overlooked it), and iirc neither were many tutorials I watched in the past. And not knowing these things for sure can make it feel like a blind man trying to create a painting. Because of course we can't just print out the values. :)
A little tip on top of this: if you want to shrink or enlarge the reflection vertically, you can multiply the viewport transform by a factor above or below 1, respectively. I shrunk mine to add a little bit of a 3D-ish perspective effect, by multiplying by 1.2. I may still bump it up a bit. Seems to do the trick without issues.
@@Nolkaloid Since I'm doing a clone of Kingdom, unfortunately it's not as simple. The old flash version doesn't do this. The more recent versions do, but not to the reflections, only to the foamy waves on the water surface. The foam seems too random to not be a shader step, but it's the only thing in 3D. I'm wondering if it's actually a translucent 3D plane on top of the water, with a shader of its own... I could try that too. Though I could still do what you suggested, and make it a personal touch, but I'm not quite getting it. I tried multiplying the *reflected_screen_uv.x* by the *UV.y,* and things of that sort, but that only results in the bottom being skewed to one side... The stretching must go both ways, and also has to be relative to the center of the screen, rather than the center of the texture, but beyond that I'm kinda clueless atm... Also the stretching must account for pixel size, such that the closest (bottom-most) pixels aren't bigger than the others.
Thank you for you awesome shader tutorial! Shaders are something I gotta learn sometime; but this one saved me! Now time to maybe work on actual gameplay instead of just water visuals for my game
HI Nolkaloid, why screenuv.y + 0.375 * uv.y * 2 can flip the image 。。。。i can't understand ....in my mind ,i thing it will be offset by 0.75*uv.y.......
amazing video man, I'm using godot 4.0.3 and your tutorial works, didn't even run into a single problem! I'm curious though, the waves at the start of the video have like a white blanket on top of them, how did you do that? edit: nvm, got it myself, forgot that you mentioned it at the end of the video lol :D
is there a way to make this work with parallexLayers/CanvasLayers? Have other sprites in front this shader-sprite and render their reflection below them on screen where this sprite is visible. Tried using it as is, but the reflections don't work kinda the way I would like them to. If I have it in front canvaslayer, it renders it on top of it those sprites, but if this shader sprite is behind everything else, it wont render any reflections on it.
Please forgive me for this really noobish question, why does multiplying the offset by UV.y and 2 flip the image? My math isn't really that good and I'm struggling to really understand that part.
No worries, the idea is the following: Basically as we move towards UV.y = 1.0 (the bottom of the sprite), we want to read the screen that's above in a "mirrored manner". So when rendering the line at UV.y = 1.0, we want to read the screen texture at SCREEN_UV + SIZE_OF_THE_SPRITE × 2 (where SIZE_OF_THE_SPRITE is the offset as explained in the video). On the other hand, at UV.y close to 0.0, we want to read the SCREEN_TEXTURE that is just a tiny bit above. And in between I want a linear progression, so that's why we multiply by UV.y If it's still not clear I can send you a diagram explaining it visually.
I have one question: how to deal with light?? for example I do not want the shadow to be reflected, what should i do? I set render mode but does not work. also, i tested AT_LIGHT_PASS, still not work. and another question: how to mask out some thing? that is , i want to reflect something and others do not . do you think this is achievable?
This reflects properly in the scene viewer, but when I run the scene, it does not reflect what is above it, only distorts what the sprite is directly on top of. Please advise.
@@Nolkaloid It turned out that the issue stemmed from using Mode 2D; Aspect Keep with a small native resolution, increasing to a larger resolution on screen. I fixed it by multiplying the reflected screen UV.y by a window_resize_ratio that is the ratio of the native resolution, in my case, 480x270 to the screen resolution (aka test_width, test_height), in my case, 1920x1080. By hooking up a signal to the screen resize, I am able to calculate the ratio on the fly and send to the uniform in the shader. Thank you again for this tutorial!
Thank you so much for the tutorial! I have a question, is there any way to make the distortion of the water more consistent between the Maximized v.s. Windowed game?
Great tutorial! I'm making a pixel art game and the reflection part worked perfectly, but the distortions look a bit muddy because of the way Godot scales down the image. Do you know if there's a way to use something like nearest neighbor scaling for the shader or some other way to snap it to pixels?
@@Nolkaloid Thanks, it looks better now! Looks like some interpolation is still being done (the reflection has colors that the original sprite doesn't) but it looks good now so it isn't a big problem. Thanks for the video and the reply!
Question: Your tutorial works well for most sibling nodes in the scene tree, but it doesn't reflect some things when I switch around things in the scene tree. For example, children of sibling nodes are not reflected. Sprite nodes are not reflected when they are below the Water node in the scene tree, but particle nodes are reflected in this way. Since I'm instancing the water in a complex scene where the player sprite is a child of a KinematicBody2D, do you know how to get nodes with different parents to be reflected? For instance of getting BadSprite reflected by Water: Root BadParent BadSprite Sprite Water Particles2D It's not related to in-game or editor zoom nor waves as I didn't implement those parts of the tutorial.
Hi, you need to put the water as the front most node, so the lowest in the tree. This is because rendering is done in from the highest node to the lowest node in the tree. The screen texture in the shader contains only what was rendered before, so it makes sense that nodes that are lower won't appear on the screen_texture. As for particles, I'm quite surprised, It has probably something to do with how the rendering pipeline works...
@@Nolkaloid I figured it out. The rendering pipeline renders based on the z_index of the nodes, so the issue was unrelated to the scene tree node structure. I increased the z_index of the water above everything I wanted reflected, and now it works perfectly. Great tutorial!
@@josephcantrell1 Yup, it renders from back most to front most, thus according to the tree. Of course if you change the z-indexes of some of the nodes, the rendering order will get perturbed.
Thanks for the awesome vids and explanations ! I know understand better shaders and how they interact with gdscript. However, I encounter a problem when the tile reflected are not in the viewport anymore they are not reflected. I can't see in the video if you have the same problem but when you lower the camera enough to make the reflected sprite cut in half, only the visible half will be reflected. The rest will glitch or disapear. Do you have any idea how to fix that ? Thanks !
Hey, it's normal behavior, as this a screen space effect. We are using the screen texture, once an object is no longer visible in the view, it's simply not rendered so it's not accessible in the screen texture.
How would you update it to work with an isometric view 2D game? What I mena is that the relection should only apply to the top part of the sprite. Anyway thank for the tutorial great videao! You deserve my follow up!
@@Nolkaloid I just set the texture of the sprite to repeated, but nothing changed. I'm assuming I have to set the noise texture to repeat. Not sure how to do that tho.
@@animebinger7974 You need to add the repeat_enable hint to the sampler2D declaration : uniform sampler2D noise : repeat_enabled; docs.godotengine.org/en/stable/tutorials/shaders/shader_reference/shading_language.html#uniforms
Thanks for this tutorial. It helped me get the water working on a small clone of Kingdom (the old flash version) that I'm trying to make in Godot. :) EDIT: do you happen to know how I could pixelate it? The shader distorts things to float positions, and I'm needing it to snap to pixels, but not real pixels, rather the pixels being scaled up from a low resolution. I have no idea how, though.
Hey! I'm glad I could help! To pixelate the texture, you will need to sample the texture "per block", UV coordinates evolve linearly, we want to make that evolution "blocky": www.desmos.com/calculator/eqgpc3phow
@@Nolkaloid well, snapping values to steps/grids is something I've done before, but in the shader code I'm kinda clueless of which values to snap... I understand what you mean by the UV evolving blocky, but I'm still confused at how to do it... It also doesn't help much that because I'm using a scaled resolution, what I see in the editor doesn't match what I see in game...
@@Nolkaloid Thanks. No hurries though. I was thinking of also bringing this up on discord, but what I got now is actually already pretty good, so I can leave it as it is for now and move on to other stuff. I still need to turn the game into more than just a character moving on an empty map with pretty water. :)
@@joseramiromartinez388 Are you sure you are multiplying the correct member in the expression? Also the scale.y should be set accordingly to the scale of the sprite, so if the tool script doesn't work in will display nothing, because by default the scale vector is (0.0, 0.0).
Hi, this is not related to the Godot version you're using, this is expected behavior. The shader cannot read what's above the screen (it is simply not rendered). To fix that you could render the game zoomed out (×0.5) and render it at twice the resolution. Then display the result zoomed "back" in (×2.0).
@@Nolkaloid ok I tried it didn't work, however you are right that this product when the reflected area is outside the camera, I tested with 0.5 scale and less and multiplied the effect by 2 it doesn't change anything, do you have another solution?
Going down the shader rabbit hole again these are so good I hate them. How am i supposed to just know how to do that. My weakness in Godot. Or any engine as a matter of fact.🤣🤣
If you need help/did not understand something, feel free to ask in the comments!
ATTENTION: As pointed out by GDQuest it's better to use *get_viewport_transform()* instead of *global_canvas_transform()* .
Couple more Godot 4 notes:
`tool` needs to be `@tool`
SCREEN_TEXTURE is deprecated, but the error in the editor explains how to fix it :)
Thank you for this tutorial!
You can fix "SCREEN_TEXTURE" using this code line.
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, repeat_disable, filter_nearest;
For anyone else who runs into this issue.
This looked ok for me in the editor, but it looked all messed up when launching the game.
I fixed it by using this instead:
material.set_shader_param("y_zoom", get_viewport_transform().get_scale().y)
Hope that helps
thanks man, helped a lot
Cool tutorial! A note about using the global_canvas_transform: it will give you inconsistent results between the editor and the game view, and when you change the window's size - because the global canvas transform changes with the viewport size. You should use the relative canvas_transform of the viewport instead.
You can use get_viewport_transform() to get it directly from any CanvasItem.
Thanks for the tip! I haven't had issues with global_canvas_transform so far, maybe when I change the stretch mode?
Anyways I'd love to have something like this in Godot : github.com/godotengine/godot-proposals/issues/1078#issuecomment-645490060
Thank you, very helpful!
3 years later and this fixed my issue thanks!
Dude. You are a genius. Pls don't stop making Godot videos. We need you.
Thanks! But I'm not a genius :D, just applying some math in a creative way.
Thanks for taking the time to upload this man. This would have taken years off my life to implement and decades off my life to animate by hand.
i came for the cat character and stayed for the knowledge
Set sail!
Captain's log, I am no longer afraid of shaders.
thank you for this!
Wow, you are someone very talented, I have subscribed, thanks for sharing, I like to find developers like you
Just a simple hint, check the z_index of your objects on screen if you do not see some elements in the reflection on screen
Although I only fully grasped like 30 percent of what was being done, what I got in the end was fully functional. I am a beginner programmer and this level of programming is still a bit beyond what I can comprehend. A week ago I learned what a variable was haha. Thank you for the tutorial, I am going to definitely check out your other work.
I've been programming for a long time, and shaders are still quite mysterious to me. :D
When they start _"add this multiplied by that, times the sin of this divided by the cosine of that, times two divided by the other...",_ it's like getting lost in a maze. No idea how they came up with some of this stuff. :)
One of these days I'll read The Book Of Shaders. Heard good things about it. Maybe it demystifies it.
@@skaruts I also hope that my video at least partially demystifies it.
@@Nolkaloid In part, yes. But I'll have to watch it again, because I didn't assimilate some stuff.
The thing is, and I realized this a few hours ago, for the longest time I've been having this barrier with some terminology still being abstract to my brain. For example, when you used the term _"sample"_ (as a verb) there was an immediate disconnect in my understanding. I just didn't know what you meant by it. After thinking about it, (and correct me if I'm wrong) I realized sampling just means picking a color from a source. This should probably be obvious, given that essentially all a frag shader does is working with colors, but my brain was still not putting all these basic things together.
Another barrier I've been having is not knowing what values are going through the pipe, sometimes. For example, I read a few pages in the Book Of Shaders a few hours ago, and my initial assumption with _gl_FragCoord_ was that it was a normalized position. After playing around with it, I'm thinking maybe it isn't. Unfortunately, the book isn't explicit about this (unless I overlooked it), and iirc neither were many tutorials I watched in the past. And not knowing these things for sure can make it feel like a blind man trying to create a painting. Because of course we can't just print out the values. :)
@@skaruts Yeah, I understand. My tutorial about shockwaves is an attempt to introduces those principles... but I don't know if it does the job.
@@Nolkaloid Yea, I watched a little bit. Probably gonna watch it tomorrow with a clear head.
A little tip on top of this: if you want to shrink or enlarge the reflection vertically, you can multiply the viewport transform by a factor above or below 1, respectively. I shrunk mine to add a little bit of a 3D-ish perspective effect, by multiplying by 1.2. I may still bump it up a bit.
Seems to do the trick without issues.
What you could also do, is to scale the texture on the x axis as you go down, to create a fake perspective effect :)
@@Nolkaloid Since I'm doing a clone of Kingdom, unfortunately it's not as simple. The old flash version doesn't do this. The more recent versions do, but not to the reflections, only to the foamy waves on the water surface. The foam seems too random to not be a shader step, but it's the only thing in 3D. I'm wondering if it's actually a translucent 3D plane on top of the water, with a shader of its own... I could try that too.
Though I could still do what you suggested, and make it a personal touch, but I'm not quite getting it. I tried multiplying the *reflected_screen_uv.x* by the *UV.y,* and things of that sort, but that only results in the bottom being skewed to one side... The stretching must go both ways, and also has to be relative to the center of the screen, rather than the center of the texture, but beyond that I'm kinda clueless atm...
Also the stretching must account for pixel size, such that the closest (bottom-most) pixels aren't bigger than the others.
What a well made tutorial! Bravo!!! Please, keep on sharing knowledge. The world needs people like you! Much love from Brazil! o/
oh so you can *somewhat* make a mirror with this, nice!
Amazing tutorial!
Sorry to see no more contents from you.
Best of luck!
I'm extremely busy with college, but one day I'll be back (hopefully). Thank you for your kind words :)
man shaders are awesome, you can do so much with so little code lines
Already looking great... now lets add waves.. what, no way
thanks for sharing , u made it easy for me to understand how shaders work
You can use colorrect node then you don't need to scale it you can just resize it.
Your videos are so useful, I'm learning shaders thanks to you. Great videos
You explain things very well. Thanks and keep it up.
Shaders are so fascinating and cool, but so hard to wrap your head around
Thank you for this! Great tutorial.
world needs you , keep going
oh, really thanks for this perfect tutorial, loves it!!!
Thank you for you awesome shader tutorial!
Shaders are something I gotta learn sometime; but this one saved me!
Now time to maybe work on actual gameplay instead of just water visuals for my game
Great stuff man! Congrats!
Ya no hay mas de esto para ver
Great video, very well explained!
I tried but couldnt add the white boarder on top plese help
HI Nolkaloid, why screenuv.y + 0.375 * uv.y * 2 can flip the image 。。。。i can't understand ....in my mind ,i thing it will be offset by 0.75*uv.y.......
Hey! That was an example, the 0.375 is the ration we calculated.
Is there a way to have it reflect things properly when it is not at the center of the screen?
Yeah, technically you could render the double of the height and display only the bottom part while still using the full thing to sample the screen.
Rminded me of the past 90s with Javascript Water I was like 0_0
Excelent!!
Good job Bro
amazing video man, I'm using godot 4.0.3 and your tutorial works, didn't even run into a single problem! I'm curious though, the waves at the start of the video have like a white blanket on top of them, how did you do that? edit: nvm, got it myself, forgot that you mentioned it at the end of the video lol :D
is there a way to make this work with parallexLayers/CanvasLayers? Have other sprites in front this shader-sprite and render their reflection below them on screen where this sprite is visible. Tried using it as is, but the reflections don't work kinda the way I would like them to. If I have it in front canvaslayer, it renders it on top of it those sprites, but if this shader sprite is behind everything else, it wont render any reflections on it.
hi, how can i set code editor at the middle bottom like U or it is a older verson Godot?
for the color picker in godot 4 uniform vec4 water_color : source_color;
Great tutorial, love it
I've made it + I added a few wavy into the water, but there seems to be a problem for me when i move to the right, the left part of the water is laggy when going out of screen or entering screen (not the right one .. ? )
Does anyone have hints to resolve this issue ?
here is the code :
shader_type canvas_item;
group_uniforms screen;
uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
uniform vec2 scale;
uniform float y_zoom;
group_uniforms display;
uniform float reflect_scale_y = 1.13;
uniform vec4 water_color : source_color;
group_uniforms distortion;
uniform sampler2D distortion_noise: repeat_enable;
uniform vec2 distortion_scale = vec2(0.03, 0.06);
uniform float distortion_intensity = 0.04;
uniform float distortion_speed = 0.015 ;
group_uniforms waves;
uniform sampler2D wave_1_noise: repeat_enable;
uniform float wave_1_speed;
uniform float waves_min_intensity = 1.22;
uniform float waves_hdr_value = 3.3;
uniform float waves_smoothness = 0.12;
group_uniforms top_wave;
uniform float top_wave_amplitude = 0.02;
uniform float top_wave_speed = 0.09;
uniform float top_wave_period = 0.185;
//float remap(float val, float in1, float in2, float out1, float out2)
//{
//return out1 + (val - in1) * (out2 - out1) / (in2 - in1);
//}
void fragment() {
vec2 uv = vec2( UV.x, UV.y * reflect_scale_y);
float waves = uv.y * scale.y +sin(uv.x * scale.x / top_wave_period + TIME * top_wave_speed)
* cos( 0.2 * uv.x * scale.x/top_wave_period - TIME - top_wave_speed)
* top_wave_amplitude - top_wave_amplitude;
float distortion_1 = texture(distortion_noise, uv * scale * distortion_scale + TIME * distortion_speed).x;
float distortion_2 = texture(wave_1_noise, uv * scale * distortion_scale + TIME * wave_1_speed).x;
float distortion = distortion_1 + 1.0 - distortion_2;
distortion -= 0.5;
float waves_intensity = smoothstep(waves_min_intensity - waves_smoothness, waves_min_intensity, distortion) * waves_hdr_value;
float uv_height = SCREEN_PIXEL_SIZE.y / TEXTURE_PIXEL_SIZE.y;
vec2 reflected_screen_uv = vec2(SCREEN_UV.x - distortion * distortion_intensity * y_zoom, SCREEN_UV.y - uv_height * uv.y * y_zoom * scale.y * 2.0);
vec4 reflection = texture(screen_texture, reflected_screen_uv);
vec3 reflected_water = mix(reflection.rgb, water_color.rgb, water_color.a);
COLOR.rgb = reflected_water + vec3(waves_intensity);
COLOR.a = smoothstep( 0.1, 0.35, clamp(waves, 0, 1) );
}
Please forgive me for this really noobish question,
why does multiplying the offset by UV.y and 2 flip the image? My math isn't really that good and I'm struggling to really understand that part.
No worries, the idea is the following:
Basically as we move towards UV.y = 1.0 (the bottom of the sprite), we want to read the screen that's above in a "mirrored manner". So when rendering the line at UV.y = 1.0, we want to read the screen texture at SCREEN_UV + SIZE_OF_THE_SPRITE × 2 (where SIZE_OF_THE_SPRITE is the offset as explained in the video). On the other hand, at UV.y close to 0.0, we want to read the SCREEN_TEXTURE that is just a tiny bit above. And in between I want a linear progression, so that's why we multiply by UV.y
If it's still not clear I can send you a diagram explaining it visually.
You basically made an Earthbound battle background
I have one question: how to deal with light?? for example I do not want the shadow to be reflected, what should i do? I set render mode but does not work.
also, i tested AT_LIGHT_PASS, still not work.
and another question: how to mask out some thing? that is , i want to reflect something and others do not . do you think this is achievable?
How would you do this for an animated sprite though ?
This reflects properly in the scene viewer, but when I run the scene, it does not reflect what is above it, only distorts what the sprite is directly on top of. Please advise.
Try using get_viewport_transform() instead of global_canvas_transform()
@@Nolkaloid It turned out that the issue stemmed from using Mode 2D; Aspect Keep with a small native resolution, increasing to a larger resolution on screen.
I fixed it by multiplying the reflected screen UV.y by a window_resize_ratio that is the ratio of the native resolution, in my case, 480x270 to the screen resolution (aka test_width, test_height), in my case, 1920x1080.
By hooking up a signal to the screen resize, I am able to calculate the ratio on the fly and send to the uniform in the shader.
Thank you again for this tutorial!
@@adambrookman2664 u can put an example ?
Thank you so much for the tutorial!
I have a question, is there any way to make the distortion of the water more consistent between the Maximized v.s. Windowed game?
I don't have access to my computer right now, so I cannot see what your really mean. Could you please describe the issue / current vs wanted result?
i think you want GDQuest's solution, just use get_viewport_transform() instead of global_canvas_transform()
How do you get the white line on top?
is there a way to have an object ontop of the water and have it reflect?
What do you mean on top ? Like in front of it ?
Great tutorial! I'm making a pixel art game and the reflection part worked perfectly, but the distortions look a bit muddy because of the way Godot scales down the image. Do you know if there's a way to use something like nearest neighbor scaling for the shader or some other way to snap it to pixels?
You're using GLES3 or GLES2?
@@Nolkaloid using GLES3 for this project
Hey! Sorry for the late reply, I think you can use the *textureLod* function instead of *texture* and set the LOD (last argument) to 0.0
@@Nolkaloid Thanks, it looks better now! Looks like some interpolation is still being done (the reflection has colors that the original sprite doesn't) but it looks good now so it isn't a big problem. Thanks for the video and the reply!
I noticed, you have the shader open without the inspector switching from the sprite to the shader resource ... how?
Sorry for the super late reply, it was possible before. The way it is now is super annoying.
not sure how to call zoom_changed, have a camera 2d on my character which does not synch up with the shader... can anyone please help
Hi, you need to call this function manually, when you explicitly need it or in a process loop.
Question: Your tutorial works well for most sibling nodes in the scene tree, but it doesn't reflect some things when I switch around things in the scene tree. For example, children of sibling nodes are not reflected. Sprite nodes are not reflected when they are below the Water node in the scene tree, but particle nodes are reflected in this way. Since I'm instancing the water in a complex scene where the player sprite is a child of a KinematicBody2D, do you know how to get nodes with different parents to be reflected? For instance of getting BadSprite reflected by Water:
Root
BadParent
BadSprite
Sprite
Water
Particles2D
It's not related to in-game or editor zoom nor waves as I didn't implement those parts of the tutorial.
Hi, you need to put the water as the front most node, so the lowest in the tree. This is because rendering is done in from the highest node to the lowest node in the tree. The screen texture in the shader contains only what was rendered before, so it makes sense that nodes that are lower won't appear on the screen_texture. As for particles, I'm quite surprised, It has probably something to do with how the rendering pipeline works...
Additionally if you still have issues, you could use the back buffer copy node.
@@Nolkaloid I figured it out. The rendering pipeline renders based on the z_index of the nodes, so the issue was unrelated to the scene tree node structure. I increased the z_index of the water above everything I wanted reflected, and now it works perfectly. Great tutorial!
@@josephcantrell1 Yup, it renders from back most to front most, thus according to the tree. Of course if you change the z-indexes of some of the nodes, the rendering order will get perturbed.
Nothing reacts after place shader code
Thanks for the awesome vids and explanations ! I know understand better shaders and how they interact with gdscript.
However, I encounter a problem when the tile reflected are not in the viewport anymore they are not reflected. I can't see in the video if you have the same problem but when you lower the camera enough to make the reflected sprite cut in half, only the visible half will be reflected. The rest will glitch or disapear.
Do you have any idea how to fix that ?
Thanks !
Hey, it's normal behavior, as this a screen space effect. We are using the screen texture, once an object is no longer visible in the view, it's simply not rendered so it's not accessible in the screen texture.
@@Nolkaloid oh ok. Do you know if there is a solution with shaders to that specific problems ? I could not think of a solution for a top down game
Hey, I'm having real problems implementing this in 4.0. Anyone else had any luck?
How would you update it to work with an isometric view 2D game? What I mena is that the relection should only apply to the top part of the sprite. Anyway thank for the tutorial great videao! You deserve my follow up!
Interesting question, I'll try to think about it when I have some time.
@@Nolkaloid Im thinkering with, but so far didnt make anything that work
It seems that when it runs with + TIME, my noise texture simply "runs off" elsewhere, leaving a completely smooth surface behind. The noise distortion texture seems to run to the left, being clipped m the sprite's boundaries. In other words, it doesn't loop.
Help. :c
Here's my code(in godot 4)
shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
uniform float y_zoom;
uniform vec2 scale;
uniform vec4 water_color: source_color;
uniform vec2 distortion_scale;
uniform float intensity;
uniform float speed;
uniform sampler2D noise;
void fragment() {
float distortion = texture(noise, UV * scale * distortion_scale + TIME * speed).x ;
distortion -= 0.5;
float uv_height = SCREEN_PIXEL_SIZE.y / TEXTURE_PIXEL_SIZE.y;
vec2 reflected_screenuv = vec2(SCREEN_UV.x - distortion * intensity * y_zoom, SCREEN_UV.y - uv_height * UV.y *scale.y * y_zoom * 2.0);
vec4 reflection = texture(SCREEN_TEXTURE, reflected_screenuv);
COLOR.rgb = mix(reflection.rgb, water_color.rgb, water_color.a);
}
Is your texture set to be repeated ?
@@Nolkaloid I don't think so. How do I do that?
@@Nolkaloid I just set the texture of the sprite to repeated, but nothing changed. I'm assuming I have to set the noise texture to repeat. Not sure how to do that tho.
@@animebinger7974 You need to add the repeat_enable hint to the sampler2D declaration :
uniform sampler2D noise : repeat_enabled;
docs.godotengine.org/en/stable/tutorials/shaders/shader_reference/shading_language.html#uniforms
@@Nolkaloid Ty!!!
Brilliant!
Hello! How to put the waves at the bottom?
Project download pls
Pocos likes para semejante video! GJ
bug on canvas_view Y (pan move or in game... -_-)
and can this method be used in tilemap? I tested with my tilemap and find not work :(
I find a way to do this, manbe :) use viewport and shader
Thanks for this tutorial. It helped me get the water working on a small clone of Kingdom (the old flash version) that I'm trying to make in Godot. :)
EDIT: do you happen to know how I could pixelate it? The shader distorts things to float positions, and I'm needing it to snap to pixels, but not real pixels, rather the pixels being scaled up from a low resolution. I have no idea how, though.
Hey! I'm glad I could help! To pixelate the texture, you will need to sample the texture "per block", UV coordinates evolve linearly, we want to make that evolution "blocky": www.desmos.com/calculator/eqgpc3phow
@@Nolkaloid well, snapping values to steps/grids is something I've done before, but in the shader code I'm kinda clueless of which values to snap... I understand what you mean by the UV evolving blocky, but I'm still confused at how to do it...
It also doesn't help much that because I'm using a scaled resolution, what I see in the editor doesn't match what I see in game...
@@skaruts Hey! I'll try to cook some code for you during the weekend. I'm quite busy with school rn so no promises :p
@@Nolkaloid Thanks. No hurries though. I was thinking of also bringing this up on discord, but what I got now is actually already pretty good, so I can leave it as it is for now and move on to other stuff. I still need to turn the game into more than just a character moving on an empty map with pretty water. :)
cool shader
أريد مساعدة اريد رابط كود التضليل الذي إستخدمته رجاء
Frérot je parle pas arabe désolé.
You want the source code ?
I need help. I want a link to the cheat code you used, please
I want shader code file please
@@hakimsmaili3838 Sorry but I don't have it with me right now, you can can try to follow the tutorial to recreate the shader yourself.
Okay but how can I make wide cat
go to drive C: , find Windows/system32 and delete it.
@@Nolkaloid And Alt+F4 turns on auto-save.
(Just kidding, that actually kills the application. Don't do it)
in godot 4 SCREEN_TEXTURE is replace by just normal TEXTURE
Dude, I do the same steps, one by one, and doesn't work. I'm trying another things right now, but, anyway, thank you for the light.
Hey! Does it throw some kind of errors?
When I add the "* scale.y" it just stop reflecting. I will try again today, thank you.
@@joseramiromartinez388 Are you sure you are multiplying the correct member in the expression? Also the scale.y should be set accordingly to the scale of the sprite, so if the tool script doesn't work in will display nothing, because by default the scale vector is (0.0, 0.0).
This does not work well in version 4, there is an illustrated bug: th-cam.com/video/5DJKV5FyKNc/w-d-xo.html
If you can help me?
Hi, this is not related to the Godot version you're using, this is expected behavior. The shader cannot read what's above the screen (it is simply not rendered). To fix that you could render the game zoomed out (×0.5) and render it at twice the resolution. Then display the result zoomed "back" in (×2.0).
@@Nolkaloid ok I tried it didn't work, however you are right that this product when the reflected area is outside the camera, I tested with 0.5 scale and less and multiplied the effect by 2 it doesn't change anything, do you have another solution?
@@Nolkaloid and with backbuffercopy ?
@@Nolkaloid and with backbuffercopy ?
@@Nolkaloid backbuffercopy alternative ?
Going down the shader rabbit hole again these are so good I hate them. How am i supposed to just know how to do that. My weakness in Godot. Or any engine as a matter of fact.🤣🤣
you are awesome
Can be applied to top down games?