zoukankan      html  css  js  c++  java
  • Unity发布WebGL后加载本地文件

    Unity发布WebGL平台的程序是不可以直接访问用户电脑的文件的。

    但是在使用浏览器的时候,很多的网站都可以弹出一个窗口,选择文件并打开。

    像下面这种(这里↓可以点击)

    代码其实就一句:<input type="file" />

    所以,我就有个思路,想办法用Unity调用这个组件,直接从这个组件里面获取到文件流。

    直接开整,先在Unity里面搞个WebGl.jslib文件。这个文件是与webgl交互用的。

    详情参照Unity官网:https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html

    文件里面的内容如下:

    mergeInto(LibraryManager.library, {
      clickSelectFileBtn:function () {
        console.log("Enter");
        clickSelectFileBtn();
      },
    });

    在Unity里面搞个C#交互脚本,去调用这里面的 clickSelectFileBtn() 方法

        [DllImport("__Internal")]
        private static extern void clickSelectFileBtn();
        /// <summary>
        /// 点击Open按钮
        /// </summary>
        public static void ClickSelectFileBtn()
        {
            clickSelectFileBtn();
        }

    第一行的方法名字与.jslib文件里面的方法名一致。

    这样在Unity里面调用到 ClickSelectFileBtn() 的时候就可以直接调用到.jslib的 clickSelectFileBtn() 方法了。

    接下来,看下Webgl端接收代码

    打完WebGL包在路径下会生成两个(没有StreamingAssets)~~~~三个文件夹(有StreamingAssets)和一个index.html文件。

     

     打开index.html文件:

     1 <!DOCTYPE html>
     2 <html lang="en-us">
     3   <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     6     <title>Unity WebGL Player | Modeleditor</title>
     7     <link rel="shortcut icon" href="TemplateData/favicon.ico">
     8     <link rel="stylesheet" href="TemplateData/style.css">
     9     <script src="TemplateData/UnityProgress.js"></script>
    10     <script src="Build/UnityLoader.js"></script>
    11     <script>
    12       var unityInstance = UnityLoader.instantiate("unityContainer", "Build/Web.json", {onProgress: UnityProgress});
    13     </script>
    14   </head>
    15   <body>
    16     <div class="webgl-content">
    17       <div id="unityContainer" style=" 960px; height: 600px"></div>
    18       <div class="footer">
    19         <div class="webgl-logo"></div>
    20         <div class="fullscreen" onclick="unityInstance.SetFullscreen(1)"></div>
    21         <div class="title">Modeleditor</div>
    22       </div>
    23     </div>
    24   </body>
    25 </html>

    第12行,unity已经帮我们获取到了Unity的实例化,可以直接使用这个变量往unity发消息。

    那我们刚才unity发送的消息怎么接收呢?

    只需要在<script>   </script>之间插入一个叫clickSelectFileBtn()的方法就行。

    function clickSelectFileBtn() {
    
    }

    这时候就可以点击Unity里面的按钮,触发webgl里面的方法了。

    在回到初衷,我们就是想用到打开文件的组件,<input type="file" />写在哪?

    只要放到<body> </body>之间即可。

    保存后刷新下网页,发现页面左上角多了一个选择文件组件

    这样还是行,需求是点击unity按钮,触发这个组件,当前这样只能手动点击触发,而且显示在这直接当bug处理。

    在这个组件里面添加一个id,方便之后用代码获取到,使用style="display:none"直接把组件隐藏,还要添加一个事件fileImport(),去处理打开的文件得到文件流,再发给unity。

        <input type="file" id="files" style="display:none" onchange="fileImport()">

    接下来就直接上代码:

       var unityInstance = UnityLoader.instantiate("unityContainer", "Build/Web.json", {onProgress: UnityProgress});
         function sendMessageToUnity(s) {
            //发送给unity
            unityInstance.SendMessage("TestObj", "GetBase64", s);
         }
    
         function clickSelectFileBtn() {
            var tempFileLayout = document.getElementById('files');
            tempFileLayout.click();
         }
    
         function fileImport() {
            //获取读取我文件的File对象
            var selectedFile = document.getElementById('files').files[0];
            if (selectedFile != null) {
                var reader = new FileReader();
                reader.readAsDataURL(selectedFile);
                reader.onload = function (e) {
                    var base64Str = e.currentTarget.result.substring(e.currentTarget.result.indexOf(',') + 1);
                    sendMessageToUnity(base64Str);
                }
            }
         }
    unityInstance.SendMessage("TestObj", "GetBase64", s);
    这里第一个参数是物体在场景中的名字,第二个参数是挂在这个物体上的脚本中方法名,第三个参数是方法的参数。

    在unity里面建个物体叫TestObj,随便写个脚本,

        public void GetBase64(string base64Str)
        {
            byte[] bs = Convert.FromBase64String(base64Str);
        }

    就这样是完全可以传输1Mb以内的贴图,文本等文件。

    但是如果文件过大,就会报异常莫名奇怪的堆栈溢出!

    Uncaught RuntimeError: memory access out of bounds

    刚开始是以为unity发布web的时候内存设置得太小了,想修改webgl内存大小,发现Unity在2019版本中的PlayerSetting移除了这个选项WebGL memory size。

    但是使用Editor编辑器发现还是可以获取到这个属性。

    using UnityEngine;
    using UnityEditor;
    
    public class ChangeWebGlMemeorySize : Editor
    {
        [MenuItem("Tool/设置webgl内存为256")]
        public static void ChangeMemorySize()
        {
            PlayerSettings.WebGL.memorySize = 256;
        }
    
        [MenuItem("Tool/查看webgl内存大小")]
        public static void GetMemorySize()
        {
            Debug.Log(PlayerSettings.WebGL.memorySize);
        }
    
    }

    然而,事情并没有预想的那么顺利,修改完webgl的内存后,还是一直报这个堆栈溢出的错误。

    最后终于找到问题:竟然是Webgl的SendMessage给Unity的时候参数不能过大,超过一定字节的时候就会报这个溢出错误!!!

    所以解决办法:

                        var base64Str = e.currentTarget.result.substring(e.currentTarget.result.indexOf(',') + 1);
                        arr = [];
                        step = 3000;
                        for (var i = 0, l = base64Str.length; i < l; i += step)
                        {
                            arr.push(base64Str.slice(i, i + step))
                        }
                        sendMessageToUnity("Start");
                        for (i = 0; i < arr.length; i++)
                        {
                            sendMessageToUnity(arr[i]);
                        }
                        sendMessageToUnity("End");

    相应的在Unity接受字符串的地方改为:

        StringBuilder stringBuilder = new StringBuilder();
        public void GetBase64(string base64Str)
        {
            if (base64Str == "Start")
            {
                stringBuilder.Clear();
            }
            else if (base64Str == "End")
            {
                byte[] bs = Convert.FromBase64String(stringBuilder.ToString());
            }
            else
            {
                stringBuilder.Append(base64Str);
            }
        }

    直接改为将字符串分成大小一定的段落,分批的发给Unity,注意要使用 StringBuilder  不然内存也会爆炸!

     

     

    就这样,拜拜~

  • 相关阅读:
    在做城市选择界面时,获取首字母并转化为大写,发现好多网上的代码,个别汉字不能转为拼音(漯河、鄢陵等)
    微信小程序之开发的坑
    前端学习之学习网站
    前端学习之Angular cli
    前端学习之npm国内镜像cnpm和yarn的快速安装
    eclipse Team之pull操作从GitLab上更新项目到本地
    前端学习之angular项目的本地运行步骤
    前端学习之vscode脚本禁用的问题
    maven项目启动提示:启动过滤器异常
    前端学习之Node.js安装及环境配置
  • 原文地址:https://www.cnblogs.com/yzxhz/p/13274634.html
Copyright © 2011-2022 走看看