WebGL 内嵌网页的一种解决方案

  之前使用的 ZFBrowser 嵌入方案可以发布到 Win, OS, Linux 上, 可是其它的就不行, 因为它用的谷歌内核嘛, 在 WebGL 上照理来说应该是最方便的啊, 因为它本身就是运行在浏览器内核上的, 前面的 BrowserInput 已经研究过向网页注入代码以及调用了, 现在试试在 WebGL 环境下来注入代码, 来创建简单的内嵌网页看看.

  Unity2017之前的方法跟 ZFBrowser 的很像, 用起来很方便, 可是以后会被禁用 :

[Obsolete("Application.ExternalEval is deprecated. See https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html for alternatives.")]
public static void ExternalEval(string script);

[Obsolete("Application.ExternalCall is deprecated. See https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html for alternatives.")]
public static void ExternalCall(string functionName, params object[] args);

  也不知道他们咋想的, 官方给的新方法是写一个 XXX.jslib 文件, 里面写的代码就是注入形式的代码, 通过 [DllImport("__Internal")] 的方式引用方法, 感觉就是编译成C++代码了, 先不说它效率高不高, 单是一个使用上就很蛋疼了啊, 看看一个 .jslib 文件, 官方的 :

mergeInto(LibraryManager.library, {

  HelloString: function (str) {
    window.alert(Pointer_stringify(str));    // unity传过来的string, 需要进行转换才能作为浏览器字符串
  },

  PrintFloatArray: function (array, size) {  // 数组还要自己传递长度
    for(var i = 0; i < size; i++)
    console.log(HEAPF32[(array >> 2) + i]);    // float[] 数组, 这样转换够奇葩了
  },

  StringReturnValueFunction: function () {
    var returnStr = "bla";                    // 网页字符串
    var bufferSize = lengthBytesUTF8(returnStr) + 1;
    var buffer = _malloc(bufferSize);
    stringToUTF8(returnStr, buffer, bufferSize);
    return buffer;                            // 传递给Unity的字符串经过转换才能传递...
  },
  
});

Unity 调用 :

    [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 string StringReturnValueFunction();
    
    void Start()
    {
        HelloString("This is a string.");            // 传递string给WebGL

        float[] myArray = new float[10];
        PrintFloatArray(myArray, myArray.Length);    // 传递Array给WebGL, 长度也要传...

        Debug.Log(StringReturnValueFunction());      // 从WebGL获取字符串
    }    

  这样反人类的做法, 估计是不能成事的了, Unity走了一条歪路......

  PS : 既然注入 JavaScript 这么绕, 那肯定是为了性能了, 看了一下编译方案, 频繁出现 Emscripten 这个字眼, 查了一下, 就是这个编译器, 在编辑器文件夹下也找到了

 

  不管怎样顺着来吧, 就是注入一个创建 iframe 的代码, 让它能够显示在 Unity 的窗口范围之内, 如果成功的话, 加上自动跟随和缩放功能, 它就是半个嵌入式网页了, 因为它只能实现最上层显示, 不能像 ZFBrowser 那样嵌入 UI 或是任意 Mesh 上显示, 没有真正的遮挡.

   添加一个创建 iframe 的代码 :

mergeInto(LibraryManager.library, {

    CreateIFrame: function () 
    {
        window.alert("CreateIFrame!!!");
        var div = window.document.createElement('div');    
        div.style.zIndex = "100";
        div.style.position="absolute";
        window.document.body.appendChild(div);

        var iframe = window.document.createElement('iframe');        
        iframe.style.zIndex = "1000";
        iframe.style.position="absolute";
        iframe.src = "http://XXXX/OOOO/";
        div.appendChild(iframe);
    },
  
});

  Unity 添加调用代码 :

    [DllImport("__Internal")]
    private static extern void CreateIFrame();
    
    void Start()
    {
        CreateIFrame();
    }    

 

  PS : Unity使用的是绝对位置, 反而比较方便进行坐标对齐操作.

  运行之后大概是这个样子, 正常实现了网页覆盖, 因为原本就是嵌入到Unity的网页, 网页背景是透明的 : 

 

  要做成嵌入式的感觉, 只需要根据Unity的坐标计算换算到网页, 设置 iframe 位置 / 缩放 就可以了, 没什么好说的, 不过因为没有遮挡关系, 没有什么实用价值...

 

posted @ 2020-07-14 10:33  tiancaiKG  阅读(3529)  评论(0编辑  收藏  举报