Search Unity

My falloff shader appears different in the editor than in game?

Discussion in 'Shaders' started by CloudyVR, Sep 5, 2019.

  1. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    715
    I am attempting to create a cutoff shader that has shadows and fades/falloff as a function of distance from camera:
    Code (csharp):
    1. Shader "Custom/Falloff"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         [NoScaleOffset] _BumpMap ("Normalmap", 2D) = "bump" {}
    7.         _Cutoff("Alpha Cutoff", Range(0,1)) = 0.5
    8.         _Color ("Tint", Color) = (1,1,1,1)
    9.  
    10.         _MinVisDistance("MinDistance",Float) = 0
    11.         _MaxVisDistance("MaxDistance",Float) = 20
    12.     }
    13.  
    14.     SubShader
    15.     {
    16.         Tags
    17.         {
    18.             "Queue"="AlphaTest"
    19.             "IgnoreProjector"="True"
    20.             "RenderType"="Transparent"
    21.             "PreviewType"="Plane"
    22.             "CanUseSpriteAtlas"="True"
    23.         }
    24.  
    25.         Cull Off
    26.         Lighting on
    27.         ZWrite off
    28.  
    29.         Blend One OneMinusSrcAlpha
    30.  
    31.         CGPROGRAM
    32.         #pragma surface surf Lambert vertex:vert nofog alphatest:_Cutoff addshadow
    33.         #pragma target 3.0
    34.  
    35.         sampler2D _MainTex;
    36.         sampler2D _BumpMap;
    37.         fixed4 _Color;
    38.         half _MinVisDistance;
    39.         half _MaxVisDistance;
    40.  
    41.         struct Input
    42.         {
    43.             float2 uv_MainTex;
    44.             float2 uv_BumpMap;
    45.             fixed4 color;
    46.         };
    47.  
    48.         void vert (inout appdata_full v, out Input o)
    49.         {    
    50.             UNITY_INITIALIZE_OUTPUT(Input, o);
    51.  
    52.             half3 viewDirW = _WorldSpaceCameraPos - mul((half4x4)unity_ObjectToWorld, v.vertex);
    53.             half viewDist = length(viewDirW);
    54.             float falloff = 1.0f - (saturate((viewDist - _MinVisDistance) / (_MaxVisDistance - _MinVisDistance)));
    55.  
    56.             o.color = v.color * _Color;
    57.             o.color.a *= falloff;
    58.         }
    59.  
    60.         void surf (Input IN, inout SurfaceOutput o)
    61.         {
    62.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * IN.color;
    63.             o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    64.             o.Albedo = c.rgb * c.a;
    65.             o.Alpha = c.a;
    66.         }
    67.         ENDCG
    68.     }
    69.  
    70. Fallback "Transparent/Cutout/VertexLit"
    71. }
    It appears fine in the editor viewport, but the main camera fails to render the same result. And when the camera's Clear Flags is set as "Skybox" the material becomes completely invisible:

    However, if i change the camera's Clear Flags to "Solid Color" then I see it is rendered:


    What am I doing incorrectly that is preventing this shader from working with the skybox??
    Thanks for any help!!
     
    Last edited: Sep 5, 2019
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    The skybox renders after the opaque queue range and uses the depth buffer to know where to draw. Since your shader has ZWrite Off, the depth buffer hasn’t been filled in where your shader is being used, and the skybox renders over it.

    Change that to ZWrite On.
     
  3. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    715
    Thanks for taking a look at my shader.

    I'm not sure if what I am trying to do is even possible, but when I turn ZWrite On the transparent parts are now opaque (and I see streamers when I move my head around):

    After moving head camera:



    I really wish I understood shader language well enough to figure this out myself. I have already created a shader that does everything I need, except shadows.. that's where I keep getting lost.

    [EDIT]
    Sorry I changed the title, after bgolus's suggestion I realized that the actual issue I am having is in regards to a mismatch between the way the editor and the game render shaders.
     
    Last edited: Sep 5, 2019
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    Ah. Yeah.

    Unity’s built in rendering paths don’t support transparent queue objects receiving shadows. And objects that don’t write to the z buffer get overwritten by the skybox.

    The hack workaround is to do what you were doing and make a transparent object be part of the opaque queue, but then don’t use a skybox. If you want to have a skybox, you’ll need to put that on a mesh in the scene and have it render before your shader.
     
    CloudyVR likes this.
  5. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    715
    Excellent points!!

    I just created a fake skybox sorta thing and I can definitely see how that is an option! :D

    Would it be possible to somehow sample what's behind the surface and just add that to the z buffer (maybe in a second Pass)?
     
    Last edited: Sep 5, 2019
  6. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    715
    I found another post by bgolus that really helped:

    I am using VR, so the only change I had to make was to set the two cameras to have the same parent, done like dinner:


    [EDIT]
    And here's a script I created for adding a "skybox camera" programmatically:
    CreateSkyboxCamera.cs
    Code (csharp):
    1. using UnityEngine;
    2.  
    3. public class CreateSkyboxCamera : MonoBehaviour
    4. {
    5.     [Tooltip ("The main camera attached to the player's head.")]
    6.     public Camera playerCamera;
    7.     //[Tooltip ("A temporary camera for processing the skybox prior to the playerCamera's alpha buffer.")]
    8.     GameObject skyboxCamera;
    9.     //[Tooltip ("A parameter to restor the playerCamera back to whenever this script is disabled or destroyed.")]
    10.     CameraClearFlags previousClearFlagsParam;
    11.  
    12.     void OnDisable()
    13.     {
    14.         playerCamera.clearFlags = previousClearFlagsParam;
    15.         if (skyboxCamera != null) {
    16.             Destroy(skyboxCamera);
    17.         }
    18.     }
    19.  
    20.     void OnEnable()
    21.     {
    22.         skyboxCamera = new GameObject ("Skybox_Camera");
    23.         skyboxCamera.transform.parent = playerCamera.transform.parent;
    24.         skyboxCamera.transform.position = playerCamera.transform.position;
    25.         skyboxCamera.transform.rotation = Quaternion.identity;// playerCamera.transform.rotation;
    26.         skyboxCamera.transform.localScale = playerCamera.transform.localScale;
    27.  
    28.         var cam = skyboxCamera.AddComponent<Camera> ();
    29.         cam.clearFlags = CameraClearFlags.Skybox;
    30.         cam.cullingMask = 0;
    31.         cam.depth = playerCamera.depth - 1;
    32.  
    33.         previousClearFlagsParam = playerCamera.clearFlags; //param to revert hmdCamera back to in OnDisable();
    34.     }      
    35. }
    [EDIT]
    And here's the finished shader (includes specular gloss map):
    FarAlpha.shader
    Code (csharp):
    1. Shader "Custom/Falloff"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Tint", Color) = (1,1,1,1)
    6.         _MainTex ("Sprite Texture", 2D) = "white" {}
    7.         [NoScaleOffset] _BumpMap ("Normalmap", 2D) = "bump" {}
    8.         [NoScaleOffset] _SpecTex ("Spec (RGB)", 2D) = "white" {}
    9.         //_Cutoff("Alpha Cutoff", Range(0,1)) = 0
    10.         _Shininess ("Shininess", Range (0.03, 1)) = 0.078125
    11.         _MinVisDistance("MinDistance",Float) = 0
    12.         _MaxVisDistance("MaxDistance",Float) = 20
    13.     }
    14.  
    15.     SubShader
    16.     {
    17.         Tags
    18.         {
    19.             "Queue"="AlphaTest"  
    20.             "RenderType"="Transparent"
    21.         }
    22.  
    23.         Blend One OneMinusSrcAlpha
    24.  
    25.         CGPROGRAM
    26.         #pragma surface surf BlinnPhong vertex:vert nofog alphatest:_Cutoff
    27.         //#pragma target 3.0
    28.  
    29.          static const float Epsilon = 1e-10;
    30.  
    31.         sampler2D _MainTex;
    32.         sampler2D _BumpMap;
    33.         sampler2D _SpecTex;
    34.         fixed4 _Color;
    35.  
    36.         half _Height;
    37.         half _Shininess;
    38.         half _MinVisDistance;
    39.         half _MaxVisDistance;
    40.  
    41.         struct Input
    42.         {
    43.             float2 uv_MainTex;
    44.             fixed4 color;
    45.         };
    46.  
    47.         void vert (inout appdata_full v, out Input o)
    48.         {    
    49.             UNITY_INITIALIZE_OUTPUT(Input, o);
    50.  
    51.             half3 viewDirW = _WorldSpaceCameraPos - mul((half4x4)unity_ObjectToWorld, v.vertex);
    52.             half viewDist = length(viewDirW);
    53.             float falloff = 1.0f - (saturate((viewDist - _MinVisDistance) / (_MaxVisDistance - _MinVisDistance)));
    54.            
    55.             o.color = v.color * _Color;
    56.             o.color.a *= falloff;
    57.         }
    58.  
    59.         void surf (Input IN, inout SurfaceOutput o)
    60.         {
    61.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * IN.color;
    62.             o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    63.  
    64.             half4 spectex = tex2D(_SpecTex, IN.uv_MainTex);
    65.             _SpecColor = spectex;
    66.             o.Specular = _Shininess * clamp(_SpecColor, Epsilon, 1.0f);
    67.  
    68.             o.Albedo = c.rgb * c.a;    
    69.             o.Gloss = c.a;
    70.             o.Alpha = c.a;
    71.         }
    72.         ENDCG
    73.     }
    74.  
    75. Fallback "Transparent/Cutout/VertexLit"
    76. }
     
    Last edited: Sep 5, 2019