2025-04-25 21:14:54 +09:00

159 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UniHumanoid;
using UnityEngine;
using UnityEngine.XR;
namespace VRM
{
public class VrmMeshUtility : UniGLTF.MeshUtility.GltfMeshUtility
{
bool _generateFirstPerson = false;
public override IEnumerable<UniGLTF.MeshUtility.MeshIntegrationGroup> CopyInstantiate(GameObject go, GameObject instance)
{
_generateFirstPerson = false;
var copy = base.CopyInstantiate(go, instance);
if (GenerateMeshForFirstPersonAuto)
{
foreach (var g in copy)
{
if (g.Name == "auto")
{
_generateFirstPerson = true;
// 元のメッシュを三人称に変更
yield return new UniGLTF.MeshUtility.MeshIntegrationGroup
{
Name = FirstPersonFlag.ThirdPersonOnly.ToString(),
IntegrationType = UniGLTF.MeshUtility.MeshIntegrationGroup.MeshIntegrationTypes.ThirdPersonOnly,
Renderers = g.Renderers.ToList(),
};
}
yield return g;
}
}
else
{
foreach (var g in copy)
{
yield return g;
}
}
}
protected override bool
TryIntegrate(
GameObject empty,
UniGLTF.MeshUtility.MeshIntegrationGroup group,
out (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) resultAndAdded)
{
if (!base.TryIntegrate(empty, group, out resultAndAdded))
{
resultAndAdded = default;
return false;
}
var (result, newGo) = resultAndAdded;
if (_generateFirstPerson && group.Name == nameof(FirstPersonFlag.Auto))
{
// Mesh 統合の後処理
// FirstPerson == "auto" の場合に
// 頭部の無いモデルを追加で作成する
Debug.Log("generateFirstPerson");
if (result.Integrated.Mesh != null)
{
// BlendShape 有り
_ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.Integrated.IntegratedRenderer);
}
if (result.IntegratedNoBlendShape.Mesh != null)
{
// BlendShape 無しの方
_ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.IntegratedNoBlendShape.IntegratedRenderer);
}
}
return true;
}
private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr)
{
var mesh = _vrmInstance.ProcessFirstPerson(firstPersonBone, smr);
if (mesh != null)
{
smr.sharedMesh = mesh;
smr.name = "auto.headless";
}
else
{
Debug.LogWarning("no result");
}
}
VRMFirstPerson _vrmInstance = null;
/// <summary>
/// glTF に比べて Humanoid や FirstPerson の処理が追加される
/// </summary>
public override (List<UniGLTF.MeshUtility.MeshIntegrationResult>, List<GameObject>) Process(
GameObject target, IEnumerable<UniGLTF.MeshUtility.MeshIntegrationGroup> copyGroup)
{
_vrmInstance = target.GetComponent<VRMFirstPerson>();
if (_vrmInstance == null)
{
throw new ArgumentException();
}
// TODO: update: spring
// TODO: update: constraint
// TODO: update: firstPerson offset
var (list, newList) = base.Process(target, copyGroup);
if (FreezeBlendShapeRotationAndScaling)
{
var animator = target.GetComponent<Animator>();
var newAvatar = AvatarDescription.RecreateAvatar(animator);
// ??? clear old avatar ???
var t = animator.gameObject;
if (Application.isPlaying)
{
GameObject.Destroy(animator);
}
else
{
GameObject.DestroyImmediate(animator);
}
t.AddComponent<Animator>().avatar = newAvatar;
}
return (list, newList);
}
public override void UpdateMeshIntegrationGroups(GameObject root)
{
MeshIntegrationGroups.Clear();
if (root == null)
{
return;
}
var vrm0 = root.GetComponent<VRMFirstPerson>();
if (vrm0 == null)
{
return;
}
foreach (var a in vrm0.Renderers)
{
var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString());
g.Renderers.Add(a.Renderer);
}
var orphan = root.GetComponentsInChildren<Renderer>().Where(x => !_HasRenderer(x)).ToArray();
if (orphan.Length > 0)
{
var g = _GetOrCreateGroup("both");
g.Renderers.AddRange(orphan);
}
}
}
}