Version: 2020.1
言語: 日本語
WebGL での入力
WebGL のパフォーマンスについて

WebGL: ブラウザースクリプトとの相互作用

Web 用のコンテンツを構築するときは、Web ページ上の他の要素とやり取りする必要があります。また、Web API を使用して Unity が現在デフォルトで公開していない機能を実装したい場合もあるかもしれません。 いずれの場合も、ブラウザーの JavaScript エンジンと直接やり取りする必要があります。Unity WebGL はこれを行うためのさまざまな方法を提供します。

Unity スクリプトから JavaScript 関数を呼び出す

プロジェクトでブラウザーの JavaScript を使用で推奨される方法は、JavaScript ソースをプロジェクトに追加し、次にスクリプトコードからそれらの関数を直接呼び出すことです。そのためには、 .jslib 拡張子を使用して、Assets フォルダー内の “Plugins” サブフォルダーに JavaScript コードのあるファイルを配置します。プラグインファイルは以下のような構文を持つ必要があります。

mergeInto(LibraryManager.library, {

  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) + i]);
  },

  AddNumbers: function (x, y) {
    return x + y;
  },

  StringReturnValueFunction: function () {
    var returnStr = "bla";
    var bufferSize = lengthBytesUTF8(returnStr) + 1;
    var buffer = _malloc(bufferSize);
    stringToUTF8(returnStr, buffer, bufferSize);
    return buffer;
  },

  BindWebGLTexture: function (texture) {
    GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
  },

});

次に、上記の関数を以下のように 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 に渡すことができます。他のデータ型は、emscripten ヒープ内のポインターとして渡されます (実際には JavaScript の大きな配列です)。文字列の場合は、Pointer_stringify ヘルパー関数を使用して JavaScript 文字列に変換できます。文字列値を返すには、メモリを割り当てるために _malloc を呼び出し、JavaScript 文字列を書き込むために stringToUTF8 ヘルパー関数を呼び出す必要があります。文字列が戻り値の場合は、il2cpp ランタイムがメモリ解放の処理をします。プリミティブ型の配列の場合、emscripten はメモリを表すさまざまなサイズの整数、符号なし整数、浮動小数点のヒープに対して、異なる ArrayBufferViews を提供します。 HEAP8、HEAPU8、HEAP16、HEAPU16、HEAP32、HEAPU32、HEAPF32、HEAPF64 などです。 WebGL のテクスチャにアクセスするために、emscripten は GL.textures 配列を提供し Unity から WebGL テクスチャオブジェクトへネイティブのテクスチャ ID をマッピングします。WebGL 関数は、emscripten の WebGL コンテキストGLctx で呼び出すことができます。

JavaScript と相互作用する方法に関して詳しくは、emscripten ドキュメント を参照してください。

さらに、Unity のインストールフォルダーの以下の場所に、参照して使用できるプラグインがいくつかあります。 PlaybackEngines/WebGLSupport/BuildTools/libPlaybackEngines/WebGLSupport/BuildTools/Emscripten/src/library*

Unity スクリプト関数を JavaScript から 呼び出す

ブラウザーの JavaScript から Unity スクリプトにデータや通知の送信が必要な場合があります。推奨される方法は、コンテンツ内でゲームオブジェクトのメソッドを呼び出すことです。プロジェクトに埋め込まれた JavaScript プラグインから呼び出しを行う場合は、以下のコードを使用します。

unityInstance.SendMessage(objectName, methodName, value);

objectName はシーンのオブジェクトの名。 methodName は、現在オブジェクトにアタッチされているスクリプトのメソッド名です。value には文字列、数字などで、以下の例のように空にしておくことも可能です。

unityInstance.SendMessage('MyGameObject', 'MyFunction');
unityInstance.SendMessage('MyGameObject', 'MyFunction', 5);

unityInstance.SendMessage('MyGameObject', 'MyFunction', 'MyString');

埋め込みページのグローバルスコープから呼び出しをしたい場合は、後述の コードの可視性 セクションを参照してください。

C 関数を Unity スクリプトから呼び出す

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

プラグインを実装するのに C++ (.cpp) を使用する場合は、名前マングリング を避けるために、関数を C リンケージで宣言してください。

# include <stdio.h>

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

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

コードの可視性

Unity 5.6 から、すべてのビルドコードはそれ自体のスコープで実行されます。このアプローチを使うと、ページに埋め込まれているコードと矛盾することなく、ページにコンテンツを埋め込むことが可能になります。また、1 つのページに複数のビルドを埋め込むことが可能になります。

プロジェクト内の JavaScript コードがすべて .jslib プラグインの形式である場合、この JavaScript コードはコンパイルされたビルドと同じスコープ内で実行され、コードは以前のバージョンの Unity とほぼ同じように動作します (例えば、Module、SendMessage、HEAP8、ccall など のオブジェクトと関数は、JavaScript プラグインコードから直接見ることができます)。

ただし、埋め込みページのグローバルスコープから内部の JavaScript 関数を呼び出そうと考えている場合は、WebGL テンプレートの index.html で unityInstance 変数を使用する必要があります。これは、Unity エンジンのインスタンス化が成功した後に行います。以下はその例です。

  var myGameInstance = null;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {...}).then((unityInstance) => {
        myGameInstance = unityInstance;
        …

その後、myGameInstance.SendMessage() を使ってビルドにメッセージを送るか、myGameInstance.Module を使ってビルドのモジュールオブジェクトにアクセスします。


  • 2020.1 で unity.Instance が createUnityInstance に変更されました。

  • コード例の誤りを修正

  • 2019.1 で WebGL インスタンスの名称が gameInstance から unityInstance に変更されました。

WebGL での入力
WebGL のパフォーマンスについて