|
| 1 | +// MaterialFromTextures.cs |
| 2 | +// Place this script inside an "Editor" folder in a Unity project running **HDRP**. |
| 3 | +// Adds **Assets ▸ Create ▸ Generate HDRP Materials From Selection** to the Project View |
| 4 | +// whenever one or more **Texture2D** assets are selected. It converts those textures |
| 5 | +// into HDRP/Lit materials based on suffixes: |
| 6 | +// <BaseName>_BaseMap.<ext> (required) |
| 7 | +// <BaseName>_MaskMap.<ext> (optional) |
| 8 | +// <BaseName>_Normal.<ext> (optional) |
| 9 | +// The resulting material **<BaseName>.mat** is written next to its BaseMap texture. |
| 10 | + |
| 11 | +using UnityEditor; |
| 12 | +using UnityEngine; |
| 13 | +using System.IO; |
| 14 | +using System.Collections.Generic; |
| 15 | + |
| 16 | +namespace EditorTools |
| 17 | +{ |
| 18 | + public static class MaterialFromTextures |
| 19 | + { |
| 20 | + private const string BaseSuffix = "BaseMap"; |
| 21 | + private const string MaskSuffix = "MaskMap"; |
| 22 | + private const string NormalSuffix = "Normal"; |
| 23 | + |
| 24 | + //------------------------------------------------------------------ |
| 25 | + // Menu item |
| 26 | + //------------------------------------------------------------------ |
| 27 | + [MenuItem("Assets/Create/Generate HDRP Materials From Selection", priority = 2050)] |
| 28 | + private static void Generate() |
| 29 | + { |
| 30 | + var selectedTextures = Selection.GetFiltered<Texture2D>(SelectionMode.Assets); |
| 31 | + if (selectedTextures.Length == 0) { |
| 32 | + EditorUtility.DisplayDialog("Generate HDRP Materials", "Select one or more texture assets first.", "OK"); |
| 33 | + return; |
| 34 | + } |
| 35 | + |
| 36 | + // Build groups keyed by base name (local dictionary) |
| 37 | + var groups = new Dictionary<string, MaterialTextures>(); |
| 38 | + |
| 39 | + foreach (var tex in selectedTextures) { |
| 40 | + var path = AssetDatabase.GetAssetPath(tex); |
| 41 | + var fileName = Path.GetFileNameWithoutExtension(path); |
| 42 | + |
| 43 | + AddTextureToGroup(fileName, tex, path, BaseSuffix, groups, (g, t) => g.baseMap = t, (g, p) => g.baseFolder = Path.GetDirectoryName(p)); |
| 44 | + AddTextureToGroup(fileName, tex, path, MaskSuffix, groups, (g, t) => g.maskMap = t); |
| 45 | + AddTextureToGroup(fileName, tex, path, NormalSuffix, groups, (g, t) => g.normalMap = t); |
| 46 | + } |
| 47 | + |
| 48 | + var hdrpShader = Shader.Find("HDRP/Lit"); |
| 49 | + if (hdrpShader == null) { |
| 50 | + EditorUtility.DisplayDialog("Generate HDRP Materials", "Shader 'HDRP/Lit' not found. Is HDRP installed?", "OK"); |
| 51 | + return; |
| 52 | + } |
| 53 | + |
| 54 | + var created = 0; |
| 55 | + foreach (var kvp in groups) { |
| 56 | + |
| 57 | + var baseName = kvp.Key; |
| 58 | + var maps = kvp.Value; |
| 59 | + if (maps.baseMap == null || string.IsNullOrEmpty(maps.baseFolder)) { |
| 60 | + continue; // Need at least a BaseMap and its location |
| 61 | + } |
| 62 | + |
| 63 | + var matPath = Path.Combine(maps.baseFolder, baseName + ".mat").Replace("\\", "/"); |
| 64 | + var mat = AssetDatabase.LoadAssetAtPath<Material>(matPath); |
| 65 | + var isNew = mat == null; |
| 66 | + |
| 67 | + if (isNew) { |
| 68 | + mat = new Material(hdrpShader); |
| 69 | + AssetDatabase.CreateAsset(mat, matPath); |
| 70 | + created++; |
| 71 | + } |
| 72 | + |
| 73 | + AssignHDRPTextures(mat, maps); |
| 74 | + EditorUtility.SetDirty(mat); |
| 75 | + } |
| 76 | + |
| 77 | + AssetDatabase.SaveAssets(); |
| 78 | + AssetDatabase.Refresh(); |
| 79 | + EditorUtility.DisplayDialog("Generate HDRP Materials", $"Created/updated {created} material(s).", "OK"); |
| 80 | + } |
| 81 | + |
| 82 | + //------------------------------------------------------------------ |
| 83 | + // Validation – show the menu item only when textures are selected |
| 84 | + //------------------------------------------------------------------ |
| 85 | + [MenuItem("Assets/Create/Generate HDRP Materials From Selection", validate = true)] |
| 86 | + private static bool ValidateGenerate() => Selection.GetFiltered<Texture2D>(SelectionMode.Assets).Length > 0; |
| 87 | + |
| 88 | + //------------------------------------------------------------------ |
| 89 | + // Helpers |
| 90 | + //------------------------------------------------------------------ |
| 91 | + private static void AddTextureToGroup(string fileName, |
| 92 | + Texture2D tex, |
| 93 | + string path, |
| 94 | + string suffix, |
| 95 | + Dictionary<string, MaterialTextures> groups, |
| 96 | + System.Action<MaterialTextures, Texture2D> texSetter, |
| 97 | + System.Action<MaterialTextures, string> folderSetter = null) |
| 98 | + { |
| 99 | + if (!fileName.EndsWith(suffix)) return; |
| 100 | + |
| 101 | + var baseName = TrimSuffix(fileName, suffix); |
| 102 | + var group = GetOrCreateGroup(groups, baseName); |
| 103 | + |
| 104 | + texSetter(group, tex); |
| 105 | + folderSetter?.Invoke(group, path); |
| 106 | + } |
| 107 | + |
| 108 | + private static string TrimSuffix(string name, string suffix) => name[..^suffix.Length].TrimEnd('_', ' ', '-'); |
| 109 | + |
| 110 | + private class MaterialTextures |
| 111 | + { |
| 112 | + public Texture2D baseMap; |
| 113 | + public Texture2D maskMap; |
| 114 | + public Texture2D normalMap; |
| 115 | + public string baseFolder; |
| 116 | + } |
| 117 | + |
| 118 | + private static MaterialTextures GetOrCreateGroup(Dictionary<string, MaterialTextures> dict, string baseName) |
| 119 | + { |
| 120 | + if (!dict.TryGetValue(baseName, out var g)) { |
| 121 | + g = new MaterialTextures(); |
| 122 | + dict[baseName] = g; |
| 123 | + } |
| 124 | + |
| 125 | + return g; |
| 126 | + } |
| 127 | + |
| 128 | + // Assign maps to an HDRP/Lit material |
| 129 | + private static void AssignHDRPTextures(Material mat, MaterialTextures m) |
| 130 | + { |
| 131 | + if (m.baseMap && mat.HasProperty("_BaseColorMap")) mat.SetTexture("_BaseColorMap", m.baseMap); |
| 132 | + if (m.maskMap && mat.HasProperty("_MaskMap")) mat.SetTexture("_MaskMap", m.maskMap); |
| 133 | + if (m.normalMap && mat.HasProperty("_NormalMap")) mat.SetTexture("_NormalMap", m.normalMap); |
| 134 | + } |
| 135 | + } |
| 136 | +} |
0 commit comments