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

Bug DrawMeshNow broken in 2021

Discussion in 'General Graphics' started by arkano22, Jun 23, 2022.

  1. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,891
    Hi there!

    I'm using the built-in render pipeline. Recently found that pretty much all of my custom editor tools are visually broken in Unity 2021 and up. After a few days spent debugging this, the culprit seems to be Graphics.DrawMeshNow. Conceptually, this is the issue:

    mesh.colors = redColors;
    Graphics.DrawMeshNow(mesh);
    mesh.colors = greenColors;
    Graphics.DrawMeshNow(mesh);
    //Mesh is drawn twice, using greenColors for both.

    Expected result: the mesh is rendered twice, once red and once green (Unity 2019.4 and older):

    Result: the mesh is rendered twice, both times green (same code, Unity 2021.3.0f1 and up, haven't tested versions in-between):


    What-the-heck. Seems like DrawMeshNow is somehow caching the mesh, instead of rendering it immediately. This used to work fine in all previous Unity versions. I'm starting to doubt the reliability of very basic stuff in Unity, which is kinda frustrating.

    Here's the actual code I'm using to test this:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class DrawMeshNowBug : MonoBehaviour
    4. {
    5.  
    6.     Material paintMaterial;
    7.     public Mesh mesh;
    8.  
    9.     Mesh copy;
    10.  
    11.     // Start is called before the first frame update
    12.     void Start()
    13.     {
    14.         paintMaterial = Resources.Load<Material>("VertexColorMaterial");
    15.         copy = GameObject.Instantiate(mesh);
    16.     }
    17.  
    18.     private void OnDestroy()
    19.     {
    20.         Destroy(copy);
    21.     }
    22.  
    23.     // Update is called once per frame
    24.     public void OnPostRender()
    25.     {
    26.  
    27.         if (paintMaterial.SetPass(0))
    28.         {
    29.             Color[] colors = new Color[copy.vertexCount];
    30.             for (int i = 0; i < colors.Length; i++)
    31.                 colors[i] = Color.red;
    32.  
    33.             copy.colors = colors;
    34.             Graphics.DrawMeshNow(copy, Matrix4x4.identity);
    35.  
    36.             for (int i = 0; i < colors.Length; i++)
    37.                 colors[i] = Color.green;
    38.  
    39.             copy.colors = colors;
    40.             Graphics.DrawMeshNow(copy, Matrix4x4.Translate(Vector3.right));
    41.  
    42.         }
    43.     }
    44. }
    This is the shader used for flat vertex color rendering (built-in pipeline), which imho is as simple as it gets:

    Code (CSharp):
    1. Pass {
    2.  
    3.             Cull Back
    4.             Fog { Mode Off }
    5.  
    6.             CGPROGRAM
    7.             #pragma vertex vert
    8.             #pragma fragment frag
    9.  
    10.             #include "UnityCG.cginc"
    11.  
    12.             struct vin{
    13.                 float4 vertex   : POSITION;
    14.                 fixed4 color    : COLOR;
    15.                 float2 texcoord  : TEXCOORD0;
    16.             };
    17.  
    18.             struct v2f {
    19.                 float4 pos: POSITION;
    20.                 fixed4 color    : COLOR;
    21.                 float2 texcoord  : TEXCOORD0;
    22.             };
    23.  
    24.             sampler2D _MainTex;
    25.  
    26.             v2f vert(vin v) {
    27.                 v2f o;
    28.                 o.pos = UnityObjectToClipPos (v.vertex);
    29.                 o.texcoord = v.texcoord;
    30.                 o.color = v.color;
    31.                 return o;
    32.             }
    33.  
    34.             fixed4 frag(v2f i) : SV_Target {
    35.                 return i.color;
    36.             }
    37.  
    38.             ENDCG
    39.         }
    Just a sanity check before I submit a proper bug report: am I doing something wrong here, or misinterpreted the way DrawMeshNow is supposed to work?

    Edit: generalized this to multiple DrawMeshNow calls in a row, modifying the mesh in-between calls: mesh data is indeed cached, only the very last form of the mesh is rendered multiple times. :eek::oops:

    The only workaround I found is to create a separate mesh for each DrawMeshNow call. Reporting this as a bug.
     
    Last edited: Jun 23, 2022
  2. joshuacwilde

    joshuacwilde

    Joined:
    Feb 4, 2018
    Posts:
    725
    It seems odd to me that it would work the other way around tbh.
     
  3. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,891
    Why? That’s the documented behavior:

    “This function will draw a given mesh immediately. Currently set shader and material (see Material.SetPass) will be used”

    So after the method has been called, modifying the mesh can’t possibly have any effect on what has been already drawn. Otherwise it means the mesh has in fact not been drawn immediately.

    Moreover, if behavior has changed with respect to older versions (since Unity 5) it should have been properly documented since it breaks a lot of existing projects.
     
    Last edited: Jun 24, 2022
  4. joshuacwilde

    joshuacwilde

    Joined:
    Feb 4, 2018
    Posts:
    725
    No the odd part to me isn't about drawing the mesh immediately, the odd part is about sending mesh data to the GPU right then. But hey if it's broken/against spec, makes sense it should be fixed.
     
  5. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,891
    I'd also assume the actual drawcall isn't issued right then and there, but mesh data copied into some sort of command and rendered later. But, surprisingly:

    https://forum.unity.com/threads/performance-implications-of-graphics-drawmeshnow.380630/
    When using multi-threaded rendering I'd expect mesh data (along with rendering state) to be internally copied, not referenced - otherwise behavior of multi-threaded and single-threaded paths would be completely different which is not a good thing. Will investigate further.
     
    Last edited: Jun 24, 2022
  6. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,891
    I reported this as a bug, and it has been confirmed as such:

     
    Pr0x1d and richardkettlewell like this.