Changed AssetsHelpers from editor window to context menu workflow.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 7952da339ee80334cb3239177f9ca90e
|
guid: 01a99230cf89a1b408a2471479651f4d
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
8
Editor/AssetsHelpers/Constants.meta
Normal file
8
Editor/AssetsHelpers/Constants.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5012fabff1a87ad418b1eb647915e70c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
10
Editor/AssetsHelpers/Constants/Shader.cs
Normal file
10
Editor/AssetsHelpers/Constants/Shader.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Misaki.ArtToolEditor
|
||||||
|
{
|
||||||
|
internal static class Constants
|
||||||
|
{
|
||||||
|
internal static class Shader
|
||||||
|
{
|
||||||
|
internal const string DECAL_SHADER_PATH = "HDRP/Decal";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/AssetsHelpers/Constants/Shader.cs.meta
Normal file
2
Editor/AssetsHelpers/Constants/Shader.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c17900c8aa57f5840b6fc3ea27cd9a67
|
||||||
8
Editor/AssetsHelpers/Implementation.meta
Normal file
8
Editor/AssetsHelpers/Implementation.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e7734f9b2e8f59f4dbc841e7fbe22629
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
47
Editor/AssetsHelpers/Implementation/Material/CreateDecal.cs
Normal file
47
Editor/AssetsHelpers/Implementation/Material/CreateDecal.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
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,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a4585b41cdb0577478ac9c4e563dc639
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
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,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4ba5b5a3211673749a18dae69e07a0f3
|
||||||
8
Editor/AssetsHelpers/Implementation/Meshes.meta
Normal file
8
Editor/AssetsHelpers/Implementation/Meshes.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 223cd2d5e7a5b9b4cba370fb38777463
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
123
Editor/AssetsHelpers/Implementation/Meshes/RemapMaterials.cs
Normal file
123
Editor/AssetsHelpers/Implementation/Meshes/RemapMaterials.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9cc9f1a0be83aa444884c32f825c5303
|
||||||
8
Editor/AssetsHelpers/View.meta
Normal file
8
Editor/AssetsHelpers/View.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ee2d58939cc61cf48afb86056b47a69b
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
28
Editor/AssetsHelpers/View/OutputOptionsView.uxml
Normal file
28
Editor/AssetsHelpers/View/OutputOptionsView.uxml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||||
|
<engine:VisualElement data-source-type="Misaki.ArtToolEditor.OutputOptionsWindow, Misaki.ArtTool.Editor" style="flex-grow: 1;">
|
||||||
|
<engine:ScrollView>
|
||||||
|
<engine:VisualElement name="content-on-top" />
|
||||||
|
<engine:Foldout text="Source" style="margin-bottom: 4px;">
|
||||||
|
<engine:ListView header-title="Source Objects" selection-type="None" allow-add="false" allow-remove="false" show-border="true" name="source-object-list" binding-source-selection-mode="AutoAssign" style="max-height: 100px;">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="itemsSource" data-source-path="_sourceObjects" binding-mode="ToTargetOnce" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:ListView>
|
||||||
|
</engine:Foldout>
|
||||||
|
<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" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:EnumField>
|
||||||
|
<engine:TextField label="Custom Path" placeholder-text="path" name="custom-path-input" tooltip="Support absolute and relative path">
|
||||||
|
<Bindings>
|
||||||
|
<engine:DataBinding property="value" data-source-path="_outputOptions.customPath" binding-mode="TwoWay" />
|
||||||
|
</Bindings>
|
||||||
|
</engine:TextField>
|
||||||
|
<engine:VisualElement name="content-before-button" />
|
||||||
|
<engine:Button text="Output" name="output-button" />
|
||||||
|
<engine:VisualElement name="content-on-bottom" />
|
||||||
|
</engine:ScrollView>
|
||||||
|
</engine:VisualElement>
|
||||||
|
</engine:UXML>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 020261090ef91d340a65b9baca11a43f
|
guid: 0413a47b12d366049baaf9a7e4b20fb7
|
||||||
ScriptedImporter:
|
ScriptedImporter:
|
||||||
internalIDToNameTable: []
|
internalIDToNameTable: []
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
179
Editor/AssetsHelpers/View/OutputOptionsWindow.cs
Normal file
179
Editor/AssetsHelpers/View/OutputOptionsWindow.cs
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.UIElements;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace Misaki.ArtToolEditor
|
||||||
|
{
|
||||||
|
public struct OutputOptions
|
||||||
|
{
|
||||||
|
public OutputDirectoryType outputDirectoryType;
|
||||||
|
public string customPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OutputOptionsWindow : EditorWindow
|
||||||
|
{
|
||||||
|
[SerializeField]
|
||||||
|
private VisualTreeAsset _visualTreeAsset = default;
|
||||||
|
[SerializeField]
|
||||||
|
private OutputOptions _outputOptions;
|
||||||
|
[SerializeField]
|
||||||
|
private IEnumerable<Object> _sourceObjects;
|
||||||
|
|
||||||
|
private VisualElement _contentOnTop;
|
||||||
|
private VisualElement _contentAfterList;
|
||||||
|
private VisualElement _contentBeforeButton;
|
||||||
|
private VisualElement _contentOnBottom;
|
||||||
|
|
||||||
|
private Func<Object, string, string> onOutput;
|
||||||
|
private Action<string> postOutput;
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
|
||||||
|
/// <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());
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateGUI()
|
||||||
|
{
|
||||||
|
var outputOptionsElement = _visualTreeAsset.Instantiate();
|
||||||
|
|
||||||
|
SetupOutputElements(outputOptionsElement);
|
||||||
|
|
||||||
|
rootVisualElement.Add(outputOptionsElement);
|
||||||
|
rootVisualElement.dataSource = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupOutputElements(VisualElement outPutOptions)
|
||||||
|
{
|
||||||
|
var sourceObjectList = outPutOptions.Q<ListView>("source-object-list");
|
||||||
|
sourceObjectList.makeItem = () => new ObjectField() { enabledSelf = false };
|
||||||
|
sourceObjectList.bindItem = (element, i) =>
|
||||||
|
{
|
||||||
|
var objectField = element as ObjectField;
|
||||||
|
objectField.objectType = typeof(Object);
|
||||||
|
objectField.value = _sourceObjects.ElementAt(i);
|
||||||
|
};
|
||||||
|
|
||||||
|
var directoryTypeEnum = outPutOptions.Q<EnumField>("directory-type-enum");
|
||||||
|
var customPathInput = outPutOptions.Q<TextField>("custom-path-input");
|
||||||
|
|
||||||
|
directoryTypeEnum.RegisterValueChangedCallback((evt) =>
|
||||||
|
{
|
||||||
|
customPathInput.style.display = evt.newValue.Equals(OutputDirectoryType.Custom) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
});
|
||||||
|
|
||||||
|
var outputButton = outPutOptions.Q<Button>("output-button");
|
||||||
|
outputButton.clickable.clicked += () =>
|
||||||
|
{
|
||||||
|
if (_sourceObjects == null)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
var assetsToReload = new HashSet<string>();
|
||||||
|
foreach (var obj in _sourceObjects)
|
||||||
|
{
|
||||||
|
var objectPath = AssetDatabase.GetAssetPath(obj);
|
||||||
|
var outputDirectory = GetOutputDirectory(Path.GetDirectoryName(objectPath));
|
||||||
|
if (!Directory.Exists(outputDirectory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(outputDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
assetsToReload.Add(onOutput?.Invoke(obj, outputDirectory));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var assetPath in assetsToReload)
|
||||||
|
{
|
||||||
|
postOutput?.Invoke(assetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentOnTop = outPutOptions.Q<VisualElement>("content-on-top");
|
||||||
|
_contentAfterList = outPutOptions.Q<VisualElement>("content-after-list");
|
||||||
|
_contentBeforeButton = outPutOptions.Q<VisualElement>("content-before-button");
|
||||||
|
_contentOnBottom = outPutOptions.Q<VisualElement>("content-on-bottom");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetOutputDirectory(string inputDirectory)
|
||||||
|
{
|
||||||
|
switch (_outputOptions.outputDirectoryType)
|
||||||
|
{
|
||||||
|
case OutputDirectoryType.CurrentDirectory:
|
||||||
|
return inputDirectory;
|
||||||
|
case OutputDirectoryType.ParentDirectory:
|
||||||
|
return Path.GetDirectoryName(inputDirectory);
|
||||||
|
case OutputDirectoryType.AssetsDirectory:
|
||||||
|
return "Assets";
|
||||||
|
case OutputDirectoryType.Custom:
|
||||||
|
if (Path.IsPathRooted(_outputOptions.customPath))
|
||||||
|
{
|
||||||
|
return _outputOptions.customPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Path.Combine(inputDirectory, _outputOptions.customPath);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return inputDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 79f83b25ad98e2243b415d8c150e11ee
|
guid: 29f3e54f493766149b280d2753bca2af
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences:
|
defaultReferences:
|
||||||
- m_VisualTreeAsset: {fileID: 9197481963319205126, guid: 020261090ef91d340a65b9baca11a43f,
|
- m_ViewDataDictionary: {instanceID: 0}
|
||||||
|
- _visualTreeAsset: {fileID: 9197481963319205126, guid: 0413a47b12d366049baaf9a7e4b20fb7,
|
||||||
type: 3}
|
type: 3}
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {instanceID: 0}
|
icon: {instanceID: 0}
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using Unity.Properties;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UIElements;
|
|
||||||
|
|
||||||
namespace Misaki.ArtToolEditor
|
|
||||||
{
|
|
||||||
public class MaterialHelpers : EditorWindow
|
|
||||||
{
|
|
||||||
[SerializeField]
|
|
||||||
private VisualTreeAsset m_VisualTreeAsset = default;
|
|
||||||
|
|
||||||
[CreateProperty(ReadOnly = true)]
|
|
||||||
public MaterialHelpersViewModel ViewModel
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
} = new();
|
|
||||||
|
|
||||||
[MenuItem("Tools/Material Helpers")]
|
|
||||||
public static void ShowExample()
|
|
||||||
{
|
|
||||||
var wnd = GetWindow<MaterialHelpers>();
|
|
||||||
wnd.titleContent = new GUIContent("Material Helpers");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateGUI()
|
|
||||||
{
|
|
||||||
var root = rootVisualElement;
|
|
||||||
|
|
||||||
var visualTree = m_VisualTreeAsset.Instantiate();
|
|
||||||
visualTree.dataSource = this;
|
|
||||||
|
|
||||||
root.Add(visualTree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
.unity-tab {
|
|
||||||
padding-top: 8px;
|
|
||||||
padding-right: 4px;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
padding-left: 4px;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 1bb19503bd1a80846a65ad378af88be0
|
|
||||||
ScriptedImporter:
|
|
||||||
internalIDToNameTable: []
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
disableValidation: 0
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
|
||||||
<Style src="project://database/Packages/com.misaki.art-tools/Editor/MaterialHelpers/MaterialHelpers.uss?fileID=7433441132597879392&guid=1bb19503bd1a80846a65ad378af88be0&type=3#MaterialHelpers" />
|
|
||||||
<engine:Label text="Material Helper" style="font-size: 16px; -unity-text-align: upper-center; margin-top: 16px; margin-bottom: 8px; -unity-font-style: bold;" />
|
|
||||||
<engine:VisualElement data-source-type="Misaki.ArtToolEditor.MaterialHelpers, Misaki.ArtTool.Editor" style="flex-grow: 1; padding-top: 8px; padding-right: 8px; padding-bottom: 8px; padding-left: 8px;">
|
|
||||||
<engine:TabView>
|
|
||||||
<engine:Tab label="Create">
|
|
||||||
<Misaki.UIToolkit.Controls.GroupPresenter header-text="Create From Selection">
|
|
||||||
<engine:TextField label="Selection Count" placeholder-text="0" enabled="false">
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="value" data-source-path="ViewModel.CurrentSelectionCount" binding-mode="ToTarget" update-trigger="OnSourceChanged" />
|
|
||||||
</Bindings>
|
|
||||||
</engine:TextField>
|
|
||||||
<engine:EnumField label="Output Directory" value="Center" type="Misaki.ArtToolEditor.OutputDirectoryType, Misaki.ArtTool.Editor">
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="value" data-source-path="ViewModel.OutputDirectoryType" binding-mode="TwoWay" />
|
|
||||||
</Bindings>
|
|
||||||
</engine:EnumField>
|
|
||||||
<Misaki.UIToolkit.Controls.SwitchPresenter>
|
|
||||||
<engine:VisualElement style="flex-grow: 1;" />
|
|
||||||
<engine:VisualElement style="flex-grow: 1;" />
|
|
||||||
<engine:VisualElement style="flex-grow: 1;" />
|
|
||||||
<engine:TextField label="Custom Path" placeholder-text="path">
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="value" data-source-path="ViewModel.CustomPath" binding-mode="TwoWay" />
|
|
||||||
</Bindings>
|
|
||||||
</engine:TextField>
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="value" data-source-path="ViewModel.OutputDirectoryTypeIndex" binding-mode="ToTarget" />
|
|
||||||
</Bindings>
|
|
||||||
</Misaki.UIToolkit.Controls.SwitchPresenter>
|
|
||||||
<Misaki.UIToolkit.Controls.BindableButton text="Create Decal">
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="Command" data-source-path="ViewModel.CreateDecalCommand" binding-mode="ToTarget" />
|
|
||||||
</Bindings>
|
|
||||||
</Misaki.UIToolkit.Controls.BindableButton>
|
|
||||||
<Misaki.UIToolkit.Controls.BindableButton text="Create Terrain Layer">
|
|
||||||
<Bindings>
|
|
||||||
<engine:DataBinding property="Command" data-source-path="ViewModel.CreateTerrainLayerCommand" binding-mode="ToTarget" />
|
|
||||||
</Bindings>
|
|
||||||
</Misaki.UIToolkit.Controls.BindableButton>
|
|
||||||
</Misaki.UIToolkit.Controls.GroupPresenter>
|
|
||||||
</engine:Tab>
|
|
||||||
<engine:Tab label="Tab" />
|
|
||||||
</engine:TabView>
|
|
||||||
</engine:VisualElement>
|
|
||||||
</engine:UXML>
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
using Misaki.UIToolkit.Mvvm;
|
|
||||||
using System.IO;
|
|
||||||
using Unity.Properties;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Rendering.HighDefinition;
|
|
||||||
|
|
||||||
namespace Misaki.ArtToolEditor
|
|
||||||
{
|
|
||||||
public partial class MaterialHelpersViewModel : ObservableObject
|
|
||||||
{
|
|
||||||
private static class ShaderPath
|
|
||||||
{
|
|
||||||
public const string DECAL_SHADER_PATH = "HDRP/Decal";
|
|
||||||
}
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private OutputDirectoryType outputDirectoryType;
|
|
||||||
[ObservableProperty]
|
|
||||||
private string customPath = "Assets";
|
|
||||||
|
|
||||||
[CreateProperty(ReadOnly = true)]
|
|
||||||
public int CurrentSelectionCount
|
|
||||||
{
|
|
||||||
get => Selection.objects.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CreateProperty(ReadOnly = true)]
|
|
||||||
public int OutputDirectoryTypeIndex
|
|
||||||
{
|
|
||||||
get => (int)outputDirectoryType;
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private void CreateDecal()
|
|
||||||
{
|
|
||||||
if (CurrentSelectionCount == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var selectedObject in Selection.objects)
|
|
||||||
{
|
|
||||||
if (selectedObject is not Material mat)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var materialPath = AssetDatabase.GetAssetPath(mat);
|
|
||||||
var outputPath = Path.Combine(GetOutputDirectory(Path.GetDirectoryName(materialPath)), mat.name + ".prefab");
|
|
||||||
var decal = AssetCreationHelpers.CreateDecal(GetOutputDirectory(outputPath));
|
|
||||||
|
|
||||||
mat.shader = Shader.Find(ShaderPath.DECAL_SHADER_PATH);
|
|
||||||
decal.transform.rotation = Quaternion.Euler(90, 0, 0);
|
|
||||||
decal.GetComponent<DecalProjector>().material = mat;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetDatabase.Refresh();
|
|
||||||
AssetDatabase.SaveAssets();
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private void CreateTerrainLayer()
|
|
||||||
{
|
|
||||||
if (CurrentSelectionCount == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var selectedObject in Selection.objects)
|
|
||||||
{
|
|
||||||
if (selectedObject is not Material mat)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var terrainLayer = new TerrainLayer()
|
|
||||||
{
|
|
||||||
diffuseTexture = mat.GetTexture("_BaseColorMap") as Texture2D,
|
|
||||||
normalMapTexture = mat.GetTexture("_NormalMap") as Texture2D,
|
|
||||||
maskMapTexture = mat.GetTexture("_MaskMap") as Texture2D,
|
|
||||||
};
|
|
||||||
|
|
||||||
var materialPath = AssetDatabase.GetAssetPath(mat);
|
|
||||||
var outputPath = Path.Combine(GetOutputDirectory(Path.GetDirectoryName(materialPath)), mat.name + ".terrainlayer");
|
|
||||||
AssetDatabase.CreateAsset(terrainLayer, GetOutputDirectory(outputPath));
|
|
||||||
}
|
|
||||||
AssetDatabase.Refresh();
|
|
||||||
AssetDatabase.SaveAssets();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetOutputDirectory(string inputDirectory)
|
|
||||||
{
|
|
||||||
switch (outputDirectoryType)
|
|
||||||
{
|
|
||||||
case OutputDirectoryType.CurrentDirectory:
|
|
||||||
return inputDirectory;
|
|
||||||
case OutputDirectoryType.ParentDirectory:
|
|
||||||
return Path.GetDirectoryName(inputDirectory);
|
|
||||||
case OutputDirectoryType.AssetsDirectory:
|
|
||||||
return "Assets";
|
|
||||||
case OutputDirectoryType.Custom:
|
|
||||||
if (Path.IsPathRooted(customPath))
|
|
||||||
{
|
|
||||||
return customPath;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Path.Combine(inputDirectory, customPath);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return inputDirectory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9ed350f58e4bd2642a9bc2bf8e161c61
|
|
||||||
@@ -5,8 +5,7 @@
|
|||||||
"GUID:343deaaf83e0cee4ca978e7df0b80d21",
|
"GUID:343deaaf83e0cee4ca978e7df0b80d21",
|
||||||
"GUID:a493da6e3ffa3d7499a58f3900cffca1",
|
"GUID:a493da6e3ffa3d7499a58f3900cffca1",
|
||||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
"GUID:d8b63aba1907145bea998dd612889d6b",
|
||||||
"GUID:457756d89b35d2941b3e7b37b4ece6f1",
|
"GUID:457756d89b35d2941b3e7b37b4ece6f1"
|
||||||
"GUID:fa3ea5a3e645a334aa5fed5e9645a5d4"
|
|
||||||
],
|
],
|
||||||
"includePlatforms": [
|
"includePlatforms": [
|
||||||
"Editor"
|
"Editor"
|
||||||
|
|||||||
8
Editor/SettingProvider.meta
Normal file
8
Editor/SettingProvider.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cb807afc71d387746931b1fd297626c8
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
23
Editor/SettingProvider/ArtToolsSettings.cs
Normal file
23
Editor/SettingProvider/ArtToolsSettings.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace Misaki.ArtToolEditor
|
||||||
|
{
|
||||||
|
[FilePath("ProjectSettings/ArtToolsSettings.asset", FilePathAttribute.Location.ProjectFolder)]
|
||||||
|
internal class ArtToolsSettings : ScriptableSingleton<ArtToolsSettings>
|
||||||
|
{
|
||||||
|
internal SerializedObject GetSerializedObject()
|
||||||
|
{
|
||||||
|
return new SerializedObject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Save()
|
||||||
|
{
|
||||||
|
Save(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/SettingProvider/ArtToolsSettings.cs.meta
Normal file
2
Editor/SettingProvider/ArtToolsSettings.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bf481249c6daba5458a7ee8fda5c632b
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "com.misaki.art-tools",
|
"name": "com.misaki.art-tools",
|
||||||
"version": "1.0.0",
|
"version": "1.1.3",
|
||||||
"displayName": "Art Tools",
|
"displayName": "Art Tools",
|
||||||
"description": "A set of tools that can speed up art workflow",
|
"description": "A set of tools that can speed up art workflow",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -14,8 +14,5 @@
|
|||||||
"name": "Misaki",
|
"name": "Misaki",
|
||||||
"email": "misaki_39@outlook.com",
|
"email": "misaki_39@outlook.com",
|
||||||
"url": "https://github.com/misakieku"
|
"url": "https://github.com/misakieku"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"com.misaki.ui-element-toolkit": "1.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user