Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question 2D Colored Fog Shader with URP

Discussion in 'Shader Graph' started by KingKonXI, Feb 26, 2024.

  1. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    I created a thread about this in the main support forum but was told to repost here.

    I am trying to get this tutorial to work:

    http://blog.moondrop.no/2016/08/creating-colored-fog-in-a-2d-game-with-unity/

    I managed to run this in a new project just fine, but in my main project where i want to use this,
    i am using the URP. unfortunately the shader and materials do not work in URP.

    It seems like i would need to adapt the scripts, but I cant figure out how.
    any help would be much apprechated.

    regards
    KM
     
  2. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    (1) practice doing some very basic 2D shaders tutorials that you find on YouTube.
    It can be a while to start to "get" shaders. So you may not want to advance to (2) until you kind of sort of get it.

    (2) Get the shader working for one SpriteRenderer first.

    Some nodes that may help are the:
    Position node
    Remap node
    Saturate node (or Clamp node)
    Lerp node

    On the Blackboard define
    - float for Min Height
    - float for Max Height
    - float for Min Depth
    - float for Max Depth

    For each of these pairs of floats (x2 height & x2 depth), use the Remap node on different position input component.

    Just Getting Depth Working
    Your scene should be arranged so Z changes how close to the camera a sprite is. Y should be up and down.

    Use a Split node to get just the y-component or z-component of the position.

    What you want to accomplish in the shader is: "if the sprite's position.Z is between 5 and 10 then color it red if 5 or less and color it blue if 10 or greater."

    This would be plugging in position.z as input into a Remap node and remapping in with Min Depth and Max Depth to zero to one range. Then use Saturate to constrain the value between zero and one.

    Then you can take that output (a value between 0 and 1) and input it into a Lerp node's input, which can lerp between two colors (red and blue for example). Then you can multiply this color to your sprite's MainTex color and put that into the output.

    The next step would be doing the same for height but since it's essentially the same so I won't describe it.

    Move your sprite around in the scene to see if it's behaving as expected and your Min/Max values are OK on your material.

    (3) A problem for multiple SpriteRenderers is dynamic batching which can fuse positions together, so don't apply your material to all the renderers in your scene yet. Cross that bridge when you get there.
     
    Last edited: Feb 27, 2024
    KingKonXI likes this.
  3. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    Hi Lo renzo,

    thank you so much for your detailed reply.

    I was trying out your suggestions but i have a few questions:
    1. remap takes 2 values for "min max in" and "-out" each, connecting minDepth and maxDepth to the remap node had no effect, when using the x, y or a vector 2 node i was able to get a switch of color when changing the z axis, however the change was almost immediately at the x value (z= -500 to z= -511) of the "in min max" (due to scale of my scene the values are -500 and +1000)

    2. i would like to have a wide spread aka several semi colored layers. my main layer is at z=0 and the front layers are each seperated at a decreasing -100 step (-100,-200 etc) and the rear layers are 100,200,300 etc. how can i spread out the transition (from "normal" to "transparent-black" to "solid-black" in front and from "normal" to "transparent-color" to "solid-color" in back) over a greater distance ? and how would i add transparencies instead of a second color?

    3. I am currently using a texture in the graph, but actually want to use the sprite the object already has, would the texture then changed via a script?

    i included my graph below.

    upload_2024-2-27_18-44-54.png
     
  4. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    1. Create a Vector2 node. Plug in MinDepth into x, and MaxDepth into Y. Then plug the Vector2 into the InMinMax input of the Remap Node.

    For OutMinMax, put 0 and 1. Overall the remap is saying "convert the input value from position.z into an output value between zero and one, where MinDepth is zero and MaxDepth is one."

    The Clamp node with 0 and 1 good, but it's output should go into Lerp's "T" input.

    Lerp's A should be red, Lerp's B should be blue. Lerp is saying "for values near 0, output A; for values near 1, output B." T stands for "time" which is typically normalized between zero and one as you have already done.

    The rest looks fine.

    2. You could accomplish this with a Gradient and Sample Gradient node. This takes a 0..1 input and you can then define whatever color transitions you want over the gradient. You might need a second gradient and sample for the alpha. To make semitransparency, you want multiply the SampleTexture's alpha output by your modifier (from the gradient) and plug it into the Alpha output in the Fragment stage output far to the right.

    3. For a SpriteRenderer, it expects you to have add a texture to your blackboard and name it MainTex (it needs that name exactly). Then it should automatically grab the correct sprite from the SpriteRenderer.
     
    KingKonXI likes this.
  5. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    thanks, the color now changes smoothly and also the mainTex works as it should!
    for 2, i basically want to controll the "tickness" of the fog, aka the opacity also depending on the z axis.

    imo i need two gradients, one for the front from transparent to black --> z=0 to z=negative-clampvalue (where its 100% black) and one from transparent to color --> z=0 to z=positive-clampvalue (where its 100%color).

    wouldnt i replace the color (red and blue) nodes with the actual gradient values? and can i bind the front 0 rear gradients into one node depending on the value?

    this is the graph currently
    upload_2024-2-27_21-33-26.png
     

    Attached Files:

  6. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    yes! that's exactly what you should do. The gradient can replace lerp & colors, with Time corresponding to Lerp's "T" input.
    not so sure I understand what you mean fully, but probably. A good deal of shader work is just fiddling around until it looks right.
     
    KingKonXI likes this.
  7. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    Thanks,
    I am still playing around with this, and it works almost as intended, but i only want the alpha of the gradient to decrease (and the color(=fog) to increase) the sprite itself should be visible 100% in all stages. Wenn connecting to the sprites (fragment) alpha the sprites opacity decreases.

    I also noted, that gradient->sample gradient seems to output a fix value of the gradient ?

    The end result should look like this;
    upload_2024-2-28_9-44-5.png
    in this, the 4. sprite is the "normal" with no gradient on z= 0. I was wondering if this needs two gradients, one to handle negative z (transparent to black) and one to handle positive z (transparent to color) or if this can be combined into one gradient with black and color?

    this is the current state which is close.
    upload_2024-2-28_10-5-4.png
    upload_2024-2-28_10-7-0.png
     

    Attached Files:

  8. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    If I understand you correctly, it has a 'fixed' value in this case based on its position.z so that's just one value per sprite. That's because you're billboarding the sprites toward the camera; across the whole sprite it is has a single z-position. If you were to rotate your sprite so it's flat, laying down in the z-plane, then it'll have multiple values.

    Since we normalized z-values to 0..1 you shouldn't need to think about positive and negative z. Instead, it should have all been remapped to 0..1. You can adjust your MinDepth and MaxDepth values to change how the range that's remapped.

    A single gradient can support alpha. If you open up the gradient node, there are little markers which let you define color, but above those there are more little markers - these are for alpha.

    So you should be able to define:

    transparent
    to opaque
    to transparent

    all within a single gradient with those upper markers.

    You're currently not handling alpha at all in your graph. You should take a Split node, get the final color right before putting it into the Fragment output, then split off w and put that into the Alpha output.
     
    KingKonXI likes this.
  9. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    ok some new progress:

    i now have black in front, color, and black again.
    its not completely what i want, but if the black in the back gets switched to the acutal color than its close.

    upload_2024-2-28_15-9-39.png
    upload_2024-2-28_15-10-37.png
     
  10. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    i have just seen your reply. working on that now
     
  11. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    You shouldn't need to do it like this. Check out my latest post above. A single gradient should work for you. Click on the gradient to open it up and define more color and alpha markers and it'll interpolate between the colors for you. I think each gradient can have quite a few markers for both alpha and color... like 8? It can interpolate between a lot of different colors.

    Important concept: a gradient with a fixed time is just like using a Color node so it's not necessary.
     
    KingKonXI likes this.
  12. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    understood with the single value, makes sense when its at a single z position.

    i might not need to seperate alpha at all, if i just want to tint the sprite its handled via the gradient itself since the sprites transparency will not be touched

    I minimized this to just one gradient, and i understand the gradients alpha values:
    upload_2024-2-28_15-34-23.png

    with just one gradient the scene is looking like this upload_2024-2-28_15-35-6.png
    and the graph like this
    upload_2024-2-28_15-35-48.png

    i do not see yet, how i can leave the front with the black fade like it is, but use the color fade for the rear, which is currently not visible.
     
  13. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    You really should be able to get it to behave the way you want by connecting the Remap into a Clamp with (0, 1), then directly into Sample Gradient's Time and then outputting the that directly into the Multiply with the Sample Texture. The smoothstep, lerp and multiply nodes could be removed.

    Then all you need to do is rearrange the markers on the Gradient. So long as your scene has its z-values within the Min/Max range of the your MinDepth/MaxDepth then it should be good to go. Don't forget to double check the Min/MaxDepth values on the material.
     
    KingKonXI likes this.
  14. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    if i reduce the graph i still get the black and a fade to color but not to solid color and not to full transparent
    upload_2024-2-28_17-0-27.png

    upload_2024-2-28_17-0-52.png

    upload_2024-2-28_17-3-1.png

    mindepth is set to 0 (tried -1000)
    maxdepth to 1 (tired +5000)

    crate in front is at z = -1705
    farthest crate is at z = +3029
     
  15. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    d - Copy.png
    You need to split the alpha and connect it to the Alpha output.
     
    KingKonXI likes this.
  16. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    yes, this makes the sprite transparent,
    but i only want the fog to be transparent, so that the underlying sprite is visible 100% with no color change
    splitting the alpha off makes the sprite invisible
    upload_2024-2-28_18-47-5.png
     
  17. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
     
  18. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    Oh I see.

    Right now it's doing Tinting
    Color * Color ... your MainTex's color * gradient color

    Perhaps what you really instead want is Lerp instead to emulate the Fog.

    So instead of the Multiply node, you'd put a Lerp node with ColorA being your MainTex color and ColorB being your Fog color (from Gradient). Then you get the Gradient's Alpha with a Split node (w) and plug that into the T value of the Lerp.
     
    KingKonXI likes this.
  19. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    if i add a another color to the gradient i can see the difference.
    somehow lighter colors have no effect on the rear tinting

    the above is with a yellow marker
    upload_2024-2-28_19-1-6.png
    upload_2024-2-28_19-1-54.png
    same image with yellow marker in blue:


    View attachment 1377737

    it seems like lighter color has no effect? maybe because the color of the crate is in the same color range and multiply has therefore a weaker effect?

    i try your suggestion with lerp now and report back
     
  20. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    with second marker in blue:
    upload_2024-2-28_19-3-59.png
     
  21. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    YEEEES
    :D

    the lerp is working with the alpha split off

    upload_2024-2-28_19-8-15.png

    upload_2024-2-28_19-8-43.png
     
  22. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    thank you so much for your help,
    can i tip you somehow?
     
  23. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,520
    No problem, glad to help! You can like my posts.
     
    KingKonXI likes this.
  24. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    its me again. i have a follow up question.
    the shader above works in a project where i use URP.
    however i would like to add this shader to instances of a prefab which use an image component and the URP shader, and combine the effect of the shader above and the sprite-lit-default material.

    can this be done or would i need to combine URP and the shader above into one shader graph?

    currently only one has an effect, depending on which is set in the inspector
     
  25. KingKonXI

    KingKonXI

    Joined:
    Apr 9, 2019
    Posts:
    22
    nevermind, when i change the material of the image component, during runtime, it combines the lit-shades and the fog shader.
    and the colored box i was seeing can be easily fixed by linking the alpha output of the texture to the alpha of the fragment so that it is preserved

    upload_2024-2-29_18-37-59.png