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

Question Shader/Material does not detect it is instanced when using DrawMeshInstancedProcedural

Discussion in 'Shaders' started by Noek1993, May 14, 2021.

  1. Noek1993

    Noek1993

    Joined:
    Jan 22, 2015
    Posts:
    25
    Hello,

    Recently I have been playing a bit with DrawMeshInstanced and DrawMeshInstancedProcedural.
    But I get different results when using either of them.

    I have a shader with the following code.
    Code (HLSL):
    1.  
    2.           #if defined(UNITY_INSTANCING_ENABLED) || defined(UNITY_PROCEDURAL_INSTANCING_ENABLED) || defined(UNITY_STEREO_INSTANCING_ENABLED)
    3.  
    4.             uint normalId = unity_InstanceID;
    5.             uint vertexId = unity_InstanceID * _Size + v.vid;
    6.             #else
    7.             uint normalId = 0;
    8.             uint vertexId = v.vid;
    9.             #endif
    10.  
    When I use DrawMeshInstanced, the define check does trigger.
    However if I use DrawMeshInstancedProcedural, it triggers the second part and thus not have the correct normalId and vertexId.

    Is there an other define I need to check when using DrawMeshInstancedProcedural?
    Is there anything specific I need to pass to the draw call?
     
  2. Noek1993

    Noek1993

    Joined:
    Jan 22, 2015
    Posts:
    25
    Just forcing to use the instance id seems to work, but does give compile errors for the normal variants.
    However when using MaterialPropertyBlock.SetVectorArray it seems to always use the first item from the array and not using the right index. As if the shader thinks its not instanced. I tried looking at the docs for
    Graphics.DrawMeshInstancedProcedural, but I can't seem to figure it out.

    I have inserted the full shader code:
    Code (CSharp):
    1. Shader "Custom/HexShader"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic ("Metallic", Range(0,1)) = 0.0
    9.     }
    10.     SubShader
    11.     {
    12.         Tags
    13.         {
    14.             "RenderType"="Opaque"
    15.         }
    16.         LOD 200
    17.  
    18.         CGPROGRAM
    19.         // Physically based Standard lighting model, and enable shadows on all light types
    20.         #pragma surface surf Standard vertex:vert addshadow fullforwardshadows
    21.         // #pragma multi_compile_shadowcaster
    22.         #pragma multi_compile_instancing
    23.  
    24.         #pragma target 5.0
    25.  
    26.         #include "UnityCG.cginc"
    27.        
    28.         sampler2D _MainTex;
    29.  
    30.         struct appdata_full_id
    31.         {
    32.             float4 vertex : POSITION;
    33.             float3 normal : NORMAL;
    34.             float4 texcoord : TEXCOORD0;
    35.             float4 texcoord1 : TEXCOORD1;
    36.             float4 texcoord2 : TEXCOORD2;
    37.             fixed4 color : COLOR;
    38.             uint vid : SV_VertexID;
    39.             // uint instance_id: SV_InstanceID;
    40.             UNITY_VERTEX_INPUT_INSTANCE_ID
    41.         };
    42.  
    43.         struct Input
    44.         {
    45.             float2 uv_MainTex;
    46.         };
    47.  
    48.         half _Glossiness;
    49.         half _Metallic;
    50.         fixed4 _Color;
    51.         int _Size;
    52.  
    53.         #ifdef SHADER_API_D3D11
    54.         StructuredBuffer<float3> _PositionBuffer; // _Count x position
    55.         StructuredBuffer<float3> _NormalBuffer; // Normal
    56.         #endif
    57.  
    58.         UNITY_INSTANCING_BUFFER_START(Props)
    59.         UNITY_DEFINE_INSTANCED_PROP(float4, _Colors)
    60.         UNITY_INSTANCING_BUFFER_END(Props)
    61.  
    62.         void vert(inout appdata_full_id v)
    63.         {
    64.             UNITY_SETUP_INSTANCE_ID(v);
    65.  
    66.             #if defined(UNITY_INSTANCING_ENABLED) || defined(UNITY_PROCEDURAL_INSTANCING_ENABLED) || defined(UNITY_STEREO_INSTANCING_ENABLED)
    67.             uint normalId = unity_InstanceID;
    68.             uint vertexId = unity_InstanceID * _Size + v.vid;
    69.             #else
    70.             uint normalId = 0;
    71.             uint vertexId = v.vid;
    72.             #endif
    73.  
    74.             #ifdef SHADER_API_D3D11
    75.             v.vertex = float4(_PositionBuffer[vertexId].xyz, 1.0);
    76.             v.normal = _NormalBuffer[normalId].xyz;
    77.             #endif
    78.         }
    79.  
    80.         void surf(Input IN, inout SurfaceOutputStandard o)
    81.         {
    82.             float4 ac = UNITY_ACCESS_INSTANCED_PROP(Props, _Colors);
    83.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color * ac;
    84.             o.Albedo = c.rgb;
    85.             o.Metallic = _Metallic;
    86.             o.Smoothness = _Glossiness;
    87.             o.Alpha = c.a;
    88.         }
    89.         ENDCG
    90.     }
    91. }
    92.  
    And the code for calling
    Code (CSharp):
    1.  
    2.  
    3. var block = new MaterialPropertyBlock();
    4. block.SetInt("_Size", VertexCount);
    5. block.SetBuffer("_PositionBuffer", vertexBuffer); // ComputeBuffer
    6. block.SetBuffer("_NormalBuffer", normalBuffer); // ComputeBuffer
    7. block.SetVectorArray("_Colors", colors); // Vector4[]
    8.  
    9. var bounds = new Bounds(Vector3.zero, Vector3.one * 20);
    10. Graphics.DrawMeshInstancedProcedural(Mesh, 0, Material, bounds, Data.Count, block);
    11.  
     
  3. rulk

    rulk

    Joined:
    Aug 1, 2015
    Posts:
    13
    Hi, was you able to figure it out eventually? I have the same problem using URP DrawMeshInstancedProcedural and constant buffers.

    I also tried providing Constant Buffer like so:
    Code (CSharp):
    1. _positionOffsetBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Constant, _count, 4 * 4);
    2. _positionOffsetBuffer.SetData(_positions);      
    3. _material.SetBuffer(PositionOffset, _positionOffsetBuffer);
    4. _matProp.SetConstantBuffer(PositionOffset, _positionOffsetBuffer, 0,_count);
    But result is the same. I have managed to get it working with StructuredBuffers like here https://prog.world/making-grass-in-unity-with-gpu-instancing/ but this requires support for StructuredBuffers.

    In openGL I would call glVertexAttribDivisor so for me it seems that something is missing from buffer configuration on c# side rather then in shader.