Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Bug Graphics.DrawMeshInstanced applies MaterialPropertyBlock incorrectly

Discussion in 'Graphics for ECS' started by Opeth001, Feb 25, 2021.

  1. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,097
    Hello everyone,
    I am creating an extension for HRv2 which supports non vulkan devices and for that I use the API DrawMeshInstanced and MaterialPropertyBlock.
    but the MaterialPropertyBlock always applies the first element of each Override property to all rendered entities.
    I tried to reproduce the bug with a simple script to make sure the issue was not with the HRv2 extension.

    note: im using the URP SimpleLit shader.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PropertiesTest : MonoBehaviour
    6. {
    7.  
    8.     public GameObject[] gameObjects;
    9.  
    10.     Vector4[] m_Float4ArrayBuffer = new Vector4[24];
    11.     Matrix4x4[] m_MatricesArray = new Matrix4x4[24];
    12.     Color color = Color.green;
    13.     Mesh mesh;
    14.     Material material;
    15.     MaterialPropertyBlock materialPropertyBlock;
    16.  
    17.     // Start is called before the first frame update
    18.     void Start()
    19.     {
    20.         if (gameObjects.Length == 0)
    21.             return;
    22.  
    23.         var firstElement = gameObjects[0];
    24.  
    25.         material = firstElement.GetComponent<MeshRenderer>().sharedMaterial;
    26.         mesh = firstElement.GetComponent<MeshFilter>().sharedMesh;
    27.  
    28.         materialPropertyBlock = new MaterialPropertyBlock();
    29.  
    30.         for (var i=0; i< gameObjects.Length; i++)
    31.         {
    32.             m_MatricesArray[i] = gameObjects[i].transform.localToWorldMatrix;
    33.             m_Float4ArrayBuffer[i] = color;
    34.         }
    35.  
    36.         m_Float4ArrayBuffer[0] = Color.red;
    37.         m_Float4ArrayBuffer[5] = Color.blue;
    38.  
    39.         materialPropertyBlock.SetVectorArray("_BaseColor", m_Float4ArrayBuffer);
    40.     }
    41.  
    42.     // Update is called once per frame
    43.     void Update()
    44.     {
    45.         Graphics.DrawMeshInstanced(mesh, 0,  material, m_MatricesArray, gameObjects.Length, materialPropertyBlock);
    46.  
    47.     }
    48. }
    49.  
    as you can see i have applied different colors to index 0 and 5, but everything is rendered with the first Color element (red).

     
  2. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    You defined _BaseColor as an instanced property in the shader?
     
  3. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,097
    _BaseColor is defined as instanced property by default in URP SimpleLit shader. please correct me if im wrong
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,629
    If you change index 0 to different color, will all cubes be that color?
    Did you set materiał to instnced?
     
    Opeth001 likes this.
  5. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,097
    yes all instanced cubes always get the first element in the Material Property Block.
    and yes the material has GPU instancing enabled.
     
  6. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,097
    btw this problem is also present on all shaders created using the Shader Graph.
     
    Last edited: Mar 1, 2021
  7. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,629
    Check if your shader graph inputs are present, in shader properties, on the top of shader. You can see that after shader compilation into code.
    Last time I used shader grap with draw mesh instannced, I had add few lines of code to 5he shade manually, after it was compiled.

    With latest ECS and Shader Graph, I moved however from draw mesh entairly. But I use it in whole game before then. Now is much easier for me to use it.
     
    Opeth001 likes this.
  8. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,097
    The properties are properly setted but from the shader code i see that they are not getting them by instance using MaterialPropertyBlock macro.
    btw even the Official Hybrid Render v2 is not working correctly with Shader Graph shaders + Property Overrides.
     
  9. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,629
    Because there a bits missing in shader scripts after conversion from shader graph. Need be added manually.
    There 2 or 3 places, few lines need be replaced.

    I am on mobile, so unable to pinpoint atm, which lines.
     
    Opeth001 likes this.
  10. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,629
    Just looked quickly into shader.

    For simple color change, look for _Color keyword

    Code (CSharp):
    1. Properties
    2.     {
    3.         _Color("Color", Vector) = (1, 0, 0, 0)
    4.     }
    Code (CSharp):
    1. // --------------------------------------------------
    2.             // Graph
    3.      
    4.             // Graph Properties
    5.             CBUFFER_START(UnityPerMaterial)
    6.                 float4 _Color;
    7.             CBUFFER_END
    8.      
    9.             // Custom Added for DOTS inputs.
    10.             UNITY_INSTANCING_BUFFER_START(Props)
    11.                 UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
    12.             UNITY_INSTANCING_BUFFER_END(Props)
    Code (CSharp):
    1. SurfaceDescription SurfaceDescriptionFunction(SurfaceDescriptionInputs IN)
    2.             {
    3.                 SurfaceDescription surface = (SurfaceDescription)0;
    4.  
    5.                 float4 _Property_C8F17703_Out_0 = UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
    6.                 // float4 _Property_C8F17703_Out_0 = _Color; // This line is replaced
    Only first SurfaceDescriptionFunction need be modified
     
    Opeth001 likes this.
  11. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,097
    Thanks, this is exactly what i did :)
     
    Antypodish likes this.