【Unity3D日常开发】Unity3D中适用WEBGL打开Window文件对话框打开/上传文件
推荐阅读
- CSDN主页
- GitHub开源地址
- Unity3D插件分享
- QQ群:398291828
- 小红书
- 小破站
大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
一、前言
Unity3D发布的WEBGL程序是不支持直接的I/O操作,所以也就不能直接访问用户电脑的文件。
但是,也是有办法去访问电脑中的文件,打开文件的。
比如情况一:如果知道电脑文件在什么位置、什么名字。
可以参考这篇文章:
【Unity3D小技巧】Unity3D中打包WEBGL后读取本地文件数据
情况二:知道要上传什么类型的文件,但是需要弹出窗口来选择文件并打开。
这篇文章就来讨论一下WEBGL打开Window文件对话框并打开文件后上传文件,显示图片/文本。
二、实现过程
先来看一下效果:

2-1、实现分析
既然Unity3D没办法直接进行I/O操作,但是JavaScript可以进行I/O操作,那是不是就可以让Unity跟JS进行通信,来进行操作。
JavaScript打开文件的代码很简单:
<input type="file" /></input>
那么就可以用Unity的按钮去调用这个组件,从这个组件中获取到文件流。
OK,理论存在,实践开始。
2-2、Unity3D中做的准备
(1)在Unity的工程中新建Plugins文件夹:

(2)在里面新建WebGl.jslib文件,编辑代码,这个文件是JS与WEBGL交互用的。
详情参照Unity官网:https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
文件里面的内容如下:
mergeInto(LibraryManager.library, {clickSelectFileBtn:function () {console.log("Enter");clickSelectFileBtn();},
});
(3)搭建Unity程序:

一个Button用来响应Js函数,一个Image用来显示图片,Text用来显示文本内容。
(3)在Hierarchy视图新建一个Scripts对象(名字需要跟我一样,因为后面要跟js脚本),挂载脚本,脚本名随意:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;public class ReceiveDataHandle : MonoBehaviour
{public Button BtnLoad;public Image showImg;public Text showText;[DllImport("__Internal")]private static extern void clickSelectFileBtn();/// <summary>/// 点击Open按钮/// </summary>public static void BtnLoadEvent(){clickSelectFileBtn();}void Start(){BtnLoad.onClick.AddListener(BtnLoadEvent);}/// <summary>/// 接收base64字符串/// </summary>/// <param name="base64Str"></param>public void GetBase64(string base64Str){Debug.Log(base64Str);string[] split = base64Str.Split('|');if (split[0].Contains("jpg")){StartCoroutine(ReadTexture(split[1], LoadImg));}else if (split[0].Contains("txt")){StartCoroutine(ReadData(split[1], LoadText));}else{Debug.Log("文件格式错误");return;}}/// <summary>/// 读取图片/// </summary>/// <param name="path"></param>/// <param name="action"></param>/// <returns></returns>IEnumerator ReadTexture(string path,UnityAction<Texture> action){Debug.Log(path);UnityWebRequest request = UnityWebRequestTexture.GetTexture(path);yield return request.SendWebRequest();if (request.isNetworkError || request.isHttpError){Debug.Log(request.error);}else{byte[] imgdata = request.downloadHandler.data;action(DownloadHandlerTexture.GetContent(request));}}/// <summary>/// 加载图片/// </summary>/// <param name="texture"></param>void LoadImg(Texture texture){Sprite ImgSprite = Sprite.Create((Texture2D)texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));showImg.sprite = ImgSprite;}/// <summary>/// 读取文本/// </summary>/// <param name="path"></param>/// <param name="action"></param>/// <returns></returns>IEnumerator ReadData(string path, UnityAction<string> action){Debug.Log(path);UnityWebRequest request = UnityWebRequest.Get(path);yield return request.SendWebRequest();if (request.isNetworkError || request.isHttpError){Debug.Log(request.error);}else{Debug.Log(request.downloadHandler.text);action(request.downloadHandler.text);}}/// <summary>/// 加载文本/// </summary>/// <param name="text"></param>void LoadText(string text){showText.text = text;}
}
注意:
clickSelectFileBtn函数用来调用Js函数,GetBase64函数用来接收数据。
2-3、打包WEBGL后修改
注意:我用的Unity2019.4.9f1版本。高版本打包出来的index.html以及Build里面的文件跟我的不一致,这个后面有空再说如何匹配高版本吧,先用2019版本演示。
打包之后:


修改index.html文件:
<!DOCTYPE html>
<html lang="en-us"><head><meta charset="utf-8"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Unity WebGL Player | Demo_WEBGLLoadFile</title><link rel="shortcut icon" href="TemplateData/favicon.ico"><link rel="stylesheet" href="TemplateData/style.css"><script src="TemplateData/UnityProgress.js"></script><script src="Build/UnityLoader.js"></script><script>var unityInstance = UnityLoader.instantiate("unityContainer", "Build/WEBGL_LoadFile.json", {onProgress: UnityProgress});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);}}}function sendMessageToUnity(s) {//发送给unityvar file=document.getElementById('files').files[0];SetFileUrlByDragEnd(file);}function SelectFile(){var file=document.getElementById('files').files[0];SetFileUrlByDragEnd(file);}function SetFileUrlByDragEnd(file) {unityInstance.SendMessage("Scripts", "GetBase64", file.name+"|"+URL.createObjectURL(file));}</script></head><body><input type="file" id="files" style="display:none" onchange="fileImport()"><div class="webgl-content"><div id="unityContainer" style="width: 960px; height: 600px"></div><div class="footer"><div class="webgl-logo"></div><div class="fullscreen" onclick="unityInstance.SetFullscreen(1)"></div><div class="title">Demo_WEBGLLoadFile</div></div></div></body>
</html>
代码解释一下:
(1)首先是加了一个<input type="file" id="files" style="display:none" onchange="fileImport()">用来响应打开文件的操作。
(2)然后用Unity程序的Button响应clickSelectFileBtn函数,去触发这个组件。
(3)添加fileImport去处理打开的文件得到文件流。
(4)获得文件名和文件路径,通过unityInstance.SendMessage("Scripts", "GetBase64", file.name+"|"+URL.createObjectURL(file));传给Unity。
(5)URL.createObjectURL(file)可以获得本地文件的缓存url,直接发给Unity,然后Unity用来加载。
2-4、效果演示

三、后记
如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。
你的点赞就是对博主的支持,有问题记得留言:
博主主页有联系方式。
博主还有跟多宝藏文章等待你的发掘哦:
| 专栏 | 方向 | 简介 |
|---|---|---|
| Unity3D开发小游戏 | 小游戏开发教程 | 分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。 |
| Unity3D从入门到进阶 | 入门 | 从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。 |
| Unity3D之UGUI | UGUI | Unity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。 |
| Unity3D之读取数据 | 文件读取 | 使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。 |
| Unity3D之数据集合 | 数据集合 | 数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。 |
| Unity3D之VR/AR(虚拟仿真)开发 | 虚拟仿真 | 总结博主工作常见的虚拟仿真需求进行案例讲解。 |
| Unity3D之插件 | 插件 | 主要分享在Unity开发中用到的一些插件使用方法,插件介绍等 |
| Unity3D之日常开发 | 日常记录 | 主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等 |
| Unity3D之日常BUG | 日常记录 | 记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。 |
相关文章:
【Unity3D日常开发】Unity3D中适用WEBGL打开Window文件对话框打开/上传文件
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群:398291828小红书小破站 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 Unity3D发布的WEBGL程序是不支持直接的I/O操…...
C# 或 .NetCore 如何使用 NPOI 导出图片到 Excel 文件
今天在本文中,我们将尝试使用NPOI库将图像插入到 Excel 文件的特定位置。请将以下逻辑添加到您的写作方法中,在 Excel 文件中添加图像(JPEG、PNG),我已经有一个示例 jpeg 文件 - Read-write-excel-npoi.jpg ,我们将尝试…...
Lambda expressions in C++ (C++ 中的 lambda 表达式)
Lambda expressions in C {C 中的 lambda 表达式} 1. Parts of a lambda expression (Lambda 表达式的各个部分)1.2. Parameter list (Optional) References lambda /ˈlm.də/:the 11th letter of the Greek alphabet (希腊语字母表的第 11 个字母)https://learn.m…...
【Rust自学】11.4. 用should_panic检查恐慌
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 11.4.1. 验证错误处理的情况 测试函数出了验证代码的返回值是否正确,还需要验证代码是否如预期的去处理了发生错误的情况。比…...
高斯函数Gaussian绘制matlab
高斯 约翰卡尔弗里德里希高斯,(德语:Johann Carl Friedrich Gau,英语:Gauss,拉丁语:Carolus Fridericus Gauss)1777年4月30日–1855年2月23日,德国著名数学家、物理学家…...
获取客户端真实IP地址
当处理来自客户端的请求时,尤其是在存在代理服务器的情况下,可能需要考虑多种HTTP请求头,以尽可能准确地获取用户的真实IP地址。以下是考虑了X-Forwarded-For、Proxy-Client-IP、WL-Proxy-Client-IP、HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR的…...
Kotlin学习(一)
1. Kotlin 作用域函数 如果同学们已经在项目中用过 Kotlin 语言,那么一定见过 let 函数!因为每当 Kotlin 检测到某个对象可能为空时,会自动帮我们修改为用 let 函数实现:user.name?.let{ textView.text it }。这里的 let 函数就…...
鸿蒙UI开发——日历选择器
1、概 述 在项目开发中,我们时常会用到日历选择器,效果如下: ArkUI已经为我们提供了组件,我们可以直接使用,下面针对日历组件做简单介绍。 2、CalendarPickerDialog 接口定义如下: // 定义日历选择器弹…...
2025-1-9 QT 使用 QXlsx库 读取 .xlsx 文件 —— 导入 QXlsx库以及读取 .xlsx 的源码 实践出真知,你我共勉
文章目录 1. 导入QXlsx库2. 使用 QXlsx库 读取 .xlsx 文件小结 网上有很多教程,但太费劲了,这里有个非常简便的好方法,分享给大家。 1. 导入QXlsx库 转载链接 :https://github.com/QtExcel/QXlsx/blob/master/HowToSetProject.md…...
React中createRoot函数原理解读——Element对象与Fiber对象、FiberRootNode与HostRootNode
【2024最新版】React18 核心源码分析教程(全61集) Element对象与Fiber对象 在 React 中,Element 对象 和 Fiber 对象 是核心概念,用于实现 React 的高效渲染和更新机制。以下是它们的详细解读: 1. Element 对象 定…...
利用Python实现Union-Find算法
Union-Find(又称 并查集)是一种高效解决 动态连通性问题 的算法。它主要提供两种操作: Union(x, y):将元素 x 和 y 连接。Find(x):找到元素 x 所属的集合的标识符(通常是集合的根节点)。 常用…...
【LeetCode: 912. 排序数组 + 归并排序】
🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...
AI时代来了,我们不再需要IDE了
大家好,我是编程乐趣。 最近在思考一个问题,那就是AI这么强大。 未来有没有可能,我们就不需要不需要开发工具了,只需一个浏览器就可以开发软件了。 一、AI带来的变化 1、代码生成与补全 AI工具如GitHub Copilot等能够根据代码…...
PL/SQL语言的网络编程
PL/SQL语言的网络编程 引言 在信息化迅速发展的今天,网络编程作为现代软件开发的重要组成部分,受到了广泛关注。而在数据库管理系统中,Oracle 提供了 PL/SQL(Procedural Language/Structured Query Language)&#x…...
vue video重复视频 设置 srcObject 视频流不占用资源 减少资源浪费
// 直接设置srcObject减少获取视频流:通过 captureStream() 方法从下方视频元素获取视频流。 // 设置 srcObject:将获取到的视频流设置为上方视频的 srcObject 减少资源浪费 // 获取到需要复制到的dom元素 const firstVideoElement proxy.$refs.firs…...
JavaFx 21 项目Markdown 预览、编辑、新建、文件树、删除、重命名
项目文件结构 项目的源代码和资源文件存放在以下路径: 源代码: src/main/java/com/kong/markdown/ 包含多个 Java 文件,主要实现了应用的功能: App.java:主类,可能包含应用的启动逻辑。FileService.java:可能与文件操作相关的服务类。MainController.java:控制器类,可…...
git项目提交步骤(简洁版)
1.创建仓库 2.填写 信息 3.点击这个按钮 4.找到要上传的文件,在目录内右键点击 5.依次执行命令 在命令窗口中输入:git init 复制仓库地址: 在命令窗口中输入:git remote add origin 仓库地址 在命令窗口中输入:…...
风水算命系统架构与功能分析
系统架构 服务端:Java(最低JDK1.8,支持JDK11以及JDK17)数据库:MySQL数据库(标配5.7版本,支持MySQL8)ORM框架:Mybatis(集成通用tk-mapper,支持myb…...
Clojure语言的学习路线
Clojure语言的学习路线 Clojure是一种现代的Lisp方言,运行于Java虚拟机(JVM)上。它具备强大的函数式编程特性,支持并发和多线程编程,适合处理复杂的数据和计算任务。由于其简洁和灵活的语法,Clojure在数据…...
网络安全核心目标CIA
网络安全的核心目标是为关键资产提供机密性(Confidentiality)、可用性(Availablity)、完整性(Integrity)。作为安全基础架构中的主要的安全目标和宗旨,机密性、可用性、完整性频频出现,被简称为CIA,也被成为你AIC,只是顺序不同而已…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
