Because the OnPreCull member of Monobehavior only works on camera objects.

OnPreCull only runs on objects with a Camera component, but I wanted a way for it to be called on my other GameObjects too (specifically, those to which I have attached a particular custom Monobehavior).

CameraPreCullCallback.cs

using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class CameraPreCullCallback : MonoBehaviour {

    public delegate void PreRenderCallback();// Camera cam);

    static public void RegisterCallbackFunctionWithCamera(PreRenderCallback function,Camera cam )
    {
        CameraPreCullCallback callbackBehavior = cam.GetComponent<CameraPreCullCallback>();
        if (callbackBehavior == null)
            callbackBehavior = cam.gameObject.AddComponent<CameraPreCullCallback>();

        if (!callbackBehavior.registeredCallbacks.Contains(function))
        {
            callbackBehavior.registeredCallbacks.Add(function);
        //    Debug.Log(" cam pre render registered" + cam.name);
        }
    }

    List<PreRenderCallback> registeredCallbacks= new List<PreRenderCallback>();
  
    private void OnPreCull()
    {
       
    private void OnPreCull()
    {
        for(int i=0, max=registeredCallbacks.Count;i<max ;i++)
        {
            PreRenderCallback f = registeredCallbacks[i];
            if (((MonoBehaviour)f.Target) != null)
                f.Invoke();
            else
            {
                Debug.Log("null target deregistering");
                registeredCallbacks.RemoveAt(i);
                max--;
                i--;
            }
        }
    }
}

Usage example; draws a mesh to the currently rendering camera, during OnPreCull:

using UnityEngine;

[ExecuteInEditMode]
public class MyDynamicMeshRenderer : MonoBehaviour
{
    public Mesh dynamicMesh;
    public Material mat;
    private void Update()
    {
        //imagine doing somthing dynamic with the mesh here.
        if (Camera.current != null)
            CameraPreCullCallback.RegisterCallbackFunctionWithCamera(PreCullRenderFunction, Camera.current);
    }
    public void PreCullRenderFunction()
    {
        Graphics.DrawMesh(dynamicMesh, transform.localToWorldMatrix, mat, 0);
    }
}

Looking both to help out anyone who might need this, and for any feedback.

Edit: Updated code to check for callback gameobject deletion.

Instead of a list, you could also use an event. (Do note that an event will handle doing callbacks to multiple listeners, but for some reason it doesn’t handle the case of 0 listeners. You need a null check for that.)

Interesting idea, thank you. But if I don’t use a list of delegates, I won’t loop through each camera to see if it has been deleted. What happens if the object that contains the event function is deleted? Is the function automatically removed from the event, if it’s no longer valid?