1
\$\begingroup\$

I'm trying to write a shader that doesn't blend additively etc etc. I'd like to take whichever of the source or destination colours is brighter and use that and BlendOp Max seemed like the tool for the job.

However, as you can see below, the shadow of one light seems to be occluding the other, which doesn't match up with how I understand BlendOp Max is supposed to work:

Could anyone clarify where I'm going wrong or provide an alternative?

Interestingly, Blend One One is working fine, however, BlendOp Add (along with all the other BlendOps apart from the 'logical' ones) are creating the same issue.

Two point lights on the plane, the shadow of one occludes the illumination of the other

Update

Shader Code:

Shader "Lantern/Flat Pullup" {
Properties {
    _LitTex ("Lit (RGB)", 2D) = "white" {}
    _UnlitTex ("Unlit (RGB)", 2D) = "white" {}
    _Pullup ("Pull up Point", Range(0,1)) = 0.7
    _BlendSize ("Blend Size", Float) = 0.3
}
SubShader {
    Pass{
        Tags { "LightMode" = "ForwardBase" }
        LOD 200

        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

        uniform sampler2D _UnlitTex;
        uniform float4 _UnlitTex_ST;
        uniform sampler2D _LitTex;
        uniform float4 _LitTex_ST;
        uniform float _Pullup;
        uniform float _BlendSize;

        uniform float4 _LightColor0;

        struct VI {
            float4 vertex : POSITION;
            float4 tex : TEXCOORD0;
        };

        struct V2F {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
            float4 posWorld : TEXCOORD1;
        };

        V2F vert(VI v){
            V2F o;
            o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
            o.tex = v.tex;
            o.posWorld = mul(_Object2World, v.vertex);
            return o;
        }

        float4 frag(V2F i) : COLOR {
            float3 flatReflection = _LightColor0.xyz * 
                (1 / length(_WorldSpaceLightPos0.xyz - i.posWorld.xyz));

            return lerp(
                tex2D(_UnlitTex, i.tex.xy * _UnlitTex_ST.xy + _UnlitTex_ST.zw),
                tex2D(_LitTex, i.tex.xy * _LitTex_ST.xy + _LitTex_ST.zw),
                clamp((length(flatReflection) - _Pullup + _BlendSize) / (2 * _BlendSize), 0, 1)
            );

        }

        ENDCG
    }

    Pass{
        Tags{"LightMode" = "ForwardAdd"}
        //Blend One One
        BlendOp Max
        LOD 200
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

        uniform sampler2D _UnlitTex;
        uniform float4 _UnlitTex_ST;
        uniform sampler2D _LitTex;
        uniform float4 _LitTex_ST;
        uniform float _Pullup;
        uniform float _BlendSize;

        uniform float4 _LightColor0;

        struct VI {
            float4 vertex : POSITION;
            float4 tex : TEXCOORD0;
        };

        struct V2F {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
            float4 posWorld : TEXCOORD1;
        };

        V2F vert(VI v){
            V2F o;
            o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
            o.tex = v.tex;
            o.posWorld = mul(_Object2World, v.vertex);
            return o;
        }

        float4 frag(V2F i) : COLOR {
            float3 flatReflection = _LightColor0.xyz * 
                (1 / length(_WorldSpaceLightPos0.xyz - i.posWorld.xyz));
            return lerp(
                float4(0,0,0,1),
                tex2D(_LitTex, i.tex.xy * _LitTex_ST.xy + _LitTex_ST.zw),
                clamp((length(flatReflection) - _Pullup + _BlendSize) / (2 * _BlendSize), 0, 1)
            );
        }
        ENDCG

    }
}   
FallBack "Diffuse"
}

Update 2

The same plane and lights rendered using Unity's standard shader, for illustrative purposes. Two point lights on a plane, rendered using Unity's standard shader

\$\endgroup\$
4
  • \$\begingroup\$ What geometry setup are we looking at here? Is this two overlapping quads? If so, the one behind might be getting rejected by the depth buffer. Sharing your queue and Z-Write/Z-Test settings would help diagnose the issue. \$\endgroup\$ Commented Sep 23, 2016 at 17:09
  • \$\begingroup\$ It's in unity, so the plane asset. Shader is written as a vert-frag shader in ShaderLab/CG. Note that the 'line of doom', as I've called it, moves in some way that's dependant on the camera and doesn't lie along an edge boundary or similar.. \$\endgroup\$ Commented Sep 23, 2016 at 17:15
  • \$\begingroup\$ That doesn't answer the question, unfortunately. Including your shader code in the question would help. Can you also clarify where these two shapes are coming from — are these two lights or two projectors shining onto one plane, or part of the texturing effect you've applied to its surface...? \$\endgroup\$ Commented Sep 23, 2016 at 17:18
  • \$\begingroup\$ Added shader code. The 'shapes' is the lighting from two point lights. The colours are part of one of the textures on the object (the _LitTex in the shader, the _UnlitTex is just black) \$\endgroup\$ Commented Sep 23, 2016 at 17:22

1 Answer 1

1
\$\begingroup\$

Turns out, that even though the OpenGL documentation says the Max/Min functions don't take your blend factors into consideration, some quirk in shaderlab means you have to specify them anyway.

As such, the lonely BlendOp Max should be have Blend One One (or suitable) specified as well.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.