Adicionalmente a la interfaz básica de script, los Native Code Plugins en Unity pueden recibir callbacks cuando ciertos eventos ocurre. Esto en su mayoría es utilizado para implementar un renderizado de bajo nivel en su plugin y le permite funcionar con el renderizado multi-hilo (multithread) de Unity.
Los encabezados definiendo interfaces expuestas por Unity se proporcionan con el editor.
Un plugin debería exportar las funciones UnityPluginLoad
and UnityPluginUnload
para manejar eventos principales de Unity. Mirar IUnityInterface.h
para las signatures correctas. IUnityInterfaces
se proporciona al plugin para acceder a Unity APIs adicionales.
#include "IUnityInterface.h"
#include "IUnityGraphics.h"
// Unity plugin load event
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
IUnityGraphics* graphics = unityInterfaces->Get<IUnityGraphics>();
}
Un plugin puede acceder la funcionalidad de gráficos genéricos del dispositivo al obtener la interfaz IUnityGraphics
. En versiones anteriores de Unity una función UnitySetGraphicsDevice
tenía que exportarse con el fin de recibir notificaciones acerca de eventos en el dispositivo gráfica. Empezando con Unity 5.2 la nueva interfaz IUnityGraphics (encontrado en IUnityGraphics.h
) proporciona una manera de registrar un callback.
#include "IUnityInterface.h"
#include "IUnityGraphics.h"
static IUnityInterfaces* s_UnityInterfaces = NULL;
static IUnityGraphics* s_Graphics = NULL;
static UnityGfxRenderer s_RendererType = kUnityGfxRendererNull;
// Unity plugin load event
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
s_UnityInterfaces = unityInterfaces;
s_Graphics = unityInterfaces->Get<IUnityGraphics>();
s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
// Run OnGraphicsDeviceEvent(initialize) manually on plugin load
// to not miss the event in case the graphics device is already initialized
OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
}
// Unity plugin unload event
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
UnityPluginUnload()
{
s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
}
static void UNITY_INTERFACE_API
OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
{
switch (eventType)
{
case kUnityGfxDeviceEventInitialize:
{
s_RendererType = s_Graphics->GetRenderer();
//TODO: user initialization code
break;
}
case kUnityGfxDeviceEventShutdown:
{
s_RendererType = kUnityGfxRendererNull;
//TODO: user shutdown code
break;
}
case kUnityGfxDeviceEventBeforeReset:
{
//TODO: user Direct3D 9 code
break;
}
case kUnityGfxDeviceEventAfterReset:
{
//TODO: user Direct3D 9 code
break;
}
};
}
Rendering in Unity can be multithreaded if the platform and number of available CPUs will allow for it. When multithreaded rendering is used, the rendering API commands happen on a thread which is completely separate from the one that runs MonoBehaviour scripts. Consequently, it is not always possible for your plugin to start doing some rendering immediately, because it might interfere with whatever the render thread is doing at the time.
Con el fin de hacer cualquier renderizado desde el plugin, usted debería llamar GL.IssuePluginEvent desde su script, lo cual va a causar que su plugin sea llamado del hilo que renderiza. Por ejemplo, si usted llama GL.IssuePluginEvent de la función de la cámara OnPostRender, usted puede obtener un callback del plugin inmediatamente después de que la cámara ha finalizado de renderizar.
Signature para el UnityRenderingEvent
callback se proporciona en IUnityGraphics.h
.
Código ejemplo de un plugin nativo:
// Plugin function to handle a specific rendering event
static void UNITY_INTERFACE_API OnRenderEvent(int eventID)
{
//TODO: user rendering code
}
// Freely defined function to pass a callback to plugin-specific scripts
extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
GetRenderEventFunc()
{
return OnRenderEvent;
}
Código ejemplo de un Managed plugin:
#if UNITY_IPHONE && !UNITY_EDITOR
[DllImport ("__Internal")]
#else
[DllImport("RenderingPlugin")]
#endif
private static extern IntPtr GetRenderEventFunc();
// Queue a specific callback to be called on the render thread
GL.IssuePluginEvent(GetRenderEventFunc(), 1);
Tales callbacks pueden ser también agregados a CommandBuffers vía CommandBuffer.IssuePluginEvent.
There are two kind of OpenGL objects: Objects shared across OpenGL contexts (texture; buffer; renderbuffer; samplers; query; shader; and programs objects) and per-OpenGL context objects (vertex array; framebuffer; program pipeline; transform feedback; and sync objects).
Unity uses multiple OpenGL contexts. When initializing and closing the editor and the player, we rely on a master context but we use dedicated contexts for rendering. Hence, you can’t create per-context objects during kUnityGfxDeviceEventInitialize
and kUnityGfxDeviceEventShutdown
events.
For example, a native plugin can’t create a vertex array object during a kUnityGfxDeviceEventInitialize
event and use it in a UnityRenderingEvent
callback, because the active context is not the one used during the vertex array object creation.
Un ejemplo de un rendering plugin de bajo nivel está en bitbucket: bitbucket.org/Unity-Technologies/graphicsdemos (NativeRenderingPlugin folder). Demuestra dos cosas:
El proyecto funciona con: