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\$
  • \$\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\$ – DMGregory Sep 23 '16 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\$ – LeftRight92 Sep 23 '16 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\$ – DMGregory Sep 23 '16 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\$ – LeftRight92 Sep 23 '16 at 17:22
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\$

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.