diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index 30476d1c1..e5c93cac1 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -1,20 +1,44 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEditor; +using UnityEditor; using UnityEngine; +using UnityEditorInternal; namespace VRM { + /// + /// Prefabをインスタンス化してPreviewに表示する + /// + /// * https://github.com/Unity-Technologies/UnityCsReference/blob/11bcfd801fccd2a52b09bb6fd636c1ddcc9f1705/Editor/Mono/Inspector/ModelInspector.cs + /// + /// public 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; } } - PreviewFaceRenderer m_renderer; + /// + /// Previewシーンに表示するPrefab + /// GameObject m_prefab; GameObject Prefab { @@ -42,6 +66,12 @@ namespace VRM } } + /// + /// シーンにBlendShapeとMaterialMorphを適用する + /// + /// + /// + /// protected void Bake(BlendShapeBinding[] values, MaterialValueBinding[] materialValues, float weight) { if (m_scene != null) @@ -88,6 +118,43 @@ namespace VRM Prefab = (GameObject)EditorGUILayout.ObjectField("prefab", Prefab, typeof(GameObject), false); } + private static int sliderHash = "Slider".GetHashCode(); + public static Vector2 Drag2D(Vector2 scrollPosition, Rect position) + { + int controlId = GUIUtility.GetControlID(sliderHash, FocusType.Passive); + Event current = Event.current; + switch (current.GetTypeForControl(controlId)) + { + case EventType.MouseDown: + if (position.Contains(current.mousePosition) && (double)position.width > 50.0) + { + GUIUtility.hotControl = controlId; + current.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) + { + scrollPosition -= current.delta * (!current.shift ? 1f : 3f) / Mathf.Min(position.width, position.height) * 140f; + scrollPosition.y = Mathf.Clamp(scrollPosition.y, -90f, 90f); + current.Use(); + GUI.changed = true; + break; + } + break; + } + return scrollPosition; + } + + Vector2 previewDir; + // very important to override this, it tells Unity to render an ObjectPreview at the bottom of the inspector public override bool HasPreviewGUI() { return true; } @@ -99,10 +166,15 @@ namespace VRM { if (Event.current.type == EventType.Repaint) { - EditorGUI.DropShadowLabel(new Rect(r.x, r.y, r.width, 40f), "Mesh preview requires\nrender texture support"); + EditorGUI.DropShadowLabel(new Rect(r.x, r.y, r.width, 40f), + "Mesh preview requires\nrender texture support"); } return; } + + previewDir = Drag2D(previewDir, r); + //Debug.LogFormat("{0}", previewDir); + if (Event.current.type != EventType.Repaint) { // if we don't need to update yet, then don't @@ -111,7 +183,7 @@ namespace VRM if (m_renderer != null && m_scene != null) { - var texture = m_renderer.Render(r, background, m_scene); + var texture = m_renderer.Render(r, background, m_scene, previewDir); if (texture != null) { // draw the RenderTexture in the ObjectPreview pane diff --git a/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs b/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs index 15c95c5e9..62c0711fd 100644 --- a/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs +++ b/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs @@ -79,7 +79,9 @@ namespace VRM } } - public Texture Render(Rect r, GUIStyle background, PreviewSceneManager scene) + //const float FACTOR = 0.1f; + + public Texture Render(Rect r, GUIStyle background, PreviewSceneManager scene, Vector2 drag) { if (scene == null) return null; @@ -88,7 +90,7 @@ namespace VRM m_previewUtility.BeginPreview(r, background); // set up the PreviewRenderUtility's mini internal scene // setup the ObjectPreview's camera - scene.SetupCamera(PreviewCamera); + scene.SetupCamera(PreviewCamera, scene.TargetPosition, -drag.x, drag.y); foreach (var item in scene.EnumRenderItems) { diff --git a/Scripts/BlendShape/PreviewSceneManager.cs b/Scripts/BlendShape/PreviewSceneManager.cs index 5f86207b2..9de0e9217 100644 --- a/Scripts/BlendShape/PreviewSceneManager.cs +++ b/Scripts/BlendShape/PreviewSceneManager.cs @@ -127,6 +127,16 @@ namespace VRM .Where(x => x.SkinnedMeshRenderer != null) .Select(x => x.Path) .ToArray(); + + var animator = GetComponent(); + if (animator != null) + { + var head = animator.GetBoneTransform(HumanBodyBones.Head); + if (head != null) + { + m_target = head; + } + } } MeshPreviewItem[] m_meshes; @@ -186,6 +196,19 @@ namespace VRM return item; } + public Transform m_target; + public Vector3 TargetPosition + { + get + { + if (m_target == null) + { + return new Vector3(0, 1.4f, 0); + } + return m_target.position; + } + } + Bounds m_bounds; public void Bake(BlendShapeBinding[] values=null, MaterialValueBinding[] materialValues=null, float weight=1.0f) { @@ -243,18 +266,28 @@ namespace VRM /// カメラパラメーターを決める /// /// - public void SetupCamera(Camera camera) + public void SetupCamera(Camera camera, Vector3 target, float yaw, float pitch) { - float magnitude = m_bounds.extents.magnitude * 0.5f; - float distance = magnitude; - camera.fieldOfView = 27f; camera.backgroundColor = Color.gray; camera.clearFlags = CameraClearFlags.Color; + + // projection + //float magnitude = m_bounds.extents.magnitude * 0.5f; + //float distance = magnitude; + var distance = target.magnitude; + + camera.fieldOfView = 27f; + camera.nearClipPlane = 0.3f; + camera.farClipPlane = distance /*+ magnitude*/ * 2.1f; + +#if false // this used to be "-Vector3.forward * num" but I hardcoded my camera position instead camera.transform.position = new Vector3(0f, 1.4f, distance); camera.transform.rotation = Quaternion.Euler(0, 180f, 0); - camera.nearClipPlane = 0.3f; - camera.farClipPlane = distance + magnitude * 1.1f; +#else + camera.transform.position = target + Quaternion.Euler(pitch, yaw, 0) * Vector3.forward * distance; + camera.transform.LookAt(target); +#endif //previewLayer のみ表示する //camera.cullingMask = 1 << PreviewLayer;