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

Use grabpass to determine color of pixel before rendering the current pixel.

Discussion in 'Shaders' started by 1337GameDev, Apr 15, 2013.

  1. 1337GameDev

    1337GameDev

    Joined:
    Oct 31, 2011
    Posts:
    54
    I have been reading up on grabpass and shader programming. I am relatively new, but understand concepts and syntax (or can look up references).

    I am curious how to grab the pixel color that is being rendered prior to rendering the current pixel. I know I need a grabpass (and use the one where I pass in a material name) and then determine my pixel coordinate, and then check this coordinate in the grabbed material to get the color I want.

    I currently want to use cg as my main language (most applicable) and shaderlab for just the grabpass and maybe color retrieval if necessary.

    My overall goal is to use the color of the pixel to change a font color to black or white, as to make it easily readable, while a status bar grows from left to right behind it.
    I currently have a shader that I have applied to a plane, and I have a unity changeable input color, and my shader turns black and white depending on the color.
    I also added grabpass and specified a material name. In my cg-shader section I specified the material name as a sampler2D type.

    How do I achieve this effect?
     
  2. BIG-BUG

    BIG-BUG

    Joined:
    Mar 29, 2009
    Posts:
    457
    Here's a simple shader that blends the object via GrabTexture instead of regular alpha blending:
    Code (csharp):
    1. Shader "Custom/GrabShaderTextured" {
    2.  
    3.     Properties {
    4.         _MainTex ("Base (RGB)", 2D) = "white" {}
    5.     }
    6.     SubShader {
    7.         // Draw ourselves after all opaque geometry
    8.         Tags { "Queue" = "Transparent" }
    9.  
    10.         // Grab the screen behind the object into _GrabTexture
    11.         GrabPass { }
    12.        
    13.         CGPROGRAM
    14.         #pragma surface surf Lambert vertex:vert
    15.         #pragma debug
    16.  
    17.         sampler2D _MainTex;
    18.         sampler2D _GrabTexture;
    19.  
    20.         struct Input {
    21.             float2 uv_MainTex;
    22.             float4 grabUV;
    23.         };
    24.  
    25.         void vert (inout appdata_full v, out Input o) {
    26.             //set custom value
    27.             float4 hpos = mul (UNITY_MATRIX_MVP, v.vertex);
    28.             o.grabUV = ComputeGrabScreenPos(hpos);
    29.         }
    30.  
    31.  
    32.         void surf (Input IN, inout SurfaceOutput o) {
    33.             half4 c = tex2D (_MainTex, IN.uv_MainTex);
    34.             half4 p = tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(IN.grabUV));
    35.             o.Albedo = c.rgb * p.rgb;
    36.         }
    37.         ENDCG
    38.    
    39.     }
    40.  
    41. }
    However you might get your result much cheaper by using some advanced blending logic...
     
  3. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    You can try Blend OneMinusDstColor Zero to use hardware to invert. Your source colour should be white.
     
  4. 1337GameDev

    1337GameDev

    Joined:
    Oct 31, 2011
    Posts:
    54
    Can I avoid using a surface shader, or make the surface shader omit light? I want to use a fragment shader for efficiency on mobile.
     
  5. BIG-BUG

    BIG-BUG

    Joined:
    Mar 29, 2009
    Posts:
    457
    If you want efficiency you should try to use regular blending like Daniel suggested. GrabTexture will have an impact on performance.

    The vertex fragment part would look pretty similar in a CG (non-surface) shader.