Graphics.DrawMeshInstanced applies MaterialPropertyBlock incorrectly

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.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PropertiesTest : MonoBehaviour
{

    public GameObject[] gameObjects;
  
    Vector4[] m_Float4ArrayBuffer = new Vector4[24];
    Matrix4x4[] m_MatricesArray = new Matrix4x4[24];
    Color color = Color.green;
    Mesh mesh;
    Material material;
    MaterialPropertyBlock materialPropertyBlock;

    // Start is called before the first frame update
    void Start()
    {
        if (gameObjects.Length == 0)
            return;

        var firstElement = gameObjects[0];

        material = firstElement.GetComponent<MeshRenderer>().sharedMaterial;
        mesh = firstElement.GetComponent<MeshFilter>().sharedMesh;

        materialPropertyBlock = new MaterialPropertyBlock();

        for (var i=0; i< gameObjects.Length; i++)
        {
            m_MatricesArray[i] = gameObjects[i].transform.localToWorldMatrix;
            m_Float4ArrayBuffer[i] = color;
        }

        m_Float4ArrayBuffer[0] = Color.red;
        m_Float4ArrayBuffer[5] = Color.blue;

        materialPropertyBlock.SetVectorArray("_BaseColor", m_Float4ArrayBuffer);
    }

    // Update is called once per frame
    void Update()
    {
        Graphics.DrawMeshInstanced(mesh, 0,  material, m_MatricesArray, gameObjects.Length, materialPropertyBlock);

    }
}

as you can see i have applied different colors to index 0 and 5, but everything is rendered with the first Color element (red).

You defined _BaseColor as an instanced property in the shader?

_BaseColor is defined as instanced property by default in URP SimpleLit shader. please correct me if im wrong

If you change index 0 to different color, will all cubes be that color?
Did you set materiał to instnced?

1 Like

yes all instanced cubes always get the first element in the Material Property Block.
and yes the material has GPU instancing enabled.

btw this problem is also present on all shaders created using the Shader Graph.

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.

1 Like

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.

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.

1 Like

Just looked quickly into shader.

For simple color change, look for _Color keyword

Properties
    {
        _Color("Color", Vector) = (1, 0, 0, 0)
    }
// --------------------------------------------------
            // Graph
      
            // Graph Properties
            CBUFFER_START(UnityPerMaterial)
                float4 _Color;
            CBUFFER_END
      
            // Custom Added for DOTS inputs.
            UNITY_INSTANCING_BUFFER_START(Props)
                UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
            UNITY_INSTANCING_BUFFER_END(Props)
SurfaceDescription SurfaceDescriptionFunction(SurfaceDescriptionInputs IN)
            {
                SurfaceDescription surface = (SurfaceDescription)0;

                float4 _Property_C8F17703_Out_0 = UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
                // float4 _Property_C8F17703_Out_0 = _Color; // This line is replaced

Only first SurfaceDescriptionFunction need be modified

1 Like

Thanks, this is exactly what i did :slight_smile:

1 Like