Added GenerateMask to AssetsHelpers;
This commit is contained in:
8
Editor/AssetsHelpers/BaseClasses.meta
Normal file
8
Editor/AssetsHelpers/BaseClasses.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 830fe7d5516c87d4a834c0a866bd9913
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public class OptionsVisualProvider
|
||||
{
|
||||
public object dataSource;
|
||||
|
||||
internal virtual VisualElement ContentOnTop()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
internal virtual VisualElement ContentAfterList()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
internal virtual VisualElement ContentBeforeButton()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
internal virtual VisualElement ContentOnBottom()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e57d7629d0768349be0c97c5e07dffe
|
||||
11
Editor/AssetsHelpers/Constants/IAssetsProcessor.cs
Normal file
11
Editor/AssetsHelpers/Constants/IAssetsProcessor.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public interface IAssetsProcessor
|
||||
{
|
||||
public void OnPreProcess(AssetsProcessContext context);
|
||||
public void OnProcess(Object source, string outputDirectory, AssetsProcessContext context);
|
||||
public void OnPostProcess(AssetsProcessContext context);
|
||||
}
|
||||
}
|
||||
2
Editor/AssetsHelpers/Constants/IAssetsProcessor.cs.meta
Normal file
2
Editor/AssetsHelpers/Constants/IAssetsProcessor.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b24bc7caf23de264e8a95f6812ff20c5
|
||||
10
Editor/AssetsHelpers/Enums/TextureFallbackType.cs
Normal file
10
Editor/AssetsHelpers/Enums/TextureFallbackType.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal enum TextureFallbackType
|
||||
{
|
||||
White,
|
||||
LinearGray,
|
||||
Gray,
|
||||
Black
|
||||
}
|
||||
}
|
||||
2
Editor/AssetsHelpers/Enums/TextureFallbackType.cs.meta
Normal file
2
Editor/AssetsHelpers/Enums/TextureFallbackType.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6171b25c39f99894d83d40c385df3d81
|
||||
10
Editor/AssetsHelpers/Enums/TextureNamingSourceType.cs
Normal file
10
Editor/AssetsHelpers/Enums/TextureNamingSourceType.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal enum TextureNamingSourceType
|
||||
{
|
||||
R,
|
||||
G,
|
||||
B,
|
||||
A
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 714cdd502bb471743bdc67a1e2e74508
|
||||
@@ -1,47 +0,0 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public class CreateDecal
|
||||
{
|
||||
[MenuItem("Assets/Art Tools/Material Helpers/Create Decal", true)]
|
||||
public static bool CreateDecalMenuValidator()
|
||||
{
|
||||
foreach (var selectedObject in Selection.objects)
|
||||
{
|
||||
if (selectedObject is not Material)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Art Tools/Material Helpers/Create Decal")]
|
||||
public static void CreateDecalMenu()
|
||||
{
|
||||
OutputOptionsWindow.ShowWindow("Decal Output Options", Selection.objects, CreateDecalInternal);
|
||||
}
|
||||
|
||||
private static string CreateDecalInternal(Object inputObject, string outputDirectory)
|
||||
{
|
||||
if (inputObject is not Material mat)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var outputPath = Path.Combine(outputDirectory, mat.name + ".prefab");
|
||||
var decal = AssetCreationHelpers.CreateDecal(outputPath);
|
||||
|
||||
mat.shader = Shader.Find(Constants.Shader.DECAL_SHADER_PATH);
|
||||
decal.transform.rotation = Quaternion.Euler(90, 0, 0);
|
||||
decal.GetComponent<DecalProjector>().material = mat;
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b4c8332e8ca2c540bc3b8c49b91e750
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal class CreateDecalMenu
|
||||
{
|
||||
[MenuItem("Assets/Art Tools/Material Helpers/Create Decal", true)]
|
||||
public static bool CreateDecalValidator()
|
||||
{
|
||||
foreach (var selectedObject in Selection.objects)
|
||||
{
|
||||
if (selectedObject is not Material)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Art Tools/Material Helpers/Create Decal")]
|
||||
public static void CreateDecal()
|
||||
{
|
||||
var createDecal = new CreateDecalMenu();
|
||||
var window = EditorWindow.GetWindow<OutputOptionsWindow>(true, "Decal Output Options");
|
||||
window.WithItemSource(Selection.objects);
|
||||
window.RegisterProcessor<CreateDecalProcessor>();
|
||||
|
||||
window.InitializeAndShow();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal class CreateDecalProcessor : IAssetsProcessor
|
||||
{
|
||||
public void OnPreProcess(AssetsProcessContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnProcess(UnityEngine.Object source, string outputDirectory, AssetsProcessContext context)
|
||||
{
|
||||
if (source is not Material mat)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var outputPath = Path.Combine(outputDirectory, mat.name + ".prefab");
|
||||
var decal = AssetCreationHelpers.CreateDecal(outputPath);
|
||||
|
||||
mat.shader = Shader.Find(Constants.Shader.DECAL_SHADER_PATH);
|
||||
decal.transform.rotation = Quaternion.Euler(90, 0, 0);
|
||||
decal.GetComponent<DecalProjector>().material = mat;
|
||||
}
|
||||
|
||||
public void OnPostProcess(AssetsProcessContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94792199a8319cd46b91c5b746992046
|
||||
@@ -1,52 +0,0 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public class CreateTerrainLayer
|
||||
{
|
||||
private const string Terrain_Layer_Extension = ".terrainlayer";
|
||||
|
||||
[MenuItem("Assets/Art Tools/Material Helpers/Create Terrain Layer", true)]
|
||||
public static bool CreateDecalMenuValidator()
|
||||
{
|
||||
foreach (var selectedObject in Selection.objects)
|
||||
{
|
||||
if (selectedObject is not Material)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Art Tools/Material Helpers/Create Terrain Layer")]
|
||||
public static void CreateDecalMenu()
|
||||
{
|
||||
OutputOptionsWindow.ShowWindow("Terrain Layer Output Options", Selection.objects, CreateTerrainLayerInternal);
|
||||
}
|
||||
|
||||
private static string CreateTerrainLayerInternal(Object inputObject, string outputDirectory)
|
||||
{
|
||||
if (inputObject is not Material mat)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var terrainLayer = new TerrainLayer()
|
||||
{
|
||||
diffuseTexture = mat.GetTexture("_BaseColorMap") as Texture2D,
|
||||
normalMapTexture = mat.GetTexture("_NormalMap") as Texture2D,
|
||||
maskMapTexture = mat.GetTexture("_MaskMap") as Texture2D,
|
||||
};
|
||||
|
||||
var outputPath = Path.Combine(outputDirectory, mat.name + Terrain_Layer_Extension);
|
||||
AssetDatabase.CreateAsset(terrainLayer, outputPath);
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0210915e427912e4fad7c31d47370949
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public class CreateTerrainLayerMenu
|
||||
{
|
||||
private const string Terrain_Layer_Extension = ".terrainlayer";
|
||||
|
||||
[MenuItem("Assets/Art Tools/Material Helpers/Create Terrain Layer", true)]
|
||||
public static bool CreateTerrainLayerValidator()
|
||||
{
|
||||
foreach (var selectedObject in Selection.objects)
|
||||
{
|
||||
if (selectedObject is not Material)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Art Tools/Material Helpers/Create Terrain Layer")]
|
||||
public static void CreateTerrainLayer()
|
||||
{
|
||||
var window = EditorWindow.GetWindow<OutputOptionsWindow>(true, "Extract Materials Output Options");
|
||||
window.WithItemSource(Selection.objects);
|
||||
window.RegisterProcessor<CreateTerrainLayerProcessor>();
|
||||
|
||||
window.InitializeAndShow();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal class CreateTerrainLayerProcessor : IAssetsProcessor
|
||||
{
|
||||
private const string Terrain_Layer_Extension = ".terrainlayer";
|
||||
|
||||
public void OnPreProcess(AssetsProcessContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnProcess(UnityEngine.Object source, string outputDirectory, AssetsProcessContext context)
|
||||
{
|
||||
if (source is not Material mat)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var terrainLayer = new TerrainLayer()
|
||||
{
|
||||
diffuseTexture = mat.GetTexture("_BaseColorMap") as Texture2D,
|
||||
normalMapTexture = mat.GetTexture("_NormalMap") as Texture2D,
|
||||
maskMapTexture = mat.GetTexture("_MaskMap") as Texture2D,
|
||||
};
|
||||
|
||||
var outputPath = Path.Combine(outputDirectory, mat.name + Terrain_Layer_Extension);
|
||||
AssetDatabase.CreateAsset(terrainLayer, outputPath);
|
||||
}
|
||||
|
||||
public void OnPostProcess(AssetsProcessContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0d5979c585023248ba3c56e7936097f
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c61caf20baa490d44a8d447822f5225d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public class ExtractMaterialsMenu
|
||||
{
|
||||
private const string Material_Extension = ".mat";
|
||||
|
||||
|
||||
|
||||
[MenuItem("Assets/Art Tools/Mesh Helpers/Extract Materials", true)]
|
||||
public static bool ExtractMaterialsValidator()
|
||||
{
|
||||
foreach (var selectedObject in Selection.objects)
|
||||
{
|
||||
var assetImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(selectedObject));
|
||||
if (assetImporter is not ModelImporter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Art Tools/Mesh Helpers/Extract Materials")]
|
||||
public static void ExtractMaterials()
|
||||
{
|
||||
var window = EditorWindow.GetWindow<OutputOptionsWindow>(true, "Extract Materials Output Options");
|
||||
window.WithItemSource(Selection.objects);
|
||||
window.RegisterVisualProvider<ExtractMaterialsVisualProvider>();
|
||||
window.RegisterProcessor<ExtractMaterialsProcessor>();
|
||||
|
||||
window.InitializeAndShow();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c21cf688d17737c4d91cec961bfce976
|
||||
@@ -0,0 +1,75 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal class ExtractMaterialsProcessor : IAssetsProcessor
|
||||
{
|
||||
private const string Material_Extension = ".mat";
|
||||
|
||||
public bool useMaterialRemap = false;
|
||||
public ModelImporterMaterialLocation materialLocation = ModelImporterMaterialLocation.InPrefab;
|
||||
public ModelImporterMaterialName materialRemapNamingOption = ModelImporterMaterialName.BasedOnMaterialName;
|
||||
public ModelImporterMaterialSearch materialRemapSearchOption = ModelImporterMaterialSearch.RecursiveUp;
|
||||
|
||||
public void OnPreProcess(AssetsProcessContext context)
|
||||
{
|
||||
context.userData = new HashSet<string>();
|
||||
}
|
||||
|
||||
public void OnProcess(Object source, string outputDirectory, AssetsProcessContext context)
|
||||
{
|
||||
var assetsToReload = (HashSet<string>)context.userData;
|
||||
|
||||
var assetImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(source));
|
||||
if (assetImporter is not ModelImporter modelImporter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (useMaterialRemap)
|
||||
{
|
||||
modelImporter.materialLocation = materialLocation;
|
||||
modelImporter.SearchAndRemapMaterials(materialRemapNamingOption, materialRemapSearchOption);
|
||||
modelImporter.SaveAndReimport();
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var materials = AssetDatabase.LoadAllAssetsAtPath(modelImporter.assetPath).Where(x => x.GetType() == typeof(Material));
|
||||
|
||||
foreach (var material in materials)
|
||||
{
|
||||
var newAssetPath = Path.Combine(outputDirectory, material.name) + Material_Extension;
|
||||
newAssetPath = AssetDatabase.GenerateUniqueAssetPath(newAssetPath);
|
||||
|
||||
var error = AssetDatabase.ExtractAsset(material, newAssetPath);
|
||||
if (string.IsNullOrEmpty(error))
|
||||
{
|
||||
assetsToReload.Add(modelImporter.assetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPostProcess(AssetsProcessContext context)
|
||||
{
|
||||
var assetsToReload = (HashSet<string>)context.userData;
|
||||
|
||||
foreach (var assetPath in assetsToReload)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.WriteImportSettingsIfDirty(assetPath);
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae6fdf97993458e47add233725aecaa4
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Properties;
|
||||
using UnityEditor;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal class ExtractMaterialsVisualProvider : OptionsVisualProvider
|
||||
{
|
||||
internal override VisualElement ContentAfterList()
|
||||
{
|
||||
var root = new VisualElement();
|
||||
var materialRemapOptionContainer = new VisualElement()
|
||||
{
|
||||
style =
|
||||
{
|
||||
display = DisplayStyle.None,
|
||||
}
|
||||
};
|
||||
|
||||
var useMaterialRemapField = new DropdownField("Use Material Remap", new List<string> { "False", "True" }, "False");
|
||||
useMaterialRemapField.SetBinding(
|
||||
nameof(DropdownField.index),
|
||||
new DataBinding()
|
||||
{
|
||||
dataSourcePath = PropertyPath.FromName(nameof(ExtractMaterialsProcessor.useMaterialRemap))
|
||||
});
|
||||
useMaterialRemapField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
materialRemapOptionContainer.style.display = evt.newValue == "True" ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
});
|
||||
|
||||
var materialLocationField = new EnumField("Location", ModelImporterMaterialLocation.External);
|
||||
materialLocationField.SetBinding(
|
||||
nameof(EnumField.value),
|
||||
new DataBinding()
|
||||
{
|
||||
dataSourcePath = PropertyPath.FromName(nameof(ExtractMaterialsProcessor.materialLocation))
|
||||
});
|
||||
|
||||
var materialRemapNamingOptionField = new EnumField("Naming Option", ModelImporterMaterialName.BasedOnTextureName);
|
||||
materialRemapNamingOptionField.SetBinding(
|
||||
nameof(EnumField.value),
|
||||
new DataBinding()
|
||||
{
|
||||
dataSourcePath = PropertyPath.FromName(nameof(ExtractMaterialsProcessor.materialRemapNamingOption))
|
||||
});
|
||||
|
||||
var materialRemapSearchOptionField = new EnumField("Search Option", ModelImporterMaterialSearch.Local);
|
||||
materialRemapSearchOptionField.SetBinding(
|
||||
nameof(EnumField.value),
|
||||
new DataBinding()
|
||||
{
|
||||
dataSourcePath = PropertyPath.FromName(nameof(ExtractMaterialsProcessor.materialRemapSearchOption))
|
||||
});
|
||||
|
||||
materialRemapOptionContainer.Add(materialLocationField);
|
||||
materialRemapOptionContainer.Add(materialRemapNamingOptionField);
|
||||
materialRemapOptionContainer.Add(materialRemapSearchOptionField);
|
||||
|
||||
root.Add(useMaterialRemapField);
|
||||
root.Add(materialRemapOptionContainer);
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74347edff42a5cd47a6a5d4989210334
|
||||
@@ -1,123 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public class RemapMaterials
|
||||
{
|
||||
private const string Material_Extension = ".mat";
|
||||
|
||||
private static bool _useMaterialRemap = false;
|
||||
private static ModelImporterMaterialLocation _materialLocation = ModelImporterMaterialLocation.InPrefab;
|
||||
private static ModelImporterMaterialName _materialRemapNamingOption = ModelImporterMaterialName.BasedOnMaterialName;
|
||||
private static ModelImporterMaterialSearch _materialRemapSearchOption = ModelImporterMaterialSearch.RecursiveUp;
|
||||
|
||||
[MenuItem("Assets/Art Tools/Mesh Helpers/Extract Materials", true)]
|
||||
public static bool CreateDecalMenuValidator()
|
||||
{
|
||||
foreach (var selectedObject in Selection.objects)
|
||||
{
|
||||
var assetImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(selectedObject));
|
||||
if (assetImporter is not ModelImporter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Art Tools/Mesh Helpers/Extract Materials")]
|
||||
public static void CreateDecalMenu()
|
||||
{
|
||||
var window = EditorWindow.GetWindow<OutputOptionsWindow>(true, "Extract Materials Output Options");
|
||||
window.WithSource(Selection.objects);
|
||||
window.WithContentBeforeButton(() =>
|
||||
{
|
||||
var root = new VisualElement();
|
||||
var materialRemapOptionContainer = new VisualElement()
|
||||
{
|
||||
style =
|
||||
{
|
||||
display = DisplayStyle.None,
|
||||
}
|
||||
};
|
||||
|
||||
var useMaterialRemap = new DropdownField("Use Material Remap", new List<string> { "False", "True" }, "False");
|
||||
useMaterialRemap.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
_useMaterialRemap = evt.newValue == "True";
|
||||
materialRemapOptionContainer.style.display = _useMaterialRemap ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
});
|
||||
|
||||
var materialLocation = new EnumField("Material Location", _materialLocation);
|
||||
materialLocation.RegisterValueChangedCallback(evt => _materialLocation = (ModelImporterMaterialLocation)evt.newValue);
|
||||
|
||||
var materialRemapNamingOption = new EnumField("Material Naming Option", _materialRemapNamingOption);
|
||||
materialRemapNamingOption.RegisterValueChangedCallback(evt => _materialRemapNamingOption = (ModelImporterMaterialName)evt.newValue);
|
||||
|
||||
var materialRemapSearchOption = new EnumField("Material Search Option", _materialRemapSearchOption);
|
||||
materialRemapSearchOption.RegisterValueChangedCallback(evt => _materialRemapSearchOption = (ModelImporterMaterialSearch)evt.newValue);
|
||||
|
||||
materialRemapOptionContainer.Add(materialLocation);
|
||||
materialRemapOptionContainer.Add(materialRemapNamingOption);
|
||||
materialRemapOptionContainer.Add(materialRemapSearchOption);
|
||||
|
||||
root.Add(useMaterialRemap);
|
||||
root.Add(materialRemapOptionContainer);
|
||||
return root;
|
||||
});
|
||||
window.WithOutput(ExtractMaterialsInternal);
|
||||
window.WithPostOutput(ExtractMaterialsPostInternal);
|
||||
|
||||
window.ShowUtility();
|
||||
}
|
||||
|
||||
private static string ExtractMaterialsInternal(Object inputObject, string outputDirectory)
|
||||
{
|
||||
var assetImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(inputObject));
|
||||
if (assetImporter is not ModelImporter modelImporter)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_useMaterialRemap)
|
||||
{
|
||||
modelImporter.materialLocation = _materialLocation;
|
||||
modelImporter.SearchAndRemapMaterials(_materialRemapNamingOption, _materialRemapSearchOption);
|
||||
modelImporter.SaveAndReimport();
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var materials = AssetDatabase.LoadAllAssetsAtPath(modelImporter.assetPath).Where(x => x.GetType() == typeof(Material));
|
||||
|
||||
foreach (var material in materials)
|
||||
{
|
||||
var newAssetPath = Path.Combine(outputDirectory, material.name) + Material_Extension;
|
||||
newAssetPath = AssetDatabase.GenerateUniqueAssetPath(newAssetPath);
|
||||
|
||||
AssetDatabase.ExtractAsset(material, newAssetPath);
|
||||
}
|
||||
|
||||
return modelImporter.assetPath;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExtractMaterialsPostInternal(string assetPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.WriteImportSettingsIfDirty(assetPath);
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cc9f1a0be83aa444884c32f825c5303
|
||||
8
Editor/AssetsHelpers/Implementation/Texture.meta
Normal file
8
Editor/AssetsHelpers/Implementation/Texture.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c45ddbe7c1e4d6246ac1957c1e88d2ea
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 819df015e3521a3479dfefbf5bed26b2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal class GenerateMaskMenu
|
||||
{
|
||||
[MenuItem("Assets/Art Tools/Texture Helpers/Generate Mask", true)]
|
||||
public static bool GenerateMaskValidator()
|
||||
{
|
||||
foreach (var selectedObject in Selection.objects)
|
||||
{
|
||||
if (selectedObject is not Texture2D)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Art Tools/Texture Helpers/Generate Mask")]
|
||||
public static void GenerateMask()
|
||||
{
|
||||
var window = EditorWindow.GetWindow<OutputOptionsWindow>(true, "Generate Mask Output Options");
|
||||
window.WithItemSource(Selection.objects);
|
||||
window.RegisterVisualProvider<GenerateMaskVisualProvider>();
|
||||
window.RegisterProcessor<GenerateMaskProcessor>();
|
||||
|
||||
window.InitializeAndShow();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 353f02bb002aafd419d5472f331069a9
|
||||
@@ -0,0 +1,227 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Unity.Collections;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal class GenerateMaskProcessor : IAssetsProcessor
|
||||
{
|
||||
private struct PackingConfig : IDisposable
|
||||
{
|
||||
public string outputDirectory;
|
||||
public NativeList<FixedString64Bytes> texturePaths;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
texturePaths.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private class Constants
|
||||
{
|
||||
internal const string Generate_Mask_Shader_Path = "Hidden/GenerateMask";
|
||||
internal const string Texture_R_Property = "_TexR";
|
||||
internal const string Texture_G_Property = "_TexG";
|
||||
internal const string Texture_B_Property = "_TexB";
|
||||
internal const string Texture_A_Property = "_TexA";
|
||||
internal const string Fallback_Property = "_Fallback";
|
||||
internal const string Has_Texture_R_Keyword = "_HAS_TEX_R";
|
||||
internal const string Has_Texture_G_Keyword = "_HAS_TEX_G";
|
||||
internal const string Has_Texture_B_Keyword = "_HAS_TEX_B";
|
||||
internal const string Has_Texture_A_Keyword = "_HAS_TEX_A";
|
||||
|
||||
internal const string Png_Extension = ".png";
|
||||
}
|
||||
|
||||
public string metallicTextureRegex = ".*_metallic";
|
||||
public string aoTextureRegex = ".*_ao|.*_ambientocclusion";
|
||||
public string detailMaskTextureRegex = ".*_detailmask";
|
||||
public string smoothnessTextureRegex = ".*_smoothness";
|
||||
|
||||
public TextureFallbackType metallicFallbackType = TextureFallbackType.Black;
|
||||
public TextureFallbackType aoFallbackType = TextureFallbackType.White;
|
||||
public TextureFallbackType detailMaskFallbackType = TextureFallbackType.White;
|
||||
public TextureFallbackType smoothnessFallbackType = TextureFallbackType.LinearGray;
|
||||
|
||||
public string textureGroupingRegex = "^([^_]+)_";
|
||||
public string namingRegex;
|
||||
public TextureNamingSourceType namingSource;
|
||||
public string replaceBy = "Mask";
|
||||
|
||||
public void OnPreProcess(AssetsProcessContext context)
|
||||
{
|
||||
context.userData = new Dictionary<string, PackingConfig>();
|
||||
}
|
||||
|
||||
public void OnProcess(UnityEngine.Object source, string outputDirectory, AssetsProcessContext context)
|
||||
{
|
||||
if (source is not Texture2D texture)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var groupConfigs = (Dictionary<string, PackingConfig>)context.userData;
|
||||
var match = Regex.Match(texture.name, textureGroupingRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
if (!match.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var groupName = match.Groups[1].Value;
|
||||
if (!groupConfigs.ContainsKey(groupName))
|
||||
{
|
||||
groupConfigs[groupName] = new PackingConfig
|
||||
{
|
||||
outputDirectory = outputDirectory,
|
||||
texturePaths = new NativeList<FixedString64Bytes>(4, Allocator.TempJob)
|
||||
};
|
||||
}
|
||||
|
||||
var config = groupConfigs[groupName];
|
||||
config.texturePaths.AddNoResize(AssetDatabase.GetAssetPath(texture));
|
||||
}
|
||||
|
||||
public void OnPostProcess(AssetsProcessContext context)
|
||||
{
|
||||
var groupConfigs = (Dictionary<string, PackingConfig>)context.userData;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var group in groupConfigs)
|
||||
{
|
||||
var metallicTexture = FindTexture(group.Value.texturePaths, metallicTextureRegex);
|
||||
var aoTexture = FindTexture(group.Value.texturePaths, aoTextureRegex);
|
||||
var detailMaskTexture = FindTexture(group.Value.texturePaths, detailMaskTextureRegex);
|
||||
var smoothnessTexture = FindTexture(group.Value.texturePaths, smoothnessTextureRegex);
|
||||
|
||||
GetTextureSizeAndName(metallicTexture, aoTexture, detailMaskTexture, out var textureSize, out var textureName);
|
||||
SetupAndBlitTexture(metallicTexture, aoTexture, detailMaskTexture, smoothnessTexture, textureSize, out var tempRT, out var material);
|
||||
ExportTextureToPNG(group, textureName, tempRT);
|
||||
|
||||
UnityEngine.Object.DestroyImmediate(material);
|
||||
tempRT.Release();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var group in groupConfigs)
|
||||
{
|
||||
group.Value.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Texture2D FindTexture(NativeList<FixedString64Bytes> texturePaths, string metallicTextureRegex)
|
||||
{
|
||||
foreach (var texturePath in texturePaths)
|
||||
{
|
||||
if (Regex.IsMatch(texturePath.ToString(), metallicTextureRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled))
|
||||
{
|
||||
return AssetDatabase.LoadAssetAtPath<Texture2D>(texturePath.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void GetTextureSizeAndName(Texture2D metallicTexture, Texture2D aoTexture, Texture2D detailMaskTexture, out Vector2Int textureSize, out string textureName)
|
||||
{
|
||||
textureSize = new Vector2Int(2048, 2048);
|
||||
textureName = string.Empty;
|
||||
switch (namingSource)
|
||||
{
|
||||
case TextureNamingSourceType.R:
|
||||
textureSize = new Vector2Int(metallicTexture.width, metallicTexture.height);
|
||||
textureName = Regex.Replace(metallicTexture.name, namingRegex, replaceBy, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
break;
|
||||
case TextureNamingSourceType.G:
|
||||
textureSize = new Vector2Int(aoTexture.width, aoTexture.height);
|
||||
textureName = Regex.Replace(aoTexture.name, namingRegex, replaceBy, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
break;
|
||||
case TextureNamingSourceType.B:
|
||||
textureSize = new Vector2Int(detailMaskTexture.width, detailMaskTexture.height);
|
||||
textureName = Regex.Replace(detailMaskTexture.name, namingRegex, replaceBy, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
break;
|
||||
case TextureNamingSourceType.A:
|
||||
textureSize = new Vector2Int(detailMaskTexture.width, detailMaskTexture.height);
|
||||
textureName = Regex.Replace(detailMaskTexture.name, namingRegex, replaceBy, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupAndBlitTexture(Texture2D textureR, Texture2D textureG, Texture2D textureB, Texture2D textureA, Vector2Int textureSize, out RenderTexture tempRT, out Material material)
|
||||
{
|
||||
tempRT = RenderTexture.GetTemporary(textureSize.x, textureSize.y, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
|
||||
tempRT.Create();
|
||||
|
||||
material = new Material(Shader.Find(Constants.Generate_Mask_Shader_Path));
|
||||
if (textureR != null)
|
||||
{
|
||||
material.SetTexture(Constants.Texture_R_Property, textureR);
|
||||
material.EnableKeyword(Constants.Has_Texture_R_Keyword);
|
||||
}
|
||||
|
||||
if (textureG != null)
|
||||
{
|
||||
material.SetTexture(Constants.Texture_G_Property, textureG);
|
||||
material.EnableKeyword(Constants.Has_Texture_G_Keyword);
|
||||
}
|
||||
|
||||
if (textureB != null)
|
||||
{
|
||||
material.SetTexture(Constants.Texture_B_Property, textureB);
|
||||
material.EnableKeyword(Constants.Has_Texture_B_Keyword);
|
||||
}
|
||||
|
||||
if (textureA != null)
|
||||
{
|
||||
material.SetTexture(Constants.Texture_A_Property, textureA);
|
||||
material.EnableKeyword(Constants.Has_Texture_A_Keyword);
|
||||
}
|
||||
|
||||
var fallback = new Vector4(
|
||||
GetFallbackValue(metallicFallbackType),
|
||||
GetFallbackValue(aoFallbackType),
|
||||
GetFallbackValue(detailMaskFallbackType),
|
||||
GetFallbackValue(smoothnessFallbackType)
|
||||
);
|
||||
material.SetVector("_Fallback", fallback);
|
||||
|
||||
Graphics.Blit(null, tempRT, material);
|
||||
}
|
||||
|
||||
private static void ExportTextureToPNG(KeyValuePair<string, PackingConfig> group, string textureName, RenderTexture tempRT)
|
||||
{
|
||||
var exportTexture = new Texture2D(tempRT.width, tempRT.height, TextureFormat.RGBA32, false);
|
||||
exportTexture.ReadPixels(new Rect(0, 0, tempRT.width, tempRT.height), 0, 0);
|
||||
exportTexture.Apply();
|
||||
var bytes = exportTexture.EncodeToPNG();
|
||||
var path = Path.Combine(group.Value.outputDirectory, textureName + Constants.Png_Extension);
|
||||
File.WriteAllBytes(path, bytes);
|
||||
|
||||
UnityEngine.Object.DestroyImmediate(exportTexture);
|
||||
|
||||
AssetDatabase.ImportAsset(path);
|
||||
}
|
||||
|
||||
private float GetFallbackValue(TextureFallbackType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
TextureFallbackType.White => 1.0f,
|
||||
TextureFallbackType.LinearGray => 0.73f,
|
||||
TextureFallbackType.Gray => 0.5f,
|
||||
TextureFallbackType.Black => 0.0f,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94ec75a6994a6db41b574c5bebf56670
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using Unity.Properties;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
internal class GenerateMaskVisualProvider : OptionsVisualProvider
|
||||
{
|
||||
internal override VisualElement ContentAfterList()
|
||||
{
|
||||
var root = new VisualElement();
|
||||
|
||||
root.Add(new HelpBox("All regex are case insensitive", HelpBoxMessageType.Info));
|
||||
|
||||
root.Add(CreateTextInputWithEnumField("Metallic Regex",
|
||||
nameof(GenerateMaskProcessor.metallicTextureRegex),
|
||||
nameof(GenerateMaskProcessor.metallicFallbackType),
|
||||
TextureFallbackType.Black));
|
||||
root.Add(CreateTextInputWithEnumField("AO Regex",
|
||||
nameof(GenerateMaskProcessor.aoTextureRegex),
|
||||
nameof(GenerateMaskProcessor.aoFallbackType),
|
||||
TextureFallbackType.White));
|
||||
root.Add(CreateTextInputWithEnumField("Detail Mask Regex",
|
||||
nameof(GenerateMaskProcessor.detailMaskTextureRegex),
|
||||
nameof(GenerateMaskProcessor.detailMaskFallbackType),
|
||||
TextureFallbackType.White));
|
||||
root.Add(CreateTextInputWithEnumField("Smoothness Regex",
|
||||
nameof(GenerateMaskProcessor.smoothnessTextureRegex),
|
||||
nameof(GenerateMaskProcessor.smoothnessFallbackType),
|
||||
TextureFallbackType.LinearGray));
|
||||
|
||||
root.Add(CreateTextInputField("Grouping Regex",
|
||||
nameof(GenerateMaskProcessor.textureGroupingRegex)));
|
||||
|
||||
root.Add(CreateTextInputWithEnumField("Naming Regex",
|
||||
nameof(GenerateMaskProcessor.namingRegex),
|
||||
nameof(GenerateMaskProcessor.namingSource),
|
||||
TextureNamingSourceType.R));
|
||||
|
||||
root.Add(CreateTextInputField("Replace By",
|
||||
nameof(GenerateMaskProcessor.replaceBy)));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private VisualElement CreateTextInputField(string label, string binding)
|
||||
{
|
||||
var textField = new TextField(label);
|
||||
textField.SetBinding(nameof(TextField.value), new DataBinding() { dataSourcePath = PropertyPath.FromName(binding) });
|
||||
return textField;
|
||||
}
|
||||
|
||||
private VisualElement CreateTextInputWithEnumField(string label, string textInputBinding, string enumBinding, Enum defaultEnumValue)
|
||||
{
|
||||
var root = new VisualElement()
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexDirection = FlexDirection.Row,
|
||||
}
|
||||
};
|
||||
|
||||
var textField = new TextField(label)
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexGrow = 1,
|
||||
}
|
||||
};
|
||||
textField.SetBinding(nameof(TextField.value), new DataBinding() { dataSourcePath = PropertyPath.FromName(textInputBinding) });
|
||||
|
||||
var enumField = new EnumField(defaultEnumValue)
|
||||
{
|
||||
style =
|
||||
{
|
||||
width = 100,
|
||||
}
|
||||
};
|
||||
enumField.SetBinding(nameof(EnumField.value), new DataBinding() { dataSourcePath = PropertyPath.FromName(enumBinding) });
|
||||
|
||||
root.Add(textField);
|
||||
root.Add(enumField);
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 591e3f52dbd05794395f0918f2b19557
|
||||
8
Editor/AssetsHelpers/Implementation/Texture/Shader.meta
Normal file
8
Editor/AssetsHelpers/Implementation/Texture/Shader.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d55aad869a0f394abc5a531318a7b7d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,85 @@
|
||||
Shader "Hidden/GenerateMask"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_TexR ("Red Channel Texture", 2D) = "white"
|
||||
_TexG ("Green Channel Texture", 2D) = "white"
|
||||
_TexB ("Blue Channel Texture", 2D) = "white"
|
||||
_TexA ("Alpha Channel Texture", 2D) = "white"
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Cull Off
|
||||
ZWrite Off
|
||||
ZTest Always
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#pragma shader_feature_local _HAS_TEX_R
|
||||
#pragma shader_feature_local _HAS_TEX_G
|
||||
#pragma shader_feature_local _HAS_TEX_B
|
||||
#pragma shader_feature_local _HAS_TEX_A
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata {
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct v2f {
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 vertex : SV_POSITION;
|
||||
};
|
||||
|
||||
v2f vert(appdata v) {
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = v.uv;
|
||||
return o;
|
||||
}
|
||||
|
||||
sampler2D _TexR;
|
||||
sampler2D _TexG;
|
||||
sampler2D _TexB;
|
||||
sampler2D _TexA;
|
||||
|
||||
float4 _Fallback;
|
||||
|
||||
float4 frag (v2f i) : SV_Target
|
||||
{
|
||||
#ifdef _HAS_TEX_R
|
||||
float r = tex2D(_TexR, i.uv).r;
|
||||
#else
|
||||
float r = _Fallback.r;
|
||||
#endif
|
||||
|
||||
#ifdef _HAS_TEX_G
|
||||
float g = tex2D(_TexG, i.uv).r;
|
||||
#else
|
||||
float g = _Fallback.g;
|
||||
#endif
|
||||
|
||||
#ifdef _HAS_TEX_B
|
||||
float b = tex2D(_TexB, i.uv).r;
|
||||
#else
|
||||
float b = _Fallback.b;
|
||||
#endif
|
||||
|
||||
#ifdef _HAS_TEX_A
|
||||
float a = tex2D(_TexA, i.uv).r;
|
||||
#else
|
||||
float a = _Fallback.a;
|
||||
#endif
|
||||
|
||||
return float4(r, g, b, a);
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 132046c0498c1ab49aa91453b6ae2766
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Editor/AssetsHelpers/Models.meta
Normal file
8
Editor/AssetsHelpers/Models.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c373d32c50e6ac7418b2dccbe17acc6c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Editor/AssetsHelpers/Models/AssetsProcessContext.cs
Normal file
7
Editor/AssetsHelpers/Models/AssetsProcessContext.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public class AssetsProcessContext
|
||||
{
|
||||
public object userData;
|
||||
}
|
||||
}
|
||||
2
Editor/AssetsHelpers/Models/AssetsProcessContext.cs.meta
Normal file
2
Editor/AssetsHelpers/Models/AssetsProcessContext.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd408317f5f21ee4798818fc5ede6631
|
||||
@@ -12,16 +12,16 @@
|
||||
<engine:VisualElement name="content-after-list" />
|
||||
<engine:EnumField label="Output Directory" value="Center" type="Misaki.ArtToolEditor.OutputDirectoryType, Misaki.ArtTool.Editor" name="directory-type-enum">
|
||||
<Bindings>
|
||||
<engine:DataBinding property="value" data-source-path="_outputOptions.outputDirectoryType" binding-mode="TwoWay" />
|
||||
<engine:DataBinding property="value" data-source-path="_outputDirectoryType" binding-mode="TwoWay" />
|
||||
</Bindings>
|
||||
</engine:EnumField>
|
||||
<engine:TextField label="Custom Path" placeholder-text="path" name="custom-path-input" tooltip="Support absolute and relative path">
|
||||
<engine:TextField label="Custom Path" placeholder-text="path" name="custom-path-input" tooltip="Support absolute and relative path" style="display: none;">
|
||||
<Bindings>
|
||||
<engine:DataBinding property="value" data-source-path="_outputOptions.customPath" binding-mode="TwoWay" />
|
||||
<engine:DataBinding property="value" data-source-path="_customPath" binding-mode="TwoWay" />
|
||||
</Bindings>
|
||||
</engine:TextField>
|
||||
<engine:VisualElement name="content-before-button" />
|
||||
<engine:Button text="Output" name="output-button" />
|
||||
<engine:Button text="Execute" name="output-button" />
|
||||
<engine:VisualElement name="content-on-bottom" />
|
||||
</engine:ScrollView>
|
||||
</engine:VisualElement>
|
||||
|
||||
@@ -10,18 +10,16 @@ using Object = UnityEngine.Object;
|
||||
|
||||
namespace Misaki.ArtToolEditor
|
||||
{
|
||||
public struct OutputOptions
|
||||
{
|
||||
public OutputDirectoryType outputDirectoryType;
|
||||
public string customPath;
|
||||
}
|
||||
|
||||
public class OutputOptionsWindow : EditorWindow
|
||||
{
|
||||
private readonly AssetsProcessContext _context = new();
|
||||
|
||||
[SerializeField]
|
||||
private VisualTreeAsset _visualTreeAsset = default;
|
||||
[SerializeField]
|
||||
private OutputOptions _outputOptions;
|
||||
private OutputDirectoryType _outputDirectoryType;
|
||||
[SerializeField]
|
||||
private string _customPath;
|
||||
[SerializeField]
|
||||
private IEnumerable<Object> _sourceObjects;
|
||||
|
||||
@@ -30,60 +28,16 @@ namespace Misaki.ArtToolEditor
|
||||
private VisualElement _contentBeforeButton;
|
||||
private VisualElement _contentOnBottom;
|
||||
|
||||
private Func<Object, string, string> onOutput;
|
||||
private Action<string> postOutput;
|
||||
private OptionsVisualProvider _visualProvider;
|
||||
private IAssetsProcessor _processor;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the source objects for the output options window.
|
||||
/// </summary>
|
||||
/// <param name="source"> The source objects to process. </param>
|
||||
public void WithSource(IEnumerable<Object> source) => _sourceObjects = source;
|
||||
public void WithItemSource(IEnumerable<Object> source) => _sourceObjects = source;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the output options for the output options window.
|
||||
/// </summary>
|
||||
/// <param name="content"> The output options to set. </param>
|
||||
public void WithContentOnTop(Func<VisualElement> content) => _contentOnTop.Add(content());
|
||||
/// <summary>
|
||||
/// Sets the output options for the output options window.
|
||||
/// </summary>
|
||||
/// <param name="content"> The output options to set. </param>
|
||||
public void WithContentAfterList(Func<VisualElement> content) => _contentAfterList.Add(content());
|
||||
/// <summary>
|
||||
/// Sets the output options for the output options window.
|
||||
/// </summary>
|
||||
/// <param name="content"> The output options to set. </param>
|
||||
public void WithContentBeforeButton(Func<VisualElement> content) => _contentBeforeButton.Add(content());
|
||||
/// <summary>
|
||||
/// Sets the output options for the output options window.
|
||||
/// </summary>
|
||||
/// <param name="content"> The output options to set. </param>
|
||||
public void WithContentOnBottom(Func<VisualElement> content) => _contentOnBottom.Add(content());
|
||||
public void RegisterVisualProvider<T>() where T : OptionsVisualProvider => _visualProvider = Activator.CreateInstance<T>();
|
||||
public void RegisterVisualProvider<T>(T visualProvider) where T : OptionsVisualProvider => _visualProvider = visualProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the output action for the output options window.
|
||||
/// </summary>
|
||||
/// <param name="outputAction"> The output action to set.
|
||||
/// <para>The parameters of the Func are:</para>
|
||||
/// <para>- Object: The object to process.</para>
|
||||
/// <para>- string: The output directory.</para>
|
||||
/// The Func returns the path of the asset, which will be use later in the post output.</param>
|
||||
public void WithOutput(Func<Object, string, string> outputAction) => onOutput = outputAction;
|
||||
/// <summary>
|
||||
/// Sets the post output action for the output options window.
|
||||
/// </summary>
|
||||
/// <param name="postOutputAction"> The post output action to set. </param>
|
||||
public void WithPostOutput(Action<string> postOutputAction) => postOutput = postOutputAction;
|
||||
|
||||
public static OutputOptionsWindow ShowWindow(string title, IEnumerable<Object> source, Func<Object, string, string> outputAction)
|
||||
{
|
||||
var window = GetWindow<OutputOptionsWindow>(true, title);
|
||||
window.WithSource(source);
|
||||
window.WithOutput(outputAction);
|
||||
window.ShowUtility();
|
||||
|
||||
return window;
|
||||
}
|
||||
public void RegisterProcessor<T>() where T : IAssetsProcessor => _processor = Activator.CreateInstance<T>();
|
||||
public void RegisterProcessor<T>(T processor) where T : IAssetsProcessor => _processor = processor;
|
||||
|
||||
private void CreateGUI()
|
||||
{
|
||||
@@ -117,12 +71,19 @@ namespace Misaki.ArtToolEditor
|
||||
var outputButton = outPutOptions.Q<Button>("output-button");
|
||||
outputButton.clickable.clicked += () =>
|
||||
{
|
||||
if (_processor == null)
|
||||
{
|
||||
Debug.LogError("No processor has been registered");
|
||||
Close();
|
||||
}
|
||||
|
||||
if (_sourceObjects == null)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
var assetsToReload = new HashSet<string>();
|
||||
_processor.OnPreProcess(_context);
|
||||
|
||||
foreach (var obj in _sourceObjects)
|
||||
{
|
||||
var objectPath = AssetDatabase.GetAssetPath(obj);
|
||||
@@ -132,13 +93,10 @@ namespace Misaki.ArtToolEditor
|
||||
Directory.CreateDirectory(outputDirectory);
|
||||
}
|
||||
|
||||
assetsToReload.Add(onOutput?.Invoke(obj, outputDirectory));
|
||||
_processor.OnProcess(obj, outputDirectory, _context);
|
||||
}
|
||||
|
||||
foreach (var assetPath in assetsToReload)
|
||||
{
|
||||
postOutput?.Invoke(assetPath);
|
||||
}
|
||||
_processor.OnPostProcess(_context);
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
AssetDatabase.SaveAssets();
|
||||
@@ -152,9 +110,39 @@ namespace Misaki.ArtToolEditor
|
||||
_contentOnBottom = outPutOptions.Q<VisualElement>("content-on-bottom");
|
||||
}
|
||||
|
||||
public void InitializeAndShow()
|
||||
{
|
||||
RecreateCustomOptions(_processor);
|
||||
ShowUtility();
|
||||
}
|
||||
|
||||
private void RecreateCustomOptions(object dataSource)
|
||||
{
|
||||
if (_visualProvider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_contentOnTop.Clear();
|
||||
_contentAfterList.Clear();
|
||||
_contentBeforeButton.Clear();
|
||||
_contentOnBottom.Clear();
|
||||
|
||||
_visualProvider.dataSource = dataSource;
|
||||
_contentOnTop.Add(_visualProvider.ContentOnTop());
|
||||
_contentAfterList.Add(_visualProvider.ContentAfterList());
|
||||
_contentBeforeButton.Add(_visualProvider.ContentBeforeButton());
|
||||
_contentOnBottom.Add(_visualProvider.ContentOnBottom());
|
||||
|
||||
_contentOnTop.dataSource = dataSource;
|
||||
_contentAfterList.dataSource = dataSource;
|
||||
_contentBeforeButton.dataSource = dataSource;
|
||||
_contentOnBottom.dataSource = dataSource;
|
||||
}
|
||||
|
||||
private string GetOutputDirectory(string inputDirectory)
|
||||
{
|
||||
switch (_outputOptions.outputDirectoryType)
|
||||
switch (_outputDirectoryType)
|
||||
{
|
||||
case OutputDirectoryType.CurrentDirectory:
|
||||
return inputDirectory;
|
||||
@@ -163,13 +151,13 @@ namespace Misaki.ArtToolEditor
|
||||
case OutputDirectoryType.AssetsDirectory:
|
||||
return "Assets";
|
||||
case OutputDirectoryType.Custom:
|
||||
if (Path.IsPathRooted(_outputOptions.customPath))
|
||||
if (Path.IsPathRooted(_customPath))
|
||||
{
|
||||
return _outputOptions.customPath;
|
||||
return _customPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.Combine(inputDirectory, _outputOptions.customPath);
|
||||
return Path.Combine(inputDirectory, _customPath);
|
||||
}
|
||||
default:
|
||||
return inputDirectory;
|
||||
|
||||
Reference in New Issue
Block a user