Flatkit 추가 및 설정
This commit is contained in:
326
Assets/FlatKit/[Render Pipeline] URP/Water/Editor/WaterEditor.cs
Normal file
326
Assets/FlatKit/[Render Pipeline] URP/Water/Editor/WaterEditor.cs
Normal file
@@ -0,0 +1,326 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using FlatKit.Water;
|
||||
using FlatKit.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
public class FlatKitWaterEditor : ShaderGUI {
|
||||
private Gradient _gradient;
|
||||
|
||||
private const string RenderingOptionsName = "Rendering Options";
|
||||
private GUIStyle _foldoutStyle;
|
||||
private static readonly Dictionary<string, bool> FoldoutStates =
|
||||
new Dictionary<string, bool> { { RenderingOptionsName, false } };
|
||||
|
||||
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) {
|
||||
Material targetMaterial = materialEditor.target as Material;
|
||||
string[] keywords = targetMaterial.shaderKeywords;
|
||||
|
||||
if (!targetMaterial.IsKeywordEnabled("_COLORMODE_LINEAR") &&
|
||||
!targetMaterial.IsKeywordEnabled("_COLORMODE_GRADIENT_TEXTURE")) {
|
||||
targetMaterial.EnableKeyword("_COLORMODE_LINEAR");
|
||||
}
|
||||
|
||||
bool isColorModeGradient = targetMaterial.IsKeywordEnabled("_COLORMODE_GRADIENT_TEXTURE");
|
||||
|
||||
int originalIntentLevel = EditorGUI.indentLevel;
|
||||
int foldoutRemainingItems = 0;
|
||||
bool latestFoldoutState = false;
|
||||
_foldoutStyle ??= new GUIStyle(EditorStyles.foldout) {
|
||||
fontStyle = FontStyle.Bold,
|
||||
margin = {
|
||||
left = -10
|
||||
},
|
||||
padding = {
|
||||
left = 20
|
||||
},
|
||||
};
|
||||
|
||||
foreach (MaterialProperty property in properties) {
|
||||
bool skipProperty = false;
|
||||
|
||||
if (isColorModeGradient) {
|
||||
skipProperty |= ShowColorGradientExportBox(materialEditor, property);
|
||||
}
|
||||
|
||||
{
|
||||
var brackets = property.displayName.Split('[', ']');
|
||||
foreach (var bracket in brackets) {
|
||||
if (bracket.Contains("FOLDOUT") || !property.displayName.Contains('[' + bracket + ']')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isNegative = bracket.StartsWith("!");
|
||||
bool isPositive = !isNegative;
|
||||
var param = bracket.TrimStart('!');
|
||||
bool keywordOn = Array.IndexOf(keywords, param) != -1;
|
||||
|
||||
if (isPositive && !keywordOn) {
|
||||
skipProperty = true;
|
||||
}
|
||||
|
||||
if (isNegative && keywordOn) {
|
||||
skipProperty = true;
|
||||
}
|
||||
|
||||
if (skipProperty) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Foldouts.
|
||||
{
|
||||
string displayName = property.displayName;
|
||||
if (displayName.Contains("FOLDOUT")) {
|
||||
string foldoutName = displayName.Split('(', ')')[1];
|
||||
string foldoutItemCount = displayName.Split('{', '}')[1];
|
||||
foldoutRemainingItems = Convert.ToInt32(foldoutItemCount);
|
||||
FoldoutStates.TryAdd(property.name, false);
|
||||
EditorGUILayout.Space();
|
||||
FoldoutStates[property.name] =
|
||||
EditorGUILayout.Foldout(FoldoutStates[property.name], foldoutName, true, _foldoutStyle);
|
||||
latestFoldoutState = FoldoutStates[property.name];
|
||||
}
|
||||
|
||||
if (foldoutRemainingItems > 0) {
|
||||
skipProperty = skipProperty || !latestFoldoutState;
|
||||
EditorGUI.indentLevel += 1;
|
||||
--foldoutRemainingItems;
|
||||
}
|
||||
}
|
||||
|
||||
bool hideInInspector = (property.GetShaderPropertyFlags() & ShaderPropertyFlags.HideInInspector) != 0;
|
||||
if (!skipProperty && !hideInInspector) {
|
||||
DrawStandard(materialEditor, property);
|
||||
}
|
||||
|
||||
if (targetMaterial.IsKeywordEnabled("_COLORMODE_GRADIENT_TEXTURE") &&
|
||||
property.GetShaderPropertyType() == ShaderPropertyType.Texture &&
|
||||
property.displayName.StartsWith("[_COLORMODE_GRADIENT_TEXTURE]") &&
|
||||
property.textureValue != null) {
|
||||
GUILayout.Space(-50);
|
||||
using (new EditorGUILayout.HorizontalScope()) {
|
||||
GUILayout.Space(15);
|
||||
if (GUILayout.Button("Reset", EditorStyles.miniButtonLeft,
|
||||
GUILayout.Width(60f), GUILayout.ExpandWidth(false))) {
|
||||
property.textureValue = null;
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(60);
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel = originalIntentLevel;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
FoldoutStates[RenderingOptionsName] =
|
||||
EditorGUILayout.Foldout(FoldoutStates[RenderingOptionsName], RenderingOptionsName, true, _foldoutStyle);
|
||||
if (FoldoutStates[RenderingOptionsName]) {
|
||||
EditorGUI.indentLevel += 1;
|
||||
DrawOpaqueField(targetMaterial);
|
||||
DrawQueueOffsetField(properties, targetMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawOpaqueField(Material material) {
|
||||
var opaque = EditorGUILayout.Toggle("Opaque", material.GetTag("RenderType", false) == "Opaque");
|
||||
if (opaque) {
|
||||
material.SetOverrideTag("RenderType", "Opaque");
|
||||
material.SetInt("_ZWrite", 1);
|
||||
material.renderQueue = (int)RenderQueue.Geometry;
|
||||
} else {
|
||||
material.SetOverrideTag("RenderType", "Transparent");
|
||||
material.SetInt("_ZWrite", 0);
|
||||
material.renderQueue = (int)RenderQueue.Transparent;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawQueueOffsetField(MaterialProperty[] properties, Material material) {
|
||||
GUIContent queueSlider = new GUIContent("Priority",
|
||||
"Determines the chronological rendering order for a Material. High values are rendered first.");
|
||||
const int queueOffsetRange = 50;
|
||||
MaterialProperty queueOffsetProp = FindProperty("_QueueOffset", properties, false);
|
||||
if (queueOffsetProp == null) return;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.showMixedValue = queueOffsetProp.hasMixedValue;
|
||||
var queue = EditorGUILayout.IntSlider(queueSlider, (int)queueOffsetProp.floatValue, -queueOffsetRange,
|
||||
queueOffsetRange);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
queueOffsetProp.floatValue = queue;
|
||||
EditorGUI.showMixedValue = false;
|
||||
material.renderQueue += queue;
|
||||
}
|
||||
|
||||
private void DrawStandard(MaterialEditor materialEditor, MaterialProperty property) {
|
||||
string displayName = property.displayName;
|
||||
|
||||
// Remove everything in brackets.
|
||||
displayName = Regex.Replace(displayName, @" ?\[.*?\]", string.Empty);
|
||||
|
||||
Tooltips.map.TryGetValue(displayName.Trim(), out string tooltip);
|
||||
displayName = Regex.Replace(displayName, @" ?\{.*?\}", string.Empty);
|
||||
|
||||
var guiContent = new GUIContent(displayName, tooltip);
|
||||
|
||||
if (property.GetShaderPropertyType() == ShaderPropertyType.Texture) {
|
||||
materialEditor.TexturePropertySingleLine(guiContent, property);
|
||||
} else {
|
||||
materialEditor.ShaderProperty(property, guiContent);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShowColorGradientExportBox(MaterialEditor materialEditor, MaterialProperty property) {
|
||||
bool isGradientTexture = property.GetShaderPropertyType() == ShaderPropertyType.Texture &&
|
||||
property.displayName.StartsWith("[_COLORMODE_GRADIENT_TEXTURE]");
|
||||
if (isGradientTexture) {
|
||||
if (property.textureValue != null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
var messageContent =
|
||||
EditorGUIUtility.TrTextContent(
|
||||
"Before the gradient can be used it needs to be exported as a texture.");
|
||||
var buttonContent = EditorGUIUtility.TrTextContent("Export");
|
||||
bool buttonPressed = GradientBoxWithButton(messageContent, buttonContent);
|
||||
if (buttonPressed) {
|
||||
var texture = GradientToTexture(_gradient);
|
||||
PromptTextureSave(materialEditor, texture, property.name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool GradientBoxWithButton(GUIContent messageContent, GUIContent buttonContent) {
|
||||
float boxHeight = 40f;
|
||||
EditorGUILayout.Space(5);
|
||||
Rect rect = GUILayoutUtility.GetRect(messageContent, EditorStyles.helpBox);
|
||||
GUILayoutUtility.GetRect(0f, boxHeight);
|
||||
rect.height += boxHeight;
|
||||
var style = new GUIStyle(EditorStyles.helpBox);
|
||||
style.fontSize += 2;
|
||||
GUI.Label(rect, messageContent, style);
|
||||
float secondLineHeight = 20f;
|
||||
float secondLineY = rect.yMax - secondLineHeight - 15f;
|
||||
var buttonPosition = new Rect(rect.xMax - 60f - 4f, secondLineY, 60f, secondLineHeight);
|
||||
bool result = GUI.Button(buttonPosition, buttonContent);
|
||||
|
||||
var gradientPosition = new Rect(rect.xMin + 8f, secondLineY, rect.width - 60f - 18f, secondLineHeight);
|
||||
if (_gradient == null) {
|
||||
_gradient = new Gradient();
|
||||
}
|
||||
|
||||
_gradient = EditorGUI.GradientField(gradientPosition, _gradient);
|
||||
EditorGUILayout.Space(10);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Texture2D GradientToTexture(Gradient g) {
|
||||
const int width = 256;
|
||||
|
||||
Texture2D texture = new Texture2D(width, 1, TextureFormat.RGBA32, /*mipChain=*/false) {
|
||||
name = "Flat Kit Water Color Gradient",
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
hideFlags = HideFlags.HideAndDontSave,
|
||||
filterMode = FilterMode.Point
|
||||
};
|
||||
for (float x = 0;
|
||||
x < width;
|
||||
x++) {
|
||||
Color32 color = g.Evaluate(x / (width - 1));
|
||||
texture.SetPixel(Mathf.CeilToInt(x), 0, color);
|
||||
}
|
||||
|
||||
texture.Apply();
|
||||
return texture;
|
||||
}
|
||||
|
||||
private void PromptTextureSave(MaterialEditor materialEditor, Texture2D texture, string propertyName) {
|
||||
Material material = materialEditor.target as Material;
|
||||
if (material == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pngNameWithExtension = $"{materialEditor.target.name}{propertyName}.png";
|
||||
|
||||
var fullPath =
|
||||
EditorUtility.SaveFilePanel("Save Gradient Texture", "Assets", pngNameWithExtension, "png");
|
||||
if (fullPath.Length > 0) {
|
||||
SaveTextureAsPng(texture, fullPath, FilterMode.Point);
|
||||
var loadedTexture = LoadTexture(fullPath);
|
||||
if (loadedTexture != null) {
|
||||
material.SetTexture(propertyName, loadedTexture);
|
||||
} else {
|
||||
Debug.LogWarning($"Could not load the texture from {fullPath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveTextureAsPng(Texture2D texture, string fullPath, FilterMode filterMode) {
|
||||
byte[] bytes = texture.EncodeToPNG();
|
||||
if (bytes == null) {
|
||||
Debug.LogError("Could not encode texture as PNG.");
|
||||
return;
|
||||
}
|
||||
|
||||
File.WriteAllBytes(fullPath, bytes);
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log($"Texture saved as: {fullPath}");
|
||||
|
||||
string pathRelativeToAssets = ConvertFullPathToAssetPath(fullPath);
|
||||
if (pathRelativeToAssets.Length == 0) {
|
||||
Debug.LogWarning($"Could not save the texture to {fullPath}.");
|
||||
}
|
||||
|
||||
TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(pathRelativeToAssets);
|
||||
Debug.Assert(importer != null,
|
||||
$"[FlatKit] Could not create importer at {pathRelativeToAssets}.");
|
||||
if (importer != null) {
|
||||
importer.filterMode = filterMode;
|
||||
importer.textureType = TextureImporterType.Default;
|
||||
importer.textureCompression = TextureImporterCompression.Uncompressed;
|
||||
importer.mipmapEnabled = false;
|
||||
var textureSettings = new TextureImporterPlatformSettings {
|
||||
format = TextureImporterFormat.RGBA32
|
||||
};
|
||||
importer.SetPlatformTextureSettings(textureSettings);
|
||||
EditorUtility.SetDirty(importer);
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
|
||||
Debug.Assert(importer != null,
|
||||
$"[FlatKit] Could not change import settings of {fullPath} [{pathRelativeToAssets}]");
|
||||
}
|
||||
|
||||
private static Texture2D LoadTexture(string fullPath) {
|
||||
string pathRelativeToAssets = ConvertFullPathToAssetPath(fullPath);
|
||||
if (pathRelativeToAssets.Length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var loadedTexture = AssetDatabase.LoadAssetAtPath(pathRelativeToAssets, typeof(Texture2D)) as Texture2D;
|
||||
if (loadedTexture == null) {
|
||||
Debug.LogError($"[FlatKit] Could not load texture from {fullPath} [{pathRelativeToAssets}].");
|
||||
return null;
|
||||
}
|
||||
|
||||
loadedTexture.filterMode = FilterMode.Point;
|
||||
loadedTexture.wrapMode = TextureWrapMode.Clamp;
|
||||
return loadedTexture;
|
||||
}
|
||||
|
||||
private static string ConvertFullPathToAssetPath(string fullPath) {
|
||||
int count = (Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar).Length;
|
||||
return fullPath.Remove(0, count);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user