Version: 2019.3
Building plug-ins for desktop platforms
低レベルのネイティブプラグイン Profiler API

低レベルネイティブプラグインインターフェース

In addition to the basic script interface, Native Code Plug-ins in Unity can receive callbacks when certain events happen. This is mostly used to implement low-level rendering in your plug-in and enable it to work with Unity’s multithreaded rendering.

Unity が公開しているインターフェースを定義するヘッダーは、エディターと一緒に提供されています。

インターフェースレジストリ

プラグインは、主要な Unity イベントを扱うために UnityPluginLoadUnityPluginUnload をエクスポートします。正しい署名は IUnityInterface.h を参照してください。IUnityInterfaces は、追加的な Unity API にアクセスするためにプラグインに提供されています。

# include "IUnityInterface.h"
# include "IUnityGraphics.h"
// Unity プラグイン load イベント
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 イベント
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
    UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
    s_UnityInterfaces = unityInterfaces;
    s_Graphics = unityInterfaces->Get<IUnityGraphics>();
        
    s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
        
    //  OnGraphicsDeviceEvent(initialize) を plugin load 上で手動で実行して
    // グラフィックスデバイスがすでにイニシアライズされている場合でも   
    //イベントを見逃さないようにします
    OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
}
    
// Unity plugin unload イベント
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: ユーザーイニシアライゼ―ションコード
            break;
        }
        case kUnityGfxDeviceEventShutdown:
        {
            s_RendererType = kUnityGfxRendererNull;
            //TODO: ユーザーシャットダウンコード
            break;
        }
        case kUnityGfxDeviceEventBeforeReset:
        {
            //TODO: ユーザー Direct3D 9 コード
            break;
        }
        case kUnityGfxDeviceEventAfterReset:
        {
            //TODO: ユーザー Direct3D 9 コード
            break;
        }
    };
}

レンダリングスレッドのプラグインコールバック

Unity のレンダリングは、プラットフォームと CPU の数が一定の条件を満たす場合は、マルチスレッドで行われます。マルチスレッドのレンダリングが使用されるとき、レンダリング API の命令は、MonoBehaviour スクリプトを実行するスレッドとは完全に別の 1 つのスレッド上で行われます。そのため、プラグインがいくつかのレンダリングを即座に開始することが常に可能ではありません。なぜなら、その時レンダースレッドが行っている処理に干渉する場合があるからです。

プラグインから いかなる レンダリングを行う場合でも、スクリプトから GL.IssuePluginEvent を参照しメインスレッドから呼び出されるようにする必要があります。例えば、カメラの OnPostRender 関数から GL.IssuePluginEvent を呼び出す場合、プラグインはカメラのレンダリング終了後すぐにコールバックを取得します。

UnityRenderingEvent コールバックのシグネチャは IUnityGraphics.h で示されます。
ネイティブプラグイン コードサンプル

// 特定のレンダリングイベントを処理するプラグイン関数
static void UNITY_INTERFACE_API OnRenderEvent(int eventID)
{
    //TODO: ユーザーレンダリングコード
}
    
// プラグイン特有のスクリプトにコールバックを渡すための自由に定義した関数
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();
    
// 指定のコールバックがレンダースレッドで呼び出されるようにキューで待機
GL.IssuePluginEvent(GetRenderEventFunc(), 1);

このコールバックは CommandBuffer.IssuePluginEvent によって CommandBuffers に追加することもできます。

OpenGL グラフィックス API を使用したプラグイン

2 種類の OpenGL オブジェクトがあります。OpenGL コンテキストをまたいで共有されるオブジェクト (テクスチャ、バッファ、レンダーバッファ、サンプラー、クエリ、シェーダー、プログラムオブジェクト) と OpenGL コンテキストごとのオブジェクト (頂点配列、フレームバッファ、プログラムパイプライン、トランスフォームフィードバック、同期オブジェクト) です。

Unity は複数の OpenGL コンテキストを使用します。エディターとプレイヤーの初期化と終了のときは マスター コンテキストに依存しますが、レンダリングには専門のコンテキストを使用します。したがって、kUnityGfxDeviceEventInitializekUnityGfxDeviceEventShutdown イベントの間、コンテキストごとのオブジェクトを作成することはできません。

例えば、ネイティブのプラグインは kUnityGfxDeviceEventInitialize イベント中に頂点配列オブジェクトを作成できず、UnityRenderingEvent コールバックでそれを使用することはできません。これは、アクティブなコンテキストが頂点配列オブジェクトの作成時に使用されるものでないからです。

An example of a low-level rendering plug-in is on github: github.com/Unity-Technologies/NativeRenderingPlugin. It demonstrates two things:

  • すべての通常レンダリングが完了した後に、C++ コードから回転する三角形を描画します。
  • C++ のコードでプロシージャルなテクスチャを塗りつぶします。コードにアクセスするために Texture.GetNativeTexturePtr を利用します。

プロジェクトは以下の仕様で動作します。

  • Windows (Visual Studio 2015) with Direct3D 11, Direct3D 12, OpenGL and Vulkan.
  • Metal、OpenGL のいずれかを持つ Mac OS X (Xcode)
  • Direct3D 11、Direct3D 12 のいずれかを持つユニバーサル Windows プラットフォーム
  • WebGL
  • Android (ndk-build) with OpenGL ES 2.0, 3.x and Vulkan

• 2017–05–16 Page amended

Building plug-ins for desktop platforms
低レベルのネイティブプラグイン Profiler API