Search Unity

Using material property block with InstancedIndirect

Discussion in 'Shaders' started by Rewaken, Apr 28, 2021.

  1. Rewaken

    Rewaken

    Joined:
    Mar 24, 2015
    Posts:
    128
    Hello, I'm trying to use drawmeshinstancedindirect with material property block to allot different texture to each instance. Here's my shader code.
    Code (CSharp):
    1. Shader "Custom/DiffTex"{
    2.     Properties
    3.     {
    4.         _TextureIdx("Texture Idx", float) = 0.0
    5.         _Textures("Textures", 2DArray) = "" {}
    6.         _Color("Color (RGBA)", Color) = (1, 1, 1, 1) // add _Color property
    7.  
    8.     }
    9.  
    10.         SubShader
    11.     {
    12.         Tags{ "RenderType" = "Opaque" }
    13.  
    14.         CGPROGRAM
    15.  
    16. #pragma surface surf Standard fullforwardshadows
    17. #pragma multi_compile_instancing
    18. #pragma instancing_options procedural:setup
    19. #pragma target 3.5
    20. #include "UnityCG.cginc"
    21.  
    22.         UNITY_DECLARE_TEX2DARRAY(_Textures);
    23.  
    24.     struct Input
    25.     {
    26.         fixed2 uv_Textures;
    27.     };
    28. #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    29.     StructuredBuffer<float4x4> transformBuffer;
    30. #endif
    31.  
    32.     void setup()
    33.     {
    34. #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    35.         unity_ObjectToWorld = transformBuffer[unity_InstanceID];
    36. #endif
    37.     }
    38.     UNITY_INSTANCING_BUFFER_START(Props)
    39.         UNITY_DEFINE_INSTANCED_PROP(float, _TextureIdx)
    40.         UNITY_INSTANCING_BUFFER_END(Props)
    41.  
    42.         void surf(Input IN, inout SurfaceOutputStandard o)
    43.     {
    44.         fixed4 c = UNITY_SAMPLE_TEX2DARRAY(
    45.             _Textures,
    46.             float3(IN.uv_Textures, UNITY_ACCESS_INSTANCED_PROP(Props, _TextureIdx))
    47.         );
    48.         o.Albedo = c.rgb;
    49.         o.Alpha = c.a;
    50.     }
    51.  
    52.     ENDCG
    53.     }
    54.         FallBack "Diffuse"}
    55.  
    I'm copying textures using Graphics.CopyTexture to Texture2DArray and then with material property block's SetFloatArray updating texture array into the shader. But it is showing first texture to all blocks while if I used it with Gpuinstance it is working well, Can anyone tell me what I'm missing.
     
  2. LennartJohansen

    LennartJohansen

    Joined:
    Dec 1, 2014
    Posts:
    2,394
    Hi. That will not work with instanced indirect.

    Try to add another structured buffer and add the texture index to that

    StructuredBuffer<float> indexBuffer;

    then sample this buffer when you need the index

    float textureIdx = indexBuffer[unity_InstanceID];
     
  3. Rewaken

    Rewaken

    Joined:
    Mar 24, 2015
    Posts:
    128
    Hello, Thanks for replying over here. I recently started learning about compute buffers and shaders so if you could answer a few doubts of mine it will be helpful.
    As you suggested I added another buffer

    Code (CSharp):
    1.     void setup()
    2.     {
    3. #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    4.         unity_ObjectToWorld = transformBuffer[unity_InstanceID];
    5.         float textureIdx = indexBuffer[unity_InstanceID];
    6.  
    7. #endif
    8.     }
    But if I'm not wrong I need to replace _TextureIdx with textureIdx in surf,like following ?

    Code (CSharp):
    1. UNITY_INSTANCING_BUFFER_START(Props)
    2.         UNITY_DEFINE_INSTANCED_PROP(float, textureIdx)
    3.         UNITY_INSTANCING_BUFFER_END(Props)
    4.  
    5.         void surf(Input IN, inout SurfaceOutputStandard o)
    6.     {
    7.         fixed4 c = UNITY_SAMPLE_TEX2DARRAY(
    8.             _Textures,
    9.             float3(IN.uv_Textures, UNITY_ACCESS_INSTANCED_PROP(Props, textureIdx))
    10.         );
    11.         o.Albedo = c.rgb;
    12.         o.Alpha = c.a;
    13.     }
    but it is not working(still same texture to all objects) can you please tell me what I'm missing out here.
     
  4. Rewaken

    Rewaken

    Joined:
    Mar 24, 2015
    Posts:
    128
    Also I amusing following to set up block
    block.SetFloatArray("_TextureIdx", m_arrTexture);
     
  5. LennartJohansen

    LennartJohansen

    Joined:
    Dec 1, 2014
    Posts:
    2,394
    No. You add your m_arrTexture to a new compute buffer.
    assign that to the material or materialpropertyblock

    then use this
    float textureIdx = indexBuffer[unity_InstanceID];

    in the surface/pixel shader where you need the index. You do not need the instanced property part.
     
  6. Rewaken

    Rewaken

    Joined:
    Mar 24, 2015
    Posts:
    128
    Hello thanks for your reply.
    Yes Im pushing data in buffer
    indexBuffer.SetData(m_arrTextureArr);
    instanceMaterial.SetBuffer("indexBuffer", indexBuffer);

    I'm creating it on setup


    Code (CSharp):
    1. void setup()
    2.     {
    3. #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    4.         unity_ObjectToWorld = transformBuffer[unity_InstanceID];
    5.         float textureIdx = indexBuffer[unity_InstanceID];
    6.  
    7. #endif
    8.     }
    And in surface giving instance to texture2d array

    Code (CSharp):
    1. void surf(Input IN, inout SurfaceOutputStandard o)
    2.     {
    3.         fixed4 c = UNITY_SAMPLE_TEX2DARRAY(
    4.             _Textures,
    5.             float3(IN.uv_Textures, textureIdx)
    6.         );
    7.         o.Albedo = c.rgb;
    8.         o.Alpha = c.a;
    9.  
    10.     }
    But nothing is being rendered after that if possible can you tell me what Im missing
     
  7. icormier

    icormier

    Joined:
    Aug 26, 2021
    Posts:
    16
    @Rewaken I am experiencing the same issue. Have you found the solution to this problem?
     
  8. Rewaken

    Rewaken

    Joined:
    Mar 24, 2015
    Posts:
    128
    I think I did. But honestly, I don't remember it now. I moved to custom assetstore solution GPUI for it.