Rendering only the top part of an object

Hey, i am doing a project for school where I have to write a shader and I am completely stuck. I want to have the shader only render the top part of the object i.e. if the normal vector of the faces are facing an upwards direction in world space, then they will be rendered and not if they are facing downwards.

What i have right now is a shader that changes the color of the faces depending on the world normal. What i would like to change it to is to render only the faces at a specified angle.

Shader "CGP/Testing"
{

    // no Properties block this time!
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // include file that contains UnityObjectToWorldNormal helper function
            #include "UnityCG.cginc"

            struct v2f {
                // we'll output world space normal as one of regular ("texcoord") interpolators
                half3 worldNormal : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            // vertex shader: takes object space normal as input too
            v2f vert (float4 vertex : POSITION, float3 normal : NORMAL)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(vertex);
                // UnityCG.cginc file contains function to transform
                // normal from object to world space, use that
                o.worldNormal = UnityObjectToWorldNormal(normal);
                return o;
            }
           
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 c = 0;
                // normal is a 3D vector with xyz components; in -1..1
                // range. To display it as color, bring the range into 0..1
                // and put into red, green, blue components
                c.rgb = i.worldNormal*0.5+0.5;
                c.a = 0;
                return c;
            }
            ENDCG
        }
    }
}

Which produces this:


What you’re looking for is a dot product. Do a dot() of your world normal and an upwards vector value. The closer to 1 the returned value is, the more the two values match and thus implies it is pointing upwards.

From there you can simply write discard; if the value is too low.

I mean, if it’s world up, then worldNormal.y is the same as dot(worldNormal, float3(0,1,0)).

This line should hide any surfaces pointing down.

clip(-i.worldNormal.y);
1 Like

Thank you I got it to work using this. It just needed to be clip(i.worldNormal.y) instead :slight_smile:

1 Like

Whoops! Yeah, the original would hide the top faces. :smile: