1
\$\begingroup\$

I'm working on a 2D Unity project where the player can only see objects in their field of view. I have successfully created a mesh that overlaps anything that would be in the player's field of view, but now I'm having trouble with only showing parts of objects that the mesh overlaps with.

Here is what I have so far (the gray area is the player's field of view which is a mesh:

Currently:

Here is the type of thing that I'm looking for:

Goal:

What can I do to get that desired effect? Shaders (I have no clue how to use shaders)? Colliders? Any ideas would be greatly appreciated. If there is any info you need that I didn't provide, comment and I add the necessary info. Thank you in advance!

\$\endgroup\$
  • \$\begingroup\$ would you be willing to share the code for the original field of view mesh? There's a lot of situations where people want to render FOV in 2D games, but good examples are rather lacking. \$\endgroup\$ – Stephan Aug 17 '18 at 18:58
3
\$\begingroup\$

First, create a simple mesh (such as a quad or a cube). Place it over top the actual game area, and stretch it so that it covers the entire camera view.

Next, create a new shader named "ObscurityShader", and paste in the following shader code:

Shader "Custom/ObscurityShader"
{
    SubShader
    {
        Tags{"Queue" = "Transparent+1" "RenderType" = "Transparent"}

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                return 0;
            }
            ENDCG
        }
    }
}

Everything inside "Pass" is just a bare-bones vertex/fragment shader. The most important part for us is the "Tags" at the top of the code.

Now create a new material and set it to use ObscurityShader. Select the mesh we made earlier and set it to use this material.

Next, create a second shader named "VisibilityShader", and paste in the following shader code:

Shader "Custom/VisibilityShader"
{
    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
        ColorMask 0

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                return 0;
            }
            ENDCG
        }
    }
}

Note that this shader is near-identical to the first, with two small differences:

  1. The rendering queue is "Transparent" rather than "Transparent+1", ensuring VisibilityShader is rendered before ObscurityShader.
  2. We use ColorMask 0, which essentially sets an invisible pixel that the ObscurityShader doesn't overwrite.

Create a new material and set it to use VisibilityShader. Set your "visible area" mesh to use this material.

Finally, set your "visible area" mesh to sit above the obscuring mesh, and you should see a hole in the black void in the shape of your visibility mesh!

Final Result

\$\endgroup\$
  • 1
    \$\begingroup\$ This is a very good answer, that I think can be improved further if you were to explain what the shader code does. It's far better than "just copy and paste" and even if the OP doesn't understand shaders, it can help someone else that browses this question that may be familiar with them. \$\endgroup\$ – TomTsagk Aug 13 '18 at 11:17
  • \$\begingroup\$ Wow, this is a fantastic answer! Although I still don't understand most of the shaders' code, I understand enough to see why this works. Thank you! \$\endgroup\$ – blinkafrootable Aug 13 '18 at 14:39

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.