Search code examples
unity-game-engineshaderarcore

Problem with surface shader for clipping with a plane in Augmented Reality


I want to clip a 3D model with a plane in Unity, found this great tutorial for it and got it to work easily in the usual Unity environment. The tutorial uses a surface shader to clip all parts above a plane and only show the parts underneath it, so that you get the impression of cutting open a 3D model (see the GIFs in the linked tutorial). Code of the surface shader is this:

Shader "Clippingplane" {
    Properties {
        _Color ("Tint", Color) = (0, 0, 0, 1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Smoothness ("Smoothness", Range(0, 1)) = 0
        _Metallic ("Metalness", Range(0, 1)) = 0
        [HDR] _Emission ("Emission", color) = (0,0,0)

        [HDR]_CutoffColor("Cutoff Color", Color) = (1,0,0,0)
    }
    SubShader {
        Tags{ "RenderType"="Opaque" "Queue"="Geometry"}

        // render faces regardless if they point towards the camera or away from it
        Cull Off

        CGPROGRAM

        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        sampler2D _MainTex;
        fixed4 _Color;

        half _Smoothness;
        half _Metallic;
        half3 _Emission;

        float4 _Plane;

        float4 _CutoffColor;

        struct Input {
            float2 uv_MainTex;
            float3 worldPos;
            float facing : VFACE;
        };

        void surf (Input i, inout SurfaceOutputStandard o) {
            //calculate signed distance to plane
            float distance = dot(i.worldPos, _Plane.xyz);
            distance = distance + _Plane.w;
            //discard surface above plane
            clip(-distance);

            float facing = i.facing * 0.5 + 0.5; //convert facing from -1/1 to 0/1 for linear interpolation

            //normal color stuff
            fixed4 col = tex2D(_MainTex, i.uv_MainTex);
            col *= _Color;
            o.Albedo = col.rgb * facing;
            o.Metallic = _Metallic * facing;
            o.Smoothness = _Smoothness * facing;
            o.Emission = lerp(_CutoffColor, _Emission, facing); // lerp = linear interpolation

        }
        ENDCG
    }
    FallBack "Standard"
}

Now I want to convert this whole interaction of moving a clipping plane through a 3D model to Augmented Reality, I use ARFoundation with ARCore for that.

For some reason, the shader doesn't work in AR as expected now anymore. The "inside color" (red) covers the whole model itself, and not only the part where the model is cut open. Seems like the shader can't differentiate between outside and inside anymore? The clipping part works, however.

Screenshot of the whole 3D model showing in red

I played around a bit, but only got it to work to show the correct colors WITHOUT the clipping part working. Especially the part with the facing variable and its conversion seems like the one messing with the result. I don't really know that much about shaders so I'm wondering if anyone could point me in the right direction what is happening with the normals and stuff? The surface shader from the tutorial works fine in AR when leaving out the "Show the inside" part. Super weird, that the shader works in the usual Unity environment and not in AR. Any help appreciated!


Solution

  • Playing around a bit more brought me to my solution, I might not have had tested enough... Seems like AR already provides VFACE in a range from 0 to 1, so converting it made things wrong. I simply removed the conversion part which left me with only:

    float facing = i.facing;

    That seems to do the job! Hope this helps anyone trying to clip stuff in AR with a surface shader.