mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-12 13:59:21 -05:00
MeshIntegratorの非VRM部分をMeshUtilityに移動
This commit is contained in:
13
Assets/MeshUtility/Runtime/MeshIntegrationResult.cs
Normal file
13
Assets/MeshUtility/Runtime/MeshIntegrationResult.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MeshUtility
|
||||
{
|
||||
[System.Serializable]
|
||||
public class MeshIntegrationResult
|
||||
{
|
||||
public List<SkinnedMeshRenderer> SourceSkinnedMeshRenderers = new List<SkinnedMeshRenderer>();
|
||||
public List<MeshRenderer> SourceMeshRenderers = new List<MeshRenderer>();
|
||||
public SkinnedMeshRenderer IntegratedRenderer;
|
||||
}
|
||||
}
|
||||
11
Assets/MeshUtility/Runtime/MeshIntegrationResult.cs.meta
Normal file
11
Assets/MeshUtility/Runtime/MeshIntegrationResult.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1c66a21d479b3e4a92eedd622d27f4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,14 +6,6 @@ namespace MeshUtility
|
||||
{
|
||||
public static class MeshIntegratorUtility
|
||||
{
|
||||
[System.Serializable]
|
||||
public class MeshIntegrationResult
|
||||
{
|
||||
public List<SkinnedMeshRenderer> SourceSkinnedMeshRenderers = new List<SkinnedMeshRenderer>();
|
||||
public List<MeshRenderer> SourceMeshRenderers = new List<MeshRenderer>();
|
||||
public SkinnedMeshRenderer IntegratedRenderer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する
|
||||
/// </summary>
|
||||
|
||||
@@ -11,7 +11,7 @@ using Object = UnityEngine.Object;
|
||||
namespace VRM
|
||||
{
|
||||
/// <summary>
|
||||
/// 複数のメッシュをまとめる
|
||||
/// 複数のメッシュをまとめて、BlendShapeClipに変更を反映する
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public static class MeshIntegratorEditor
|
||||
@@ -39,12 +39,12 @@ namespace VRM
|
||||
private static void Foo()
|
||||
{
|
||||
var go = Selection.activeObject as GameObject;
|
||||
|
||||
|
||||
Debug.Log(SkinnedMeshUtility.IsPrefab(go));
|
||||
}
|
||||
|
||||
|
||||
public static List<MeshIntegratorUtility.MeshIntegrationResult> Integrate(GameObject prefab)
|
||||
public static List<MeshUtility.MeshIntegrationResult> Integrate(GameObject prefab)
|
||||
{
|
||||
Undo.RecordObject(prefab, "Mesh Integration");
|
||||
var instance = SkinnedMeshUtility.InstantiatePrefab(prefab);
|
||||
@@ -63,18 +63,18 @@ namespace VRM
|
||||
|
||||
// Backup Exists
|
||||
BackupVrmPrefab(prefab);
|
||||
|
||||
|
||||
// Execute
|
||||
var results = MeshIntegratorUtility.Integrate(instance, clips);
|
||||
var results = VRMMeshIntegratorUtility.Integrate(instance, clips);
|
||||
|
||||
foreach (var res in results)
|
||||
{
|
||||
if (res.IntegratedRenderer == null) continue;
|
||||
|
||||
|
||||
SaveMeshAsset(res.IntegratedRenderer.sharedMesh, instance, res.IntegratedRenderer.gameObject.name);
|
||||
Undo.RegisterCreatedObjectUndo(res.IntegratedRenderer.gameObject, "Integrate Renderers");
|
||||
}
|
||||
|
||||
|
||||
// destroy source renderers
|
||||
foreach (var res in results)
|
||||
{
|
||||
@@ -90,31 +90,31 @@ namespace VRM
|
||||
renderer.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Apply to Prefab
|
||||
SkinnedMeshUtility.ApplyChangesToPrefab(instance);
|
||||
Object.DestroyImmediate(instance);
|
||||
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void BackupVrmPrefab(GameObject rootPrefab)
|
||||
{
|
||||
var proxy = rootPrefab.GetComponent<VRMBlendShapeProxy>();
|
||||
|
||||
var srcAvatar = proxy.BlendShapeAvatar;
|
||||
var dstAvatar = (BlendShapeAvatar) BackupAsset(srcAvatar, rootPrefab);
|
||||
|
||||
var clipMapper = srcAvatar.Clips.ToDictionary(x => x, x => (BlendShapeClip) BackupAsset(x, rootPrefab));
|
||||
var srcAvatar = proxy.BlendShapeAvatar;
|
||||
var dstAvatar = (BlendShapeAvatar)BackupAsset(srcAvatar, rootPrefab);
|
||||
|
||||
var clipMapper = srcAvatar.Clips.ToDictionary(x => x, x => (BlendShapeClip)BackupAsset(x, rootPrefab));
|
||||
dstAvatar.Clips = clipMapper.Values.ToList();
|
||||
|
||||
|
||||
var dstPrefab = BackupAsset(rootPrefab, rootPrefab);
|
||||
var dstInstance = SkinnedMeshUtility.InstantiatePrefab(dstPrefab);
|
||||
dstInstance.GetComponent<VRMBlendShapeProxy>().BlendShapeAvatar = dstAvatar;
|
||||
SkinnedMeshUtility.ApplyChangesToPrefab(dstInstance);
|
||||
Object.DestroyImmediate(dstInstance);
|
||||
}
|
||||
|
||||
|
||||
private static T BackupAsset<T>(T asset, GameObject rootPrefab) where T : UnityEngine.Object
|
||||
{
|
||||
var srcAssetPath = UnityPath.FromAsset(asset);
|
||||
@@ -124,7 +124,7 @@ namespace VRM
|
||||
var backupPath = UnityPath.FromAsset(rootPrefab).Parent.Child(backupDir);
|
||||
backupPath.EnsureFolder();
|
||||
var dstAssetPath = backupPath.Child(assetName);
|
||||
|
||||
|
||||
AssetDatabase.CopyAsset(srcAssetPath.Value, dstAssetPath.Value);
|
||||
return dstAssetPath.LoadAsset<T>();
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace VRM
|
||||
MaterialList[] m_duplicateMaterials;
|
||||
|
||||
[Header("Result")]
|
||||
public MeshIntegratorUtility.MeshIntegrationResult[] integrationResults;
|
||||
public MeshUtility.MeshIntegrationResult[] integrationResults;
|
||||
|
||||
[MenuItem(MENU_KEY)]
|
||||
static void CreateWizard()
|
||||
@@ -124,7 +124,7 @@ namespace VRM
|
||||
return;
|
||||
}
|
||||
|
||||
m_uniqueMaterials = MeshIntegratorUtility.EnumerateSkinnedMeshRenderer(m_root.transform, false)
|
||||
m_uniqueMaterials = MeshUtility.MeshIntegratorUtility.EnumerateSkinnedMeshRenderer(m_root.transform, false)
|
||||
.SelectMany(x => x.sharedMaterials)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
"references": [
|
||||
"VRM",
|
||||
"UniJSON",
|
||||
"UniHumanoid"
|
||||
"UniHumanoid",
|
||||
"MeshUtility"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRM
|
||||
{
|
||||
public static class MeshIntegratorUtility
|
||||
{
|
||||
[System.Serializable]
|
||||
public class MeshIntegrationResult
|
||||
{
|
||||
public List<SkinnedMeshRenderer> SourceSkinnedMeshRenderers = new List<SkinnedMeshRenderer>();
|
||||
public List<MeshRenderer> SourceMeshRenderers = new List<MeshRenderer>();
|
||||
public SkinnedMeshRenderer IntegratedRenderer;
|
||||
}
|
||||
|
||||
public static bool IntegrateRuntime(GameObject vrmRootObject)
|
||||
{
|
||||
if (vrmRootObject == null) return false;
|
||||
var proxy = vrmRootObject.GetComponent<VRMBlendShapeProxy>();
|
||||
if (proxy == null) return false;
|
||||
var avatar = proxy.BlendShapeAvatar;
|
||||
if (avatar == null) return false;
|
||||
var clips = avatar.Clips;
|
||||
|
||||
var results = Integrate(vrmRootObject, clips);
|
||||
if (results.Any(x => x.IntegratedRenderer == null)) return false;
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
foreach (var renderer in result.SourceSkinnedMeshRenderers)
|
||||
{
|
||||
Object.Destroy(renderer);
|
||||
}
|
||||
|
||||
foreach (var renderer in result.SourceMeshRenderers)
|
||||
{
|
||||
Object.Destroy(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<MeshIntegrationResult> Integrate(GameObject root, List<BlendShapeClip> blendshapeClips)
|
||||
{
|
||||
var result = new List<MeshIntegratorUtility.MeshIntegrationResult>();
|
||||
|
||||
var withoutBlendShape = IntegrateInternal(root, onlyBlendShapeRenderers: false);
|
||||
if (withoutBlendShape.IntegratedRenderer != null)
|
||||
{
|
||||
result.Add(withoutBlendShape);
|
||||
}
|
||||
|
||||
var onlyBlendShape = IntegrateInternal(root, onlyBlendShapeRenderers: true);
|
||||
if (onlyBlendShape.IntegratedRenderer != null)
|
||||
{
|
||||
result.Add(onlyBlendShape);
|
||||
FollowBlendshapeRendererChange(blendshapeClips, onlyBlendShape, root);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void FollowBlendshapeRendererChange(List<BlendShapeClip> clips, MeshIntegrationResult result, GameObject root)
|
||||
{
|
||||
if (clips == null || result == null || result.IntegratedRenderer == null || root == null) return;
|
||||
|
||||
var rendererDict = result.SourceSkinnedMeshRenderers
|
||||
.ToDictionary(x => x.transform.RelativePathFrom(root.transform), x => x);
|
||||
|
||||
var dstPath = result.IntegratedRenderer.transform.RelativePathFrom(root.transform);
|
||||
|
||||
foreach (var clip in clips)
|
||||
{
|
||||
if (clip == null) continue;
|
||||
|
||||
for (var i = 0; i < clip.Values.Length; ++i)
|
||||
{
|
||||
var val = clip.Values[i];
|
||||
if (rendererDict.ContainsKey(val.RelativePath))
|
||||
{
|
||||
var srcRenderer = rendererDict[val.RelativePath];
|
||||
var name = srcRenderer.sharedMesh.GetBlendShapeName(val.Index);
|
||||
var newIndex = result.IntegratedRenderer.sharedMesh.GetBlendShapeIndex(name);
|
||||
|
||||
val.RelativePath = dstPath;
|
||||
val.Index = newIndex;
|
||||
}
|
||||
|
||||
clip.Values[i] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static MeshIntegrationResult IntegrateInternal(GameObject go, bool onlyBlendShapeRenderers)
|
||||
{
|
||||
var result = new MeshIntegrationResult();
|
||||
|
||||
var meshNode = new GameObject();
|
||||
if (onlyBlendShapeRenderers)
|
||||
{
|
||||
meshNode.name = "MeshIntegrator(BlendShape)";
|
||||
}
|
||||
else
|
||||
{
|
||||
meshNode.name = "MeshIntegrator";
|
||||
}
|
||||
meshNode.transform.SetParent(go.transform, false);
|
||||
|
||||
// レンダラから情報を集める
|
||||
var integrator = new MeshUtility.MeshIntegrator();
|
||||
|
||||
if (onlyBlendShapeRenderers)
|
||||
{
|
||||
foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, true))
|
||||
{
|
||||
integrator.Push(x);
|
||||
result.SourceSkinnedMeshRenderers.Add(x);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, false))
|
||||
{
|
||||
integrator.Push(x);
|
||||
result.SourceSkinnedMeshRenderers.Add(x);
|
||||
}
|
||||
|
||||
foreach (var x in EnumerateMeshRenderer(go.transform))
|
||||
{
|
||||
integrator.Push(x);
|
||||
result.SourceMeshRenderers.Add(x);
|
||||
}
|
||||
}
|
||||
|
||||
var mesh = new Mesh();
|
||||
mesh.name = "integrated";
|
||||
|
||||
if (integrator.Positions.Count > ushort.MaxValue)
|
||||
{
|
||||
Debug.LogFormat("exceed 65535 vertices: {0}", integrator.Positions.Count);
|
||||
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
}
|
||||
|
||||
mesh.vertices = integrator.Positions.ToArray();
|
||||
mesh.normals = integrator.Normals.ToArray();
|
||||
mesh.uv = integrator.UV.ToArray();
|
||||
mesh.tangents = integrator.Tangents.ToArray();
|
||||
mesh.boneWeights = integrator.BoneWeights.ToArray();
|
||||
mesh.subMeshCount = integrator.SubMeshes.Count;
|
||||
for (var i = 0; i < integrator.SubMeshes.Count; ++i)
|
||||
{
|
||||
mesh.SetIndices(integrator.SubMeshes[i].Indices.ToArray(), MeshTopology.Triangles, i);
|
||||
}
|
||||
mesh.bindposes = integrator.BindPoses.ToArray();
|
||||
|
||||
if (onlyBlendShapeRenderers)
|
||||
{
|
||||
integrator.AddBlendShapesToMesh(mesh);
|
||||
}
|
||||
|
||||
var integrated = meshNode.AddComponent<SkinnedMeshRenderer>();
|
||||
integrated.sharedMesh = mesh;
|
||||
integrated.sharedMaterials = integrator.SubMeshes.Select(x => x.Material).ToArray();
|
||||
integrated.bones = integrator.Bones.ToArray();
|
||||
result.IntegratedRenderer = integrated;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static IEnumerable<SkinnedMeshRenderer> EnumerateSkinnedMeshRenderer(Transform root, bool hasBlendShape)
|
||||
{
|
||||
foreach (var x in Traverse(root))
|
||||
{
|
||||
var renderer = x.GetComponent<SkinnedMeshRenderer>();
|
||||
if (renderer != null &&
|
||||
renderer.gameObject.activeInHierarchy &&
|
||||
renderer.sharedMesh != null &&
|
||||
renderer.enabled &&
|
||||
renderer.sharedMesh.blendShapeCount > 0 == hasBlendShape)
|
||||
{
|
||||
yield return renderer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<MeshRenderer> EnumerateMeshRenderer(Transform root)
|
||||
{
|
||||
foreach (var x in Traverse(root))
|
||||
{
|
||||
var renderer = x.GetComponent<MeshRenderer>();
|
||||
var filter = x.GetComponent<MeshFilter>();
|
||||
|
||||
if (renderer != null &&
|
||||
filter != null &&
|
||||
renderer.gameObject.activeInHierarchy &&
|
||||
filter.sharedMesh != null)
|
||||
{
|
||||
yield return renderer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Transform> Traverse(Transform parent)
|
||||
{
|
||||
if (parent.gameObject.activeSelf)
|
||||
{
|
||||
yield return parent;
|
||||
|
||||
foreach (Transform child in parent)
|
||||
{
|
||||
foreach (var x in Traverse(child))
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a982d9d30c0145038245b0214dc2f2e4
|
||||
timeCreated: 1560190306
|
||||
@@ -0,0 +1,92 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRM
|
||||
{
|
||||
/// <summary>
|
||||
/// Meshを統合し、統合後のMeshのBlendShapeの変化をVRMのBlendShapeClipに反映する
|
||||
/// </summary>
|
||||
public static class VRMMeshIntegratorUtility
|
||||
{
|
||||
public static bool IntegrateRuntime(GameObject vrmRootObject)
|
||||
{
|
||||
if (vrmRootObject == null) return false;
|
||||
var proxy = vrmRootObject.GetComponent<VRMBlendShapeProxy>();
|
||||
if (proxy == null) return false;
|
||||
var avatar = proxy.BlendShapeAvatar;
|
||||
if (avatar == null) return false;
|
||||
var clips = avatar.Clips;
|
||||
|
||||
var results = Integrate(vrmRootObject, clips);
|
||||
if (results.Any(x => x.IntegratedRenderer == null)) return false;
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
foreach (var renderer in result.SourceSkinnedMeshRenderers)
|
||||
{
|
||||
Object.Destroy(renderer);
|
||||
}
|
||||
|
||||
foreach (var renderer in result.SourceMeshRenderers)
|
||||
{
|
||||
Object.Destroy(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<MeshUtility.MeshIntegrationResult> Integrate(GameObject root, List<BlendShapeClip> blendshapeClips)
|
||||
{
|
||||
var result = new List<MeshUtility.MeshIntegrationResult>();
|
||||
|
||||
var withoutBlendShape = MeshUtility.MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: false);
|
||||
if (withoutBlendShape.IntegratedRenderer != null)
|
||||
{
|
||||
result.Add(withoutBlendShape);
|
||||
}
|
||||
|
||||
var onlyBlendShape = MeshUtility.MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: true);
|
||||
if (onlyBlendShape.IntegratedRenderer != null)
|
||||
{
|
||||
result.Add(onlyBlendShape);
|
||||
FollowBlendshapeRendererChange(blendshapeClips, onlyBlendShape, root);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void FollowBlendshapeRendererChange(List<BlendShapeClip> clips, MeshUtility.MeshIntegrationResult result, GameObject root)
|
||||
{
|
||||
if (clips == null || result == null || result.IntegratedRenderer == null || root == null) return;
|
||||
|
||||
var rendererDict = result.SourceSkinnedMeshRenderers
|
||||
.ToDictionary(x => x.transform.RelativePathFrom(root.transform), x => x);
|
||||
|
||||
var dstPath = result.IntegratedRenderer.transform.RelativePathFrom(root.transform);
|
||||
|
||||
foreach (var clip in clips)
|
||||
{
|
||||
if (clip == null) continue;
|
||||
|
||||
for (var i = 0; i < clip.Values.Length; ++i)
|
||||
{
|
||||
var val = clip.Values[i];
|
||||
if (rendererDict.ContainsKey(val.RelativePath))
|
||||
{
|
||||
var srcRenderer = rendererDict[val.RelativePath];
|
||||
var name = srcRenderer.sharedMesh.GetBlendShapeName(val.Index);
|
||||
var newIndex = result.IntegratedRenderer.sharedMesh.GetBlendShapeIndex(name);
|
||||
|
||||
val.RelativePath = dstPath;
|
||||
val.Index = newIndex;
|
||||
}
|
||||
|
||||
clip.Values[i] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8eebeb093136b7f429c0e9e7295816b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user