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

HLSL (or ShaderGraph) Skybox Shader with Single Pass Instancing

Discussion in 'Universal Render Pipeline' started by peaj_metric, Feb 3, 2022.

  1. peaj_metric

    peaj_metric

    Joined:
    Sep 15, 2014
    Posts:
    146
    I am trying to implement a custom skybox shader with HLSL.
    I figured however that URP is still using the (legacy?) CG Skybox shader and any shader created with either Shader Graph or HLSL is not rendered at all.

    This is my HLSL implementation:
    Code (HLSL):
    1. Shader "Skybox/Gradient"
    2. {
    3.     SubShader
    4.     {
    5.         Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
    6.         Cull Off ZWrite Off
    7.  
    8.         Pass
    9.         {
    10.             HLSLPROGRAM
    11.             #pragma target 2.0
    12.             #pragma vertex vert
    13.             #pragma fragment frag
    14.            
    15.             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"          
    16.  
    17.             sampler2D _SkyGradient;
    18.            
    19.             struct Attributes
    20.             {
    21.                 float4 positionOS   : POSITION;    
    22.                 float2 uv : TEXCOORD0;
    23.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    24.             };
    25.  
    26.             struct Varyings
    27.             {
    28.                 float4 positionHCS  : SV_POSITION;
    29.                 float2 uv : TEXCOORD0;
    30.                 UNITY_VERTEX_OUTPUT_STEREO
    31.             };          
    32.            
    33.             Varyings vert(Attributes IN)
    34.             {
    35.                 Varyings OUT;
    36.                 UNITY_SETUP_INSTANCE_ID(IN);
    37.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
    38.                 OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
    39.                 OUT.uv = IN.uv;
    40.                 return OUT;
    41.             }
    42.            
    43.             half4 frag(Varyings IN) : SV_Target
    44.             {
    45.                 return tex2D(_SkyGradient, float2((IN.uv.y+1.0)*0.5,0));
    46.             }
    47.             ENDHLSL
    48.         }
    49.     }
    50. }
    Which is not being rendered. The sky is black and will not even be cleared.

    This is the exact same shader in CG but it works:
    Code (CG):
    1. Shader "Skybox/Gradient Legacy"
    2. {
    3.     SubShader
    4.     {
    5.         Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
    6.         Cull Off ZWrite Off
    7.  
    8.         Pass
    9.         {
    10.             CGPROGRAM
    11.             #pragma target 2.0
    12.             #pragma vertex vert
    13.             #pragma fragment frag
    14.  
    15.             #include "UnityCG.cginc"
    16.  
    17.             sampler2D _SkyGradient;
    18.  
    19.             struct Attributes
    20.             {
    21.                 float4 vertex : POSITION;
    22.                 float2 uv : TEXCOORD0;
    23.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    24.             };
    25.            
    26.             struct Varyings
    27.             {
    28.                 float4 positionHCS : SV_POSITION;
    29.                 float2 uv : TEXCOORD0;
    30.                 UNITY_VERTEX_OUTPUT_STEREO
    31.             };
    32.            
    33.             Varyings vert (Attributes IN)
    34.             {
    35.                 Varyings OUT;
    36.                 UNITY_SETUP_INSTANCE_ID(IN);
    37.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
    38.                 OUT.positionHCS = UnityObjectToClipPos(IN.vertex);
    39.                 OUT.uv = IN.uv;
    40.                 return OUT;
    41.             }
    42.            
    43.             half4 frag (Varyings IN) : SV_Target
    44.             {
    45.                 return tex2D(_SkyGradient, float2((IN.uv.y+1.0)*0.5,0));
    46.             }
    47.             ENDCG
    48.         }
    49.     }
    50. }
    So I wonder: Is it just not possible to use HLSL for Skybox shaders? Isn't HLSL supposed to replace CG in the new render pipelines?
     
  2. rjonaitis

    rjonaitis

    Unity Technologies

    Joined:
    Jan 5, 2017
    Posts:
    115
    Your HLSL shader works fine, you just need to assign actual texture to _SkyGradient. And assign your material to the skybox (Window->Rendering->Lighting, Skybox material)
     
  3. peaj_metric

    peaj_metric

    Joined:
    Sep 15, 2014
    Posts:
    146
    The texture is being assigned via Shader.SetGlobalTexture and I am switching between both shaders in the assigned Sky material.
    But this even happens in a shader that just outputs a simple color without any inputs.

    Both shaders work in edit mode, non VR mode and Multi Pass rendering and show the correct gradient.
    But with single pass instanced rendering the HLSL shader does not render at all.
    The sky does not even get cleared, which means the foreground elements "paint" into the sky.
    Also it does not display any errors.

    The same happens for any shader created with Shader Graph which is why I started impementing it in HLSL in the first place. I thought there might be some stereo macro missing from the generated shader code.

    I am using URP 10.6.0 with Unity 2020.3.17f1 btw.
     
  4. rjonaitis

    rjonaitis

    Unity Technologies

    Joined:
    Jan 5, 2017
    Posts:
    115
    Oh, I missed the "Single pass instancing" part. Hmm, it does reproduce, but not with all graphics APIs.

    Try adding "ZClip False" to shader seems to make it work as expected.
     
  5. rjonaitis

    rjonaitis

    Unity Technologies

    Joined:
    Jan 5, 2017
    Posts:
    115
    ok, so the problem is "single pass instancing" needs different skybox scaling, but when simulating VR it chooses wrong path and scales skybox too much, it ends up outside clipping plane and gets ZClipped. So adding "ZClip False" to your shader will workaround it.
     
  6. peaj_metric

    peaj_metric

    Joined:
    Sep 15, 2014
    Posts:
    146
    Wow I didn't even know it was possible to disable clipping with a ShaderLab command.
    This might also help with my infinite grid renderer.
    Glad that you could find the root of the cause.
    Are there any plans to update the skybox shaders to use HLSL?
    As from my understanding the CG shaders in URP are considered legacy?

    Thanks!
     
  7. rjonaitis

    rjonaitis

    Unity Technologies

    Joined:
    Jan 5, 2017
    Posts:
    115
  8. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Is it a logged bug regarding simulating VR choosing the wrong path?
     
  9. rjonaitis

    rjonaitis

    Unity Technologies

    Joined:
    Jan 5, 2017
    Posts:
    115
    I am creating a bug report. It only affects simulating VR with MockHMD. On real VR devices there is no problem.
     
    hippocoder likes this.
  10. peaj_metric

    peaj_metric

    Joined:
    Sep 15, 2014
    Posts:
    146
    This does not only effect MockHMD. It also happens with any OpenVR device I tested (Vive and Index) and I think my colleague also had the same problem on Oculus Quest
     
  11. rjonaitis

    rjonaitis

    Unity Technologies

    Joined:
    Jan 5, 2017
    Posts:
    115
    Ok, got it, I'll send to QA for more testing, I don't have these devices on hand.
     
    peaj_metric likes this.
  12. AndreasWang

    AndreasWang

    Joined:
    Jul 31, 2019
    Posts:
    23
    Is there any information on whether this has been fixed yet?

    I seem to be experiencing the same issue on a Quest 2 with OpenXR, OpenGL ES and URP in 2022.1. The skybox shadergraph renders fine in Multi-pass mode, but not with Single Pass Instanced. In Android builds it seems like the skybox is cleared with one colour while in editor play mode it is uninitialised instead.

    Unfortunately, it does not seem like the ZClip False workaround does anything on my end so that may point towards this being a somewhat different issue with similar symptoms :(
     
  13. jeromeWork

    jeromeWork

    Joined:
    Sep 1, 2015
    Posts:
    426
    Can confirm that I'm having this happen on Unity 2021.3.16 / URP 12.1.8 / Oculus runtime - on Quest2 and Index.

    Do you have a link to the bug report that was filed so I can see if this was fixed in a later version?
     
    AlexBourgeois, MarekLg and heskey30 like this.