Listen for changes to Mesh class for rebuilding metadata (reactive programming in Unity)?

Hi I wasn’t sure who to ask about this. If there is a forum for advanced topics, writing libraries etc, I can try there.

My question is: can we detect when the Mesh class’s vertex arrays get updated, so that I can update metadata (normals, tangents and similar) for my shader? The idea being that people could use my shader effect globally, or add it as a component on a model with no additional code required.

This is very similar to the Mesh.RecalculateNormals() concept, but for my own metadata. I believe that I’m trying to replicate the OnMeshChanged delegate from Unreal Engine:

https://docs.unrealengine.com/en-US/API/Plugins/ModelingComponents/USimpleDynamicMeshComponent/OnMeshChanged/index.html

***** details *****

From what I can tell, it is NOT possible to do reactive programming in Unity at this time, at least not for most of the built-in Unity classes like GameObject and Mesh, which are sealed so can’t be inherited. I asked a similar question 2 years ago with no viable solutions so far:

But short of that, I may have found a workaround for my use case specifically, by using MeshUpdateFlags with the Mesh class and then intercepting the “mesh users” notification in a Renderer, MeshRenderer or ShapeModule:

By default, it appears that MeshUpdateFlags.DontNotifyMeshUsers is false by default, so Mesh change notifications from methods like Mesh.SetVertexBufferData() should already be happening:

But I see no indication of this in Unity, and can’t find a way to expose those events so I can watch them.

The reason I’m asking this has to do with writing future-proof code in libraries. I could attempt to hack around this issue by creating a MyMesh class that’s not inherited from Mesh but has a Mesh member variable inside it via composition. I could override all of the functions so that MyMesh is a wrapper and passes calls through to the Mesh like a proxy. There are problems with this approach though that prevents it from being future-proof:

  • I could include a MeshInterface in MyMesh so that it’s a drop-in replacement wherever Mesh is used, but the Unity maintainers didn’t provide an interface for Mesh. And even if I could use an interface this way, I would have to update my interface and re-release my library every time there’s a Unity release that updates the Mesh class’s interface (this is an anti-pattern)
  • I wouldn’t be able to run my shader as a global effect in an existing project, because all of the code would have to be refactored to use MyMesh instead of Mesh (this is an anti-pattern)

These approaches would have been future-proof:

  • I could have used something like the INotifyPropertyChanged interface for this, if Unity had implemented it on all of their objects
  • I could have Unity register MyMesh as the primary Mesh class globally through an inversion of control (IOC) or IOC container system, but this doesn’t seem to be a thing in Unity at this time

The Mesh changed notification behavior appears to be undocumented. So I’m still blocked, but if someone could answer one of the following, hopefully a solution will materialize:

  • Can someone post an example of logging the Mesh changed events in a Renderer, MeshRenderer or ShapeModule so that I can extend it for my own purposes (or post a link to code that does)?
  • Short of that, can someone post an example of logging all delegate events/callbacks/etc in Unity either globally or for an object/component so I can see what’s being sent by Mesh and listen for that?

Thanks!

I’ve added a StackOverflow question about this:

https://stackoverflow.com/questions…o-mesh-class-for-rebuilding-metadata-in-unity

And here’s the previous discussion again for convenience:

I’m sorry disappoint, you can look at Unity’s C# side of the Mesh class here and here. As evident in the code, the behaviors you mention are fully implemented in the native side of Unity. All “MeshUsers” exist only as native objects and there’s no way you can create a user or register a listener from the C# side.

You could try messing with Unity’s native code but that would likely be very brittle and require separate implementations for every platform.

I also wouldn’t hold my breath for anything to be fundamentally changed with the Mesh class. Changes will be more likely related to DOTS and follow a data-oriented approach.

You could try filing bug report to request a mesh change event to be exposed, bug reports are the best way get someone from Unity to look at feedback.

Here’s my solution:

public sealed class MeshObserver : AssetPostprocessor
{
    private static string _meshPath;
    public static System.Action OnMeshChanged;

    public static void Observe(Mesh mesh)
    {
        _meshPath = AssetDatabase.GetAssetPath(mesh);
    }

    private void OnPostprocessModel(GameObject gameObject)
    {
        if (assetPath == _meshPath)
            OnMeshChanged();
    }
}

Hi I’m unclear on how to use the MeshObserver class. How do i get OnPostprocessModel to run

Simply place the script into an Editor folder or folder controlled by an editor-only asmdef. It runs automatically when the editor detects changes to the file or is told to reimport.

AssetPostprocessor

In regards to the original post I suspect they rather wanted something at runtime which is basically going to require polling which this will not handle.