texture stitcher (literally psd layers but im lazy)
This commit is contained in:
parent
d8a57c3817
commit
2c3589b408
7 changed files with 249 additions and 0 deletions
8
TextureStitcher.meta
Normal file
8
TextureStitcher.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa7127f4d0f097941933b00115d22660
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
16
TextureStitcher/TextureStitcher.asmdef
Normal file
16
TextureStitcher/TextureStitcher.asmdef
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "TextureStitcher",
|
||||||
|
"rootNamespace": "",
|
||||||
|
"references": [],
|
||||||
|
"includePlatforms": [
|
||||||
|
"Editor"
|
||||||
|
],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
7
TextureStitcher/TextureStitcher.asmdef.meta
Normal file
7
TextureStitcher/TextureStitcher.asmdef.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dd440ea69f98580448e1719b0b71607d
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
129
TextureStitcher/TextureStitcher.cs
Normal file
129
TextureStitcher/TextureStitcher.cs
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace gay.lilyy.TextureStitcher
|
||||||
|
{
|
||||||
|
[CreateAssetMenu(fileName = "TextureStitcherSettings", menuName = "Texture Stitcher/Settings")]
|
||||||
|
public class TextureStitcherSettings : ScriptableObject
|
||||||
|
{
|
||||||
|
public Texture2D[] textures;
|
||||||
|
public string savePath = "Assets/StitchedTexture.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomEditor(typeof(TextureStitcherSettings))]
|
||||||
|
public class TextureStitcherEditor : Editor
|
||||||
|
{
|
||||||
|
private SerializedProperty texturesProp;
|
||||||
|
private SerializedProperty savePathProp;
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
texturesProp = serializedObject.FindProperty("textures");
|
||||||
|
savePathProp = serializedObject.FindProperty("savePath");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
serializedObject.Update();
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField("Texture Layers (Top → Bottom)", EditorStyles.boldLabel);
|
||||||
|
EditorGUILayout.PropertyField(savePathProp);
|
||||||
|
|
||||||
|
DrawReversedArray(texturesProp);
|
||||||
|
|
||||||
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
if (GUILayout.Button("Generate Stitched Texture"))
|
||||||
|
GenerateStitchedTexture();
|
||||||
|
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawReversedArray(SerializedProperty array)
|
||||||
|
{
|
||||||
|
if (!array.isArray)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Draw size field (normal Unity behavior)
|
||||||
|
EditorGUILayout.PropertyField(array.FindPropertyRelative("Array.size"));
|
||||||
|
|
||||||
|
// Reverse array in-place
|
||||||
|
int count = array.arraySize;
|
||||||
|
for (int i = 0; i < count / 2; i++)
|
||||||
|
array.MoveArrayElement(i, count - 1 - i);
|
||||||
|
|
||||||
|
// Draw array normally
|
||||||
|
EditorGUILayout.PropertyField(array, GUIContent.none, true);
|
||||||
|
|
||||||
|
// Restore original order
|
||||||
|
for (int i = 0; i < count / 2; i++)
|
||||||
|
array.MoveArrayElement(i, count - 1 - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateStitchedTexture()
|
||||||
|
{
|
||||||
|
TextureStitcherSettings settings = (TextureStitcherSettings)target;
|
||||||
|
GenerateStitchedTexture(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void GenerateStitchedTexture(TextureStitcherSettings settings)
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
|
||||||
|
foreach (var tex in settings.textures)
|
||||||
|
{
|
||||||
|
if (!tex) continue;
|
||||||
|
width = Mathf.Max(width, tex.width);
|
||||||
|
height = Mathf.Max(height, tex.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D output = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||||
|
Color[] pixels = new Color[width * height];
|
||||||
|
for (int i = 0; i < pixels.Length; i++) pixels[i] = Color.clear;
|
||||||
|
|
||||||
|
output.SetPixels(pixels);
|
||||||
|
|
||||||
|
// Bottom → top
|
||||||
|
for (int i = 0; i < settings.textures.Length; i++)
|
||||||
|
{
|
||||||
|
var tex = settings.textures[i];
|
||||||
|
if (!tex) continue;
|
||||||
|
|
||||||
|
Texture2D resized = Resize(tex, width, height);
|
||||||
|
Color[] src = resized.GetPixels();
|
||||||
|
Color[] dst = output.GetPixels();
|
||||||
|
|
||||||
|
for (int p = 0; p < dst.Length; p++)
|
||||||
|
{
|
||||||
|
Color s = src[p];
|
||||||
|
dst[p] = Color.Lerp(dst[p], s, s.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.SetPixels(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Apply();
|
||||||
|
File.WriteAllBytes(settings.savePath, output.EncodeToPNG());
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
|
||||||
|
Debug.Log("Stitched texture saved to " + settings.savePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Texture2D Resize(Texture2D src, int width, int height)
|
||||||
|
{
|
||||||
|
RenderTexture rt = RenderTexture.GetTemporary(width, height, 0);
|
||||||
|
Graphics.Blit(src, rt);
|
||||||
|
|
||||||
|
RenderTexture.active = rt;
|
||||||
|
Texture2D result = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||||
|
result.ReadPixels(new Rect(0, 0, width, height), 0, 0);
|
||||||
|
result.Apply();
|
||||||
|
|
||||||
|
RenderTexture.active = null;
|
||||||
|
RenderTexture.ReleaseTemporary(rt);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
TextureStitcher/TextureStitcher.cs.meta
Normal file
11
TextureStitcher/TextureStitcher.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7ebbfd7bebbeb0748bb1bf5a9191377f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
67
TextureStitcher/TextureStitcherAutoRegen.cs
Normal file
67
TextureStitcher/TextureStitcherAutoRegen.cs
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace gay.lilyy.TextureStitcher
|
||||||
|
{
|
||||||
|
public class TextureStitcherAutoRegen : AssetPostprocessor
|
||||||
|
{
|
||||||
|
private const string MenuPath = "LillithRosePup/Import Regens/Texture Stitcher";
|
||||||
|
private const string PrefKey = "TextureStitcher.AutoRegen";
|
||||||
|
|
||||||
|
[MenuItem(MenuPath)]
|
||||||
|
private static void Toggle()
|
||||||
|
{
|
||||||
|
bool enabled = !EditorPrefs.GetBool(PrefKey, true);
|
||||||
|
EditorPrefs.SetBool(PrefKey, enabled);
|
||||||
|
Menu.SetChecked(MenuPath, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem(MenuPath, true)]
|
||||||
|
private static bool ToggleValidate()
|
||||||
|
{
|
||||||
|
Menu.SetChecked(MenuPath, EditorPrefs.GetBool(PrefKey, true));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsEnabled()
|
||||||
|
{
|
||||||
|
return EditorPrefs.GetBool(PrefKey, true);
|
||||||
|
}
|
||||||
|
static void OnPostprocessAllAssets(
|
||||||
|
string[] importedAssets,
|
||||||
|
string[] deletedAssets,
|
||||||
|
string[] movedAssets,
|
||||||
|
string[] movedFromAssetPaths)
|
||||||
|
{
|
||||||
|
if (!IsEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (importedAssets.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var stitchers = AssetDatabase
|
||||||
|
.FindAssets("t:TextureStitcherSettings")
|
||||||
|
.Select(guid =>
|
||||||
|
AssetDatabase.LoadAssetAtPath<TextureStitcherSettings>(
|
||||||
|
AssetDatabase.GUIDToAssetPath(guid)))
|
||||||
|
.Where(s => s && s.textures != null && s.textures.Length > 0)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (stitchers.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (string path in importedAssets)
|
||||||
|
{
|
||||||
|
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
|
||||||
|
if (!tex) continue;
|
||||||
|
|
||||||
|
foreach (var stitcher in stitchers)
|
||||||
|
{
|
||||||
|
if (stitcher.textures.Contains(tex))
|
||||||
|
TextureStitcherEditor.GenerateStitchedTexture(stitcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
TextureStitcher/TextureStitcherAutoRegen.cs.meta
Normal file
11
TextureStitcher/TextureStitcherAutoRegen.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f4211ffa1dc66ca43af9c753c61933c1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Loading…
Add table
Add a link
Reference in a new issue