2
\$\begingroup\$

I am trying to make a shader that applies a black image with 50% transparency to the entire screen, with the exception of a designated area. I am starting by just trying to apply a shader to the entire screen. So I am using the default ImageEffect Shader.

This is my before and after when applying my shader, which should invert everything. It inverts everything except for the Balmer's Peak, which is a Unity Image:

Before:

enter image description here

After:

enter image description here

Example of what I am going for:

enter image description here

I attached a script using OnRenderImage to the Camera, and the attached material is being applied to everything in sight, except the UI. What can I do to make my material applied to everything on the screen, including the UI?

I am new to shaders, so this may seem like a bit of a dumb question. But I am not sure what direction I should be headed. Here are my scripts, although I did not really change anything from what Unity provided me:

Script attached to camera:

using UnityEngine;

public class ButtonHighlight : MonoBehaviour
{
    [Tooltip("Material which is to be applied")]
    [SerializeField]
    private Material material;

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Graphics.Blit(source, material);
    }
}

Shader attached to material above:

Shader "Magic/Magic Shader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                // just invert the colors
                col = 1 - col;
                return col;
            }
            ENDCG
        }
    }
}

What is the correct approach to apply a shader to the entire screen? (Keeping in mind, that the purpose is to add a filter to most, but not all, of the screen.)

\$\endgroup\$
5
\$\begingroup\$

The default behavior for Unity's UI is to draw after the post-processing effects have been applied. This is dictated by the Render Mode setting on your scene's Canvas object.

Switch the Render Mode to Screen Space - Camera, and drag your scene's main camera into the Render Camera property (which will appear when you change the render mode). Now your canvas's UI will draw before that camera's post-processing.

There's more information about render modes in the Unity documentation about Canvas.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.