2017年2月2日 星期四

Unity WebGL的低階Plugins

作者:Marco Trivellato 原文
潤稿:Kelvin Lo

我們之前分享了詳解Unity WebGL記憶體。今天我們一起來看看Unity WebGL平台如何使用低階
(Low-Level)Plugin,如果你想用網頁重用現有的C/C++程式碼,例如OpenGL ES的圖形效果,就別錯過今天的內容。我們從Plugin類型、如何實現以及展示範例幾個方面進行探討。

Unity支援兩種類型的Plugin:託管(Managed)
Plugin和原生(Native)Plugin。對於託管Plugin來說,WebGL與其它平台支援託管Plugin的方式一致,唯一的區別在於Plugin的託管程式集與引擎及使用者的託管程式碼會一起轉為JavaScript,這裡指asm.js/wasm。

對於原生
Plugin來說,針對網頁來談"native"真的有意義嗎?如果原生指的是例如Mac,Win 32/64等底層架構,當然沒有意義。然而,Unity WebGL也支援幾種其它類型的Plugin:JavaScript、C/C++以及預編譯的LLVM位元組碼。

Unity使用手冊中有幾個WebGL平台下JavaScript和C語言
Plugin的例子,並且展示了如何透過程式和它們溝通。既然可以使用C/C++原始程式碼,那就可以存取低階的Plugin介面來渲染。Unity 5.5就可以透過新加的連結器,來和低階Plugin綁定

如你所見,我們需要加很多程式,來看看實現Plugin需要哪些步驟。

介接Plugin


首先,需要將Unity安裝目錄下Editor/Data/PluginAPI中的Plugin API標頭檔,複製到
Plugin原始檔案所在的目錄。Plugin使用標頭檔IUnityInterface.h和IUnityGraphics.h來宣告所需的介面。由於這些標頭檔適用於特定的Unity版本,所以確保與編輯器版本同步是很重要的。註冊Plugin需要呼叫函數UnityRegisterRenderingPlugin。

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

無論如何,首先需要實現Load和Unload的callback函數來取得IUnityGraphics介面,並註冊或登出用於底層渲染的圖形設備callback函數。程式如下:


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);
}

實現了以上介面,就可以註冊
Plugin了。

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

最後,啟動時需要加上C#綁定並註冊
Plugin,確保UnityRegisterRenderingPlugin確實執行了。

class MyRenderPlugin
{
    #if UNITY_WEBGL && !UNITY_EDITOR
    [DllImport ("__Internal")]
    private static extern void RegisterPlugin();
    #endif

    void Start()
    {
        RegisterPlugin();
    }
}

然後需要實現OnGraphicsDeviceEvent並加上渲染碼。

#include <GLES2/gl2.h>

static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
{
    // OpenGL ES calls here...
}

請注意,如果不同的平台使用相同的
Plugin原始檔案,可以檢查__EMSCRIPTEN__或UNITY_WEBGL(僅限Unity 5.6及以上版本)來條件編譯程式。

#if defined(UNITY_WEBGL)

// Unity WebGL-specific code

#endif

最後,如果需要瀏覽系統標頭檔,如:gl2.h,可以在Unity安裝目錄下找到:

Editor/Data/PlaybackEngines/WebGLSupport/BuildTools/Emscripten/system/include

Plugin範例


如果有興趣嘗試製作渲染
Plugin,研究Unity官方Bitbucket上的NativeRenderingPlugin是一個非常棒的起點。它已經設定註冊了所需的callbacks,編譯了自己的著色器,並展示如何在簡單的Unity場景中渲染一個三角面。

注意,在Unity WebGL中不需要單獨建立C/C++
Plugin。這個範例中的Unity專案包含一個簡單的檔(Plugins / WebGL / RenderingPlugin.cpp),其中包含了Plugin的具體實現,如下所示:


#include "../../../../PluginSource/source/RenderingPlugin.cpp"

#include "../../../../PluginSource/source/RenderAPI.cpp"

#include "../../../../PluginSource/source/RenderAPI_OpenGLCoreES.cpp"

展示


最初的OpenGL 2.0 Demo是用C++和GLSL寫的,所以只需做一些修改,就能和前面的原生渲染Plugin Demo完美相容。您可以下載Unity的Demo專案和Plugin原始碼

總結


本文介紹了Unity WebGL中低階
Plugin的實現辦法。考慮到Unity WebGL平台的除錯工具並不豐富,建議可以在不同的GLES2/3 API平台上製作原型,確保WebGL平台一旦建立成功同時也能在iOS、Android或PC正常執行。

沒有留言:

張貼留言

著作人