기본적인 스크립트 인터페이스 외에 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에 추가됩니다.
OpenGL 오브젝트에는 OpenGL 컨텍스트(텍스처, 버퍼, 렌더 버퍼, 샘플러, 쿼리, 셰이더 및 프로그램 오브젝트) 간에 공유되는 오브젝트와 OpenGL당 컨텍스트 오브젝트(버텍스 배열, 프레임버퍼, 프로그램 파이프라인, 트랜스폼 피드백 및 동기화 오브젝트), 두 종류가 있습니다.
Unity에서는 여러 OpenGL 컨텍스트를 사용합니다. 에디터와 플레이어를 초기화하고 닫을 때는 master 컨텍스트를 사용하지만 렌더링에는 전용 컨텍스트를 사용합니다. 그러므로 kUnityGfxDeviceEventInitialize
및 kUnityGfxDeviceEventShutdown
이벤트 동안은 컨텍스트당 오브젝트를 생성할 수 없습니다.
예를 들어, 네이티브 플러그인은 액티브 컨텍스트가 버텍스 배열 오브젝트 생성 시 사용된 컨텍스트가 아니므로 kUnityGfxDeviceEventInitialize
이벤트기 진행되는 동안 버텍스 배열을 만들 수 없으며 UnityRenderingEvent
콜백에 사용합니다.
로우 레벨 렌더링 플러그인의 예제는 bitbucket에 있습니다. bitbucket.org/Unity-Technologies/graphicsdemos (NativeRenderingPlugin folder). 이 예제는 두 가지를 보여줍니다.
프로젝트는 다음에서 작동합니다.