Search Unity

Question How to mask out part of a 3D object outside of boundaries of another 3D object

Discussion in 'General Graphics' started by igoapp, Dec 14, 2022.

  1. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    Hi,

    I have a 3D Object imitating an archery target. I also have a few 3D objects (planes) that imitate marks where shots hit the target. At present, the mark objects are drawn fully including the areas that go outside of the boundaries of the target. Is it possible to mask out these mark areas to show only what is within the target? The image shows what it is now and what I am trying to achieve.

    I have made some research and looks like the way to do it would be through writing some code in the shader (I am using URP). However, it is not clear what exactly should I do. Your help would be greatly appreciated!

    Thanks,

    IT
     

    Attached Files:

  2. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    So, I dug a little bit deeper, and applied a stencil shader like the following. I created a Sprite (circle) located right in front of the target and used this shader for it:

    Code (CSharp):
    1.  
    2. Shader "Custom/StencilMask" {
    3.  
    4.     Properties {
    5.             _Color ("Color", Color) = (1,1,1,1)
    6.             _StencilMask("Stencil Mask", Range(0, 255)) = 1
    7.         }
    8.         SubShader {
    9.             Tags { "RenderType"="Transparent" "Queue"="Geometry-1"}
    10.             LOD 200
    11.  
    12.             //ColorMask 0
    13.             Stencil {
    14.                 Ref 1
    15.                 Comp Never
    16.                 Fail Replace
    17.             }
    18.             Pass{}
    19.         }
    20.  
    21. }
    22.  
    For the Mark, I used the following shader:

    Code (CSharp):
    1.  
    2. Shader "Custom/StencilEffect" {
    3.     Properties {
    4.         _MainTex ("Base (RGB)", 2D) = "white" {}
    5.     }
    6.     SubShader {
    7.         Tags { "RenderType"="Opaque"}
    8.  
    9.         Stencil {
    10.             Ref 1
    11.             Comp equal
    12.             Pass Keep
    13.         }
    14.  
    15.         CGPROGRAM
    16.         #pragma surface surf Lambert
    17.  
    18.         sampler2D _MainTex;
    19.  
    20.         struct Input {
    21.             float2 uv_MainTex;
    22.         };
    23.  
    24.         void surf (Input IN, inout SurfaceOutput o) {
    25.             half4 c = tex2D (_MainTex, IN.uv_MainTex);
    26.             o.Albedo = c.rgb;
    27.             o.Alpha = c.a;
    28.         }
    29.         ENDCG
    30.     }
    31.     FallBack "Diffuse"
    32. }
    33.  

    So, two issues now. I do not see the marks only if I look at them from the back side of the target (not from the camera view) as shown in the images. Second issue: my Marks are pink rectangles now, a texture with a circle is gone. Anyway to apply it using a custom shader?

    Thanks a lot!

    IT
     

    Attached Files:

  3. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    So, I have almost solved the issue.

    First, I created a transparent sprite circle and put it on top of the target. Used the following shader:

    Code (CSharp):
    1.  
    2. Shader "Custom/StencilMaskShader"
    3. {
    4.     Properties
    5.     {
    6.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    7.         _Color ("Tint", Color) = (1,1,1,1)
    8.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    9.         [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
    10.         [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
    11.         [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
    12.         [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
    13.     }
    14.  
    15.     SubShader
    16.     {
    17.         Tags
    18.         {
    19.             "Queue"="Transparent"
    20.             "IgnoreProjector"="True"
    21.             "RenderType"="Transparent"
    22.             "PreviewType"="Plane"
    23.             "CanUseSpriteAtlas"="True"
    24.         }
    25.  
    26.         Cull Off
    27.         Lighting Off
    28.         ZWrite Off
    29.         Blend One OneMinusSrcAlpha
    30.  
    31.         //stencil operation
    32.         Stencil{
    33.             Ref 1
    34.             Comp Always
    35.             Pass Replace
    36.         }
    37.  
    38.         Pass
    39.         {
    40.             CGPROGRAM
    41.                 #pragma vertex SpriteVert
    42.                 #pragma fragment SpriteFrag
    43.                 #pragma target 2.0
    44.                 #pragma multi_compile_instancing
    45.                 #pragma multi_compile_local _ PIXELSNAP_ON
    46.                 #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
    47.                 #include "UnitySprites.cginc"
    48.             ENDCG
    49.         }
    50.     }
    51. }
    Then, I created a 3D Plane with a mark texture, and added the following to the shader:
    Code (CSharp):
    1.  
    2. Stencil
    3. {
    4.      Ref 1
    5.      Comp Equal
    6. }
    7.  
    It is working as expected except for one problem. Although the sprite mask is shown as circle, when the stencil effect is used, it appears not as circle but a figure with edges/faces. Can anyone give a hint how to fix it?

    Thanks!
     

    Attached Files: