Search Unity

Invert the colors of the Camera

Discussion in 'General Graphics' started by Raial, Aug 5, 2017.

  1. Raial

    Raial

    Joined:
    May 2, 2017
    Posts:
    24
    Hi,
    I've been dealing with this problem for many days.

    I want to invert the colors of all my scene in my Android Game.
    I tried using post-processing efects, but I didn't see any of them that could invert the colors.

    I also tried to use shaders, although I don't know much about them.
    I applied a shader to the Camera (I copied and pasted the code of Unity Standard Assets -> Image Effects, I founded a shader that inverts colors and I pasted there).
    Now in the editor and in some android devices (those who have a lot of cpu and gpu) works like a charm.

    The problem is that in low-quality android devices it all starts doing strange things and the game seems almost blocked when I active that shader.

    How should I do? I don't know much about shaders.
    Thanks:)
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    The default image effect shader that Unity creates when you create a new image effect shader in the project view is actually a color inversion shader. It's a super simple effect.

    The problem with old android devices is the way Unity handles image effects is to copy the frame buffer to a render texture and pass that to the image effect shader. This is pretty fast on most hardware, but very very slow on older hardware. The usual fix people will suggest is to not use Unity's built in OnRenderImage and instead have your camera render directly to a render texture and do everything with command buffers and manually swapping the render target.

    However for the effect of flipping the color there's an easy way that doesn't require using image effects, or render textures, or any of this. All that's needed is a quad in front of the camera with a very simple shader.

    Code (CSharp):
    1. Shader "Custom/InvertColor"
    2. {
    3.     SubShader
    4.     {
    5.         Pass
    6.         {
    7.             Tags { "Queue"="Overlay+100" "IgnoreProjector"="True" }
    8.  
    9.             Blend OneMinusDstColor Zero
    10.             ColorMask RGB
    11.  
    12.             ZWrite Off
    13.             ZTest Always
    14.  
    15.             CGPROGRAM
    16.             #pragma vertex vert
    17.             #pragma fragment frag
    18.  
    19.             float4 vert(float4 vertex : POSITION) : SV_Position {
    20.               return UnityObjectToClipPos(vertex);
    21.             }
    22.  
    23.             fixed4 frag() : SV_Target {
    24.               return fixed4(1,1,1,1);
    25.             }
    26.  
    27.             ENDCG
    28.         }
    29.     }
    30. }
    The key part is that Blend line. Basically the rest of the shader does the absolute minimum work possible to render the mesh to the screen, and the blend mode is what tells it to render the current screen color inverted.

    edit: Fixed shader so it compiles
     
    Last edited: Aug 5, 2017
    ifurkend and Raial like this.
  3. Raial

    Raial

    Joined:
    May 2, 2017
    Posts:
    24
    Hi,

    Thanks for your answer, the shader you did works perfectly.
    I did what you said, a quad with your shader. I tried it in low-quality mobiles and it works! Thank you very much!

    I have a last question, I need to change the colour from normal to inverted in a transition, like if normal was 0 and inverted color was 1, what I would do is change the value from 0 to 0.25, then 0.5, etc.


    Thank you so much, this was the last thing I needed to finish my game.
     
  4. ifurkend

    ifurkend

    Joined:
    Sep 4, 2012
    Posts:
    350
    bgolus' shader can't change the inversion level, but this can be fixed:
    Code (CSharp):
    1.     Shader "Custom/InvertColor"
    2.     Properties {
    3.         _TintColor ("Tint Color", Color) = (1,1,1,1)
    4.     }
    5.     {
    6.         SubShader
    7.         {
    8.             Pass
    9.             {
    10.                 Tags { "Queue"="Overlay+100" "IgnoreProjector"="True" }
    11.    
    12.                 Blend OneMinusDstColor OneMinusSrcColor
    13.                 ColorMask RGB
    14.    
    15.                 ZWrite Off
    16.                 ZTest Always
    17.    
    18.                 CGPROGRAM
    19.                 #pragma vertex vert
    20.                 #pragma fragment frag
    21.    
    22.                 float4 vert(float4 vertex : POSITION) : SV_Position {
    23.                   return UnityObjectToClipPos(vertex);
    24.                 }
    25.    
    26.                 fixed4 frag() : SV_Target {
    27.                   return fixed4(1,1,1,1);
    28.                 }
    29.    
    30.                 ENDCG
    31.             }
    32.         }
    33.     }
    Then you change the Tint Color between black and white (or other color like red for actually tinting the result). In script you SetColor to _TintColor and apply lerp to RGB (alpha is irrelevant).
     
    reinfeldx, Raial and Mauri like this.
  5. Raial

    Raial

    Joined:
    May 2, 2017
    Posts:
    24
    It works fine, like bgolus's one.
    But when I try to set the colour like you said, nothing changes.

    Code (CSharp):
    1. material.SetColor("_TintColor", Color.Lerp(Color.white, Color.black, 1f));
    2. //and then the same but from  black to white
    3. material.SetColor("_TintColor", Color.Lerp(Color.black, Color.white, 1f));
    If I change the color manually in the inspector, nothing changes either.
    The texture is black and remains black.

    I think I should learn how to code shaders:confused:
    Thanks for everything!
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    I believe @ifurkend forgot to update the shader fully. He defined the _TintColor property and modified the Blend mode, but never actually makes use of the new property. I suspect this is what he had intended to post.

    Code (CSharp):
    1. Shader "Custom/InvertColor"
    2. {
    3.     Properties {
    4.         _TintColor ("Tint Color", Color) = (1,1,1,1)
    5.     }
    6.     SubShader
    7.     {
    8.         Pass
    9.         {
    10.             Tags { "Queue"="Overlay+100" "IgnoreProjector"="True" }
    11.    
    12.             Blend OneMinusDstColor OneMinusSrcColor
    13.             ColorMask RGB
    14.    
    15.             ZWrite Off
    16.             ZTest Always
    17.  
    18.             CGPROGRAM
    19.             #pragma vertex vert
    20.             #pragma fragment frag
    21.    
    22.             float4 vert(float4 vertex : POSITION) : SV_Position {
    23.               return UnityObjectToClipPos(vertex);
    24.             }
    25.  
    26.             fixed4 _TintColor;
    27.  
    28.             fixed4 frag() : SV_Target {
    29.               return _TintColor;
    30.             }
    31.  
    32.             ENDCG
    33.         }
    34.     }
    35. }
     
  7. Raial

    Raial

    Joined:
    May 2, 2017
    Posts:
    24
    Thank you very much for your help!!
    Now the shader works perfectly, and in low-quality mobiles it does too!

    I can finally end my game.
    Many thanks to both for your help!!:):D
     
  8. ifurkend

    ifurkend

    Joined:
    Sep 4, 2012
    Posts:
    350
    @bgolus: Yes. Because I already have my invert color shader, I forgot to compile the code before posting... orz
     
  9. reinfeldx

    reinfeldx

    Joined:
    Nov 23, 2013
    Posts:
    164
    I realize this thread is a couple of years old, but is there a way to "cut a hole" in the inverted shader above using a texture with transparency?

    Here's what I've got: inverted-color-mask.png

    Code (CSharp):
    1. Shader "Custom/InvertColor1"
    2. {
    3.     Properties{
    4.         _TintColor("Tint Color", Color) = (1,1,1,1)
    5.         //_MainTex("Base (RGB)", 2D) = "white" {} TODO
    6.     }
    7.         SubShader
    8.     {
    9.         Pass
    10.         {
    11.             Tags { "Queue" = "Overlay+100" "IgnoreProjector" = "True" }
    12.  
    13.             Blend OneMinusDstColor OneMinusSrcColor
    14.             ColorMask RGB
    15.  
    16.             ZWrite Off
    17.             ZTest Always
    18.  
    19.             CGPROGRAM
    20.             #pragma vertex vert
    21.             #pragma fragment frag
    22.  
    23.             float4 vert(float4 vertex : POSITION) : SV_Position {
    24.               return UnityObjectToClipPos(vertex);
    25.             }
    26.  
    27.             fixed4 _TintColor;
    28.  
    29.             fixed4 frag() : SV_Target {
    30.               return _TintColor;
    31.             }
    32.  
    33.             ENDCG
    34.         }
    35.     }
    36. }