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 所公开的接口的头文件随 Editor 一起提供。
A plug-in should export UnityPluginLoad
and UnityPluginUnload
functions to handle main Unity events. See IUnityInterface.h
for the correct signatures. IUnityInterfaces
is provided to the plug-in to access further Unity APIs.
# include "IUnityInterface.h"
# include "IUnityGraphics.h"
// Unity 插件加载事件
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
IUnityGraphics* graphics = unityInterfaces->Get<IUnityGraphics>();
}
A plug-in can access generic graphics device functionality by getting the IUnityGraphics
interface. In earlier versions of Unity a UnitySetGraphicsDevice
function had to be exported in order to receive notification about events on the graphics device. Starting with Unity 5.2 the new IUnityGraphics interface (found in IUnityGraphics.h
) provides a way to register a callback.
# include "IUnityInterface.h"
# include "IUnityGraphics.h"
static IUnityInterfaces* s_UnityInterfaces = NULL;
static IUnityGraphics* s_Graphics = NULL;
static UnityGfxRenderer s_RendererType = kUnityGfxRendererNull;
// Unity 插件加载事件
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)
// 在图形设备已初始化的情况下不错过该事件
OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
}
// Unity 插件卸载事件
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;
}
};
}
如果平台和可用 CPU 数允许,则在 Unity 中的渲染可以是多线程的。当使用多线程渲染时,执行这些渲染 API 命令的线程完全独立于运行 MonoBehaviour 脚本的线程。因此,您的插件并非总是可以立即开始进行渲染,因为它可能会干扰渲染线程此时正在进行的工作。
为了从插件中进行任何渲染,应从脚本中调用 GL.IssuePluginEvent。这将导致从渲染线程调用提供的本机函数。例如,如果从摄像机的 OnPostRender 函数调用 GL.IssuePluginEvent,则在该摄像机已完成渲染后,您将立即获得插件回调。
在 IUnityGraphics.h
中提供了 UnityRenderingEvent
回调的签名。
原生插件代码示例:
// 用于处理特定渲染事件的插件函数
static void UNITY_INTERFACE_API OnRenderEvent(int eventID)
{
//TODO:用户渲染代码
}
// 自由定义的函数,用于将回调传递给特定于插件的脚本
extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
GetRenderEventFunc()
{
return OnRenderEvent;
}
Managed plug-in code example:
# if UNITY_IPHONE && !UNITY_EDITOR
[DllImport ("__Internal")]
# else
[DllImport("RenderingPlugin")]
# endif
private static extern IntPtr GetRenderEventFunc();
// 对要在渲染线程上调用的特定回调进行排队
GL.IssuePluginEvent(GetRenderEventFunc(), 1);
现在还可通过 CommandBuffer.IssuePluginEvent 将此类回调添加到 CommandBuffer。
有两种 OpenGL 对象:跨 OpenGL 上下文共享的对象(纹理、缓冲、渲染缓冲、采样器、查询、着色器和程序对象)和每个 OpenGL 的上下文对象(顶点数组、帧缓冲、程序管线、变换反馈和同步对象)。
Unity 使用多个 OpenGL 上下文。在初始化和关闭 Editor 和播放器时,我们依赖于主上下文,但我们使用专用上下文进行渲染。因此,在 kUnityGfxDeviceEventInitialize
和 kUnityGfxDeviceEventShutdown
事件期间无法创建每个上下文的对象。
For example, a native plug-in 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.
An example of a low-level rendering plug-in is on bitbucket: bitbucket.org/Unity-Technologies/graphicsdemos (NativeRenderingPlugin folder). It demonstrates two things:
该项目适用于:
• 2017–05–16 Page amended with no editorial review