Unity打包后从本地指定目录加载并转换纹理为Texture的方法
Unity加载本地图片并转换为Texture2D赋值给场景对象
没问题,我来帮你搞定这个!既然你已经通过对话框选中文件并复制到Application.persistentDataPath了,接下来只需要把本地文件转换成Texture2D,再赋值给平面的材质就行。下面是具体的实现方案,包含同步/异步两种方式,还有实际开发中的注意事项:
核心步骤:读取文件并转换为Texture2D
Unity的Texture2D.LoadImage()方法非常实用,它可以直接读取jpg、png等格式的字节流并自动生成纹理,不需要手动指定图片格式,省了很多麻烦。
1. 同步加载(适合小图片)
如果你的图片尺寸不大,同步加载足够用,代码简单直接:
using UnityEngine; using System.IO; public class TextureLoader : MonoBehaviour { public GameObject targetPlane; // 拖拽场景中的平面对象到Inspector面板 public void LoadTexture(string localFilePath) { if (!File.Exists(localFilePath)) { Debug.LogError("文件不存在,请检查路径是否正确!"); return; } // 读取本地文件的字节数据 byte[] imageBytes = File.ReadAllBytes(localFilePath); // 创建临时Texture2D,初始尺寸随便填,LoadImage会自动调整为图片实际尺寸 Texture2D texture = new Texture2D(2, 2); // 将字节数据加载为纹理 if (texture.LoadImage(imageBytes)) { // 优化纹理显示效果(可选) texture.filterMode = FilterMode.Bilinear; // 开启平滑过滤 texture.wrapMode = TextureWrapMode.Clamp; // 边缘不重复拉伸 // 给平面的材质赋值纹理 Renderer planeRenderer = targetPlane.GetComponent<Renderer>(); if (planeRenderer != null) { planeRenderer.material.mainTexture = texture; } else { Debug.LogError("目标平面缺少Renderer组件,请添加后重试!"); Destroy(texture); // 销毁无用纹理避免内存浪费 } } else { Debug.LogError("图片格式不支持,请确认是jpg/png等常见图像格式!"); Destroy(texture); } } }
2. 异步加载(推荐大图片)
如果图片尺寸较大,同步加载会导致主线程卡顿,建议用异步方式读取:
using UnityEngine; using System.IO; using System.Threading.Tasks; public class AsyncTextureLoader : MonoBehaviour { public GameObject targetPlane; private bool isTextureLoaded = false; private Texture2D loadedTexture; public async void LoadTextureAsync(string localFilePath) { if (!File.Exists(localFilePath)) { Debug.LogError("文件不存在,请检查路径是否正确!"); return; } try { // 异步读取文件字节,不阻塞主线程 byte[] imageBytes = await File.ReadAllBytesAsync(localFilePath); // 纹理创建操作必须在主线程执行,这里先在后台加载字节,再回到主线程处理 await Task.Run(() => { loadedTexture = new Texture2D(2, 2); if (loadedTexture.LoadImage(imageBytes)) { loadedTexture.filterMode = FilterMode.Bilinear; loadedTexture.wrapMode = TextureWrapMode.Clamp; isTextureLoaded = true; } else { Debug.LogError("图片加载失败,请检查文件完整性!"); Destroy(loadedTexture); } }); } catch (System.Exception e) { Debug.LogError($"加载纹理时出错:{e.Message}"); } } // 在Update中处理主线程的材质赋值 private void Update() { if (isTextureLoaded && loadedTexture != null) { Renderer planeRenderer = targetPlane.GetComponent<Renderer>(); if (planeRenderer != null) { planeRenderer.material.mainTexture = loadedTexture; } else { Debug.LogError("目标平面缺少Renderer组件!"); Destroy(loadedTexture); } isTextureLoaded = false; } } }
关键注意事项
- 权限问题:在移动端(Android/iOS),需要申请读取外部存储的权限。Android 13+需要
READ_MEDIA_IMAGES权限,iOS需要开启Photo Library访问权限。 - 内存管理:当不再需要该纹理时,一定要调用
Destroy(texture)释放内存,避免内存泄漏。如果是频繁切换纹理,建议用对象池复用Texture2D。 - 纹理格式优化:如果需要更好的性能,可以在加载后转换纹理格式,比如
texture.ConvertToTextureFormat(TextureFormat.RGBA32),根据目标平台选择合适的格式(比如移动端用ETC2格式)。 - 材质赋值细节:如果用的是URP/HDRP管线,材质的主纹理属性可能叫
_BaseMap而不是mainTexture,可以用planeRenderer.material.SetTexture("_BaseMap", texture)来赋值。
调用示例
假设你已经把选中的图片复制到了Application.persistentDataPath下的selected_image.jpg,调用方式如下:
string texturePath = Path.Combine(Application.persistentDataPath, "selected_image.jpg"); // 同步加载 GetComponent<TextureLoader>().LoadTexture(texturePath); // 或者异步加载 GetComponent<AsyncTextureLoader>().LoadTextureAsync(texturePath);
内容的提问来源于stack exchange,提问作者wkwoczak
相关产品推荐
相关产品推荐

