- Edited
Shader Graph to submerge character in water? (Example)
This is an excellent shader, see video below, any idea how it was made?
https://m.youtube.com/watch?v=46xSkGmklR0
We want a shader to have our character in water, and ideally also the bottom part of the character is semitransparent, or actually having a blueish tint and being able to adjust the position of the surface.
Can this be done using Shader Graph? I'm very afraid of writing shader code.
Thanks!
That's a nice shader effect indeed!
nicmar wroteCan this be done using Shader Graph? I'm very afraid of writing shader code.
You don't need a lot of functionality for such a shader, so I would be surprised if it could not be implemented using Shader Graph as well.
Basically I would do the following:
1) The wave top end would be based on object-space vertex Y position, with top end being the height
parameter + a random (noise) wave Y addition based on vertex X position. Then waterDepth = vertex.pos.y - waveTopEnd
.
2) Vertex position offset for distortion part, in random direction (noisetex sampled at vertex position again).
3) Overlaid color gradient and output color alpha reduction based on water depth.
At least that's what it looks like to me.
Thanks, I'd love to try that, i would know how to if it was a simple sprite, but since the Spine model is in an atlas, how do I get that working?
This simple shader:
Gives this funky result:
How do I apply it to the entire Spine model from bottom to top instead of on the atlas?
I'm working with Nic to try to get this figured out. I didn't know it was possible to get object-space! Am I correct that object-space in the sense of Spine (or Sprites) would basically be the the space relative to the Mesh? If so (and testing seems to be pointing in that direction) that opens up a lot of cool shader ideas!
(Edit: Quick note - the issue in Nic's post just before this one is that it is using UV instead of a Position node set to Object Space)
I am testing it out, and trying to figure out how the value-range on the Object-Space position works. I was expecting it to be something standardized like 0 to 1, or -1 to 1, or -0.5 to 0.5. What I am finding is that the total value-range varies, but I don't know why. This happens with both Sprites and Spine characters.
Things I tested:
-A basic "Circle Sprite" created by right-clicking -> 2D Objects -> Sprite -> Circle. The origin/pivot of the sprite is at the default center of it. With this default sprite, the Object-Space coordinates range from -0.5 to 0.5 on the X and Y axes. This is what I would expect, and matches up with the 'preview' in Shader Graph.
-My own sprite that is an image of a Tent. This sprite also has its pivot set to its center. The Object-Space range on this appears to be around -10 to 10. Scaling the gameobject transform does not affect the Object-Space range. Changing the pivot point however DOES affect it. When the pivot point is set to "bottom" (causing the sprite to move upwards such that the bottom of the sprite is now at the gameobject's transform position), its as though the pivot point is considered the 'center' of the Object-Space range, meaning that the actual object-space-y-axis-values in the shader are now starting at 0 at the bottom of the Tent, and increase as you move upward (AKA instead of being in a -X to +X range, the range is now 0 to 2X).
-Testing out a SkeletonAnimation seems to be acting the same way as my Tent sprite. The Object-Space range seems to have some arbitrary -X to +X range, and it also is affected by where the origin is (which appears to be the origin point in the actual spine project).
So TL;DR, I think I have two questions:
1) Is there any way to get the Object Space range to be a standardized range (without having to manually figure out and pass in some material property block values like the Bottom and Top position for each individual character)?
2) Is there a way to account for the Origin/Pivot position without manually passing in a material property block value for it?
Thanks for any help, and if we can get this figured out we can definitely share the shaders for others to check out :grinteeth:
Glad to hear you're collaborating on this one, always nice to see! 8)
Jamez0r wrote(Edit: Quick note - the issue in Nic's post just before this one is that it is using UV instead of a Position node set to Object Space)
Yes, UV coords are not helpful here.
Object space position is the raw vertex position that is input as vertex data, before any transformation (World and View) matrices have transformed the vertex. It should be game units when having a transform with scale 1 and position and rotation of 0.
Jamez0r wrote1) Is there any way to get the Object Space range to be a standardized range (without having to manually figure out and pass in some material property block values like the Bottom and Top position for each individual character)?
Hm, it would require setting the import scale of your skeleton to change the object space vertex position accordingly. Another way would be to pass this as a material parameter and normalize it in the shader.
Jamez0r wrote2) Is there a way to account for the Origin/Pivot position without manually passing in a material property block value for it?
Your origin is the same as authored in Spine. I assume your skeletons all have the origin at the same height (either at ground level or at the center of the skeleton), so there should not be much compensation needed.
Harald wroteGlad to hear you're collaborating on this one, always nice to see! 8)
Jamez0r wrote(Edit: Quick note - the issue in Nic's post just before this one is that it is using UV instead of a Position node set to Object Space)
Yes, UV coords are not helpful here.
Object space position is the raw vertex position that is input as vertex data, before any transformation (World and View) matrices have transformed the vertex. It should be game units when having a transform with scale 1 and position and rotation of 0.
Jamez0r wrote1) Is there any way to get the Object Space range to be a standardized range (without having to manually figure out and pass in some material property block values like the Bottom and Top position for each individual character)?
Hm, it would require setting the import scale of your skeleton to change the object space vertex position accordingly. Another way would be to pass this as a material parameter and normalize it in the shader.
Jamez0r wrote2) Is there a way to account for the Origin/Pivot position without manually passing in a material property block value for it?
Your origin is the same as authored in Spine. I assume your skeletons all have the origin at the same height (either at ground level or at the center of the skeleton), so there should not be much compensation needed.
Awesome, thanks a lot for the info Harald!
Here is a shadergraph shader that does a configurable horizontal-fade for a character. There are 2 parameters for the shader: FadeMidpointHeight is the vertical position in object-space where the centerpoint of the fade is. Spread is how 'wide' the fade is.
Note: This is using the Create > Shader Graph > URP > Sprite Unlit Shadergraph template. So if you want it to be lit, or don't want the URP version, etc, just create your own empty shader with whichever template and set it up with that.
Shader Download: https://drive.google.com/file/d/1T0xI1ktUuPZacpNRxfr9a9lKeCGunLJ3/view?usp=sharing
Glad it helped, thanks for sharing your shader!
If you want some wave-effect as well, you could add some added noise-offset sampled by object- or world-space x position (so use x for both U and V input of the noise function) to your offsetMidpointHeight
.
Just be sure to not use y position as v input, otherwise you get some swiss cheese effect .
Hi and how do you manage when sprites overlap each other and those lines
I assume that you've exported with PMA (pre-multiplied alpha) workflow (see the FAQ here). The easiest fix would be to switch to straight-alpha workflow.
Otherwise you would need to change your Shader Graph shader output blend mode to premultiplied. Alternatively, if the shader graph output must be set to straight-alpha, divide your texture's RGB values by the texture's alpha channel, and cover the case if texture.a == 0
by not doing anything.