Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Make vertices before players transparent (with local multiplayer)

Discussion in 'Shaders' started by Azurexis, Jun 11, 2019.

  1. Azurexis

    Azurexis

    Joined:
    Oct 26, 2018
    Posts:
    7
    Hey guys!

    I'm kinda new to unity and tried to solve this on my own, but had no luck yet.
    I have some procedural generated meshes in a minecraft style, but the game is not in first person, but rather like in a top-down perspective.


    (Sprites are placeholders)

    When I dig underground, I can't see the player object anymore. So I thought, it would be best if I could turn all blocks with a higher y and a lower z than the player transparent.

    As far as I understood this is possible with a shader.

    But is possible to apply different shader to different cameras? I wanted to implement a couch-coop possibility with a splitscreen, but for that I would have to apply different vertex shaders to each camera. Is that even possible? And if yes, how?
     
  2. Azurexis

    Azurexis

    Joined:
    Oct 26, 2018
    Posts:
    7
    Hey, it's me again!

    So I've tried to wrap my head around shaders (I managed to get a palette swap shader working!), but I still can't even figure out how to do this shader for one person.

    I kinda managed to make the blocks before the player transparent (please ignore the chunk borders haha):


    However, you can't see the blocks where the player has been digging.

    Here you can see, that there are some block triangles that indicate the path where the player has been digging.


    This is my shader code:
    Code (CSharp):
    1. Shader "Custom/TransparentBlocks"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Main Color", Color) = (1,1,1,1)
    6.         _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    7.         _Metallic ("Metallic", Range(0,1)) = 0.5
    8.  
    9.         _PlayerPosition ("Player Position", Vector) = (0, 0, 0)
    10.     }
    11.     SubShader
    12.     {
    13.         Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
    14.  
    15.         Pass
    16.         {
    17.             ZWrite On
    18.             ColorMask 0
    19.         }
    20.  
    21.         CGPROGRAM
    22.         #pragma surface surf Standard fullforwardshadows alpha
    23.         #pragma target 3.0
    24.  
    25.         struct Input
    26.         {
    27.             float2 uv_MainTex;
    28.             float3 worldPos;
    29.             float4 color : COLOR;
    30.         };
    31.  
    32.         sampler2D _MainTex;
    33.         fixed4 _Color;
    34.         half _Metallic;
    35.         fixed3 _PlayerPosition;
    36.  
    37.         void surf (Input IN, inout SurfaceOutputStandard o)
    38.         {
    39.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex)* _Color;
    40.             o.Albedo = c.rgb;
    41.             o.Albedo *= IN.color.rgb;
    42.             o.Metallic = _Metallic;
    43.            
    44.             if (distance(IN.worldPos.x, _PlayerPosition.x) < 5 && IN.worldPos.y > _PlayerPosition.y && IN.worldPos.z < _PlayerPosition.z)
    45.             {              
    46.                 o.Alpha = 0.2;
    47.             }
    48.             else
    49.             {
    50.                 o.Alpha = c.a;  
    51.             }
    52.         }
    53.  
    54.         ENDCG
    55.     }
    56.  
    57.     FallBack "Diffuse"
    58.  
    59. }
    Can someone tell me how to make the path visible? I've tried different stuff with ZTest, ZWrite, discarding vertices, multiple render passes but nothing seems to work. I could of course rerender the mesh everytime the player moves, but a shader would be much more convenient for multiplayer.

    Thanks in advance for any answers!
     
  3. Azurexis

    Azurexis

    Joined:
    Oct 26, 2018
    Posts:
    7
    Hey, sorry for double posting, but I really need help with this problem. I've been trying to solve it for a few days. I searched all over the internet, but couldn't find a solution, probably doesn't help that I'm kinda new to shaders.

    I managed to advance the shader to the following state:

    The paths can be seen now, however the shader won't work with lights and shadows. Furthermore I have some ugly black triangles that are (randomly?) shown.

    This is the shader code at the moment:
    Code (CSharp):
    1. Shader "Custom/TransparentBlocks"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.  
    7.         _PlayerPosition ("Player Position", Vector) = (0, 0, 0)
    8.     }
    9.     SubShader
    10.     {
    11.         Tags {"Queue"="Transparent" "RenderType"="Transparent" }
    12.         LOD 100
    13.  
    14.         ZWrite On
    15.         Blend SrcAlpha OneMinusSrcAlpha
    16.  
    17.         Pass
    18.         {
    19.             CGPROGRAM
    20.             #pragma target 3.0
    21.             #pragma vertex vert
    22.             #pragma fragment frag
    23.             #include "UnityCG.cginc"
    24.             struct appdata{
    25.                 float4 position : POSITION;
    26.                 float2 uv : TEXCOORD0;
    27.             };
    28.             struct v2f {
    29.                 float4 position : SV_POSITION;
    30.                 float2 uv : TEXCOORD0;
    31.                 float4 worldSpacePos : TEXCOORD1;
    32.             };
    33.             sampler2D _MainTex;
    34.             float4 _MainTex_ST;
    35.             fixed3 _PlayerPosition;
    36.             v2f vert(appdata vertex)
    37.             {
    38.                 v2f output;
    39.                 output.position = UnityObjectToClipPos(vertex.position);
    40.                 output.worldSpacePos = mul(unity_ObjectToWorld, vertex.position);
    41.                 output.uv = TRANSFORM_TEX(vertex.uv, _MainTex);
    42.                 return output;
    43.             }
    44.             fixed4 frag(v2f input) : SV_TARGET
    45.             {
    46.                 fixed4 col = tex2D(_MainTex, input.uv);
    47.                 col.a = 1;
    48.              
    49.                 if(distance(input.worldSpacePos.xyz, _PlayerPosition.xyz) < 7 && input.worldSpacePos.y > _PlayerPosition.y && input.worldSpacePos.z < _PlayerPosition.z + 1)
    50.                 {
    51.                     discard;
    52.                 }
    53.              
    54.                 return col;
    55.              }
    56.  
    57.              ENDCG
    58.         }
    59.  
    60.         CGPROGRAM
    61.         #pragma surface surf Standard fullforwardshadows alpha
    62.         #pragma target 3.0
    63.  
    64.         struct Input
    65.         {
    66.             float2 uv_MainTex;
    67.             float3 worldPos;
    68.             float4 color : COLOR;
    69.         };
    70.  
    71.         sampler2D _MainTex;
    72.         fixed4 _Color;
    73.         half _Metallic;
    74.         fixed3 _PlayerPosition;
    75.  
    76.         void surf (Input IN, inout SurfaceOutputStandard o)
    77.         {
    78.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex)* _Color;
    79.             o.Albedo = c.rgb;
    80.             o.Albedo *= IN.color.rgb;
    81.             o.Metallic = _Metallic;
    82.        
    83.             if (distance(IN.worldPos.xyz, _PlayerPosition.xyz) < 7 && IN.worldPos.y > _PlayerPosition.y && IN.worldPos.z < _PlayerPosition.z + 1)
    84.             {            
    85.                 o.Alpha = 0.5;
    86.             }
    87.             else
    88.             {
    89.                 o.Alpha = c.a;
    90.             }
    91.         }
    92.  
    93.         ENDCG
    94.  
    95.     }
    96. }
    Is there a way to implement shadows/light and to get rid of the unwanted triangles?

    Sorry, I really don't want to spam, but I'm searching desperately for help on this one.

    Would be really grateful for any answers!!
     
    Last edited: Jun 16, 2019
  4. Azurexis

    Azurexis

    Joined:
    Oct 26, 2018
    Posts:
    7
    Managed to get it even further. Now I almost have the desired effect. The only bug that is left now, is that the see-through window creates no shadow, although there is a ceiling.


    Tried to solve the shadow bug for the whole day, couldn't solve it. Help is appreciated <3

    This is the code now:
    Code (CSharp):
    1. Shader "Custom/NewSurfaceShader"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic ("Metallic", Range(0,1)) = 0.0
    9.         _Cutoff("Cutoff", Range(0, 1)) = 0.5
    10.  
    11.         _PlayerPosition ("Player Position", Vector) = (0, 0, 0)
    12.     }
    13.     SubShader
    14.     {  
    15.         Tags { "Queue"="Geometry" }
    16.  
    17.         CGPROGRAM
    18.  
    19.             #pragma surface surf Standard fullforwardshadows addshadow
    20.             #pragma target 3.0
    21.  
    22.             sampler2D _MainTex;
    23.  
    24.             struct Input
    25.             {
    26.                 float2 uv_MainTex;
    27.                 float3 worldPos;
    28.             };
    29.  
    30.             half _Glossiness;
    31.             half _Metallic;
    32.             fixed4 _Color;
    33.             fixed3 _PlayerPosition;
    34.  
    35.             void surf (Input IN, inout SurfaceOutputStandard o)
    36.             {
    37.                 fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    38.                 o.Albedo = c.rgb;
    39.                 o.Metallic = _Metallic;
    40.                 o.Smoothness = _Glossiness;
    41.                  if (distance(IN.worldPos.xz, _PlayerPosition.xz) < 7 && IN.worldPos.y > _PlayerPosition.y)
    42.                 {            
    43.                     clip(-1);
    44.                 }
    45.             }
    46.  
    47.         ENDCG
    48.  
    49.         Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
    50.  
    51.         CGPROGRAM
    52.  
    53.             #pragma surface surf Standard addshadow alpha:fade
    54.             #pragma target 3.0
    55.  
    56.             sampler2D _MainTex;
    57.  
    58.             struct Input
    59.             {
    60.                 float2 uv_MainTex;
    61.                 float3 worldPos;
    62.             };
    63.  
    64.             half _Glossiness;
    65.             half _Metallic;
    66.             fixed4 _Color;
    67.             fixed3 _PlayerPosition;
    68.  
    69.             void surf (Input IN, inout SurfaceOutputStandard o)
    70.             {
    71.                 fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    72.                 o.Albedo = c.rgb;
    73.                 o.Metallic = 0;
    74.                 o.Smoothness = _Glossiness;
    75.                  if (distance(IN.worldPos.xz, _PlayerPosition.xz) < 7 && IN.worldPos.y > _PlayerPosition.y)
    76.                 {  
    77.                     o.Albedo *= 0;
    78.                     o.Alpha = 0.2;
    79.                 }
    80.                 else
    81.                 {
    82.                     discard;
    83.                 }
    84.             }
    85.  
    86.         ENDCG
    87.  
    88.     }
    89.     FallBack Off
    90. }
    91.  
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    A few things:

    Shaders can only have one queue & render type. If you have more than one defined, it’s only going to use one of them. If you want to different queues, you’d need to use two separate materials. Just remove the second set of Tags if you’re not noticing any problems.

    Second, shaders only use the first shadow caster pass in the shader. You have two; one generated by the first surface shader (via addshadow) with the top surface clipped away, a the second generated by the second surface shader which is ignored. Unity’s main directional lighting uses that shadow caster pass in two ways, one for what to render shadows onto, and the other for what you expect for what to cast shadows from. Unity’s main directional shadows cast onto a world position derived from the camera depth texture, which is generated by rendering the scene in a pre-pass using the shadow caster shader pass from the view of the camera.

    For this shader you effectively need to render the geometry clipped for the camera depth texture, and visible for the shadow maps. To do that you need to detect when you’re rendering to shadows vs the camera depth, but there’s no 100% perfect way to do that. The closest thing is to test if the current projection matrix is orthographic or not, since the main directional light is always orthographic.

    The first post in this thread is still the only way I’ve found to do this, and it means shadows will be wrong for spot lights.
    https://forum.unity.com/threads/dif...dow-caster-and-shadow-receiver-in-5-2.362653/

    Basically, remove addshadow from the second surface shader, and add the above linked code to the first surf function to skip the discard if you’re rendering with an orthographic projection and “SHADOWS_DEPTH” is defined (which is automatically set for shadow maps and depth texture rendering).

    One last thought. Maybe put in a depth only pass between the two surface shaders. That’ll remove the “random” dark polygons (caused by the mesh’s triangle order).