using System; using UnityEditor; using UnityEngine; namespace VRM { public static class BlendShapeClipEditorHelper { /// /// BlendShape List のElement描画 /// public static bool DrawBlendShapeBinding(Rect position, SerializedProperty property, PreviewSceneManager scene) { bool changed = false; if (scene != null) { var height = 16; var y = position.y; var rect = new Rect(position.x, y, position.width, height); int pathIndex; var (relChanged, oldIndex) = StringPopup(rect, property.FindPropertyRelative("RelativePath"), scene.SkinnedMeshRendererPathList, out pathIndex); if (relChanged) { changed = true; } y += height; rect = new Rect(position.x, y, position.width, height); if (!relChanged && oldIndex == -1) { EditorGUI.HelpBox(rect, "renderer not found ! please fix", MessageType.Error); } else { int blendShapeIndex; if (IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetBlendShapeNames(pathIndex), out blendShapeIndex)) { changed = true; } } y += height; rect = new Rect(position.x, y, position.width, height); if (FloatSlider(rect, property.FindPropertyRelative("Weight"), 100)) { changed = true; } } return changed; } /// /// Material List のElement描画 /// public static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, PreviewSceneManager scene) { bool changed = false; if (scene != null) { var height = 16; var y = position.y; var rect = new Rect(position.x, y, position.width, height); int materialIndex; if (StringPopup(rect, property.FindPropertyRelative("MaterialName"), scene.MaterialNames, out materialIndex).Item1) { changed = true; } if (materialIndex >= 0) { var materialItem = scene.GetMaterialItem(scene.MaterialNames[materialIndex]); if (materialItem != null) { y += height; rect = new Rect(position.x, y, position.width, height); // プロパティ名のポップアップ int propIndex; if (StringPopup(rect, property.FindPropertyRelative("ValueName"), materialItem.PropNames, out propIndex).Item1) { changed = true; } if (propIndex >= 0) { // 有効なプロパティ名が選択された var propItem = materialItem.PropMap[materialItem.PropNames[propIndex]]; { switch (propItem.PropertyType) { case ShaderUtil.ShaderPropertyType.Color: { property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; // max y += height; rect = new Rect(position.x, y, position.width, height); if (ColorProp(rect, property.FindPropertyRelative("TargetValue"))) { changed = true; } } break; case ShaderUtil.ShaderPropertyType.TexEnv: { property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; // max y += height; rect = new Rect(position.x, y, position.width, height); if (OffsetProp(rect, property.FindPropertyRelative("TargetValue"))) { changed = true; } } break; } } } } } } return changed; } #region Private static (bool, int?) StringPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) { if (options == null) { newIndex = -1; return (false, default); } var oldIndex = Array.IndexOf(options, prop.stringValue); newIndex = EditorGUI.Popup(rect, oldIndex, options); if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) { prop.stringValue = options[newIndex]; return (true, oldIndex); } else { return (false, oldIndex); } } static bool IntPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) { if (options == null) { newIndex = -1; return false; } var oldIndex = prop.intValue; newIndex = EditorGUI.Popup(rect, oldIndex, options); if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) { prop.intValue = newIndex; return true; } else { return false; } } static bool FloatSlider(Rect rect, SerializedProperty prop, float maxValue) { var oldValue = prop.floatValue; var newValue = EditorGUI.Slider(rect, prop.floatValue, 0, 100f); if (newValue != oldValue) { prop.floatValue = newValue; return true; } else { return false; } } static bool ColorProp(Rect rect, SerializedProperty prop) { var oldValue = (Color)prop.vector4Value; var newValue = EditorGUI.ColorField(rect, prop.displayName, oldValue); if (newValue != oldValue) { prop.vector4Value = newValue; return true; } else { return false; } } static Rect AdvanceRect(ref float x, float y, float w, float h) { var rect = new Rect(x, y, w, h); x += w; return rect; } static float[] v2 = new float[2]; static GUIContent[] l2 = new GUIContent[]{ new GUIContent("x"), new GUIContent("y") }; static Vector4 TilingOffset(Rect rect, string label, Vector4 src) { /* var style = new GUIStyle() { alignment = TextAnchor.MiddleRight, }; */ var quad = (rect.width - 56); var x = rect.x; //EditorGUIUtility.labelWidth = 18; EditorGUI.LabelField(AdvanceRect(ref x, rect.y, 40, rect.height), "Tiling"); v2[0] = src.x; v2[1] = src.y; EditorGUI.MultiFloatField(AdvanceRect(ref x, rect.y, quad, rect.height), l2, v2); src.x = v2[0]; src.y = v2[1]; //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); //src.y = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", src.y); rect.y += EditorGUIUtility.singleLineHeight; x = rect.x; EditorGUI.LabelField(AdvanceRect(ref x, rect.y, 40, rect.height), "Offset"); v2[0] = src.z; v2[1] = src.w; EditorGUI.MultiFloatField(AdvanceRect(ref x, rect.y, quad, rect.height), l2, v2); src.z = v2[0]; src.w = v2[1]; //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad * 2, rect.height), "Offset X", style); //src.z = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "X", src.z); //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); //src.w = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", src.w); return src; } static bool OffsetProp(Rect rect, SerializedProperty prop) { var oldValue = prop.vector4Value; //var newValue = EditorGUI.Vector4Field(rect, prop.displayName, oldValue); var newValue = TilingOffset(rect, prop.displayName, oldValue); if (newValue != oldValue) { prop.vector4Value = newValue; return true; } else { return false; } } #endregion } /// https://gist.github.com/gszauer/7799899 public class TextureScale { private static Color[] texColors; private static Color[] newColors; private static int w; private static float ratioX; private static float ratioY; private static int w2; public static void Scale(Texture2D tex, int newWidth, int newHeight) { texColors = tex.GetPixels(); newColors = new Color[newWidth * newHeight]; ratioX = 1.0f / ((float)newWidth / (tex.width - 1)); ratioY = 1.0f / ((float)newHeight / (tex.height - 1)); w = tex.width; w2 = newWidth; BilinearScale(0, newHeight); tex.Reinitialize(newWidth, newHeight); tex.SetPixels(newColors); tex.Apply(); } private static void BilinearScale(int start, int end) { for (var y = start; y < end; y++) { int yFloor = (int)Mathf.Floor(y * ratioY); var y1 = yFloor * w; var y2 = (yFloor + 1) * w; var yw = y * w2; for (var x = 0; x < w2; x++) { int xFloor = (int)Mathf.Floor(x * ratioX); var xLerp = x * ratioX - xFloor; newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor + 1], xLerp), ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor + 1], xLerp), y * ratioY - yFloor); } } } private static Color ColorLerpUnclamped(Color c1, Color c2, float value) { return new Color(c1.r + (c2.r - c1.r) * value, c1.g + (c2.g - c1.g) * value, c1.b + (c2.b - c1.b) * value, c1.a + (c2.a - c1.a) * value); } /// http://light11.hatenadiary.com/entry/2018/04/19/194015 public static Texture2D GetResized(Texture2D texture, int width, int height) { // リサイズ後のサイズを持つRenderTextureを作成して書き込む var rt = RenderTexture.GetTemporary(width, height); Graphics.Blit(texture, rt); // リサイズ後のサイズを持つTexture2Dを作成してRenderTextureから書き込む var preRT = RenderTexture.active; RenderTexture.active = rt; var ret = new Texture2D(width, height); ret.ReadPixels(new Rect(0, 0, width, height), 0, 0); ret.Apply(); RenderTexture.active = preRT; RenderTexture.ReleaseTemporary(rt); return ret; } } }