WebGLを対象とした場合に必要なメモリへの配慮
WebGL テンプレートの使用

WebGL: ブラウザのスクリプトと通信を行う

Web コンテンツを構築していくとき Web ページ上の要素と通信を行う必要が出てくる場合があります。または Unity API として実装されていない Web API を使用して機能を実装したい場合もあるかもしれません。これらは、直接ブラウザの JavaScript エンジンと直接インターフェースで繋ぐ必要があります。Unity の WebGL はこれらを行うためのさまざまな方法を提供しています。

Unity と JavaScript コード間の呼び出し

Application.ExternalCall()Application.ExternalEval() 関数を使って、埋め込まれた web ページで JavaScript コードを起動できます。ブラウザから JavaScript を使ってコンテンツのゲームオブジェクト上にメソッドを呼び出すには、以下のコードを使用できます。

SendMessage ('MyGameObject', 'MyFunction', 'foobar');

プラグインから JavaScript の関数を呼び出す

ブラウザの JavaScript を使用する他の方法として、プロジェクト内に JavaScript のソースを組み込み、スクリプトコードから直接 JavaScript のコードを呼び出す方法があります。この方法を行うには、“Assets/Plugins/WebGL” フォルダーに .jslib 拡張子で JavaScript のファイルを配置することです( .js だと UnityScript コンパイラーでコンパイルされてしまうため .jslib にしています)。プラグインとしての JavaScript ファイルは以下の様なシンタックスを持ちます:

Assets/Plugins/WebGL/MyPlugin.jslib

var MyPlugin = {
    Hello: function()
    {
        window.alert("Hello, world!");
    },
    HelloString: function(str)
    {
        window.alert(Pointer_stringify(str));
    },
    PrintFloatArray: function(array, size)
    {
        for(var i=0;i<size;i++)
            console.log(HEAPF32[(array>>2)+size]);
    },
    AddNumbers: function(x,y)
    {
        return x + y;
    },
    StringReturnValueFunction: function()
    {
        var returnStr = "bla";
        var buffer = _malloc(lengthBytesUTF8(returnStr) + 1);
        writeStringToMemory(returnStr, buffer);
        return buffer;
    },
    BindWebGLTexture: function(texture)
    {
        GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
    }
};

mergeInto(LibraryManager.library, MyPlugin);

次に、上記の関数を C# スクリプトから呼び出す例です:

using UnityEngine;
using System.Runtime.InteropServices;

public class NewBehaviourScript : MonoBehaviour {

    [DllImport("__Internal")]
    private static extern void Hello();

    [DllImport("__Internal")]
    private static extern void HelloString(string str);

    [DllImport("__Internal")]
    private static extern void PrintFloatArray(float[] array, int size);

    [DllImport("__Internal")]
    private static extern int AddNumbers(int x, int y);

    [DllImport("__Internal")]
    private static extern string StringReturnValueFunction();

    [DllImport("__Internal")]
    private static extern void BindWebGLTexture(int texture);

    void Start() {
        Hello();
        
        HelloString("This is a string.");
        
        float[] myArray = new float[10];
        PrintFloatArray(myArray, myArray.Length);
        
        int result = AddNumbers(5, 7);
        Debug.Log(result);
        
        Debug.Log(StringReturnValueFunction());
        
        var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);
        BindWebGLTexture(texture.GetNativeTextureID());
    }
}

シンプルな数値であれば特に変換の必要せずに関数の引数パラメータとして JavaScript に渡すことができます。他のデータ型である場合は、(JavaScript の大きな配列として)emscripten ヒープ内のポインタとして渡されます。文字列の場合は、Pointer_stringify ヘルパー関数を使用して JavaScript の文字列へと変換することができます。JavaScript から 文字列を返すには malloc_ を呼び出してメモリを割り当て、writeStringToMemory__ ヘルパー関数で JavaScript の文字列を書き込む必要があります。Unity 側で戻り値として文字列を取得した場合は、IL2CPP のランタイムがメモリ周りの開放を世話してくれます。プリミティブ型の配列の場合、integer、unsigned integer、floating のメモリ表現が異なるサイズでヒープされるため、さまざまな ArrayBufferView を提供します: HEAP8、HEAPU8、HEAP16、HEAPU16、HEAP32、HEAPU32、HEAPF32、HEAPF64 。 WebGL のテクスチャにアクセスするために、emscripten は Unity から WebGL テクスチャオブジェクトの ネイティブテクスチャ ID のマップである GL.textures を提供します。

プラグインから C++ 関数を呼び出す

Unity は ソースコードを emscripten を使用して C++ のコードから JavaScript へとコンパイルしているので、同じように C または C++ のコードをプラグインとして書くことができます。そして C# のコードからそれらの関数を呼び出すこともできます。よって上記の例のような jslib の代わりに、下記のような c ファイルを扱うことが可能です。- このプラグインは自動でコンパイルされ、上記の JavaScript コードのサンプルのようにスクリプト側から呼び出すことが可能です。

C++ (.cpp) を使用してプラグインを実装する場合は、マングリング(name mangling)問題を回避するために C リンケージを持つようにしなければいけません。

Assets/Plugins/WebGL/MyPlugin.c

#include <stdio.h>

void Hello ()
{
    printf("Hello, world!\n");
}

int AddNumbers (int x, int y)
{
    return x + y;
}

互換性チェックとエラーハンドラーのカスタマイズ

Unity はデフォルトでは、プラットホームの互換性チェックとエラー制御のために、ビルド時にいくらかの JavaScript を作成します。このコードは、モバイルデバイスで Unity の WebGL コンテンツを実行しようとした場合など、サポートしていないプラットホームで実行された時に、警告メッセージを表示します。既知のエラーをチェックし、より判りやすいエラーメッセージとともにエラーダイアログを表示するために、ブラウザからエラーと例外値の追跡もできます。

例えば、モバイル上で WebGL コンテンツを表示したときに発生する警告メッセージを非表示にしたい場合に、カスタマイズすることによって実現が可能です。カスタマイズする方法は、生成された index.html ファイルにある errorhandler と compatibilitycheck が null のところに Javascript 関数を実装することです。

  var Module = {
    TOTAL_MEMORY: 268435456,
    errorhandler: null,
    compatibilitycheck: null,
  };

compatibilitycheck 関数は、起動時に呼び出され、サポートされていないデバイスだと検出したときに表示されるメッセージをコードによって実装することができます。

errorhandler 関数は、window.onerror イベントハンドラーが実行されたときに呼び出されるものです。引数も window.onerror と同じものが渡されます。 true を返すと場合はデフォルトのエラーハンドラーが実行されず、false を返すとUnityのデフォルトハンドラーが実行されます。

例:

  var Module = {
    TOTAL_MEMORY: 268435456,
    errorhandler: function(err, url, line) {
        alert("error " + err + " occurred at line " + line);

        // return true so Unity's error handler is not executed.
        return true;
    },
    compatibilitycheck: function() {
        // check compatibility ...
    }
  };
WebGLを対象とした場合に必要なメモリへの配慮
WebGL テンプレートの使用