346 lines
15 KiB
C#
346 lines
15 KiB
C#
using FIMSpace.FEditor;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace FIMSpace.FTextureTools
|
|
{
|
|
public class FTexEqualizeWindow : FTextureProcessWindow
|
|
{
|
|
private float Equalize = 0.5f;
|
|
private float EqualizeWhites = 1f;
|
|
private float EqualizeBlacks = 1f;
|
|
private float EqualizeTexture = 0f;
|
|
|
|
bool MaskingMode = false;
|
|
Texture2D TexturizeWith;
|
|
Color MaskingColor = Color.white;
|
|
bool TexturizeReadable = false;
|
|
float TexturizeTiling = 1f;
|
|
|
|
AnimationCurve WhitesIntensity = AnimationCurve.EaseInOut(0f, 1f, 1f, 1f);
|
|
AnimationCurve ShadowsIntensity = AnimationCurve.EaseInOut(0f, 1f, 1f, 1f);
|
|
|
|
Texture2D texturizeMemo = null;
|
|
EMaskExport maskExport = EMaskExport.None;
|
|
|
|
public static void Init()
|
|
{
|
|
FTexEqualizeWindow window = (FTexEqualizeWindow)GetWindow(typeof(FTexEqualizeWindow));
|
|
window.titleContent = new GUIContent("Texure Equalize", FTextureToolsGUIUtilities.FindIcon("SPR_EqualizerGen"), "Tweak too bright or too dark parts of your texture");
|
|
window.previewScale = FEPreview.m_1x1;
|
|
window.drawPreviewScale = true;
|
|
|
|
window.position = new Rect(340, 50, 585, 630);
|
|
window.Show();
|
|
called = true;
|
|
}
|
|
|
|
|
|
protected override void OnGUICustom()
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
GUI.backgroundColor = new Color(0.6f, 1f, 0.7f);
|
|
Equalize = EditorGUILayout.Slider(new GUIContent("Equalize Amount"), Equalize, 0.0f, 1f);
|
|
GUI.backgroundColor = Color.white;
|
|
GUILayout.Space(8);
|
|
|
|
EditorGUI.indentLevel++;
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUIUtility.labelWidth = 0;
|
|
EqualizeWhites = EditorGUILayout.Slider(new GUIContent("Whites"), EqualizeWhites, 0f, 2f, GUILayout.MaxWidth(position.width - 60));
|
|
EditorGUIUtility.labelWidth = 5;
|
|
WhitesIntensity = EditorGUILayout.CurveField(new GUIContent(" ", "Whites mapping power intensity control basing on the pixel brightness. X = brightness value -> 0 is black 1 is white, Y = highlights intensity blend from 0 to 1"), WhitesIntensity, Color.cyan, new Rect(0f, 0, 1f, 1f), GUILayout.Width(44));
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUIUtility.labelWidth = 0;
|
|
EqualizeBlacks = EditorGUILayout.Slider(new GUIContent("Shadows"), EqualizeBlacks, 0f, 2f, GUILayout.MaxWidth(position.width - 60));
|
|
EditorGUIUtility.labelWidth = 5;
|
|
ShadowsIntensity = EditorGUILayout.CurveField(new GUIContent(" ", "shadows mapping power intensity control basing on the pixel brightness. X = brightness value -> 0 is black 1 is white, Y = shadows intensity blend from 0 to 1"), ShadowsIntensity, Color.gray, new Rect(0f, 0, 1f, 1f), GUILayout.Width(44));
|
|
EditorGUIUtility.labelWidth = 0;
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
GUILayout.Space(8);
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
MaskingMode = EditorGUILayout.Toggle(new GUIContent("Masking Mode:", "Using single color to replace target texture areas, which can be useful when generating masks for shaders."), MaskingMode);
|
|
|
|
if (MaskingMode)
|
|
{
|
|
MaskingColor = EditorGUILayout.ColorField("Masking Color", MaskingColor);
|
|
|
|
if (GUILayout.Button(new GUIContent(" Export", FTextureToolsGUIUtilities.FindIcon("SPR_GrayscaleS"), "Export mask as grayscale .png file"), GUILayout.MaxWidth(70)))
|
|
{
|
|
Texture2D newFile = GenerateExtraFile();
|
|
if (newFile != null)
|
|
{
|
|
maskExport = EMaskExport.Grayscale;
|
|
ApplyTexProcessToFile(newFile);
|
|
}
|
|
}
|
|
|
|
if (GUILayout.Button(new GUIContent(" Export", FTextureToolsGUIUtilities.FindIcon("SPR_rgbscale"), "Export mask as color channel .png file"), GUILayout.MaxWidth(70)))
|
|
{
|
|
Texture2D newFile = GenerateExtraFile();
|
|
if (newFile != null)
|
|
{
|
|
maskExport = EMaskExport.Color;
|
|
ApplyTexProcessToFile(newFile);
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
else
|
|
{
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
GUI.backgroundColor = new Color(0.6f, 1f, 0.6f, 1f);
|
|
EqualizeTexture = EditorGUILayout.Slider(new GUIContent("Texturize Blend:"), EqualizeTexture, 0f, 1f);
|
|
GUI.backgroundColor = Color.white;
|
|
|
|
TexturizeReadable = false;
|
|
if (EqualizeTexture > 0f)
|
|
{
|
|
EditorGUILayout.HelpBox("Texture should be tileable in order to paint mask without seams.", MessageType.None);
|
|
|
|
TexturizeWith = (Texture2D)EditorGUILayout.ObjectField(new GUIContent("Texturize (Optional)"), TexturizeWith, typeof(Texture2D), false, GUILayout.Height(40));
|
|
|
|
seed = EditorGUILayout.IntSlider(new GUIContent(" Seed", FTextureToolsGUIUtilities.FindIcon("FRandomIcon")), seed, -50, 50);
|
|
|
|
if (TexturizeWith != null)
|
|
{
|
|
string path = AssetDatabase.GetAssetPath(TexturizeWith);
|
|
TextureImporter tImp = (TextureImporter)AssetImporter.GetAtPath(path);
|
|
if (tImp is null == false)
|
|
{
|
|
TexturizeReadable = tImp.isReadable;
|
|
|
|
GUILayout.Space(4);
|
|
EditorGUILayout.BeginHorizontal();
|
|
GUILayout.Space(32);
|
|
if (tImp.isReadable == false) GUI.backgroundColor = Color.green;
|
|
if (GUILayout.Button("Switch readonly for '" + TexturizeWith.name + "' to " + (!tImp.isReadable).ToString()))
|
|
{
|
|
tImp.isReadable = !tImp.isReadable;
|
|
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
|
|
TexturizeReadable = tImp.isReadable;
|
|
}
|
|
GUI.backgroundColor = Color.white;
|
|
GUILayout.Space(32);
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
GUILayout.Space(5);
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
float highRange = TexturizeTiling > 4f ? 16f : 4.001f;
|
|
TexturizeTiling = EditorGUILayout.Slider("Texturize Tiling:", TexturizeTiling, 0.05f, highRange);
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
Texture2D srcTex = GetFirstTexture;
|
|
if (srcTex) if (TexturizeWith.width != srcTex.width)
|
|
{
|
|
EditorGUILayout.HelpBox("Texture sizes differs, preview can look different than final file result!", MessageType.None);
|
|
}
|
|
}
|
|
|
|
if (TexturizeReadable == false)
|
|
EditorGUILayout.HelpBox("Texture must have 'Read/Write' enabled", MessageType.Warning);
|
|
}
|
|
else
|
|
TexturizeReadable = false;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
maskExport = EMaskExport.None;
|
|
|
|
EditorGUI.indentLevel--;
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
somethingChanged = true;
|
|
else
|
|
somethingChanged = false;
|
|
}
|
|
|
|
|
|
protected override void ProcessTexture(Texture2D source, Texture2D target, bool preview = true)
|
|
{
|
|
if (!preview) EditorUtility.DisplayProgressBar("Equalizing Texture...", "Preparing... ", 2f / 5f);
|
|
|
|
#region Preparing variables to use down below
|
|
|
|
Color32[] sourcePixels = source.GetPixels32();
|
|
Color32[] newPixels = source.GetPixels32();
|
|
|
|
Color32[] texturizePixels = sourcePixels;
|
|
Texture2D texturizeSource = source;
|
|
|
|
if (MaskingMode)
|
|
{
|
|
texturizePixels = texturizeSource.GetPixels32();
|
|
for (int i = 0; i < texturizePixels.Length; i++) texturizePixels[i] = (Color32)MaskingColor;
|
|
}
|
|
else
|
|
{
|
|
if (TexturizeWith != null) if (TexturizeReadable)
|
|
{
|
|
int targetWidth = Mathf.RoundToInt(source.width / TexturizeTiling);
|
|
int targetHeight = Mathf.RoundToInt(source.height / TexturizeTiling);
|
|
if (targetWidth < 1) targetWidth = 1;
|
|
if (targetHeight < 1) targetHeight = 1;
|
|
|
|
|
|
if (texturizeMemo == null || texturizeMemo.width != targetWidth || texturizeMemo.height != targetHeight)
|
|
{
|
|
texturizeMemo = FTextureEditorToolsMethods.GenerateScaledTexture2DReference(TexturizeWith, new Vector2(targetWidth, targetHeight), preview ? 2 : 4);
|
|
}
|
|
|
|
texturizeSource = texturizeMemo;
|
|
texturizePixels = texturizeSource.GetPixels32();
|
|
}
|
|
}
|
|
|
|
|
|
if (source.width != target.width || source.height != target.height)
|
|
{
|
|
Debug.LogError("[SEAMLESS GENERATOR] Source texture is different scale or target texture! Can't create seamless texture!");
|
|
return;
|
|
}
|
|
|
|
Vector2 dimensions = GetDimensions(source);
|
|
|
|
#endregion
|
|
|
|
|
|
#region Equalizing Texture
|
|
|
|
if (!preview)
|
|
EditorUtility.DisplayProgressBar("Equalizing...", "Equalizing... ", 3f / 5f);
|
|
|
|
|
|
Vector3 rgbAverages = new Vector3(0.0f, 0.0f, 0.0f);
|
|
Vector3 hsvAverages = new Vector3(0.0f, 0.0f, 0.0f);
|
|
Vector2 dim = new Vector2(source.width, source.height);
|
|
|
|
for (int x = 0; x < source.width; x++)
|
|
{
|
|
for (int y = 0; y < source.height; y++)
|
|
{
|
|
int px = GetPX(x, y, dim);
|
|
Color c = sourcePixels[px];
|
|
rgbAverages.x += c.r;
|
|
rgbAverages.y += c.g;
|
|
rgbAverages.z += c.b;
|
|
|
|
float h, s, v;
|
|
Color.RGBToHSV(sourcePixels[px], out h, out s, out v);
|
|
hsvAverages.x += h;
|
|
hsvAverages.y += s;
|
|
hsvAverages.z += v;
|
|
}
|
|
}
|
|
|
|
float norm = source.width * source.height;
|
|
Vector3 rgbAveragesN = rgbAverages / norm;
|
|
Vector3 hsvAveragesN = hsvAverages / norm;
|
|
|
|
float highestVDiff = 0f;
|
|
for (int x = 0; x < source.width; x++)
|
|
{
|
|
for (int y = 0; y < source.height; y++)
|
|
{
|
|
int px = GetPX(x, y, dim);
|
|
|
|
float h, s, v;
|
|
Color.RGBToHSV(sourcePixels[px], out h, out s, out v);
|
|
hsvAverages.x += h;
|
|
hsvAverages.y += s;
|
|
hsvAverages.z += v;
|
|
|
|
float diff = Mathf.Abs(v - hsvAveragesN.z);
|
|
if (diff > highestVDiff) highestVDiff = diff;
|
|
}
|
|
}
|
|
|
|
|
|
Color avgHsvCol = Color.HSVToRGB(hsvAveragesN.x, hsvAveragesN.y, hsvAveragesN.z);
|
|
int randX = RandomRange(texturizeSource.width / 2, texturizeSource.width / 2 + (RandomRange(0f, 1f) < 0.5f ? texturizeSource.width / 3 : -source.width / 3));
|
|
int randY = RandomRange(texturizeSource.height / 2, texturizeSource.height / 2 + (RandomRange(0f, 1f) < 0.5f ? texturizeSource.height / 3 : -source.height / 3));
|
|
|
|
for (int x = 0; x < source.width; x++)
|
|
{
|
|
for (int y = 0; y < source.height; y++)
|
|
{
|
|
int px = GetPX(x, y, dim);
|
|
Color srcPixel = sourcePixels[px];
|
|
float h, s, v;
|
|
Color.RGBToHSV(srcPixel, out h, out s, out v);
|
|
float vDiff = v - hsvAveragesN.z;
|
|
float diffTexBase = Mathf.Abs(v - hsvAveragesN.z);
|
|
|
|
if (vDiff > 0)
|
|
{
|
|
// Whites lower then less changed
|
|
vDiff *= WhitesIntensity.Evaluate(vDiff) * EqualizeWhites;
|
|
}
|
|
else
|
|
if (vDiff < 0)
|
|
{
|
|
// Blacks lower then less changed
|
|
vDiff *= ShadowsIntensity.Evaluate(1f - Mathf.Abs(vDiff)) * EqualizeBlacks;
|
|
}
|
|
|
|
float lerpV = Mathf.Abs(vDiff) / highestVDiff;
|
|
float tgtV = Mathf.LerpUnclamped(v, hsvAveragesN.z, lerpV);
|
|
Color tgtColor = Color.HSVToRGB(h, s, tgtV);
|
|
|
|
if (MaskingMode)
|
|
{
|
|
if (maskExport == EMaskExport.None)
|
|
{
|
|
Color offsetRefColor = texturizePixels[GetPXLoopSkipEdges(randX + x, randY + y, new Vector2(texturizeSource.width, texturizeSource.height))];
|
|
tgtColor = Color.Lerp(tgtColor, offsetRefColor, lerpV * 2f);
|
|
}
|
|
else if (maskExport == EMaskExport.Color)
|
|
{
|
|
tgtColor = Color.Lerp(Color.black, MaskingColor, lerpV * 2f);
|
|
}
|
|
else if (maskExport == EMaskExport.Grayscale)
|
|
{
|
|
tgtColor = Color.Lerp(Color.black, Color.white, lerpV * 2f);
|
|
}
|
|
}
|
|
else if (EqualizeTexture > 0f)
|
|
{
|
|
Color offsetRefColor = texturizePixels[GetPXLoopSkipEdges(randX + x, randY + y, new Vector2(texturizeSource.width, texturizeSource.height))];
|
|
tgtColor = Color.Lerp(tgtColor, offsetRefColor, lerpV * 2f * EqualizeTexture);
|
|
}
|
|
|
|
tgtColor.a = srcPixel.a;
|
|
newPixels[px] = Color32.LerpUnclamped(sourcePixels[px], tgtColor, Equalize);
|
|
}
|
|
}
|
|
|
|
maskExport = EMaskExport.None;
|
|
|
|
#endregion
|
|
|
|
|
|
// Finalizing changes
|
|
if (!preview) EditorUtility.DisplayProgressBar("Equalizing Texture...", "Applying Equalization to Texture... ", 3.85f / 5f);
|
|
|
|
target.SetPixels32(newPixels);
|
|
target.Apply(false, false);
|
|
|
|
if (!preview)
|
|
EditorUtility.ClearProgressBar();
|
|
|
|
}
|
|
|
|
|
|
}
|
|
} |