Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resolved [2D, URP] How do I make a shader using shader graph that flashes the sprite white?

Discussion in 'General Graphics' started by Infinite-3D, Feb 18, 2023.

  1. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    39
    I'm trying to make a shader graph shader that flashes a sprite white. The below shader mostly works, but if the SpriteRenderer's color property is set to anything other than white, it flashes that color instead of white.
    upload_2023-2-18_17-12-47.png
    I've tried dividing the final color by the color given by the Vertex Color node, which mostly works, but it fails if any of the color's RGB values are 0.
    upload_2023-2-18_17-17-40.png
    Is there some sort of way to ignore the SpriteRenderer's color in a shader, or is a shader like this impossible?
     
  2. Torbach78

    Torbach78

    Joined:
    Aug 10, 2013
    Posts:
    296
    (vertexColor * MainTexture) + variable color

    variable = 0 = nothing added
    variable = 1 = white no matter how black the other two become

    you need variable to respect the sprites alpha?
    (vertexColor * MainTexture) + (variable color * MainTexture_Alpha)
     
  3. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    39
    Thanks, but this doesn't fix my problem. It still doesn't work with sprite colors that have any RGB value at 0, and it doesn't work well with a flash color that isn't white.
     
  4. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,503
    This is a longstanding problem with ShaderGraph for sprites.

    The best workaround is to create a non-graph shader since this is a pretty simple shader. Go to Project then search in "Packages" for Sprite-Lit-Default (or unlit if this is unlit) and copy paste that. Start from that template to make your shader.

    For graphs, we're waiting on Unity to provide a fix, which I imagine is as easy as adding a checkbox to disable that final multiply by vertex color. So expect it fixed in 3 years. ;)
     
    Last edited: Feb 19, 2023
  5. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    39
    Classic Unity. Thanks for your help though
     
  6. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    39
    After an hour of learning how to write shaders, here's a simple unlit sprite shader that fixes my problem. Hope this helps someone.
    Code (CSharp):
    1. Shader "Unlit/Hit"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _Hit ("Hit Amount", Float) = 0
    7.         _HitColor ("Hit Color", Color) = (1,1,1,1)
    8.     }
    9.  
    10.     SubShader
    11.     {
    12.         Tags {"Queue" = "Transparent" "RenderType" = "Transparent" "RenderPipeline" = "UniversalPipeline" }
    13.  
    14.         Blend SrcAlpha OneMinusSrcAlpha
    15.         Cull Off
    16.         ZWrite Off
    17.  
    18.         Pass
    19.         {
    20.  
    21.             HLSLPROGRAM
    22.             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    23.  
    24.             #pragma vertex vert
    25.             #pragma fragment frag
    26.  
    27.             struct Attributes
    28.             {
    29.                 float3 positionOS   : POSITION;
    30.                 float4 color        : COLOR;
    31.                 float2 uv           : TEXCOORD0;
    32.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    33.             };
    34.  
    35.             struct Varyings
    36.             {
    37.                 float4  positionCS  : SV_POSITION;
    38.                 half4   color       : COLOR0;
    39.                 float2  uv          : TEXCOORD0;
    40.                 float   hit         : COLOR1; //for some reason this has to be marked as a color even though it isnt
    41.                 float3  hitColor    : COLOR2;
    42.                 UNITY_VERTEX_OUTPUT_STEREO
    43.             };
    44.  
    45.             TEXTURE2D(_MainTex);
    46.             SAMPLER(sampler_MainTex);
    47.             half4 _MainTex_ST;
    48.             float _Hit;
    49.             float3 _HitColor;
    50.  
    51.  
    52.             Varyings vert(Attributes v)
    53.             {
    54.                 Varyings o;
    55.                 UNITY_SETUP_INSTANCE_ID(v);
    56.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    57.  
    58.                 o.positionCS = TransformObjectToHClip(v.positionOS);
    59.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    60.                 o.color = v.color;
    61.                 o.hit = _Hit;
    62.                 o.hitColor = _HitColor;
    63.                 return o;
    64.             }
    65.  
    66.             half4 frag(Varyings i) : SV_Target
    67.             {
    68.                 float4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
    69.                 float4 mainTex = float4(lerp(i.color.xyz * tex.xyz, _HitColor, i.hit), tex.a * i.color.a);
    70.                 return mainTex;
    71.             }
    72.  
    73.             float3 lerp(float3 a, float3 b, float t){
    74.                 return a * (1 - t) + b * t;
    75.             }
    76.          
    77.             ENDHLSL
    78.         }
    79.     }
    80. }
    81.  
     
  7. Torbach78

    Torbach78

    Joined:
    Aug 10, 2013
    Posts:
    296
    glad you managed to teach yourself shader code in 1hour and found your LERP solution
    now I am now confused

    here is LERP in shadergraph*; (I am not seeing issues preventing working with sprites)
    is this a lighting model issue in URP or HDRP?

    2021.2.14
    simpleLerp.gif

    graph*
    upload_2023-2-19_22-51-31.png


    here is the non LERP** version I outlined (V.color * MainTex) + (Offset * MainTex.Alpha) and I put in more blacks to show black can still be flashed to the new added color

    graph**
    upload_2023-2-19_22-48-58.png

    it doesn't need the float bc you accomplish it from black in the Sprite renderer
    simpleMaths.gif

    what are we talking about , perhaps a specific visual/better example of the limitation or it breaking in some way?
     
    Last edited: Feb 20, 2023
  8. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,503
    Sprite Lit, Sprite Unlit, Sprite Custom Lit have this issue. I think the devs didn't want people to need to remember to apply Vertex Color, so they apply it automatically.
     
  9. Torbach78

    Torbach78

    Joined:
    Aug 10, 2013
    Posts:
    296
    i am even more confused.

    you can detach vertex color out of the shadergraph and the sprite renderer component color does nothing.. and then only supply _Color on the material if you'd like


    upload_2023-2-19_23-5-49.png noVcolor.gif
    (edit ^ better demo)

    is Unlit>transparent on my Graph settings not what you intend?
     
    Last edited: Feb 20, 2023
  10. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,503
    You're showing Universal > Unlit. The problem is Sprite Lit, Sprite Unlit, and Sprite Custom Lit. Unless something has changed, these shaders add an automatic multiply after your graph runs: finalColor = whateverColorYouveMadeInYourGraph * colorMultYouCantRemove.
     
  11. Torbach78

    Torbach78

    Joined:
    Aug 10, 2013
    Posts:
    296
    Oh upload_2023-2-19_23-12-7.png

    i didnt even know those existed. i treat these as high-level presets for simplicity, but just don't us it since it comes with those underthehood operations

    are they extensively specialized and <should> be used for sprites?
     
  12. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,503
    Outside these shaders, Unity disallows accessing the Light Texture node. They're specialized for the 2D Renderer's lights. But I would be surprised if there's a big performance difference or something. Universal Unlit has more options which might be desirable in some situations.
     
  13. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    39
    So I can still use shader graph as long as I switch the shader material to "Unlit" instead of "Sprite Unlit", multiply the color by the Vertex Color node, and don't use 2D lights? I just tested it and it works, is there some reason why I shouldn't do this?
     
  14. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,503
    Sure, you could do that. Alternatively you could use normal Sprite-Lit/Unlit materials then when flashing white swap materials temporarily to your Universal Unlit one. Since the white flash only lasts a fraction of a second, the cost here would be marginal - perhaps a broken batch.
     
  15. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    39
    That would also work, but using a custom shader allows me to smoothly interpolate between flashing and not flashing. Would switching to one of the built-in sprite shaders when something's not flashing at all improve performance?
     
  16. Torbach78

    Torbach78

    Joined:
    Aug 10, 2013
    Posts:
    296
    yes ,but... your shader flash LERP is so cheap the idea that it would be the reason your project bottlenecks ; probably not going to happen

    performance metrics need to isolate each bottleneck of the rendering pipeline, as each one can ruin the game independently.

    1. i'd trend leave main Sprite cheap so they batch & shader+overdraw is low.
    2. i'd clone an instance of the sprite using a shader that simplifies the flash
      • Color = 2f * White(1,1,1,1) * v.color * MainTex.Alpha
      • you could be pulling a generic 'flash' sprite object from an FXpool (re-use a set number of them) and assigning the sprite texture from the parent

    the approach avoids material animation and abstracts flash as a separated VFX (vertex driven) rather than embedding the instructions on all objects
    • activate and vertex drive the flash
    • you could LOD a lower mipmap (therefore have a lower-res blur version scaled separately)
    • so now you could make the flash scale & glow bigger than the sprite art itself (additive blend mode 'SrcAlpha, One')

    but this is splitting hairs afaik. (without knowing the scope of your project, a vertical slice and some profiling..) i just doubt you'd have much to worry about performance wise with 2D sprites
     
    Last edited: Feb 21, 2023