From fb26b02a20ef751cdd1832abc925b5e57bb2234b Mon Sep 17 00:00:00 2001 From: yum Date: Sat, 1 Feb 2025 19:15:58 -0800 Subject: Implement surface stable fractal dithering --- Editor/stack_2d_noise_to_3d.cs | 120 +++++++++++++++++++++++++++++++++++++++++ Editor/tooner.cs | 28 ++++++++++ 2 files changed, 148 insertions(+) create mode 100644 Editor/stack_2d_noise_to_3d.cs (limited to 'Editor') diff --git a/Editor/stack_2d_noise_to_3d.cs b/Editor/stack_2d_noise_to_3d.cs new file mode 100644 index 0000000..adc2773 --- /dev/null +++ b/Editor/stack_2d_noise_to_3d.cs @@ -0,0 +1,120 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; + +public class ImageSequenceToTexture3D : EditorWindow +{ + private List sourceImages = new List(); + private string textureName = "Texture3DFromSequence"; + private FilterMode filterMode = FilterMode.Bilinear; + private TextureWrapMode wrapMode = TextureWrapMode.Repeat; + + [MenuItem("Tools/yum_food/Image Sequence to Texture3D")] + public static void ShowWindow() + { + GetWindow("Image Sequence to Texture3D"); + } + + private void OnGUI() + { + GUILayout.Label("Image Sequence to Texture3D Converter", EditorStyles.boldLabel); + EditorGUILayout.HelpBox("Add images in the order they should appear in the Z-axis", MessageType.Info); + + // Image sequence management + EditorGUILayout.LabelField("Source Images", EditorStyles.boldLabel); + for (int i = 0; i < sourceImages.Count; i++) + { + EditorGUILayout.BeginHorizontal(); + sourceImages[i] = (Texture2D)EditorGUILayout.ObjectField($"Slice {i}", sourceImages[i], typeof(Texture2D), false); + if (GUILayout.Button("Remove", GUILayout.Width(60))) + { + sourceImages.RemoveAt(i); + GUILayout.EndHorizontal(); + break; + } + EditorGUILayout.EndHorizontal(); + } + + if (GUILayout.Button("Add Image Slot")) + { + sourceImages.Add(null); + } + + textureName = EditorGUILayout.TextField("Texture Name", textureName); + filterMode = (FilterMode)EditorGUILayout.EnumPopup("Filter Mode", filterMode); + wrapMode = (TextureWrapMode)EditorGUILayout.EnumPopup("Wrap Mode", wrapMode); + + if (GUILayout.Button("Generate 3D Texture")) + { + if (ValidateInputs()) + { + Generate3DTexture(); + } + } + } + + private bool ValidateInputs() + { + if (sourceImages.Count == 0) + { + EditorUtility.DisplayDialog("Error", "Please add at least one image.", "OK"); + return false; + } + + if (sourceImages.Contains(null)) + { + EditorUtility.DisplayDialog("Error", "Please assign all image slots.", "OK"); + return false; + } + + // Verify all images have the same dimensions + int width = sourceImages[0].width; + int height = sourceImages[0].height; + + for (int i = 1; i < sourceImages.Count; i++) + { + if (sourceImages[i].width != width || sourceImages[i].height != height) + { + EditorUtility.DisplayDialog("Error", + $"All images must have the same dimensions. Expected {width}x{height}, but image {i} is {sourceImages[i].width}x{sourceImages[i].height}", + "OK"); + return false; + } + } + + return true; + } + + private void Generate3DTexture() + { + int width = sourceImages[0].width; + int height = sourceImages[0].height; + int depth = sourceImages.Count; + + // Create the 3D texture + Texture3D texture3D = new Texture3D(width, height, depth, TextureFormat.RGBA32, false); + texture3D.filterMode = filterMode; + texture3D.wrapMode = wrapMode; + + // Prepare the color array + Color[] colors = new Color[width * height * depth]; + + // Copy the pixel data from each source image + for (int z = 0; z < depth; z++) + { + Color[] imageColors = sourceImages[z].GetPixels(); + System.Array.Copy(imageColors, 0, colors, z * width * height, width * height); + } + + texture3D.SetPixels(colors); + texture3D.Apply(); + + // Save the texture asset + string path = $"Assets/{textureName}.asset"; + AssetDatabase.CreateAsset(texture3D, path); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + EditorUtility.DisplayDialog("Success", $"3D texture generated and saved at {path}", "OK"); + } +} diff --git a/Editor/tooner.cs b/Editor/tooner.cs index fab06e0..c7d89d4 100644 --- a/Editor/tooner.cs +++ b/Editor/tooner.cs @@ -3236,6 +3236,33 @@ public class ToonerGUI : ShaderGUI { EditorGUI.indentLevel -= 1; } + void DoSurfaceStableFractalDithering() { + MaterialProperty bc; + + bc = FindProperty("_Surface_Stable_Fractal_Dithering_Enable_Static"); + bool enabled = (bc.floatValue != 0.0); + EditorGUI.BeginChangeCheck(); + enabled = Toggle("Stable fractal dithering", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + SetKeyword("_SURFACE_STABLE_FRACTAL_DITHERING", enabled); + + if (!enabled) { + return; + } + + EditorGUI.indentLevel += 1; + + bc = FindProperty("_Surface_Stable_Fractal_Dithering_Noise"); + TexturePropertySingleLine(MakeLabel(bc, "Noise"), bc); + bc = FindProperty("_Surface_Stable_Fractal_Dithering_Scale"); + FloatProperty(bc, "Scale"); + bc = FindProperty("_Surface_Stable_Fractal_Dithering_Max_Fwidth"); + FloatProperty(bc, "Max fwidth"); + + EditorGUI.indentLevel -= 1; + } + void DoGimmicks() { show_ui.Add(AddCollapsibleMenu("Gimmicks", "_Gimmicks")); EditorGUI.indentLevel += 1; @@ -3269,6 +3296,7 @@ public class ToonerGUI : ShaderGUI { DoGeoScroll(); DoGimmickEpilepsyMode(); DoLens00(); + DoSurfaceStableFractalDithering(); EditorGUI.indentLevel -= 1; show_ui.RemoveAt(show_ui.Count - 1); -- cgit v1.2.3