Firefox loads and runs Unity3D WebGL apps MUCH faster than Chrome.<p>The point of UnityJS is to tightly and efficiently integrate Unity3D and JavaScript, so it does a lot of JavaScript <=> C# calls, and I'm looking forward to it getting even faster!<p><a href="https://github.com/SimHacker/UnityJS" rel="nofollow">https://github.com/SimHacker/UnityJS</a><p>You can pass delegates to C# functions that are directly callable into JavaScript using some magic PInvoke attributes and the Unity Runtime.dynCall function.<p>Declare a delegate that describes the signature of your C# function you want to call from JavaScript:<p><a href="https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Assets/Libraries/UnityJS/Scripts/BridgeTransportWebGL.cs#L35" rel="nofollow">https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Ass...</a><p><pre><code> public delegate int AllocateTextureDelegate(int width, int height);
</code></pre>
Then declare a C# static method with the MonoPInvokeCallback attribute, to implement you C# function:<p><a href="https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Assets/Libraries/UnityJS/Scripts/BridgeTransportWebGL.cs#L82" rel="nofollow">https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Ass...</a><p><pre><code> [MonoPInvokeCallback(typeof(AllocateTextureDelegate))]
public static int AllocateTexture(int width, int height) { ... }
</code></pre>
Then pass those specially marked delegates to JavaScript and stash them in JS variables when you initialize (it doesn't work unless you use the magic MonoPInvokeCallback attribute):<p><a href="https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Assets/Libraries/UnityJS/Scripts/BridgeTransportWebGL.cs#L48" rel="nofollow">https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Ass...</a><p><pre><code> [DllImport(PLUGIN_DLL)]
public static extern void _UnityJS_HandleAwake(AllocateTextureDelegate allocateTextureCallback, FreeTextureDelegate freeTextureCallback, LockTextureDelegate lockTextureCallback, UnlockTextureDelegate unlockTextureCallback);
</code></pre>
<a href="https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Assets/Libraries/UnityJS/Scripts/BridgeTransportWebGL.cs#L175" rel="nofollow">https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Ass...</a><p><pre><code> public override void HandleAwake()
{
//Debug.Log("BridgeTransportWebGL: HandleAwake: this: " + this + " bridge: " + bridge);
_UnityJS_HandleAwake(
AllocateTexture,
FreeTexture,
LockTexture,
UnlockTexture);
}
</code></pre>
In the awake function on the JavaScript side of your Unity WebGL extension (a .jslib file), wrap the C# delegate in a JavaScript thunk that calls into it via Runtime.dynCall:<p><a href="https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Assets/Libraries/UnityJS/Plugins/WebGL/UnityJS.jslib#L11" rel="nofollow">https://github.com/SimHacker/UnityJS/blob/master/UnityJS/Ass...</a><p><pre><code> // Called by Unity when awakened.
_UnityJS_HandleAwake: function _UnityJS_HandleAwake(allocateTextureCallback, freeTextureCallback, lockTextureCallback, unlockTextureCallback)
{ [...]
function _UnityJS_AllocateTexture(width, height)
{
//console.log("UnityJS.jslib: _UnityJS_AllocateTexture: width: " + width + " height: " + height + " allocateTextureCallback: " + allocateTextureCallback);
var result = Runtime.dynCall('iii', allocateTextureCallback, [width, height]);
//console.log("UnityJS.jslib: _UnityJS_AllocateTexture: result: " + result);
return result;
};
window.bridge._UnityJS_AllocateTexture = _UnityJS_AllocateTexture;
</code></pre>
Then you can call the C# method from JavaScript:<p><a href="https://github.com/SimHacker/UnityJS/blob/f0a4e1fb07fd9e8aaba2849fefd1d2239c262a97/UnityJS/Assets/StreamingAssets/game.jss#L348" rel="nofollow">https://github.com/SimHacker/UnityJS/blob/f0a4e1fb07fd9e8aab...</a><p><pre><code> params.cache.backgroundSharedTextureID = id =
window.bridge._UnityJS_AllocateTexture(params.width, params.height);
</code></pre>
This is zillions of time faster and more flexible than using Unity's terrible SendMessage technique to send messages from JS=>C#, whose only parameter is a single string, and which inefficiently dispatches messages by looking up Unity objects by name, and is asynchronous and can't return a result.<p>I use this technique to efficiently copy binary textures and arrays of numbers between JavaScript and C#. MUCH better than serializing it as JSON, or base 64 encoded PNG files in a data: url (yuck!).<p><a href="https://github.com/SimHacker/UnityJS/blob/674eda49be12a7081205b6af4bf3986cb76ac7d7/UnityJS/Assets/StreamingAssets/game.jss#L382" rel="nofollow">https://github.com/SimHacker/UnityJS/blob/674eda49be12a70812...</a><p><pre><code> function DrawToCanvas(params, drawer, success, error)
{ [...]
var id = params.pie.backgroundSharedTextureID;
if (!id) {
params.pie.backgroundSharedTextureID = id =
window.bridge._UnityJS_AllocateTexture(params.width, params.height);
//console.log("game.js: DrawToCanvas: WebGL: AllocateTexture: width: " + params.width + " height: " + params.height + " id: " + id);
}
var imageData =
context.getImageData(0, 0, params.width, params.height);
window.bridge._UnityJS_UpdateTexture(id, imageData);
texture = {
type: 'sharedtexture',
id: id
};
success(texture, params);
canvasNode.parentNode.removeChild(canvasNode);
</code></pre>
This lets me draw 2D user interface stuff, pie charts, diagrams, data visualizations, etc, in JavaScript with canvas, d3, or whatever library I like, and then efficiently use those images in Unity3D as user interface overlays, 3D textures, etc. It works great, and it's smooth and interactive, mixing up 2D canvas graphics with 3D Unity stuff!<p>Unity is sorely lacking a decent 2D drawing library like canvas, not to mention fancy stuff built on top of it like d3.<p>I'm currently working on the plumbing to send binary arrays of floats from JavaScript to Unity, so I can pass them right into shaders!<p>Here's some discussion about the magic MonoPInvokeCallback attribute:<p><a href="https://forum.unity.com/threads/monopinvokecallback-in-unity.132510/" rel="nofollow">https://forum.unity.com/threads/monopinvokecallback-in-unity...</a><p>And about Unity.dyncall and the WebGL runtime:<p><a href="https://forum.unity.com/threads/c-jslib-2-way-communication.323629/" rel="nofollow">https://forum.unity.com/threads/c-jslib-2-way-communication....</a><p>and:<p><a href="https://forum.unity.com/threads/super-fast-javascript-interaction-on-webgl.382734/" rel="nofollow">https://forum.unity.com/threads/super-fast-javascript-intera...</a>