基本的なスクリプトのインターフェースに加えて、プラグイン は Unity 上で発生したの特定のイベントをコールバックで受け取ることができます。これは主に、プラグインで低レベルのレンダリングを実装し、Unity のマルチスレッドレンダリングを操作できるようにするために使用されます。
Unity が提供しているインターフェースを定義するヘッダはエディターと一緒に提供されています。
プラグインは、主要な Unity イベントを扱うために UnityPluginLoad
と UnityPluginUnload
をエクスポートします。正しい署名は IUnityInterface.h
で参照してください。 IUnityInterfaces
は、追加的な Unity API にアクセスするためにプラグイン用に提供されています。
#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>();
}
プラグインは、 IUnityGraphics
インターフェースを取得することでジェネリックのデバイス機能にアクセスできます。旧バージョンの Unity では、 グラフィックス デバイス上のイベントに関する通知を受け取るには UnitySetGraphicsDevice
関数がエクスポートされる必要がありました。 Unity 5.2 からは、新しい IUnityGraphics インターフェース(IUnityGraphics.h
にあります)によってコールバックを登録することが可能となっています。
#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;
}
};
}
Unity は当該プラットフォームでの CPU 数により実現できる範囲でレンダリングをマルチスレッド化することができます。マルチスレッドレンダリングを使うときレンダリング API コマンドは MonoBehaviour とは完全に別の、独立したスレッド上で実行します。そのため、いつでもプラグインからレンダリングを起動することが可能とは限りません。そして、レンダリングスレッドは干渉する可能性があります。
プラグインから どのような レンダリングを行う場合でも、プラグインはスクリプトから GL.IssuePluginEvent を参照しメインスレッドから呼び出されるようにする必要があります。例えば、カメラの OnPostRender 関数から GL.IssuePluginEvent を呼び出す場合、プラグインはカメラのレンダリング終了後すぐにコールバックを取得します。
UnityRenderingEvent
コールバックの署名は IUnityGraphics.h
で提供されています。
ネイティブプラグイン コードサンプル
// 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;
}
マネージドプラグイン コードサンプル
#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);
このコールバックは CommandBuffer.IssuePluginEvent によって CommandBuffers に追加することもできます。
低レベルレンダリングプラグインのサンプルを 2 つ紹介します。ここでダウンロードできます
プロジェクトは以下で動作します。