除了基本脚本接口之外,Unity 中的原生代码插件还可以在发生某些事件时接收回调。这主要用于实现插件中的低级渲染,并使低级渲染能够与 Unity 的多线程渲染一起使用。
定义 Unity 所公开的接口的头文件随 Editor 一起提供。
插件应导出 UnityPluginLoad
和 UnityPluginUnload
函数来处理主要的 Unity 事件。请参阅 IUnityInterface.h
以查看正确的签名。提供给插件的 IUnityInterfaces
是为了访问更多的 Unity API。
# include "IUnityInterface.h"
# include "IUnityGraphics.h"
// Unity 插件加载事件
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 插件加载事件
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;
}
托管插件代码示例:
# 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
事件期间无法创建每个上下文的对象。
例如,原生插件在 kUnityGfxDeviceEventInitialize
事件期间无法创建顶点数组对象并在 UnityRenderingEvent
回调中使用该对象,因为活动上下文不是顶点数组对象创建期间使用的上下文。
GitHub 上提供了一个低级渲染插件的示例:github.com/Unity-Technologies/NativeRenderingPlugin。该示例展示了两个方面:
该项目适用于:
• 2017–05–16 页面已修订
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.