- Home /
Manual Graphics.Blit
I'm having some issues preserving stencil buffer data with Graphics.Blit.
In the Unity documentation, it says if you want to preserve stencil buffer data:
Source: https://docs.unity3d.com/ScriptReference/Graphics.Blit.html"Note that if you want to use depth or stencil buffer that is part of the source (Render)texture, you'll have to do equivalent of Blit functionality manually - i.e. Graphics.SetRenderTarget with destination color buffer and source depth buffer, setup orthographic projection (GL.LoadOrtho), setup material pass (Material.SetPass) and draw a quad (GL.Begin)."
Could anyone provide example code for how to do this? It's not listed in the documentation.
I figured out how to do the second part, (and can confirm this preserves stencil buffer data). But haven't used render targets before and documentation is sparse.
Here's what I have so far:
    public Shader shader;
    private Material mat;
    // Will be called from camera after regular rendering is done.
    public void OnPostRender()
    {
        if (!mat)
        {
            mat = new Material(shader);
            mat.hideFlags = HideFlags.HideAndDontSave;
        }
        GL.PushMatrix();
        GL.LoadOrtho();
        // activate the first shader pass (in this case we know it is the only pass)
        mat.SetPass(0);
        // draw a quad over whole screen
        GL.Begin(GL.QUADS);
        GL.Vertex3(0, 0, 0);
        GL.Vertex3(1, 0, 0);
        GL.Vertex3(1, 1, 0);
        GL.Vertex3(0, 1, 0);
        GL.End();
        GL.PopMatrix();
    }
 I essentially want to create an image effect, but have to do it manually because of the stencil buffer issue. I want to preserve the camera's texture data (presumably in a buffer, as described) and feed it into the shader as I would in a normal blit operation. 
               Thanks!
Answer by markefus · Jan 27, 2019 at 06:16 AM
For any lost soul struggling with preserving stencil buffer data in image effects.... It just works.
  public Shader shader;
  private Material mat;
   
  void OnEnable()
  {
      mat = new Material(shader);
  }
 
  //'It Just Works' -- Todd Howard
  void OnRenderImage(RenderTexture source, RenderTexture destination)
  {
      RenderTexture buffer = RenderTexture.GetTemporary(source.width, source.height, 24);
      Graphics.Blit(source, buffer, mat);  
      Graphics.Blit(buffer, destination);
      RenderTexture.ReleaseTemporary(buffer);
  }
Answer by ArminRigo · Feb 10, 2020 at 10:12 AM
FWIW, I'm trying to use a similar CustomBlit() function and eventually found out the correct tweak. For the next person's usage, I'm copying here the complete thing:
 /* Sometimes you need to save and restore the active rendertexture. */
 var original = RenderTexture.active;
 RenderTexture.active = destination;   /* or Graphics.SetRenderTarget(..) */
 
 // Set the '_MainTex' variable to the texture given by 'source'
 mat.SetTexture("_MainTex", source);
 GL.PushMatrix();
 GL.LoadOrtho();
 // activate the first shader pass (in this case we know it is the only pass)
 mat.SetPass(0);
 // draw a quad over whole screen
 GL.Begin(GL.QUADS);
 GL.TexCoord2(0f, 0f); GL.Vertex3(0f, 0f, 0f);    /* note the order! */
 GL.TexCoord2(0f, 1f); GL.Vertex3(0f, 1f, 0f);    /* also, we need TexCoord2 */
 GL.TexCoord2(1f, 1f); GL.Vertex3(1f, 1f, 0f);
 GL.TexCoord2(1f, 0f); GL.Vertex3(1f, 0f, 0f);
 GL.End();
 GL.PopMatrix();
 RenderTexture.active = original;    /* restore */
The shader itself:
 Shader "Unlit/MyCustomBlit"
 {
     Properties
     {
         _MainTex ("Texture", 2D) = "white" {}
     }
     SubShader
     {
         Tags { "RenderType"="Opaque" }
         LOD 100
 
         Pass
         {
             CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag
 
             struct appdata
             {
                 float4 vertex : POSITION;
                 float2 uv : TEXCOORD0;
             };
 
             struct v2f
             {
                 float2 uv : TEXCOORD0;
                 float4 vertex : SV_POSITION;
             };
 
             sampler _MainTex;
 
             v2f vert (appdata v)
             {
                 v2f o;
                 o.vertex = UnityObjectToClipPos(v.vertex);
                 o.uv = v.uv;     /* just copy the coordinates here */
                 return o;
             }
 
             float4 frag (v2f i) : SV_Target
             {
                 float4 input_col = tex2D(_MainTex, i.uv);
                 /* post-processing here */
                 return input_col;
             }
             ENDCG
         }
     }
 }
 
Answer by markefus · Jan 27, 2019 at 02:21 AM
So have some updates, but it still isn't working. Any ideas??
 public Shader shader;
 private Material mat;
 private Camera cam;
 void OnEnable()
 {
     // Create a material that uses the desired shader
     mat = new Material(shader);
     // Get the camera object (this script must be assigned to a camera)
     cam = GetComponent<Camera>();
 }
 [ImageEffectOpaque] // Draw after opaque, but before transparent geometry
 void OnRenderImage(RenderTexture source, RenderTexture destination)
 {
     // Call custom Blit function
     // (usually Graphics.Blit is used)
     CustomBlit(source, destination, mat);
 }
 void CustomBlit(RenderTexture source, RenderTexture destination, Material mat)
 {
     // Custom Blit
     // ===========
     // Set the given destination texture as the active render texture
     Graphics.SetRenderTarget(destination.colorBuffer, source.depthBuffer);
    
     // Set the '_MainTex' variable to the texture given by 'source'
     mat.SetTexture("_MainTex", source);
     GL.PushMatrix();
     GL.LoadOrtho();
     // activate the first shader pass (in this case we know it is the only pass)
     mat.SetPass(0);
     // draw a quad over whole screen
     GL.Begin(GL.QUADS);
     GL.Vertex3(0, 0, 0);
     GL.Vertex3(1, 0, 0);
     GL.Vertex3(1, 1, 0);
     GL.Vertex3(0, 1, 0);
     GL.End();
     GL.PopMatrix();
 }
Your answer
 
 
              koobas.hobune.stream
koobas.hobune.stream 
                       
               
 
			 
                