What shader emulates Photoshop's Screen / Linear Dodge?

I have three quads for a 2D game, each with a circular matteerial. When they come together, I want them to do a Screen / Linear Dodge (Photoshop effect) on themselves, with the ability to change alpha transparency.

The “Additive” filter in Unity doesn’t seem to generate this effect because it takes into consideration the colors behind the objects, and not just the objects themselves.

Maybe I’m just using Additive wrong, because it sort of generates the desired effect, but not exactly like the attached file. (Should they be on their own separate layer with their own separate camera, or something?)

The documentation for shaders is hard to slog through, since it’s listed by shader and not a list of “What do you want your object to do visually?” So even if such a shader doesn’t exist and needs to be written, there’s no documentation I can find that says “do X to get effect Y.”

Both of these Photoshop layer blending modes can be expressed using shader blend operations and factors. See ShaderLab syntax: Blending for details.

Screen Blend Mode

In ShaderLab syntax, it looks like this:

BlendOp Add
Blend   OneMinusDstColor One, One Zero // screen

Linear Dodge

BlendOp Add
Blend   SrcAlpha One, One Zero // linear dodge

Example
Here is an unlit “Screen” shader example to play around with.

Shader "Unlit/ScreenBlend" {
Properties {
   _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
   _Color ("Color", Color) = (1,1,1,1)
}

SubShader {
   Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
   LOD 100

   BlendOp Add
   Blend OneMinusDstColor One, One Zero // screen
   //Blend SrcAlpha One, One Zero // linear dodge
   ZWrite Off
   AlphaTest Greater .01
     
   Pass {
     CGPROGRAM
       #pragma vertex vert
       #pragma fragment frag
     
       #include "UnityCG.cginc"

       struct appdata_t {
         float4 vertex : POSITION;
         float2 texcoord : TEXCOORD0;
       };

       struct v2f {
         float4 vertex : SV_POSITION;
         half2 texcoord : TEXCOORD0;
       };

       sampler2D _MainTex;
       float4 _MainTex_ST;
       float4 _Color;
     
       v2f vert (appdata_t v)
       {
         v2f o;
         o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
         o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
         return o;
       }
     
       fixed4 frag (v2f i) : COLOR
       {
         fixed4 col = _Color*tex2D(_MainTex, i.texcoord);
         col.rgb *= col.a;
         return col;
       }
     ENDCG
   }
}
}

Hope it helps!

2 Likes

Thank you! I’ll try it out asap!

I can confirm that this shader works perfectly.

It starts to lag when about 100 objects are in the same spot, so I’ll be sure to use it sparingly. :slight_smile: