webgl unity_Unity WebGL中的低级插件

webgl unity_Unity WebGL中的低级插件

webgl unity

去年,我们在WebGL上发布了一系列技术博客文章,从内存中的几篇文章开始。 现在是时候继续一个新主题了。
您是否曾经需要/想要重复使用网页中的现有C / C ++代码? 也许是用OpenGL ES编写的图形效果? 有了Unity WebGL,就有了一种方法! (Last year we launched a series of technical blog posts on WebGL, starting with a couple of posts on memory. Now it’s time to continue with a new topic.
Have you ever needed/wanted to re-use existing C/C++ code in a web page? Perhaps a graphics effect written in OpenGL ES? With Unity WebGL there is a way!)

Unity supports two types of plugins: managed and native. On WebGL, managed plugins are supported like on other platforms. The only difference is that the managed assembly of the plug-in is converted, along with the engine and user’s managed code, to JavaScript (asm.js/wasm to be specific).

Unity支持两种类型的插件 :托管和本机。 与其他平台一样, 在WebGL上 也支持 托管插件 。 唯一的区别是,插件的托管程序集与引擎和用户的托管代码一起转换为JavaScript(具体来说为asm.js / wasm)。

What about native plugins? Does it even make sense to talk about something “native” on the web? When referring to native as something specific to the underlying architecture (mac, win32/64, etc.), it certainly does not. However, Unity WebGL does support several other types of plugins: JavaScript, C/C++ and pre-compiled LLVM byte code.

本机插件 呢? 在网络上谈论“本机”甚至有意义吗? 当将native称为特定于基础架构的东西(mac,win32 / 64等)时,它当然不是。 但是,Unity WebGL确实支持其他几种类型的插件:JavaScript,C / C ++和预编译的LLVM字节码。

In the Unity User Manual, there are a couple of examples of both JavaScript and C plugins that demonstrate how to interact with them via scripts. So, since we can use C/C++ sources, what’s stopping us from accessing the Low-Level plugin interface for rendering purposes? Well… nothing in Unity 5.5 ;-)

在Unity 用户手册中 ,有两个JavaScript和C插件示例,它们演示了如何 通过脚本与它们进行 交互 。 因此,由于我们可以使用C / C ++源,是什么阻止了我们 出于渲染目的而 访问 Low-Level插件接口 ? 好吧... Unity 5.5中什么都没有;-)

In fact, Unity 5.5 adds the missing hooks to allow you to register a low-level plugin:

实际上,Unity 5.5添加了缺少的钩子,以允许您注册低级插件:

As you can see, the amount of code we had to add is massive. Now let’s see what you need to do to implement your plug-in!

如您所见,我们必须添加大量的代码。 现在,让我们看看实现插件所需要做的!

实作 (Implementation)

First of all, you need to copy the Plugin API headers from the Unity install path Editor/Data/PluginAPI to the location that will contain your plug-in source file(s).

首先,您需要将Unity安装路径Editor / Data / PluginAPI中的Plugin API标头复制到将包含您的插件源文件的位置。

The headers you are interested in are IUnityInterface.h and IUnityGraphics.h, which declare the interfaces needed for the plugin. Remember that these headers are specific to a version of Unity, so it’s important to keep them in sync with the Editor.

您感兴趣的标头是IUnityInterface.hIUnityGraphics.h ,它们声明了插件所需的接口。 请记住,这些标头特定于Unity版本,因此使它们与编辑器保持同步很重要。

The function you need to call to register your plugin is UnityRegisterRenderingPlugin:

注册插件需要调用的函数是UnityRegisterRenderingPlugin

1
extern "C" void UnityRegisterRenderingPlugin(PluginLoadFunc loadPlugin, PluginUnloadFunc unloadPlugin);
1
extern "C" void UnityRegisterRenderingPlugin ( PluginLoadFunc loadPlugin , PluginUnloadFunc unloadPlugin ) ;

However, first you need to implement both Load and Unload callbacks to get the IUnityGraphics interface and register/unregister the graphics device event callback for your low-level rendering. Here is an example:

但是,首先,您需要同时实现LoadUnload回调,以获取IUnityGraphics接口并为低级渲染注册/注销图形设备事件回调。 这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
IUnityInterfaces* s_UnityInterfaces = 0;
IUnityGraphics* s_Graphics = 0;
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
    s_UnityInterfaces = unityInterfaces;
    s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
    s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
    // Run OnGraphicsDeviceEvent(initialize) manually on plugin load
    OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
    s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
IUnityInterfaces * s_UnityInterfaces = 0 ;
IUnityGraphics * s_Graphics = 0 ;
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad ( IUnityInterfaces * unityInterfaces )
{
     s_UnityInterfaces = unityInterfaces ;
     s_Graphics = s_UnityInterfaces -> Get < IUnityGraphics > ( ) ;
     s_Graphics -> RegisterDeviceEventCallback ( OnGraphicsDeviceEvent ) ;
     // Run OnGraphicsDeviceEvent(initialize) manually on plugin load
     OnGraphicsDeviceEvent ( kUnityGfxDeviceEventInitialize ) ;
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload ( )
{
     s_Graphics -> UnregisterDeviceEventCallback ( OnGraphicsDeviceEvent ) ;
}

Once those are implemented, you can register them:

一旦实现,就可以注册它们:

1
2
3
4
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API RegisterPlugin()
{
    UnityRegisterRenderingPlugin(UnityPluginLoad, UnityPluginUnload);
}
1
2
3
4
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API RegisterPlugin ( )
{
     UnityRegisterRenderingPlugin ( UnityPluginLoad , UnityPluginUnload ) ;
}

And finally, you need to add the the C# binding and register the plug-in on startup (so that UnityRegisterRenderingPlugin is actually executed):

最后,您需要添加C#绑定并在启动时注册插件(以便实际上执行UnityRegisterRenderingPlugin ):

1
2
3
4
5
6
7
8
9
10
11
12
class MyRenderPlugin
{
    #if UNITY_WEBGL && !UNITY_EDITOR
    [DllImport ("__Internal")]
    private static extern void RegisterPlugin();
    #endif
    void Start()
    {
        RegisterPlugin();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
class MyRenderPlugin
{
     #if UNITY_WEBGL && !UNITY_EDITOR
     [ DllImport ( "__Internal" ) ]
     private static extern void RegisterPlugin ( ) ;
     #endif
     void Start ( )
     {
         RegisterPlugin ( ) ;
     }
}

Then all you need to do is to implement OnGraphicsDeviceEvent and add your rendering code.

然后,您所需要做的就是实现OnGraphicsDeviceEvent并添加渲染代码。

1
2
3
4
5
6
#include <GLES2/gl2.h>
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
{
    // OpenGL ES calls here...
}
1
2
3
4
5
6
#include <GLES2/gl2.h>
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent ( UnityGfxDeviceEventType eventType )
{
     // OpenGL ES calls here...
}

Note that if the same plug-in source files are used on different platforms, you can check __EMSCRIPTEN__ or UNITY_WEBGL (5.6+ only) to conditionally compile your code:

请注意,如果在不同平台上使用了相同的插件源文件,则可以检查__EMSCRIPTEN__UNITY_WEBGL (仅5.6+)来有条件地编译代码:

1
2
3
4
5
#if defined(UNITY_WEBGL)
// Unity WebGL-specific code
#endif
1
2
3
4
5
#if defined(UNITY_WEBGL)
// Unity WebGL-specific code
#endif

Finally, if you need to browse system headers (e.g.: gl2.h), you can find those in your Unity install path under: Editor/Data/PlaybackEngines/WebGLSupport/BuildTools/Emscripten/system/include

最后,如果您需要浏览系统头文件(例如:gl2.h),则可以在Unity安装路径中的以下位置找到这些文件头: Editor / Data / PlaybackEngines / WebGLSupport / BuildTools / Emscripten / system / include

样本插件 (Sample plug-in)

Our NativeRenderingPlugin on Bitbucket is a great starting point if you are interested in trying to make your own rendering plug-in. It’s already setup to register the required callbacks, compile own Shaders, and it demostrates how to render a triangle on top of a simple Unity Scene.

如果您有兴趣尝试制作自己的呈现插件,那么 我们 在Bitbucket上的 NativeRenderingPlugin 是一个很好的起点。 它已经设置为注册所需的回调,编译自己的着色器,并且演示了如何在简单的Unity场景之上渲染三角形。

Note that on Unity WebGL, there is no need to build the C/C++ plug-in separately. The Unity project of this sample contains a simple file (Plugins/WebGL/RenderingPlugin.cpp), which includes the actual implementation of the plug-in and looks like the following:

请注意,在Unity WebGL上,无需单独构建C / C ++插件。 此示例的Unity项目包含一个简单文件( Plugins / WebGL / RenderingPlugin.cpp ),其中包含该插件的实际实现,如下所示:

1
2
3
#include "../../../../PluginSource/source/RenderingPlugin.cpp"
#include "../../../../PluginSource/source/RenderAPI.cpp"
#include "../../../../PluginSource/source/RenderAPI_OpenGLCoreES.cpp"
1
2
3
#include "../../../../PluginSource/source/RenderingPlugin.cpp"
#include "../../../../PluginSource/source/RenderAPI.cpp"
#include "../../../../PluginSource/source/RenderAPI_OpenGLCoreES.cpp"

演示版 (Demo)

If you are viewing this page on a browser/device supported by Unity WebGL, see the demo below, which demonstrates a Mandelbrot effect written in OpenGL ES via Native Rendering Plugin:

如果您在Unity WebGL支持的浏览器/设备上查看此页面,请参见下面的演示,该演示演示了通过本机渲染插件以OpenGL ES编写的Mandelbrot效果:

The original OpenGL 2.0 demo was written in C++ and GLSL, so we only had to make a few modifications to make it work with our Native Rendering Plugin sample mentioned earlier.

原始的OpenGL 2.0 演示是用C ++和GLSL编写的,因此我们只需要进行一些修改即可使其与前面提到的Native Rendering Plugin示例一起使用。

If you want to take a peek at this demo Unity project and plug-in source code, click here to download them.

如果您想看一下这个演示Unity项目和插件源代码, 请单击此处下载它们

结论 (Conclusion)

There might be several different reasons for writing low-level plug-ins; at least now you know that it is possible. One final suggestion: considering the lack of debugging tools on Unity WebGL, you might want to prototype on a different GLES2/3 API platform, so that you only build for WebGL once everything works properly on iOS/Android or Standalone.

编写底层插件的原因可能有多种。 至少现在您知道这是可能的。 最后的建议是:考虑到Unity WebGL上缺少调试工具,您可能想在其他GLES2 / 3 API平台上进行原型设计,以便仅在iOS / Android或Standalone上一切正常运行后才为WebGL进行构建。

Have fun!

玩得开心!

翻译自: https://blogs.unity3d.com/2017/01/19/low-level-plugins-in-unity-webgl/

webgl unity