Unity の ネイティブプラグインは、特定のイベントが発生したときにコールバックを受け取ることができます。これを利用して、プラグインに低レベルレンダリングを実装し、Unity のマルチスレッドレンダリングと連携できます。
Unity のメインイベントをハンドルするには、プラグインは UnityPluginLoad および UnityPluginUnload の関数をエクスポートする必要があります。IUnityInterfaces を使用すると、プラグインがこれらの関数にアクセスすることができます。IUnityInterfaces は、プラグイン API の IUnityInterface.h にあります。
#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.h にある IUnityGraphics インターフェースを使用すると、プラグインが汎用グラフィックスデバイス機能にアクセスできるようになります。このスクリプトは、IUnityGraphics インターフェースを使用して、コールバックを登録する方法を示します。
#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 on graphics device initialization.
For example, D3D11 resource creation.
break;
}
case kUnityGfxDeviceEventShutdown:
{
s_RendererType = kUnityGfxRendererNull;
//TODO: user graphics API code to call on graphics device shutdown.
break;
}
case kUnityGfxDeviceEventBeforeReset:
{
//TODO: user graphics API code to call before graphics device reset.
break;
}
case kUnityGfxDeviceEventAfterReset:
{
//TODO: user graphics API code to call after graphics device reset.
break;
}
};
}
プラットフォームと使用可能な CPU の数が許す限り、Unity でマルチスレッドを使用してレンダリングすることができます。
ノート: マルチスレッドレンダリングを使用すると、レンダリング API のコマンドは、MonoBehaviour スクリプトを実行するスレッドとは完全に別のスレッドで実行されます。メインスレッドとレンダースレッドの間で通信が行われるため、メインスレッドがレンダースレッドに渡した作業量によっては、プラグインがすぐにレンダリングを開始しない場合があります。
プラグインからレンダリングするには、マネージプラグインスクリプトから GL.IssuePluginEvent を呼び出します。これにより、以下のコード例に示すように、Unity のレンダーパイプラインがレンダースレッドからネイティブ関数を呼び出します。例えば、Camera の OnPostRender 関数から GL.IssuePluginEvent を呼び出すと、この関数は、カメラがレンダリングを終了するとすぐにプラグインコールバックを呼び出します。
ネイティブプラグインのコード
// Plugin function to handle a specific rendering event
static void UNITY_INTERFACE_API OnRenderEvent(int eventID)
{
// 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);
UnityRenderingEvent コールバックのシグネチャは、ネイティブレンダリングプラグインのサンプルの IUnityGraphics.h にあります。
OpenGL オブジェクトには 2 種類あります。
Unity は複数の OpenGL コンテキストを使用します。エディターとプレイヤーの起動時と終了時にはマスターコンテキストに依存し、レンダリング時には専用のコンテキストを使用します。つまり、kUnityGfxDeviceEventInitialize および kUnityGfxDeviceEventShutdown のイベント中にコンテキストごとのオブジェクトを作成することはできません。