Search Unity

Creating Image effects for SinglePass stereo rendering with multiple shader passes.

Discussion in 'Image Effects' started by Mutimir, Jul 15, 2019.

  1. Mutimir

    Mutimir

    Joined:
    Dec 6, 2018
    Posts:
    36
    I am creating a simple bloom effect for a Oculus quest app. It works in multi pass rendering but am having some issues making it work in single pass stereo rendering. I was following this docs: https://docs.unity3d.com/Manual/Android-SinglePassStereoRendering.html
    and for simplicity have made a simple image effect that demonstrates the problem i have. It has 2 shader passes. The first one just inverts the colors and the second one creates a grayscale from the red channel. Both passes work by themselves and work together in multipass rendering but in single pass i get a grayish white left eye and a black right eye.
    Here is the shader
    Code (CSharp):
    1. Shader "Hidden/InvertColours"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.     }
    7.  
    8.     CGINCLUDE
    9.     #include "UnityCG.cginc"
    10.  
    11.     UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex);
    12.     uniform    half4 _MainTex_ST;
    13.  
    14.     struct appdata
    15.     {
    16.         float4 vertex : POSITION;
    17.         float2 uv : TEXCOORD0;
    18.     };
    19.  
    20.     struct v2f
    21.     {
    22.         float2 uv : TEXCOORD0;
    23.         float4 vertex : SV_POSITION;
    24.         UNITY_VERTEX_OUTPUT_STEREO
    25.     };
    26.  
    27.     v2f vertPass1 (appdata v)
    28.     {
    29.         v2f o;
    30.         UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o)
    31.         o.vertex = UnityObjectToClipPos(v.vertex);
    32.         o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    33.         return o;
    34.     }
    35.  
    36.     fixed4 fragPass1 (v2f i) : SV_Target
    37.     {
    38.         UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    39.         fixed4 col = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv);
    40.         // just invert the colors
    41.         col.rgb = 1 - col.rgb;
    42.         return col;
    43.     }
    44.  
    45.      v2f vertPass2 (appdata v)
    46.     {
    47.         v2f o;
    48.         UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o)
    49.         o.vertex = UnityObjectToClipPos(v.vertex);
    50.         o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    51.         return o;
    52.     }
    53.  
    54.     fixed4 fragPass2 (v2f i) : SV_Target
    55.     {
    56.         UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    57.         fixed4 col = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv);
    58.         // just make a greyscale from red chanel
    59.         col.rgb = col.rrr;
    60.         return col;
    61.     }
    62.     ENDCG
    63.  
    64.     SubShader
    65.     {
    66.         // No culling or depth
    67.         Cull Off ZWrite Off ZTest Always
    68.  
    69.         Pass
    70.         {
    71.             CGPROGRAM
    72.             #pragma vertex vertPass1
    73.             #pragma fragment fragPass1
    74.  
    75.             ENDCG
    76.         }
    77.  
    78.         Pass
    79.         {
    80.             CGPROGRAM
    81.             #pragma vertex vertPass2
    82.             #pragma fragment fragPass2
    83.  
    84.             ENDCG
    85.         }
    86.     }
    87. }
    88.  
    and here is the cs script attached to the camera:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [ExecuteInEditMode]
    6. [RequireComponent(typeof(Camera))]
    7. public class InvertColours : MonoBehaviour
    8. {
    9.     public Material fastInvertColourMaterial = null;
    10.  
    11.     private void OnRenderImage(RenderTexture source, RenderTexture destination)
    12.     {
    13.         RenderTexture rt = RenderTexture.GetTemporary(source.width, source.height, 0, source.format);
    14.         Graphics.Blit(source, rt, fastInvertColourMaterial, 0);
    15.         Graphics.Blit(rt, destination, fastInvertColourMaterial, 1);
    16.     }
    17.  
    18. }
    19.  
     
  2. Mutimir

    Mutimir

    Joined:
    Dec 6, 2018
    Posts:
    36
    Here is the solution for anyone wondering. The RenderTexture needs to be set up correctly to store data between passes. Hope it helps.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.XR;
    5.  
    6. [ExecuteInEditMode]
    7. [RequireComponent(typeof(Camera))]
    8. public class InvertColours : MonoBehaviour
    9. {
    10.     public Material fastInvertColourMaterial = null;
    11.  
    12.     private void OnRenderImage(RenderTexture source, RenderTexture destination)
    13.     {
    14.         RenderTextureDescriptor desc;
    15.         if (XRSettings.enabled)
    16.             desc = XRSettings.eyeTextureDesc;
    17.         else
    18.             desc = new RenderTextureDescriptor(Screen.width, Screen.height); // Not XR
    19.  
    20.         RenderTexture rt = RenderTexture.GetTemporary(desc);
    21.         Graphics.Blit(source, rt, fastInvertColourMaterial, 0);
    22.         Graphics.Blit(rt, destination, fastInvertColourMaterial, 1);
    23.         RenderTexture.ReleaseTemporary(rt);
    24.     }
    25.  
    26. }
     
  3. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,349
    Thanks for this information, seems one of the most vital parts is missing in stereo documentation.

    I wonder if this is same handling if use a quad to draw directly to screen with GL functions ?