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.h和IUnityGraphics.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:
但是,首先,您需要同时实现Load和Unload回调,以获取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