Search Unity

GPUInstancing + Texture2dArray Issue

Discussion in 'General Graphics' started by ShaderRig, Sep 17, 2019.

  1. ShaderRig

    ShaderRig

    Joined:
    Feb 26, 2019
    Posts:
    18
    Hi! I’ve been throwing myself at this problem for the last few days but I can’t find enough information to work out where I’m going wrong.

    I’m trying to reduce draw calls on a project by using GPU Instancing which was simple enough but this broke down as soon as I had multiple materials. To work around this I found a few good references about using “Material Property Blocks” (https://catlikecoding.com/unity/tutorials/rendering/part-19/) to help batch the same objects together. I have this working perfectly for ints and floats within the script / shader but when trying to pass custom textures this broke down. I’ve been looking at Tikkub’s post here:

    https://www.reddit.com/r/Unity3D/comments/6uueox/gpu_instancing_texture2darray/

    They use a 2D texture array to batch textures. After trying the same thing I don’t get the same result, the objects aren’t batching anymore. Would love some advice on what I’ve missed.

    Image below showing, No textures 22 calls, with textures 742 calls.

    GPUInst_Ball.png

    Game Object Script
    Code (CSharp):
    1. using UnityEngine;
    2. public class GPUInstancingTest : MonoBehaviour
    3. {
    4.     public Transform mesh;
    5.     public Material material;
    6.     private MaterialPropertyBlock Props;
    7.  
    8.     public Color Color1, Color2;
    9.     public Color emissionColor;
    10.     public int instances = 5000;
    11.     public float radius = 50f;
    12.  
    13.     public Texture2D[] textures;
    14.     int textureWidth = 1024;
    15.     int textureHeight = 1024;
    16.  
    17.     void Start()
    18.     {
    19.         Props = new MaterialPropertyBlock();
    20.  
    21.         Texture2DArray textureArray = new Texture2DArray(textureWidth, textureHeight, textures.Length, TextureFormat.RGBA32, false);
    22.         //textureArray.Apply(false, true); //Didn't fix compression issue.
    23.  
    24.         for (int i = 0; i < textures.Length; i++)
    25.         {
    26.             Graphics.CopyTexture(textures[i], 0, 0, textureArray, i, 0);
    27.         }
    28.  
    29.         //Comment out below line. Everything batches but no textures at set.
    30.         Props.SetTexture("_MainTex", textureArray);
    31.  
    32.         for (int i = 0; i < instances; i++)
    33.         {
    34.             Props.SetColor("_Color", Color1);
    35.             Props.SetFloat("_Glossiness", 0.0f);
    36.             Props.SetFloat("_Metallic", 5.0f);
    37.             Props.SetFloat("_OcclusionStrength", 0.0f);
    38.             Props.SetColor("_EmissionColor", emissionColor);
    39.             Props.SetInt("_TextureIndex", 1);
    40.  
    41.             Transform t = Instantiate(mesh);
    42.             t.localPosition = Random.insideUnitSphere * radius;
    43.             t.SetParent(transform);
    44.             t.GetComponent<MeshRenderer>().SetPropertyBlock(Props);
    45.         }
    46.  
    47.         for (int i = 0; i < instances; i++)
    48.         {
    49.             Props.SetColor("_Color", Color2);
    50.             Props.SetFloat("_Glossiness", 1.0f);
    51.             Props.SetFloat("_Metallic", 0.3f);
    52.             Props.SetFloat("_OcclusionStrength", 0.0f);
    53.             Props.SetInt("_TextureIndex", 0);
    54.  
    55.             Transform r = Instantiate(mesh);
    56.             r.localPosition = Random.insideUnitSphere * radius;
    57.             r.SetParent(transform);
    58.             r.GetComponent<MeshRenderer>().SetPropertyBlock(Props);
    59.         }
    60.  
    61.         for (int i = 0; i < instances; i++)
    62.         {
    63.             Props.SetColor("_Color", Color.green);
    64.             Props.SetFloat("_Glossiness", 0.5f);
    65.             Props.SetFloat("_Metallic", 1.0f);
    66.             Props.SetFloat("_OcclusionStrength", 0.0f);
    67.  
    68.             Transform k = Instantiate(mesh);
    69.             k.localPosition = Random.insideUnitSphere * radius;
    70.             k.SetParent(transform);
    71.             k.GetComponent<MeshRenderer>().SetPropertyBlock(Props);
    72.         }
    73.     }
    74. }
    Shader
    Code (CSharp):
    1. Shader "Custom/Example" {
    2.  
    3.     Properties{
    4.  
    5.         //---Core Properties---//
    6.         [Header(Core Properties)]
    7.  
    8.         _Color("Color", Color) = (1,1,1,1)
    9.         _MainTex("Textures", 2DArray) = "" {}
    10.  
    11.         _Glossiness("Roughness Strength", Range(0.0, 2.0)) = 1.0
    12.         _Metallic("Metallic Strength", Range(0.0, 2.0)) = 1.0
    13.         _OcclusionStrength("Occlusion Strength", Range(0.0, 2.0)) = 1.0
    14.  
    15.         [Header(Emissive)]
    16.         _EmissionColor("Emission Color", Color) = (0,0,0)
    17.     }
    18.  
    19.         SubShader
    20.         {
    21.             Tags
    22.             {
    23.                 "Queue" = "Geometry"
    24.                 "RenderType" = "Opaque"
    25.             }
    26.  
    27.             LOD 300
    28.             ZWrite On
    29.              
    30.             CGPROGRAM
    31.             #pragma surface surf Standard fullforwardshadows addshadow
    32.             #pragma target 3.5
    33.             #include "UnityCG.cginc"
    34.            
    35.             UNITY_DECLARE_TEX2DARRAY(_MainTex);
    36.  
    37.             UNITY_INSTANCING_BUFFER_START(Props)
    38.  
    39.             half _Glossiness;
    40.             half _Metallic;
    41.             half _OcclusionStrength;
    42.            
    43.             float4 _Color;
    44.  
    45.             float _TextureIndex;
    46.  
    47.             fixed4 _EmissionColor;
    48.  
    49.             UNITY_INSTANCING_BUFFER_END(Props)
    50.  
    51.             struct Input
    52.             {
    53.                 float2 uv_MainTex;
    54.             };
    55.  
    56.             void surf(Input IN, inout SurfaceOutputStandard o)
    57.             {
    58.                 fixed4 c = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(IN.uv_MainTex, UNITY_ACCESS_INSTANCED_PROP(Props, _TextureIndex))) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
    59.                 fixed4 e = UNITY_ACCESS_INSTANCED_PROP(Props, _EmissionColor);
    60.                
    61.                 o.Albedo = c.rgb;
    62.  
    63.                 o.Emission = c.rgb;
    64.                 o.Emission *= e.rgb;
    65.  
    66.                 o.Smoothness = (1 - UNITY_ACCESS_INSTANCED_PROP(Props, _Glossiness));
    67.  
    68.                 o.Metallic = UNITY_ACCESS_INSTANCED_PROP(Props, _Metallic);
    69.  
    70.                 o.Occlusion = UNITY_ACCESS_INSTANCED_PROP(Props, _OcclusionStrength);
    71.             }
    72.             ENDCG
    73.  
    74.         }
    75.             FallBack "Diffuse"
    76. }
    77.  
     
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    What does the Frame Debugger say? (It has a message about why each batch was broken)
     
  3. ShaderRig

    ShaderRig

    Joined:
    Feb 26, 2019
    Posts:
    18
    Hi richardkettlewell, thank you for the response.

    The Frame Debugger says "Non-instanced properties set for instanced shader."

    I'm unsure why the Texture2DArray can't be instanced. Both Tikkub and my favorite snail bgolus confirmed this should work.

    "If you want to use multiple textures you need to use a Texture2DArray you construct yourself, and set a per-instance index." - bgolus

    https://forum.unity.com/threads/non-instanced-properties-set-for-instanced-shader.573502/
     
  4. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Interesting. Could you submit a bug report with a reproduction project? We can then take a closer look.
    I can't see any obvious problem with your code, but maybe someone else reading this will spot something. But, in case the problem is in Unity's code, the bug report will help us fix it :)

    Reply here with the case number once you have it. Thanks!
     
  5. ShaderRig

    ShaderRig

    Joined:
    Feb 26, 2019
    Posts:
    18
    Hi richardkettlewell, thank you again.

    As requested I've submitted a bug report, the case number is: 1186136
     
    richardkettlewell likes this.
  6. ShaderRig

    ShaderRig

    Joined:
    Feb 26, 2019
    Posts:
    18
    Hi Richard, I'm not sure if I'm looking in the wrong place but I've not heard anything since posting the bug report. Do you know how long it will take to resolve the issue?
     
  7. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Hey, I've contacted the developer who will be working on this issue. Hopefully they will be able to provide an update.
     
  8. ShaderRig

    ShaderRig

    Joined:
    Feb 26, 2019
    Posts:
    18
    Thank you Richard