using UnityEditor; using UnityEngine; using UnityEditorInternal; using System; using System.Linq; using System.Collections.Generic; using System.IO; namespace VRM { /// /// Prefabをインスタンス化してPreviewに表示する /// /// * https://github.com/Unity-Technologies/UnityCsReference/blob/11bcfd801fccd2a52b09bb6fd636c1ddcc9f1705/Editor/Mono/Inspector/ModelInspector.cs /// /// public abstract class PreviewEditor : Editor { /// /// PreviewRenderUtilityを管理する。 /// /// * PreviewRenderUtility.m_cameraのUnityVersionによる切り分け /// /// PreviewFaceRenderer m_renderer; /// /// Prefabをインスタンス化したシーンを管理する。 /// /// * BlendShapeのBake /// * MaterialMorphの適用 /// * Previewカメラのコントロール /// * Previewライティングのコントロール /// /// PreviewSceneManager m_scene; protected PreviewSceneManager PreviewSceneManager { get { return m_scene; } } /// /// Previewシーンに表示するPrefab /// GameObject m_prefab; protected GameObject Prefab { get { return m_prefab; } private set { if (m_prefab == value) return; //Debug.LogFormat("Prefab = {0}", value); m_prefab = value; if (m_scene != null) { //Debug.LogFormat("OnDestroy"); GameObject.DestroyImmediate(m_scene.gameObject); m_scene = null; } if (m_prefab != null) { m_scene = VRM.PreviewSceneManager.GetOrCreate(m_prefab); if (m_scene != null) { m_scene.gameObject.SetActive(false); } Bake(); } } } protected abstract PreviewSceneManager.BakeValue GetBakeValue(); /// /// Preview シーンに BlendShape と MaterialValue を適用する /// protected void Bake() { if (m_scene != null) { //Debug.Log("Bake"); m_scene.Bake(GetBakeValue()); } } protected virtual GameObject GetPrefab() { return BlendShapeClip.VrmPrefabSearch(target); } protected virtual void OnEnable() { m_renderer = new PreviewFaceRenderer(); Prefab = GetPrefab(); } protected virtual void OnDisable() { if (m_renderer != null) { m_renderer.Dispose(); m_renderer = null; } } protected virtual void OnDestroy() { if (m_scene != null) { //Debug.LogFormat("OnDestroy"); m_scene.Clean(); GameObject.DestroyImmediate(m_scene.gameObject); m_scene = null; } } protected static void Separator() { EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); //GUILayout.Space(); GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); } public override void OnInspectorGUI() { //base.OnInspectorGUI(); Prefab = (GameObject)EditorGUILayout.ObjectField("Preview Prefab", Prefab, typeof(GameObject), false); //Separator(); } private static int sliderHash = "Slider".GetHashCode(); float m_yaw = 180.0f; float m_pitch; Vector3 m_position = new Vector3(0, 0, -0.8f); // very important to override this, it tells Unity to render an ObjectPreview at the bottom of the inspector public override bool HasPreviewGUI() { return true; } public RenderTexture PreviewTexture; // the main ObjectPreview function... it's called constantly, like other IMGUI On*GUI() functions public override void OnPreviewGUI(Rect r, GUIStyle background) { // if this is happening, you have bigger problems if (!ShaderUtil.hardwareSupportsRectRenderTexture) { if (Event.current.type == EventType.Repaint) { EditorGUI.DropShadowLabel(new Rect(r.x, r.y, r.width, 40f), "Mesh preview requires\nrender texture support"); } return; } var src = r; var min = Mathf.Min(r.width, r.height); r.width = min; r.height = min; r.x = src.x + (src.width - min) / 2; r.y = src.y + (src.height - min) / 2; //previewDir = Drag2D(previewDir, r); { int controlId = GUIUtility.GetControlID(sliderHash, FocusType.Passive); Event e = Event.current; switch (e.GetTypeForControl(controlId)) { case EventType.MouseDown: if (r.Contains(e.mousePosition) && (double)r.width > 50.0) { GUIUtility.hotControl = controlId; e.Use(); EditorGUIUtility.SetWantsMouseJumping(1); break; } break; case EventType.MouseUp: if (GUIUtility.hotControl == controlId) GUIUtility.hotControl = 0; EditorGUIUtility.SetWantsMouseJumping(0); break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlId) { if (e.button == 2) { var shift = e.delta * (!e.shift ? 1f : 3f) / Mathf.Min(r.width, r.height); m_position.x -= shift.x; m_position.y += shift.y; e.Use(); GUI.changed = true; } else if ( e.button == 0 || e.button == 1) { var shift = e.delta * (!e.shift ? 1f : 3f) / Mathf.Min(r.width, r.height) * 140f; m_yaw += shift.x; m_pitch += shift.y; m_pitch = Mathf.Clamp(m_pitch, -90f, 90f); e.Use(); GUI.changed = true; } break; } break; case EventType.ScrollWheel: //Debug.LogFormat("wheel: {0}", current.delta); if (r.Contains(e.mousePosition)) { if (e.delta.y > 0) { m_position.z *= 1.1f; Repaint(); } else if (e.delta.y < 0) { m_position.z *= 0.9f; Repaint(); } } break; } //return scrollPosition; } //Debug.LogFormat("{0}", previewDir); if (Event.current.type != EventType.Repaint) { // if we don't need to update yet, then don't return; } if (m_renderer != null && m_scene != null) { PreviewTexture = m_renderer.Render(r, background, m_scene, m_yaw, m_pitch, m_position) as RenderTexture; if (PreviewTexture != null) { // draw the RenderTexture in the ObjectPreview pane GUI.DrawTexture(r, PreviewTexture, ScaleMode.StretchToFill, false); } } } } }