Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

2D Top-down Reflective Shader, help please!

Discussion in 'Shaders' started by Samacvuk, Jan 17, 2018.

  1. Samacvuk

    Samacvuk

    Joined:
    Jan 8, 2017
    Posts:
    30
    Howdy!
    Hope you are fine and having a wonderful day!

    Introduction to the problem:
    For almost a year now I have studied shaders and started doing some for my upcoming game, for the past two weeks I'm stuck on a top-down reflection shader, what was aimed for is to create reflections on the base of the sprites that are behind of the transparent material (a gameObject containing a sprite renderer containing the material with the shader).

    What I did:
    I use GrabPass{"_GrabFloor"} to render what is behind the material and invert it in the Vertex function:

    Code (CSharp):
    1. v2f vert (appdata_full a)
    2.             {
    3.                 v2f o;
    4.                 o.vertex = UnityObjectToClipPos(a.vertex);
    5.                 o.uvgrab = ComputeGrabScreenPos(o.vertex);            
    6.                 o.uvgrab.y = 1 - (o.uvgrab.y);
    7.                 return o;
    8.             }
    Later on the Fragment function i aply the perlin noise distortion (which is turned off in the pictures) and the transparency:

    Code (CSharp):
    1. half4 frag (v2f v) : SV_TARGET
    2.             {
    3.                 half4 bump = tex2D(_DistortionTex, v.uvgrab);
    4.                 half2 noise = UnpackNormal(bump).rg;
    5.                 v.uvgrab.xy += noise * _Magnitude;
    6.                 fixed4 color = tex2D(_GrabFloor, v.uvgrab);
    7.                 color.a = _Transparency;
    8.                 return color;
    9.             }
    It is all badly blended togheter, for i have not yet learned how to properly use Blending in shaderlab:

    Code (CSharp):
    1. Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" }
    2.         ZWrite Off Lighting Off Cull Off Fog { Mode Off }
    3.  
    4.         GrabPass{"_GrabFloor"}
    5.  
    6.         Pass
    7.         {
    8.             Blend SrcAlpha OneMinusSrcAlpha

    Result:

    shader_problem_1.png shader_problem_2.png shader_problem_3.png

    What is needed:
    I need to find a way to project the reflections on the base of each sprite considering player movement on the X and Y axis.

    Any help is really welcome, I have researched this topic deeply and have found similar results in sidescroller games (Kingdom for instance).

    Have a nice day :3
     
  2. Samacvuk

    Samacvuk

    Joined:
    Jan 8, 2017
    Posts:
    30
    anyone have any idea on the direction i can take ?
    ty
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Kingdome has the benefit of the reflection at a single horizontal line for the entire game, as well as the "flat" side view. Flipping the screen and offsetting / scaling it vertically looks "perfect" in that case.

    For what you're doing you're better off duplicating your sprites and rendering them upside down, then having a transparent layer above them to fake a reflective surface.
     
  4. Samacvuk

    Samacvuk

    Joined:
    Jan 8, 2017
    Posts:
    30
    Thank you for you reply !
    the problem i have with that approach is the animations, there is no automatic workflow (that i know of) to properly duplicate the current sprite on the screen, would you know the way ?
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    I've not done anything with sprites in Unity to know if there's an easy way. My first inclination would be to write a script that duplicates all of a game object's sprites and their positions, mirrored and positioned appropriately and have that run on objects during the game.
     
  6. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,495
    What if you simply made your environment object shader do 2 passes, the first pass simply flips the object in the vertex shader (maybe a bit squished, shouldn't need to offset it if your sprite pivot is at bottom of object) and renders it blended with the ground color. Then the second pass simply renders the tree normally, making sure the reflections never cover up the real objects.

    I assume this should work fairly easily?

    You'll have to make sure "DisableBatching"="True" in these "reflected" shader's Tag section, otherwise all the trees would be rendered as one mesh and thus this would not work.
     
    Last edited: Jan 18, 2018
  7. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,511
    I am looking at the similar issue and rendering upside down sprite can work to some degree.. but it all depends on the sprite image. If the sprite has depth at bottom of the object, meaning say for example a rounded barrel, flipping it at the bottom pivot gives wrong reflection around the round corner. In this case another reflection sprite has to be made .. which is a cost. Have not found neat way to solve this yet.