Unity中Windows与Mac平台运行时加载本地纹理的实现方案咨询
解决方案
你当前的代码仅能唤起资源管理器展示目录,无法实现文件选择回调,要实现和移动端一致的选图逻辑,可按以下适配方案实现,覆盖编辑器调试和Windows/Mac正式打包场景:
适配说明
- 编辑器环境下直接使用Unity官方
EditorUtility接口实现文件选择 - Standalone正式打包环境下使用原生系统对话框接口实现选择回调
- 选到图片路径后复用和移动端一致的纹理加载逻辑即可
完整整合代码
using UnityEngine; using System.IO; #if UNITY_EDITOR using UnityEditor; #endif public class DisplayHandler : MonoBehaviour { public GameObject Display; public int maxImageSize = 2048; // 最大纹理尺寸,可在Inspector调整 // 按钮点击直接调用这个方法即可,全平台通用 public void PickImage() { #if UNITY_IOS || UNITY_ANDROID // 原有移动端逻辑不变 NativeGallery.Permission permission = NativeGallery.GetImageFromGallery((path) => { Debug.Log("Image path: " + path); if (path != null) { LoadTextureToDisplay(path, maxImageSize); } }); Debug.Log("Permission result: " + permission); #elif UNITY_STANDALONE || UNITY_EDITOR // PC端(含编辑器)选图逻辑 string selectedPath = ""; #if UNITY_EDITOR // 编辑器环境直接用官方接口 selectedPath = EditorUtility.OpenFilePanel("选择图片", "", "png,jpg,jpeg,bmp"); #else // 打包后Standalone环境的原生对话框实现 selectedPath = StandaloneFileBrowser.OpenFilePanel("选择图片", "", new[] { "图片文件", "png,jpg,jpeg,bmp" }, false); #endif if (!string.IsNullOrEmpty(selectedPath) && File.Exists(selectedPath)) { LoadTextureToDisplay(selectedPath, maxImageSize); } #endif } // 公共纹理加载方法,移动端PC端共用 private void LoadTextureToDisplay(string imagePath, int maxSize) { Texture2D texture = null; #if UNITY_IOS || UNITY_ANDROID texture = NativeGallery.LoadImageAtPath(imagePath, maxSize); #else // PC端自行加载纹理 byte[] imageBytes = File.ReadAllBytes(imagePath); texture = new Texture2D(2, 2); texture.LoadImage(imageBytes); // 等比缩放纹理到最大尺寸限制 if (texture.width > maxSize || texture.height > maxSize) { float scale = (float)maxSize / Mathf.Max(texture.width, texture.height); int newWidth = Mathf.RoundToInt(texture.width * scale); int newHeight = Mathf.RoundToInt(texture.height * scale); TextureScale.Bilinear(texture, newWidth, newHeight); } #endif if (texture == null) { Debug.Log("Couldn't load texture from " + imagePath); return; } Material material = Display.GetComponent<Renderer>().material; if (!material.shader.isSupported) material.shader = Shader.Find("Legacy Shaders/Diffuse"); material.mainTexture = texture; } // Standalone平台原生文件选择器实现,不需要额外插件 #if !UNITY_EDITOR && UNITY_STANDALONE public static class StandaloneFileBrowser { #if UNITY_STANDALONE_WIN [System.Runtime.InteropServices.DllImport("comdlg32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)] private static extern bool GetOpenFileName(ref OPENFILENAME ofn); [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Auto)] private class OPENFILENAME { public int lStructSize = 0; public System.IntPtr hwndOwner = System.IntPtr.Zero; public System.IntPtr hInstance = System.IntPtr.Zero; public string lpstrFilter = null; public string lpstrCustomFilter = null; public int nMaxCustFilter = 0; public int nFilterIndex = 0; public System.IntPtr lpstrFile = System.IntPtr.Zero; public int nMaxFile = 0; public string lpstrFileTitle = null; public int nMaxFileTitle = 0; public string lpstrInitialDir = null; public string lpstrTitle = null; public int Flags = 0; public short nFileOffset = 0; public short nFileExtension = 0; public string lpstrDefExt = null; public System.IntPtr lCustData = System.IntPtr.Zero; public System.IntPtr lpfnHook = System.IntPtr.Zero; public string lpTemplateName = null; public System.IntPtr pvReserved = System.IntPtr.Zero; public int dwReserved = 0; public int flagsEx = 0; } public static string OpenFilePanel(string title, string directory, string[] filters, bool multiselect) { OPENFILENAME ofn = new OPENFILENAME(); ofn.lStructSize = System.Runtime.InteropServices.Marshal.SizeOf(ofn); ofn.lpstrTitle = title; ofn.lpstrInitialDir = directory; string filter = ""; for(int i=0; i<filters.Length; i+=2) { filter += filters[i] + "\0" + filters[i+1].Replace(",", ";") + "\0"; } filter += "\0"; ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; ofn.lpstrFile = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(2048); System.Runtime.InteropServices.Marshal.WriteByte(ofn.lpstrFile, 0); ofn.nMaxFile = 2048; ofn.Flags = 0x00080000 | 0x00001000 | (multiselect ? 0x00000200 : 0); if(GetOpenFileName(ref ofn)) { string path = System.Runtime.InteropServices.Marshal.PtrToStringAuto(ofn.lpstrFile); System.Runtime.InteropServices.Marshal.FreeCoTaskMem(ofn.lpstrFile); return path; } System.Runtime.InteropServices.Marshal.FreeCoTaskMem(ofn.lpstrFile); return null; } #elif UNITY_STANDALONE_OSX [System.Runtime.InteropServices.DllImport("StandaloneFileBrowser")] private static extern System.IntPtr OpenFilePanel(string title, string directory, string[] filters, int filterCount, bool multiselect); public static string OpenFilePanel(string title, string directory, string[] filters, bool multiselect) { System.IntPtr ptr = OpenFilePanel(title, directory, filters, filters.Length/2, multiselect); string path = System.Runtime.InteropServices.Marshal.PtrToStringUTF8(ptr); return path; } #endif } // 纹理缩放工具类 public static class TextureScale { public static void Bilinear(Texture2D tex, int newWidth, int newHeight) { Color[] newColors = new Color[newWidth * newHeight]; float ratioX = 1.0f / ((float)newWidth / (tex.width - 1)); float ratioY = 1.0f / ((float)newHeight / (tex.height - 1)); for (int y = 0; y < newHeight; y++) { int yFloor = Mathf.FloorToInt(y * ratioY); float yLerp = y * ratioY - yFloor; for (int x = 0; x < newWidth; x++) { int xFloor = Mathf.FloorToInt(x * ratioX); float xLerp = x * ratioX - xFloor; newColors[y * newWidth + x] = Color.Lerp( Color.Lerp(tex.GetPixel(xFloor, yFloor), tex.GetPixel(xFloor + 1, yFloor), xLerp), Color.Lerp(tex.GetPixel(xFloor, yFloor + 1), tex.GetPixel(xFloor + 1, yFloor + 1), xLerp), yLerp); } } tex.Reinitialize(newWidth, newHeight); tex.SetPixels(newColors); tex.Apply(); } } #endif }
注意事项
- 如果不需要限制纹理最大尺寸,可以移除纹理缩放的相关逻辑
- Mac平台打包时如果遇到接口缺失问题,可直接将宏定义内的Mac实现替换为C#调用AppleScript唤起选择对话框,逻辑一致
- 代码已整合全平台逻辑,按钮点击直接调用
PickImage()方法即可,不需要区分平台调用
内容的提问来源于stack exchange,提问作者IWOS
相关产品推荐
相关产品推荐

