Search Unity

Issues tryint to add Light Probe support to instanced shaders

Discussion in 'Shaders' started by Kolyasisan, Nov 16, 2019.

  1. Kolyasisan

    Kolyasisan

    Joined:
    Feb 2, 2015
    Posts:
    397
    Hello. Here's the problem.

    I have a bare-bones shader with instancing enabled. Here it is:

    Code (CSharp):
    1. Shader "Unlit/USH_InstancedLightProbesTest"
    2. {
    3.     Properties
    4.     {
    5.  
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "RenderType" = "Opaque" }
    10.         LOD 300
    11.  
    12.         Pass
    13.         {
    14.             Name "FORWARD"
    15.             Tags { "LightMode" = "ForwardBase" }
    16.  
    17.             Blend One Zero
    18.             ZWrite On
    19.  
    20.             CGPROGRAM
    21.             #pragma target 3.0
    22.  
    23.             #pragma multi_compile_fwdbase
    24.             #pragma multi_compile_instancing
    25.  
    26.             #pragma vertex vert
    27.             #pragma fragment frag
    28.  
    29.             #include "UnityCG.cginc"
    30.  
    31.             struct appdata
    32.             {
    33.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    34.                 float4 vertex : POSITION;
    35.             };
    36.  
    37.             struct v2f
    38.             {
    39.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    40.                 float4 vertex : SV_POSITION;
    41.             };
    42.  
    43.             sampler2D _MainTex;
    44.             float4 _MainTex_ST;
    45.  
    46.             v2f vert(appdata v)
    47.             {
    48.                 v2f o;
    49.                 UNITY_SETUP_INSTANCE_ID(v);
    50.                 UNITY_TRANSFER_INSTANCE_ID(v, o);
    51.                 o.vertex = UnityObjectToClipPos(v.vertex);
    52.                 return o;
    53.             }
    54.  
    55.             fixed4 frag(v2f i) : SV_Target
    56.             {
    57.                 UNITY_SETUP_INSTANCE_ID(i);
    58.                 return 1;
    59.             }
    60.             ENDCG
    61.         }
    62.     }
    63. }
    The problem here is that this shader doesn't work with instancing if light probes are enabled (it's refuses to instance at all, the Frame Debugger states that "The objects are affected by different light probes". If I force the mesh renderers not to use light probes then the instancing works. Instancing will also work if I will have "Always" as a "LightMode" tag value (or remove the tag entirely). UnityCG.cginc is unmodified.

    Due to no reasonable documentation for adding instancing with light probes and/or lightmaps support and having no luck finding the answer in the standard shader and generated surface shader, I ask here: how can I do this and where can I find direct examples of the implementation? Thank you.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    It’s covered a bit here:
    https://docs.unity3d.com/Manual/GPUInstancing.html

    The TLDR is you need to use a Light Probe Proxy Volume, aka a LPPV.
    https://docs.unity3d.com/Manual/class-LightProbeProxyVolume.html

    Or you need to manually calculate and pass the light probe data to shaders as the built in probe data isn’t setup to be instanced. But converting the probe data to what Unity’s shaders use isn’t exposed anywhere in Unity’s code, so you have to search online for how to calculate that data from the interpolated probe data. And Unity breaks instancing even with a LPPV, so even then it doesn’t work properly even through it should. :(
     
  3. Kolyasisan

    Kolyasisan

    Joined:
    Feb 2, 2015
    Posts:
    397
    But wait, that doesn't add up at all... Standard shader and surface shaders can all use instancing with light probes, they don't need LPPV at all. I dug in them and the generated surface shader code and found no signs of them manually calculating/interpolating the SH data. I do not draw my meshes using C# apis, they are drawn using Mesh Renderers, so the SH data needs to be calculated nicely by Unity itself if the standard and surface shaders can work with them.

    The manual even states this: "You can use GPU Instancing to automatically batch dynamic Mesh Renderers affected by baked Light Probes (including their occlusion data)", but there's no explanation on how to actually implement it (hence me stating about no manual on implementing more "advanced" instancing features).

    Finally, UnityInstancing.cginc actually has redefinitions of SH data to point to an array, just like with transform matricies, so that most certainly has to be working.
     
    Last edited: Nov 17, 2019
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Hmm, you’re right. They’ve updated instancing w/ light probes since I last looked at this. Ideally there shouldn’t be anything you need to do to make instancing work then. The fact that it doesn’t seems like a bug.
     
  5. Kolyasisan

    Kolyasisan

    Joined:
    Feb 2, 2015
    Posts:
    397
    Yeah, it really does sound like a bug. Guess I'll write a bug report in case if I won't find a solution in a couple of days.
     
  6. Zylex

    Zylex

    Joined:
    Nov 25, 2008
    Posts:
    238
    Did you resolve this issue in the end? I also seem to have this issue still and was wondering if there is a fix.
     
  7. SashaSK8

    SashaSK8

    Joined:
    Feb 18, 2013
    Posts:
    2
    If you add this to your shader

    #pragma multi_compile _ LIGHTPROBE_SH

    it should enable instancing for light probes
     
  8. Zylex

    Zylex

    Joined:
    Nov 25, 2008
    Posts:
    238
    Thanks for your reply. I have tried adding it to the shader but it still will not instance together, see:
     
  9. SashaSK8

    SashaSK8

    Joined:
    Feb 18, 2013
    Posts:
    2
    I don't see INSTANCING_ON keyword there, did you enable GPU Instancing in your material?

    here's simple shader example with working instanced light probes
    Code (CSharp):
    1. Shader "Unlit/lightprobes"
    2. {
    3.     Properties
    4.     {
    5.     }
    6.     SubShader
    7.     {
    8.         Tags {
    9.             "RenderType" = "Opaque"
    10.             "LightMode" = "ForwardBase"
    11.             }
    12.         LOD 100
    13.  
    14.         Pass
    15.         {
    16.             CGPROGRAM
    17.             #pragma multi_compile _ LIGHTPROBE_SH
    18.  
    19.             #pragma multi_compile_instancing
    20.  
    21.             #pragma vertex vert
    22.             #pragma fragment frag
    23.  
    24.             #include "UnityCG.cginc"
    25.  
    26.             struct appdata
    27.             {
    28.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    29.                 float4 vertex : POSITION;
    30.                 fixed3 normal : NORMAL;
    31.             };
    32.  
    33.             struct v2f
    34.             {
    35.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    36.                 float4 vertex : SV_POSITION;
    37.                 fixed3 normal : NORMAL;
    38.                 fixed3 ambient : TEXCOORD0;
    39.             };
    40.  
    41.             v2f vert (appdata v)
    42.             {
    43.                 UNITY_SETUP_INSTANCE_ID(v);
    44.                 v2f o;
    45.                
    46.                 // UNITY_TRANSFER_INSTANCE_ID(v, o); //if you need per pixel light probe lighting, uncomment this
    47.                 o.vertex = UnityObjectToClipPos(v.vertex);
    48.                 o.normal = UnityObjectToWorldNormal(v.normal);
    49.  
    50.                 o.ambient = ShadeSH9(fixed4(o.normal, 1));
    51.                 return o;
    52.             }
    53.  
    54.             fixed4 frag (v2f i) : SV_Target
    55.             {
    56.                 //per pixel lighting
    57.                 // UNITY_SETUP_INSTANCE_ID(i);
    58.                 // fixed3 ambient = ShadeSH9(fixed4(i.normal, 1));
    59.                
    60.                 fixed3 ambient = i.ambient;
    61.                 return fixed4(ambient, 1);
    62.             }
    63.             ENDCG
    64.         }
    65.     }
    66. }
    67.