mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-14 06:50:19 -05:00
add BlendShapeClip
This commit is contained in:
89
Scripts/BlendShape/Editor/BlendShapeClipEditor.cs
Normal file
89
Scripts/BlendShape/Editor/BlendShapeClipEditor.cs
Normal file
@@ -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<GameObject>(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());
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Scripts/BlendShape/Editor/BlendShapeClipEditor.cs.meta
Normal file
12
Scripts/BlendShape/Editor/BlendShapeClipEditor.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b3d6730e24442c44baaa50a1e6f3a6d
|
||||
timeCreated: 1522927173
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
165
Scripts/BlendShape/Editor/PreviewFaceRenderer.cs
Normal file
165
Scripts/BlendShape/Editor/PreviewFaceRenderer.cs
Normal file
@@ -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<SkinnedMeshRenderer>())
|
||||
.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<m_Renderers.Length; ++j)
|
||||
{
|
||||
var renderer = m_Renderers[j];
|
||||
var mesh = m_baked[j];
|
||||
|
||||
// now, actually render out the RenderTexture
|
||||
//RenderMeshPreview(previewMesh, skinMeshRender.sharedMaterials);
|
||||
// submesh support, in case the mesh is made of multiple parts
|
||||
int subMeshCount = mesh.subMeshCount;
|
||||
for (int i = 0; i < subMeshCount; i++)
|
||||
{
|
||||
// PreviewRenderUtility.DrawMesh() actually draws the mesh
|
||||
m_previewUtility.DrawMesh(mesh,
|
||||
renderer.transform.position, renderer.transform.rotation,
|
||||
renderer.sharedMaterials[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // 重複する呼び出しを検出するには
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: マネージ状態を破棄します (マネージ オブジェクト)。
|
||||
if (this.m_previewUtility != null)
|
||||
{
|
||||
this.m_previewUtility.Cleanup();
|
||||
this.m_previewUtility = null;
|
||||
}
|
||||
if (m_previewInstance != null)
|
||||
{
|
||||
GameObject.DestroyImmediate(m_previewInstance);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。
|
||||
// TODO: 大きなフィールドを null に設定します。
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。
|
||||
// ~PreviewFaceRenderer() {
|
||||
// // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// このコードは、破棄可能なパターンを正しく実装できるように追加されました。
|
||||
public void Dispose()
|
||||
{
|
||||
// このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
Dispose(true);
|
||||
// TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
Scripts/BlendShape/Editor/PreviewFaceRenderer.cs.meta
Normal file
12
Scripts/BlendShape/Editor/PreviewFaceRenderer.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b59705d1618086148b505c2c3d9f1992
|
||||
timeCreated: 1522931965
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user