using System; using System.Collections.Generic; using System.Linq; using UniGLTF; using UnityEngine; namespace VRM { public class VRMFirstPerson : MonoBehaviour { public const int FIRSTPERSON_ONLY_LAYER = 9; public const int THIRDPERSON_ONLY_LAYER = 10; [SerializeField] public Transform FirstPersonBone; [SerializeField] public Vector3 FirstPersonOffset; [Serializable] public struct RendererFirstPersonFlags { public Renderer Renderer; public FirstPersonFlag FirstPersonFlag; public Mesh SharedMesh { get { var renderer = Renderer as SkinnedMeshRenderer; if (renderer != null) { return renderer.sharedMesh; } var filter = Renderer.GetComponent(); if (filter != null) { return filter.sharedMesh; } return null; } } } [SerializeField] public List Renderers = new List(); static IEnumerable Traverse(Transform parent) { yield return parent; foreach (Transform child in parent) { foreach (var x in Traverse(child)) { yield return x; } } } public void CopyTo(GameObject _dst, Dictionary map) { var dst = _dst.AddComponent(); dst.FirstPersonBone = FirstPersonBone; dst.FirstPersonOffset = FirstPersonOffset; dst.Renderers = Renderers.Select(x => { var renderer = map[x.Renderer.transform].GetComponent(); return new VRMFirstPerson.RendererFirstPersonFlags { Renderer = renderer, FirstPersonFlag = x.FirstPersonFlag, }; }).ToList(); } public void SetDefault() { FirstPersonOffset = new Vector3(0, 0.06f, 0); var animator = GetComponent(); if (animator != null) { FirstPersonBone = animator.GetBoneTransform(HumanBodyBones.Head); } } private void Reset() { TraverseRenderers(); } public void TraverseRenderers(VRMImporterContext context = null) { Renderers = Traverse(transform) .Select(x => x.GetComponent()) .Where(x => x != null) .Select(x => new RendererFirstPersonFlags { Renderer = x, FirstPersonFlag = context == null ? FirstPersonFlag.Auto : GetFirstPersonFlag(context, x) }) .ToList() ; } static FirstPersonFlag GetFirstPersonFlag(VRMImporterContext context, Renderer r) { var mesh = r.transform.GetSharedMesh(); if (mesh == null) { return FirstPersonFlag.Auto; } var index = context.Meshes.FindIndex(x => x.Mesh == mesh); if (index == -1) { return FirstPersonFlag.Auto; } foreach(var x in context.GLTF.extensions.VRM.firstPerson.meshAnnotations) { if (x.mesh == index) { return EnumUtil.TryParseOrDefault(x.firstPersonFlag); } } return FirstPersonFlag.Auto; } void CreateHeadlessModel(Renderer _renderer, Transform EraseRoot) { var renderer = _renderer as SkinnedMeshRenderer; if (renderer != null) { var go = new GameObject("_headless_" + renderer.name); go.layer = FIRSTPERSON_ONLY_LAYER; go.transform.SetParent(renderer.transform, false); var m_eraseBones = renderer.bones.Select(x => { var eb = new BoneMeshEraser.EraseBone { Bone = x, }; if (EraseRoot != null) { // 首の子孫を消去 if (eb.Bone.Ancestor().Any(y => y == EraseRoot)) { //Debug.LogFormat("erase {0}", x); eb.Erase = true; } } return eb; }) .ToArray(); var bones = renderer.bones; var eraseBones = m_eraseBones .Where(x => x.Erase) .Select(x => bones.IndexOf(x.Bone)) .ToArray(); var mesh = BoneMeshEraser.CreateErasedMesh(renderer.sharedMesh, eraseBones); var erased = go.AddComponent(); erased.sharedMesh = mesh; erased.sharedMaterials = renderer.sharedMaterials; erased.bones = renderer.bones; erased.rootBone = renderer.rootBone; } } bool m_done; /// /// 配下のモデルのレイヤー設定など /// public void Setup() { if (m_done) return; m_done = true; foreach (var x in Renderers) { switch (x.FirstPersonFlag) { case FirstPersonFlag.Auto: x.Renderer.gameObject.layer = THIRDPERSON_ONLY_LAYER; CreateHeadlessModel(x.Renderer, FirstPersonBone); break; case FirstPersonFlag.FirstPersonOnly: x.Renderer.gameObject.layer = FIRSTPERSON_ONLY_LAYER; break; case FirstPersonFlag.ThirdPersonOnly: x.Renderer.gameObject.layer = THIRDPERSON_ONLY_LAYER; break; case FirstPersonFlag.Both: //x.Renderer.gameObject.layer = 0; break; } } } } }