Construyendo Plugins para Plataformas de Escritorio
AssetBundles

Interfaz de Plugin Nativo de Bajo Nivel

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.

Registro de interfaz

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>();
}

Acceso al Dispositivo de Gráficos

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;
        }
    };
}

Plugin Callbacks en el Rendering Thread

El renderizado en Unity puede ser multi-hilo si la plataforma y el número de CPUs disponibles lo permiten. Cuando el renderizado multi-hilo es usado, los comandos del API de renderizado sucede en un hilo que es completamente diferente del que está ejecutando los scripts de MonoBehaviour. En consecuencia, no es siempre posible para su plugin que empiece hacer algo de renderización inmediatamente, ya que podría interferir con lo que el hilo de renderizado esté haciendo en ese tiempo.

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.

Ejemplo

Un ejemplo de un rendering plugin de bajo nivel está en bitbucket: bitbucket.org/Unity-Technologies/graphicsdemos (NativeRenderingPlugin folder). Demuestra dos cosas:

  • Renderiza un triángulo girando desde código C++ después de que todo el renderizado regular se ha hecho.
  • Llena una textura de procedimiento desde código C++, utilizando Texture.GetNativeTexturePtr para acceder a ello.

El proyecto funciona con:

  • Windows (Visual Studio 2015) con Direct3D 9, Direct3D 11, Direct3D 12 y OpenGL.
  • Mac OS X (Xcode) con Metal y OpenGL.
  • Windows Store Apps (Windows 10 y Windows 8.1 flavors) con Direct3D 11 y Direct3D 12.
Construyendo Plugins para Plataformas de Escritorio
AssetBundles