Unity 模型缩略图生成工具【Unity6000.5.0】

张开发
2026/4/7 8:31:25 15 分钟阅读

分享文章

Unity 模型缩略图生成工具【Unity6000.5.0】
最近需要一个模型的缩略图用于展示所以就弄了一个这样的工具废话不多说‍一、工具预览Unity编辑器扩展工具用于批量导出选中资源的预览缩略图并支持实时调整图片的亮度、对比度和背景色。特别适合需要对大量模型如树木、建筑、角色等生成统一风格预览图的场景。主要功能1.批量导出支持在Project窗口同时选中多个资源一键批量导出所有选中资源的缩略图自动处理文件重名冲突2.图片尺寸控制可自定义导出图片大小默认128x128至2048x2048保持原始宽高比选项3.颜色调整亮度调节0.5-2.5倍解决模型过暗问题特别适合树木、植物对比度调节0.5-2.5倍增强细节表现两种调整模式自然模式Gamma校正效果柔和色彩过渡自然标准模式线性调整效果强烈对比突出4.背景处理自动识别Unity预览图的灰色背景支持替换为任意颜色白、浅蓝、透明等背景与模型颜色调整分离处理5.画质优化️支持抗锯齿最高8倍高质量纹理缩放Trilinear滤波PNG格式无损导出6.参数记忆所有设置自动保存下次打开工具自动恢复上次设置提供重置默认值按钮二、代码放到Editor文件夹下就可以在工具面板就可以找到打开就可以使用using UnityEditor; using UnityEngine; using System.IO; public class ExportPreviewToolWindow : EditorWindow { // 参数保存的Key名称 private const string PREFS_PREFIX ExportPreviewTool_; private int exportSize; private string saveFolder; private bool enableAntiAliasing; private bool keepAspectRatio; private Color backgroundColor; private bool replaceBackground; private float brightness; private float contrast; private bool adjustColor; private bool useNaturalAdjustment; private bool autoCloseAfterExport; [MenuItem(Tools/预制体缩略图生成)] public static void ShowWindow() { var window GetWindowExportPreviewToolWindow(预览图导出工具); window.LoadSettings(); // 打开时加载保存的设置 window.Show(); } private void OnEnable() { LoadSettings(); // 每次启用时加载设置 } private void OnDisable() { SaveSettings(); // 关闭时保存设置 } private void LoadSettings() { // 加载保存的参数如果没有保存过则使用默认值 exportSize EditorPrefs.GetInt(PREFS_PREFIX exportSize, 128); saveFolder EditorPrefs.GetString(PREFS_PREFIX saveFolder, Assets/ExportedPreviews); enableAntiAliasing EditorPrefs.GetBool(PREFS_PREFIX enableAntiAliasing, true); keepAspectRatio EditorPrefs.GetBool(PREFS_PREFIX keepAspectRatio, true); replaceBackground EditorPrefs.GetBool(PREFS_PREFIX replaceBackground, false); adjustColor EditorPrefs.GetBool(PREFS_PREFIX adjustColor, true); brightness EditorPrefs.GetFloat(PREFS_PREFIX brightness, 1.7f); contrast EditorPrefs.GetFloat(PREFS_PREFIX contrast, 1.2f); useNaturalAdjustment EditorPrefs.GetBool(PREFS_PREFIX useNaturalAdjustment, true); autoCloseAfterExport EditorPrefs.GetBool(PREFS_PREFIX autoCloseAfterExport, false); // 加载颜色Color需要单独处理 float r EditorPrefs.GetFloat(PREFS_PREFIX bgColor_R, 0.5f); float g EditorPrefs.GetFloat(PREFS_PREFIX bgColor_G, 0.5f); float b EditorPrefs.GetFloat(PREFS_PREFIX bgColor_B, 0.5f); backgroundColor new Color(r, g, b); } private void SaveSettings() { // 保存当前参数 EditorPrefs.SetInt(PREFS_PREFIX exportSize, exportSize); EditorPrefs.SetString(PREFS_PREFIX saveFolder, saveFolder); EditorPrefs.SetBool(PREFS_PREFIX enableAntiAliasing, enableAntiAliasing); EditorPrefs.SetBool(PREFS_PREFIX keepAspectRatio, keepAspectRatio); EditorPrefs.SetBool(PREFS_PREFIX replaceBackground, replaceBackground); EditorPrefs.SetBool(PREFS_PREFIX adjustColor, adjustColor); EditorPrefs.SetFloat(PREFS_PREFIX brightness, brightness); EditorPrefs.SetFloat(PREFS_PREFIX contrast, contrast); EditorPrefs.SetBool(PREFS_PREFIX useNaturalAdjustment, useNaturalAdjustment); EditorPrefs.SetBool(PREFS_PREFIX autoCloseAfterExport, autoCloseAfterExport); // 保存颜色 EditorPrefs.SetFloat(PREFS_PREFIX bgColor_R, backgroundColor.r); EditorPrefs.SetFloat(PREFS_PREFIX bgColor_G, backgroundColor.g); EditorPrefs.SetFloat(PREFS_PREFIX bgColor_B, backgroundColor.b); } private void OnGUI() { GUILayout.Label(导出设置, EditorStyles.boldLabel); exportSize EditorGUILayout.IntField(导出尺寸, exportSize); saveFolder EditorGUILayout.TextField(保存路径, saveFolder); enableAntiAliasing EditorGUILayout.Toggle(启用抗锯齿, enableAntiAliasing); keepAspectRatio EditorGUILayout.Toggle(保持宽高比, keepAspectRatio); GUILayout.Space(10); GUILayout.Label(颜色调整, EditorStyles.boldLabel); adjustColor EditorGUILayout.Toggle(启用颜色调整, adjustColor); if (adjustColor) { brightness EditorGUILayout.Slider(亮度, brightness, 0.5f, 2.5f); contrast EditorGUILayout.Slider(对比度, contrast, 0.5f, 2.5f); useNaturalAdjustment EditorGUILayout.Toggle(使用自然调整模式, useNaturalAdjustment); GUILayout.Space(5); if (useNaturalAdjustment) { EditorGUILayout.HelpBox(自然模式使用Gamma校正效果更柔和自然适合大多数模型, UnityEditor.MessageType.Info); } else { EditorGUILayout.HelpBox(标准模式线性调整效果更强烈适合需要突出对比的场景, UnityEditor.MessageType.Info); } } GUILayout.Space(10); GUILayout.Label(背景设置, EditorStyles.boldLabel); replaceBackground EditorGUILayout.Toggle(替换背景色, replaceBackground); if (replaceBackground) { backgroundColor EditorGUILayout.ColorField(背景颜色, backgroundColor); } GUILayout.Space(10); autoCloseAfterExport EditorGUILayout.Toggle(导出后自动关闭窗口, autoCloseAfterExport); GUILayout.Space(20); if (GUILayout.Button(导出选中的资源, GUILayout.Height(40))) { ExportSelectedAssets(exportSize, saveFolder, enableAntiAliasing, replaceBackground ? backgroundColor : (Color?)null, adjustColor ? brightness : (float?)null, adjustColor ? contrast : (float?)null, adjustColor ? useNaturalAdjustment : (bool?)null); if (autoCloseAfterExport) { Close(); } } GUILayout.Space(10); EditorGUILayout.HelpBox(提示\n• 所有设置会自动保存下次打开时保留上次的设置\n• 在Project窗口选中要导出的资源\n• 支持模型、材质、贴图等各类资源\n• 更大的尺寸需要更长的处理时间,UnityEditor. MessageType.Info); GUILayout.Space(5); if (GUILayout.Button(重置所有参数为默认值)) { ResetToDefaults(); } } private void ResetToDefaults() { exportSize 128; saveFolder Assets/ExportedPreviews; enableAntiAliasing true; keepAspectRatio true; replaceBackground false; adjustColor true; brightness 1.7f; contrast 1.2f; useNaturalAdjustment true; autoCloseAfterExport false; backgroundColor Color.gray; SaveSettings(); // 保存重置后的值 Repaint(); // 刷新界面 Debug.Log(参数已重置为默认值); } // 以下是原有的导出函数保持不变 private static void ExportSelectedAssets(int size, string folder, bool antiAlias, Color? bgColor null, float? brightness null, float? contrast null, bool? useNatural null) { if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string[] assetGUIDs Selection.assetGUIDs; if (assetGUIDs.Length 0) { Debug.LogWarning(请先在Project窗口中选择要导出的资源); return; } int successCount 0; for (int i 0; i assetGUIDs.Length; i) { string assetPath AssetDatabase.GUIDToAssetPath(assetGUIDs[i]); Object asset AssetDatabase.LoadAssetAtPathObject(assetPath); if (asset null) continue; EditorUtility.DisplayProgressBar(导出预览图, $正在处理: {asset.name} ({i 1}/{assetGUIDs.Length}), (float)i / assetGUIDs.Length); Texture2D preview GetPreviewWithWait(asset); if (preview ! null) { Texture2D final ProcessPreview(preview, size, antiAlias, bgColor, brightness, contrast, useNatural); string exportPath ${folder}/{asset.name}.png; exportPath GetUniqueFilePath(exportPath); byte[] pngData final.EncodeToPNG(); File.WriteAllBytes(exportPath, pngData); string mode useNatural.HasValue useNatural.Value ? 自然模式 : 标准模式; Debug.Log($已导出: {Path.GetFileName(exportPath)} (亮度:{brightness ?? 1f}, 对比度:{contrast ?? 1f}, {mode})); successCount; Object.DestroyImmediate(final); } else { Debug.LogWarning($无法获取预览图: {asset.name}); } } EditorUtility.ClearProgressBar(); AssetDatabase.Refresh(); Debug.Log($导出成功: {successCount}/{assetGUIDs.Length}保存位置: {folder}); } private static Texture2D GetPreviewWithWait(Object asset) { Texture2D preview AssetPreview.GetAssetPreview(asset); int maxRetries 50; int retryCount 0; while ((preview null || AssetPreview.IsLoadingAssetPreview(asset.GetEntityId())) retryCount maxRetries) { System.Threading.Thread.Sleep(10); preview AssetPreview.GetAssetPreview(asset); retryCount; } if (preview null) { preview AssetPreview.GetMiniThumbnail(asset); } return preview; } private static Texture2D ProcessPreview(Texture2D source, int targetSize, bool antiAlias, Color? bgColor, float? brightness, float? contrast, bool? useNatural) { Texture2D result ScaleTexture(source, targetSize, targetSize, antiAlias); Color[] pixels result.GetPixels(); for (int i 0; i pixels.Length; i) { Color pixel pixels[i]; bool isBackground IsBackgroundPixel(pixel); if (isBackground bgColor.HasValue) { pixels[i] bgColor.Value; } else if (!isBackground brightness.HasValue contrast.HasValue) { if (useNatural.HasValue useNatural.Value) { pixels[i] AdjustColorNatural(pixel, brightness.Value, contrast.Value); } else { pixels[i] AdjustColor(pixel, brightness.Value, contrast.Value); } } else { pixels[i] pixel; } } result.SetPixels(pixels); result.Apply(); return result; } private static Texture2D ScaleTexture(Texture2D source, int targetWidth, int targetHeight, bool antiAlias) { RenderTexture rt RenderTexture.GetTemporary(targetWidth, targetHeight, 24, RenderTextureFormat.ARGB32); rt.filterMode antiAlias ? FilterMode.Trilinear : FilterMode.Bilinear; if (antiAlias) { rt.antiAliasing 8; } RenderTexture.active rt; Graphics.Blit(source, rt); Texture2D result new Texture2D(targetWidth, targetHeight, TextureFormat.RGBA32, false); result.filterMode FilterMode.Bilinear; result.ReadPixels(new Rect(0, 0, targetWidth, targetHeight), 0, 0); result.Apply(); RenderTexture.active null; rt.Release(); return result; } private static bool IsBackgroundPixel(Color color) { float h, s, v; Color.RGBToHSV(color, out h, out s, out v); return s 0.2f v 0.3f v 0.7f; } private static Color AdjustColor(Color color, float brightness, float contrast) { float r color.r * brightness; float g color.g * brightness; float b color.b * brightness; r 0.5f (r - 0.5f) * contrast; g 0.5f (g - 0.5f) * contrast; b 0.5f (b - 0.5f) * contrast; return new Color( Mathf.Clamp01(r), Mathf.Clamp01(g), Mathf.Clamp01(b), color.a ); } private static Color AdjustColorNatural(Color color, float brightness, float contrast) { float r Mathf.Pow(color.r * brightness, 1.0f / contrast); float g Mathf.Pow(color.g * brightness, 1.0f / contrast); float b Mathf.Pow(color.b * brightness, 1.0f / contrast); return new Color( Mathf.Clamp01(r), Mathf.Clamp01(g), Mathf.Clamp01(b), color.a ); } private static string GetUniqueFilePath(string path) { if (!File.Exists(path)) return path; string directory Path.GetDirectoryName(path); string filename Path.GetFileNameWithoutExtension(path); string extension Path.GetExtension(path); int counter 1; string newPath; do { newPath Path.Combine(directory, ${filename}_{counter}{extension}); counter; } while (File.Exists(newPath)); return newPath; } }

更多文章