You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 03:06:07