UniversalViewer/Assets/DanMachi/Scripts/Containers/DanMachiCharacterContainer.cs

348 lines
14 KiB
C#
Raw Permalink Normal View History

2024-04-22 06:00:51 +08:00
using System.Collections.Generic;
using System.IO;
2024-04-22 06:00:51 +08:00
using System.Linq;
using UnityEngine;
public class DanMachiCharacterContainer : ObjectContainer, IAnimated
2024-04-22 06:00:51 +08:00
{
protected override System.Type _serializeType => typeof(DanMachiCharacterSerializable);
protected override System.Type _keyframeType => typeof(DanMachiCharacterKeyframeData);
2024-04-22 06:00:51 +08:00
public CharacterAsset Data;
public string AnimationSet;
public string Animation;
public GameObject Body;
2024-04-22 06:00:51 +08:00
public MorphPanel MorphPanel;
public CharacterPanel CharacterPanel;
public List<AnimationClip> Animations;
private Animator _animator;
private AnimatorOverrideController _animatorController;
private Dictionary<HumanBodyBones, Transform> _humanBones = new Dictionary<HumanBodyBones, Transform>();
public List<Transform> Bones = new List<Transform>();
2024-04-22 06:00:51 +08:00
public void Init()
2024-04-22 06:00:51 +08:00
{
_animator = GetComponentInChildren<Animator>();
if(_animator != null)
{
_animator.applyRootMotion = false;
_animator.runtimeAnimatorController = _animatorController = Instantiate(SharedResources.Instance.GenericAnimatorController);
}
else
2024-04-22 06:00:51 +08:00
{
Error.Log(Color.red, $"{name} has no animator");
2024-04-22 06:00:51 +08:00
}
CreateMorphPanel();
CreateCharacterPanel();
SetBones();
2024-04-22 06:00:51 +08:00
}
public void Rebuild(CharacterAsset model)
2024-04-22 06:00:51 +08:00
{
DestroyImmediate(Body);
Build(model);
2024-04-22 06:00:51 +08:00
}
public void Build(CharacterAsset model)
{
Data = model;
var assetPath = Path.Combine(DanMachiAssetLibrary.Instance.LocalFilesPath, model.FilePath);
var characterAsset = AssetLibrary.LoadFromFile(assetPath);
var assetNames = characterAsset.GetAllAssetNames();
var characterModel = assetNames.FirstOrDefault(a => Path.GetFileName(a).StartsWith("CP_") && a.EndsWith(".prefab"));
2024-04-22 06:00:51 +08:00
if(!string.IsNullOrEmpty(characterModel))
{
Body = Instantiate(characterAsset.LoadAsset(characterModel), transform) as GameObject;
}
else
2024-04-22 06:00:51 +08:00
{
Body = new GameObject();
Body.transform.SetParent(transform);
foreach (var go in characterAsset.LoadAllAssets<GameObject>())
{
Instantiate(go, Body.transform);
}
2024-04-22 06:00:51 +08:00
}
LoadedAssets = new List<AssetBundleEntry>() { new AssetBundleEntry(model.AssetName, assetPath, characterAsset) };
AssetLibrary.UnloadAsset(assetPath);
2024-04-22 06:00:51 +08:00
SetDefaultMaterials(transform);
Init();
}
public void LoadAnimationSet(CharacterAsset animationSet)
{
if (animationSet != null)
{
AnimationSet = animationSet.Costume;
Animation = "";
var animationAsset = AssetBundle.LoadFromFile(Path.Combine(DanMachiAssetLibrary.Instance.LocalFilesPath, animationSet.FilePath));
2024-04-22 06:00:51 +08:00
Animations = animationAsset.LoadAllAssets<AnimationClip>().ToList();
animationAsset.Unload(false);
}
}
public void PlayAnimation(string clipName)
{
var anim = Animations.FirstOrDefault(a=>a.name == clipName);
PlayAnimation(anim);
}
public void PlayAnimation(AnimationClip anim)
{
if(_animator == null)
{
Error.Log(Color.red, $"{name} has no animator");
return;
}
2024-04-22 06:00:51 +08:00
if(anim == null)
{
Animation = "";
_animator.enabled = false;
}
else
{
Animation = anim.name;
_animator.enabled = true;
_animatorController["Anim"] = anim;
}
}
public void SetDefaultMaterials(Transform t)
{
List<Material> materials = new List<Material>();
foreach (var renderer in t.GetComponentsInChildren<Renderer>())
{
foreach (var material in renderer.sharedMaterials)
{
if (materials.Contains(material)) continue;
materials.Add(material);
material.shader = Shader.Find("DanMachiUnlit");
2024-04-22 06:00:51 +08:00
}
}
}
public void SetBones()
{
_humanBones.Clear();
Bones.Clear();
if (_animator == null) return;
2024-04-22 06:00:51 +08:00
var humanBones = new Dictionary<HumanBodyBones, Transform>();
var allBones = new Dictionary<string, Transform>();
foreach(var bone in _animator.transform.GetComponentsInChildren<Transform>())
{
if (!allBones.ContainsKey(bone.name))
{
allBones[bone.name] = bone;
}
}
humanBones.Add(HumanBodyBones.Hips, TryGet(allBones,"Hips"));
humanBones.Add(HumanBodyBones.Spine, TryGet(allBones,"Spine"));
humanBones.Add(HumanBodyBones.RightUpperLeg, TryGet(allBones,"RightUpLeg"));
humanBones.Add(HumanBodyBones.RightLowerLeg, TryGet(allBones,"RightLeg"));
humanBones.Add(HumanBodyBones.RightFoot, TryGet(allBones,"RightFoot"));
humanBones.Add(HumanBodyBones.RightToes, TryGet(allBones,"RightToeBase"));
humanBones.Add(HumanBodyBones.LeftUpperLeg, TryGet(allBones,"LeftUpLeg"));
humanBones.Add(HumanBodyBones.LeftLowerLeg, TryGet(allBones,"LeftLeg"));
humanBones.Add(HumanBodyBones.LeftFoot, TryGet(allBones,"LeftFoot"));
humanBones.Add(HumanBodyBones.LeftToes, TryGet(allBones,"LeftToeBase"));
humanBones.Add(HumanBodyBones.Chest, TryGet(allBones,"Spine1"));
humanBones.Add(HumanBodyBones.UpperChest, TryGet(allBones,"Spine2"));
humanBones.Add(HumanBodyBones.Neck, TryGet(allBones,"Neck"));
humanBones.Add(HumanBodyBones.Head, TryGet(allBones,"Head"));
humanBones.Add(HumanBodyBones.RightShoulder, TryGet(allBones,"RightShoulder"));
humanBones.Add(HumanBodyBones.RightUpperArm, TryGet(allBones,"RightArm"));
humanBones.Add(HumanBodyBones.RightLowerArm, TryGet(allBones,"RightForeArm"));
humanBones.Add(HumanBodyBones.RightHand, TryGet(allBones,"RightHand"));
2024-04-22 06:00:51 +08:00
humanBones.Add(HumanBodyBones.RightIndexProximal, TryGet(allBones,"RightHandIndex1"));
humanBones.Add(HumanBodyBones.RightIndexIntermediate, TryGet(allBones,"RightHandIndex2"));
humanBones.Add(HumanBodyBones.RightMiddleProximal, TryGet(allBones,"RightHandMiddle1"));
humanBones.Add(HumanBodyBones.RightMiddleIntermediate, TryGet(allBones,"RightHandMiddle2"));
humanBones.Add(HumanBodyBones.RightRingProximal, TryGet(allBones,"RightHandRing1"));
humanBones.Add(HumanBodyBones.RightRingIntermediate, TryGet(allBones,"RightHandRing2"));
humanBones.Add(HumanBodyBones.RightLittleProximal, TryGet(allBones,"RightHandPinky1"));
humanBones.Add(HumanBodyBones.RightLittleIntermediate, TryGet(allBones,"RightHandPinky2"));
humanBones.Add(HumanBodyBones.RightThumbProximal, TryGet(allBones,"RightHandThumb1"));
humanBones.Add(HumanBodyBones.RightThumbIntermediate, TryGet(allBones,"RightHandThumb2"));
humanBones.Add(HumanBodyBones.LeftShoulder, TryGet(allBones,"LeftShoulder"));
humanBones.Add(HumanBodyBones.LeftUpperArm, TryGet(allBones,"LeftArm"));
humanBones.Add(HumanBodyBones.LeftLowerArm, TryGet(allBones,"LeftForeArm"));
humanBones.Add(HumanBodyBones.LeftHand, TryGet(allBones,"LeftHand"));
humanBones.Add(HumanBodyBones.LeftIndexProximal, TryGet(allBones,"LeftHandIndex1"));
humanBones.Add(HumanBodyBones.LeftIndexIntermediate, TryGet(allBones,"LeftHandIndex2"));
humanBones.Add(HumanBodyBones.LeftMiddleProximal, TryGet(allBones,"LeftHandMiddle1"));
humanBones.Add(HumanBodyBones.LeftMiddleIntermediate, TryGet(allBones,"LeftHandMiddle2"));
humanBones.Add(HumanBodyBones.LeftRingProximal, TryGet(allBones,"LeftHandRing1"));
humanBones.Add(HumanBodyBones.LeftRingIntermediate, TryGet(allBones,"LeftHandRing2"));
humanBones.Add(HumanBodyBones.LeftLittleProximal, TryGet(allBones,"LeftHandPinky1"));
humanBones.Add(HumanBodyBones.LeftLittleIntermediate, TryGet(allBones,"LeftHandPinky2"));
humanBones.Add(HumanBodyBones.LeftThumbProximal, TryGet(allBones,"LeftHandThumb1"));
humanBones.Add(HumanBodyBones.LeftThumbIntermediate, TryGet(allBones,"LeftHandThumb2"));
2024-04-22 06:00:51 +08:00
foreach(var bone in humanBones)
{
if(bone.Value != null)
{
var tags = new List<SerializableBone.BoneTags>() { SerializableBone.BoneTags.Humanoid };
if (bone.Value.name.Contains("Left"))
{
tags.Add(SerializableBone.BoneTags.Left);
}
else if (bone.Value.name.Contains("Right"))
{
tags.Add(SerializableBone.BoneTags.Right);
}
if((bone.Key >= HumanBodyBones.LeftThumbProximal && bone.Key <= HumanBodyBones.LeftLittleDistal)
|| (bone.Key >= HumanBodyBones.RightThumbProximal && bone.Key <= HumanBodyBones.RightLittleDistal))
{
tags.Add(SerializableBone.BoneTags.Finger);
}
UIHandle.CreateAsChild<UIHandleBone>(bone.Value).Init(this, tags).WithLineRenderer();
2024-04-22 06:00:51 +08:00
}
}
foreach(var bone in allBones.Values.Except(humanBones.Values))
{
var tags = new List<SerializableBone.BoneTags>();
if (bone.GetComponent<Unity.Animations.SpringBones.SpringBone>() != null)
{
tags.Add(SerializableBone.BoneTags.Dynamic);
}
UIHandle.CreateAsChild<UIHandleBone>(bone).Init(this, tags).WithLineRenderer();
2024-04-22 06:00:51 +08:00
}
_humanBones = humanBones;
Bones = allBones.Values.ToList();
2024-04-22 06:00:51 +08:00
}
public T TryGet<T>(Dictionary<string, T> dict, string key)
{
if (dict.ContainsKey(key))
{
return dict[key];
}
return default(T);
}
public void CreateMorphPanel()
{
var morphRenderers = new Dictionary<SkinnedMeshRenderer, List<MorphHelper>>();
foreach (var rend in gameObject.GetComponentsInChildren<SkinnedMeshRenderer>())
{
if(rend.sharedMesh.blendShapeCount > 0)
{
morphRenderers.Add(rend, new List<MorphHelper>());
}
}
if (morphRenderers.Count == 0)
{
if(MorphPanel != null)
{
Destroy(MorphPanel.gameObject);
MorphPanel = null;
InstantiatedObjects.Remove(MorphPanel.gameObject);
}
return;
}
2024-04-22 06:00:51 +08:00
if(MorphPanel != null)
{
MorphPanel.Init(morphRenderers.Select(mr => mr.Key.sharedMesh.name).ToList());
}
else
{
MorphPanel = MorphPanel.Create(morphRenderers.Select(mr => mr.Key.sharedMesh.name).ToList());
MorphPanel.name = $"Chr_{Data.Id} Morphs";
InstantiatedObjects.Add(MorphPanel.gameObject);
DanMachiInterface.Instance.SelectedObjectToolbar.AttachToThis(MorphPanel.GetComponent<UIElementDragger>());
}
2024-04-22 06:00:51 +08:00
foreach (var rend in morphRenderers)
2024-04-22 06:00:51 +08:00
{
var mesh = rend.Key.sharedMesh;
for(int i = 0; i < mesh.blendShapeCount; i++)
{
var panel = MorphPanel.CreateMorph(mesh.name, this, rend.Key, i, mesh.GetBlendShapeName(i).Replace("blendShape1.",""));
var helper = panel.MorphHelper;
if (morphRenderers.ContainsKey(rend.Key))
morphRenderers[rend.Key].Add(helper);
else
morphRenderers.Add(rend.Key, new List<MorphHelper>() { helper });
2024-04-22 06:00:51 +08:00
}
}
Morphs = morphRenderers;
}
public void CreateCharacterPanel()
{
if(CharacterPanel != null)
{
CharacterPanel.Init(this);
}
else
{
CharacterPanel = CharacterPanel.Create(this);
CharacterPanel.name = $"Chr_{Data.Id} Settings";
InstantiatedObjects.Add(CharacterPanel.gameObject);
DanMachiInterface.Instance.SelectedObjectToolbar.AttachToThis(CharacterPanel.GetComponent<UIElementDragger>());
}
2024-04-22 06:00:51 +08:00
}
public override Vector3 GetCenter()
{
if (_humanBones.ContainsKey(HumanBodyBones.Hips))
{
return _humanBones[HumanBodyBones.Hips].position;
}
return base.GetCenter();
}
public Animator GetAnimator()
2024-04-22 06:00:51 +08:00
{
return _animator;
2024-04-22 06:00:51 +08:00
}
public override void PastePose(KeyframeData frame, PoseLoadOptions pasteParams)
2024-04-22 06:00:51 +08:00
{
PlayAnimation("");
if (pasteParams.Root)
{
transform.SetTransform(frame.Root);
}
var frameData = frame as DanMachiCharacterKeyframeData;
if (frameData == null) return;
foreach (var bone in frameData.Bones.Bones)
{
var targetBone = Bones.FirstOrDefault(b => b.name == bone.Name);
if (targetBone == null) continue;
bone.Transform.ApplyTo(targetBone.transform);
}
foreach(var morph in frameData.Morphs)
{
var renderer = Morphs.Keys.FirstOrDefault(k => k.name == morph.Key);
if (renderer == null) continue;
foreach(var value in morph.Value)
{
var helper = Morphs[renderer].FirstOrDefault(h => h.Name == value.Name);
if (helper == null) continue;
helper.Value = value.Value;
helper.UpdateMorph(value.Strength);
}
}
SetKeyframe();
2024-04-22 06:00:51 +08:00
}
}