diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs new file mode 100644 index 000000000..deaeb0064 --- /dev/null +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -0,0 +1,89 @@ +using UnityEditor; +using UnityEngine; + + +namespace VRM +{ + [CustomEditor(typeof(BlendShapeClip))] + public class BlendShapeClipEditor : Editor + { + GameObject m_prefab; + PreviewFaceRenderer m_renderer; + BlendShapeClip m_target; + + private void OnEnable() + { + m_target = (BlendShapeClip)target; + var assetPath = AssetDatabase.GetAssetPath(target); + + //Debug.LogFormat("BlendShapeClipEditor: {0}", assetPath); + if (!string.IsNullOrEmpty(assetPath)) + { + m_prefab = AssetDatabase.LoadAssetAtPath(assetPath); + + if (m_prefab != null) + { + if (m_renderer != null) + { + m_renderer.Dispose(); + m_renderer = null; + } + m_renderer = new PreviewFaceRenderer(m_prefab); + } + } + } + + private void OnDisable() + { + if (m_renderer != null) + { + m_renderer.Dispose(); + m_renderer = null; + } + } + + private void OnDestroy() + { + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + //攻撃力の数値をラベルとして表示する + //EditorGUILayout.LabelField("攻撃力", character.攻撃力.ToString()); + } + + // very important to override this, it tells Unity to render an ObjectPreview at the bottom of the inspector + public override bool HasPreviewGUI() { return true; } + + // 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; + } + if (Event.current.type != EventType.Repaint) + { // if we don't need to update yet, then don't + return; + } + + if (m_renderer == null) + { + return; + } + + var image = m_renderer.Render(r, background); + GUI.DrawTexture(r, image, ScaleMode.StretchToFill, false); // draw the RenderTexture in the ObjectPreview pane + + EditorGUI.DropShadowLabel(new Rect(r.x, r.y, r.width, 40f), + BlendShapeKey.CreateFrom(m_target).ToString()); + } + } +} diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs.meta b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs.meta new file mode 100644 index 000000000..c23db2306 --- /dev/null +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4b3d6730e24442c44baaa50a1e6f3a6d +timeCreated: 1522927173 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs b/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs new file mode 100644 index 000000000..0859264dd --- /dev/null +++ b/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs @@ -0,0 +1,165 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; + + +namespace VRM +{ + public class PreviewFaceRenderer : IDisposable + { + const string PreviewInstanceName = "FaceMorphemePreviewInstance"; + + PreviewRenderUtility m_previewUtility; + GameObject m_prefab; + GameObject m_previewInstance; + SkinnedMeshRenderer[] m_Renderers; + Mesh[] m_baked; + Bounds m_bounds; + + void SetupCamera(Camera camera) + { + float magnitude = m_bounds.extents.magnitude; + float distance = 4f * magnitude; + camera.fieldOfView = 27f; + camera.backgroundColor = Color.gray; + camera.clearFlags = CameraClearFlags.Color; + // this used to be "-Vector3.forward * num" but I hardcoded my camera position instead + camera.transform.position = new Vector3(0f, 1.4f, 1.5f); + camera.transform.rotation = Quaternion.Euler(0, 180f, 0); + camera.nearClipPlane = 0.3f; + camera.farClipPlane = distance + magnitude * 1.1f; + } + + public PreviewFaceRenderer(GameObject prefab) + { + m_prefab = prefab; + m_previewUtility = new PreviewRenderUtility(); + + // if we already instantiated a PreviewInstance previously but just lost the reference, then use that same instance instead of making a new one + var oldInstance = GameObject.Find(PreviewInstanceName); + if (oldInstance != null) + { + m_previewInstance = oldInstance; + } + else + { // no previous instance detected, so now let's make a fresh one + // very important: this loads the PreviewInstance prefab and temporarily instantiates it into PreviewInstance + m_previewInstance = (GameObject)GameObject.Instantiate(m_prefab, m_prefab.transform.position, m_prefab.transform.rotation); + m_previewInstance.name = PreviewInstanceName; + // HideFlags are special editor-only settings that let you have *secret* GameObjects in a scene, or to tell Unity not to save that temporary GameObject as part of the scene + m_previewInstance.hideFlags = HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild; // you could also hide it from the hierarchy or inspector, but personally I like knowing everything that's there + } + + m_Renderers = m_previewInstance.transform.Traverse() + .Select(x => x.GetComponent()) + .Where(x => x != null && x.sharedMesh != null) + .ToArray(); + m_baked = m_Renderers.Select(x => x.sharedMesh) + .ToArray(); + for (int i = 0; i < m_Renderers.Length; ++i) + { + if (m_baked[i] == null) + { + m_baked[i] = new Mesh(); + } + m_Renderers[i].BakeMesh(m_baked[i]); + + m_bounds.Expand(m_baked[i].bounds.min); + m_bounds.Expand(m_baked[i].bounds.max); + } + } + + public Texture Render(Rect r, GUIStyle background) + { + // we are technically rendering everything in the scene, so scene fog might affect it... + bool fog = RenderSettings.fog; // ... let's remember the current fog setting... + Unsupported.SetRenderSettingsUseFogNoDirty(false); // ... and then temporarily turn it off + try + { + m_previewUtility.BeginPreview(r, background); // set up the PreviewRenderUtility's mini internal scene + + _Render(); + + // VERY IMPORTANT: this manually tells the camera to render and produce the render texture + m_previewUtility.m_Camera.Render(); + + // reset the scene's fog from before + return m_previewUtility.EndPreview(); // grab the RenderTexture resulting from DoRenderPreview() > RenderMeshPreview() > PreviewRenderUtility.m_Camera.Render() + } + finally + { + Unsupported.SetRenderSettingsUseFogNoDirty(fog); + } + } + + private void _Render() + { + // setup the ObjectPreview's camera + SetupCamera(m_previewUtility.m_Camera); + + // very important: we have to call BakeMesh, to bake that animated SkinnedMesh into a plain static Mesh suitable for Graphics.DrawMesh() + for(int j=0; j