Search Unity

Unity3 surface shader GrabPass

Discussion in 'Shaders' started by zephiro, Aug 1, 2010.

  1. zephiro

    zephiro

    Joined:
    Apr 26, 2009
    Posts:
    21
    Hello :)

    It's possible to use GrabPass Texture in unity 3.0 surface shader and How to ?
     
  2. LumaPxxx

    LumaPxxx

    Joined:
    Oct 3, 2010
    Posts:
    339
    I need this too.
    Anyone knows?
     
  3. the_gnoblin

    the_gnoblin

    Joined:
    Jan 10, 2009
    Posts:
    722
    I am not sure, but maybe like this?

    Code (csharp):
    1. Shader "New Shader" {
    2.     Properties {
    3.         _MainTex ("Base (RGB)", 2D) = "white" {}
    4.        
    5.     }
    6.     SubShader {
    7.         Tags { "RenderType"="Opaque" }
    8.         LOD 200
    9.        
    10.         CGPROGRAM
    11.         #pragma surface surf Lambert
    12.  
    13.         sampler2D _MainTex;
    14.  
    15.         struct Input {
    16.             float2 uv_MainTex;
    17.         };
    18.  
    19.         void surf (Input IN, inout SurfaceOutput o) {
    20.             half4 c = tex2D (_MainTex, IN.uv_MainTex);
    21.             o.Albedo = c.rgb;
    22.             o.Alpha = c.a;
    23.         }
    24.         ENDCG
    25.        
    26.         // Grab the screen behind the object into _GrabTexture, using default values
    27.         GrabPass { }
    28.  
    29.         // Render the object with the texture generated above.
    30.         Pass {
    31.             SetTexture [_GrabTexture] { combine texture }
    32.         }
    33.        
    34.     }
    35.     FallBack "Diffuse"
    36. }
     
  4. iverson

    iverson

    Joined:
    Dec 27, 2008
    Posts:
    81
    SB
     
  5. ChenA

    ChenA

    Joined:
    Jul 15, 2010
    Posts:
    21
    i also want to know.

    i know that we can sample the grab texture use _GrabTexture.
    the key point is calculate the grab texture uv from the the screenPos
    uvgrab = screenPos.xy * scale + offset

    but i don't know how to calculate the scale and offset.

    anyone know more?
     
  6. ChenA

    ChenA

    Joined:
    Jul 15, 2010
    Posts:
    21
    i get it now.

    float2 grabTexcoord = IN.screenPos.xy / IN.screenPos.w;
    grabTexcoord.y = 1.0f - grabTexcoord.y;

    half4 background = tex2D(_GrabTexture, grabTexcoord);

    then you can get the background color;
     
    macpook_pro_16 likes this.
  7. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    I would have said that what you need is a #if for opengl or dx
     
  8. ChenA

    ChenA

    Joined:
    Jul 15, 2010
    Posts:
    21
    en, i miss this.
    do you know how to check if the _GrabTexture is flipped?
     
  9. ChenA

    ChenA

    Joined:
    Jul 15, 2010
    Posts:
    21
  10. Steven-1

    Steven-1

    Joined:
    Sep 11, 2010
    Posts:
    471
    old thread but whatever,
    the question is wether "it's possible to use GrabPass Texture in unity 3.0 surface shader and How to ?"
    and that question hasn't been answered,
    In this thread and others people seem to say yes, and then give an example of a shader that has both a grabpass and a surface shader in it, but NOT a surface shader that uses a grabpass texture.

    From my experience it seems that a grabpasstexture can only be accessed in a pass, and a surface shader can't be in a pass.
    So I don't see how a grabpass can be used in a surface shader.
    Please correct me if I'm wrong, because I'd love to know how make it work.

    Urgh, writing shaders in itself is fun and all, but not how badly documented it all is, which makes it more trial and error than anything.
    (which makes it all extremely frustrating)
     
  11. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Luckily, this actually IS documented, and I confirm that it works.
    So you can sample _GrabTexture, like a regular texture (Although you'll probably want to use tex2Dproj)

    It's like it's science ;)
     
  12. BIG-BUG

    BIG-BUG

    Joined:
    Mar 29, 2009
    Posts:
    457
    This shader uses a grab texture and applies it at the same screen position (for learning purposes)
    Code (csharp):
    1. Shader "Custom/GrabShader" {
    2.  
    3.     SubShader {
    4.         // Draw ourselves after all opaque geometry
    5.         Tags { "Queue" = "Transparent" }
    6.  
    7.         // Grab the screen behind the object into _MyGrabTexture
    8.         GrabPass { "_MyGrabTexture" }
    9.        
    10.         CGPROGRAM
    11.         #pragma surface surf Lambert vertex:vert
    12.         #pragma debug
    13.  
    14.         sampler2D _MainTex;
    15.         sampler2D _MyGrabTexture;
    16.  
    17.         struct Input {
    18.             float4 grabUV;
    19.         };
    20.  
    21.         void vert (inout appdata_full v, out Input o) {
    22.             float4 hpos = mul (UNITY_MATRIX_MVP, v.vertex);
    23.             o.grabUV = ComputeGrabScreenPos(hpos);
    24.         }
    25.  
    26.  
    27.         void surf (Input IN, inout SurfaceOutput o) {
    28.             o.Albedo = tex2Dproj( _MyGrabTexture, UNITY_PROJ_COORD(IN.grabUV));
    29.         }
    30.         ENDCG
    31.    
    32.     }
    33.  
    34. }
    P.S. The documentation does not explain how to combine surface shaders with grab pass. The quoted paragraph only says that GrabPass might be also used without parameter...
     
    Last edited: Jan 29, 2013
    GameDevMig and MinD128 like this.
  13. Lulucifer

    Lulucifer

    Joined:
    Jul 8, 2012
    Posts:
    358
    74
     
  14. Steven-1

    Steven-1

    Joined:
    Sep 11, 2010
    Posts:
    471
    I have ofcourse already read the documentation,
    but what you're saying isn't a surface shader that uses a grabpass texture, which is what I was talking about:

    Exactly
    I could swear that's exactly what I've tried. hm, I'll go see what I did wrong
     
    Last edited: Jan 31, 2013
  15. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Besides showing that grabpass can be used without a parameter, it also hints at the fact that the resulting texture is available to further passes.
    Surface shaders create their own passes, that's why you can still use the grabpass texture in a surface shader. Perhaps that could be clearer in the documentation. The ability to create functions used in the vertex shader, with surface shaders, which you need to calculate the uv coordinates, isn't mentioned all that much either, I guess.
     
  16. MPanknin

    MPanknin

    Joined:
    Nov 20, 2011
    Posts:
    361
    Hi,

    I'm also having a bit of trouble with this. I tried to grab the current screen content using GrabPass and then apply the resulting _GrabTexture to a plane object. Using proper texture coordinates and no other color/lighting should render the plane completely transparent, right?

    The following works as expected:

    Code (csharp):
    1.  
    2. GrabPass {}
    3.    
    4. Pass
    5. {
    6.     SetTexture [_GrabTexture] { combine texture }
    7. }
    8.  
    The result of the above code is this (which is correct, as you only see the objects in the background):



    However, when I try to reconstruct this exact behaviour using a SurfaceShader, I have no success in rendering the _GrabTexture fully transparent, which is quite strange in my opinion:

    Code (csharp):
    1.  
    2. GrabPass {}
    3.    
    4. CGPROGRAM
    5. #pragma surface surf Lambert vertex:vert alpha
    6.  
    7. sampler2D _GrabTexture;
    8.  
    9. struct Input
    10. {
    11.       float4 grabUV;
    12. };
    13.  
    14. void vert (inout appdata_full v, out Input o)
    15. {
    16.       float4 hpos = mul (UNITY_MATRIX_MVP, v.vertex);
    17.       o.grabUV = ComputeGrabScreenPos(hpos);
    18. }
    19.  
    20. void surf (Input IN, inout SurfaceOutput o)
    21. {
    22.       o.Albedo = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(IN.grabUV));;
    23.       o.Alpha = 1.0;
    24. }
    25. ENDCG
    26.  
    Using this snippet gives me the following result, which is obviously incorrect as the plane is clearly visible:



    My approach is almost identical to the above example from BIG BUG. I think the only difference is, he's grabing the screen content into a named texture while I'm using the _GrabTexture directly. Nevertheless using his shader gives me the exact same result. I'm puzzled.

    How do you properly use GrabPass for later use inside a surface shader?

    I'd really appreciate any hints.

    Attached you find a unitypackage that illustrates the issue.

    cheers
     

    Attached Files:

  17. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Output it to o.Emission instead. The scene that has been rendered onto the plane was already lit, so you want to avoid the lighting calculations performed on o.Albedo.
     
  18. MPanknin

    MPanknin

    Joined:
    Nov 20, 2011
    Posts:
    361
    Awesome, thank you!
     
  19. BIG-BUG

    BIG-BUG

    Joined:
    Mar 29, 2009
    Posts:
    457
    Yeah the original code shows a transparent but still lit material. If you don't need any lighting calculation you could use a regular shader instead of a surface shader as this would be more efficient.