mirror of
https://github.com/LazyDuchess/OpenTS2.git
synced 2025-01-23 00:31:47 -05:00
Merge branch 'master' of https://github.com/LazyDuchess/OpenTS2
This commit is contained in:
commit
0229014e46
3 changed files with 121 additions and 24 deletions
|
@ -57,16 +57,16 @@ namespace OpenTS2.Components
|
||||||
public ScenegraphComponent Scenegraph { get; private set; }
|
public ScenegraphComponent Scenegraph { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is the unity object that all the animation rigging constraints get placed into.
|
/// This is the unity object that all the animation rigs get placed into.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private GameObject _animationRig;
|
private GameObject _animationRigs;
|
||||||
|
private Animator _animator;
|
||||||
private RigBuilder _rigBuilder;
|
private RigBuilder _rigBuilder;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set of IK chains that have already been applied to this sim so they don't get re-applied.
|
/// Set of IK chains that have already been applied to this sim so they don't get re-applied.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly HashSet<uint> _appliedIKChains = new HashSet<uint>();
|
private readonly Dictionary<uint, RigLayer> _appliedIKChains = new Dictionary<uint, RigLayer>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// These are basically parent bones of IK chains, this is needed so that if an animation updates the position
|
/// These are basically parent bones of IK chains, this is needed so that if an animation updates the position
|
||||||
|
@ -90,13 +90,13 @@ namespace OpenTS2.Components
|
||||||
boneRenderer.transforms = boneTransforms.ToArray();
|
boneRenderer.transforms = boneTransforms.ToArray();
|
||||||
|
|
||||||
// Add an animator component to the auskel.
|
// Add an animator component to the auskel.
|
||||||
var animator = skeleton.AddComponent<Animator>();
|
_animator = skeleton.AddComponent<Animator>();
|
||||||
// Add a rig builder.
|
// Add a rig builder.
|
||||||
_rigBuilder = skeleton.AddComponent<RigBuilder>();
|
_rigBuilder = skeleton.AddComponent<RigBuilder>();
|
||||||
|
|
||||||
// Add a child rig to the skeleton.
|
// Add a child rig to the skeleton.
|
||||||
_animationRig = new GameObject("UnityAnimationRig", typeof(Rig));
|
_animationRigs = new GameObject("UnityAnimationRigs");
|
||||||
_animationRig.transform.SetParent(skeleton.transform, worldPositionStays: false);
|
_animationRigs.transform.SetParent(skeleton.transform, worldPositionStays: false);
|
||||||
|
|
||||||
// HACK: In the auskel model, for some reason the bones that represent the IK goals for the hands are
|
// HACK: In the auskel model, for some reason the bones that represent the IK goals for the hands are
|
||||||
// parented to the root_trans of the skeleton. This is done even though in animations the IK goal bones
|
// parented to the root_trans of the skeleton. This is done even though in animations the IK goal bones
|
||||||
|
@ -120,8 +120,8 @@ namespace OpenTS2.Components
|
||||||
|
|
||||||
AddGizmosAroundInverseKinmaticsPositions();
|
AddGizmosAroundInverseKinmaticsPositions();
|
||||||
|
|
||||||
_rigBuilder.layers.Add(new RigLayer(_animationRig.GetComponent<Rig>()));
|
//_rigBuilder.layers.Add(new RigLayer(_animationRig.GetComponent<Rig>()));
|
||||||
_rigBuilder.layers[0].Initialize(animator);
|
//_rigBuilder.layers[0].Initialize(animator);
|
||||||
_rigBuilder.Build();
|
_rigBuilder.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,14 +155,35 @@ namespace OpenTS2.Components
|
||||||
Destroy(spherePrimitive);
|
Destroy(spherePrimitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddInverseKinematicsFromAnimation(AnimResourceConstBlock anim)
|
public void AdjustInverseKinematicWeightsForAnimation(AnimResourceConstBlock anim)
|
||||||
{
|
{
|
||||||
|
// TODO: This should eventually live in the animation controller for the sim. This is here for easy testing
|
||||||
|
// for now.
|
||||||
var auSkelTarget = anim.AnimTargets.FirstOrDefault(t => t.TagName.ToLower() == "auskel");
|
var auSkelTarget = anim.AnimTargets.FirstOrDefault(t => t.TagName.ToLower() == "auskel");
|
||||||
if (auSkelTarget == null)
|
if (auSkelTarget == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
AddInverseKinematicsFromAnimation(auSkelTarget);
|
||||||
|
|
||||||
|
// Disable all current rigs.
|
||||||
|
foreach (var rigLayer in _appliedIKChains.Values)
|
||||||
|
{
|
||||||
|
rigLayer.active = false;
|
||||||
|
}
|
||||||
|
// Activate the ones present in the current animation.
|
||||||
|
foreach (var chain in auSkelTarget.IKChains)
|
||||||
|
{
|
||||||
|
if (!_appliedIKChains.TryGetValue(chain.NameCrc, out var rigLayer))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rigLayer.active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddInverseKinematicsFromAnimation(AnimResourceConstBlock.AnimTarget auSkelTarget)
|
||||||
|
{
|
||||||
AddInverseKinematicsFromIKChains(auSkelTarget.IKChains);
|
AddInverseKinematicsFromIKChains(auSkelTarget.IKChains);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,10 +191,13 @@ namespace OpenTS2.Components
|
||||||
{
|
{
|
||||||
foreach (var chain in ikChains)
|
foreach (var chain in ikChains)
|
||||||
{
|
{
|
||||||
if (_appliedIKChains.Contains(chain.NameCrc))
|
if (_appliedIKChains.ContainsKey(chain.NameCrc))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
var rigObject = new GameObject($"ik-rig-{chain.NameCrc:X}", typeof(Rig));
|
||||||
|
rigObject.transform.SetParent(_animationRigs.transform);
|
||||||
|
var rig = rigObject.GetComponent<Rig>();
|
||||||
|
|
||||||
Debug.Assert(chain.BeginBoneCrc != 0, "ikChain without a beginning bone");
|
Debug.Assert(chain.BeginBoneCrc != 0, "ikChain without a beginning bone");
|
||||||
Debug.Assert(chain.EndBoneCrc != 0, "ikChain without an end bone");
|
Debug.Assert(chain.EndBoneCrc != 0, "ikChain without an end bone");
|
||||||
|
@ -222,7 +246,7 @@ namespace OpenTS2.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
ikChainObj.GetComponent<TwoBoneIKConstraint>().data = twoBoneConstraint;
|
ikChainObj.GetComponent<TwoBoneIKConstraint>().data = twoBoneConstraint;
|
||||||
ikChainObj.transform.parent = _animationRig.transform;
|
ikChainObj.transform.parent = rigObject.transform;
|
||||||
|
|
||||||
if (target.Rotation2Crc != 0)
|
if (target.Rotation2Crc != 0)
|
||||||
{
|
{
|
||||||
|
@ -237,10 +261,13 @@ namespace OpenTS2.Components
|
||||||
space = OverrideTransformData.Space.Local,
|
space = OverrideTransformData.Space.Local,
|
||||||
};
|
};
|
||||||
rotationConstraint.GetComponent<OverrideTransform>().data = rotationOverrideConstraint;
|
rotationConstraint.GetComponent<OverrideTransform>().data = rotationOverrideConstraint;
|
||||||
rotationConstraint.transform.parent = _animationRig.transform;
|
rotationConstraint.transform.parent = rigObject.transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
_appliedIKChains.Add(chain.NameCrc);
|
var rigLayer = new RigLayer(rig);
|
||||||
|
_rigBuilder.layers.Add(rigLayer);
|
||||||
|
rigLayer.Initialize(_animator);
|
||||||
|
_appliedIKChains[chain.NameCrc] = rigLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
_rigBuilder.Build();
|
_rigBuilder.Build();
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
using OpenTS2.Common;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenTS2.Common;
|
||||||
using OpenTS2.Components;
|
using OpenTS2.Components;
|
||||||
using OpenTS2.Content;
|
using OpenTS2.Content;
|
||||||
using OpenTS2.Content.DBPF.Scenegraph;
|
using OpenTS2.Content.DBPF.Scenegraph;
|
||||||
|
@ -10,6 +13,15 @@ namespace OpenTS2.Engine.Tests
|
||||||
{
|
{
|
||||||
public class SimAnimationTest : MonoBehaviour
|
public class SimAnimationTest : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
public string animationName = "";
|
||||||
|
|
||||||
|
[TextArea(minLines: 10, maxLines: 10)]
|
||||||
|
public string matchedNames = "";
|
||||||
|
|
||||||
|
private readonly Dictionary<string, ScenegraphAnimationAsset> _animations = new Dictionary<string, ScenegraphAnimationAsset>();
|
||||||
|
private Animation _animationObj;
|
||||||
|
private SimCharacterComponent _sim;
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
var contentProvider = ContentProvider.Get();
|
var contentProvider = ContentProvider.Get();
|
||||||
|
@ -19,24 +31,78 @@ namespace OpenTS2.Engine.Tests
|
||||||
Filesystem.GetPackagesInDirectory(Filesystem.GetDataPathForProduct(ProductFlags.BaseGame) +
|
Filesystem.GetPackagesInDirectory(Filesystem.GetDataPathForProduct(ProductFlags.BaseGame) +
|
||||||
"/Res/Sims3D"));
|
"/Res/Sims3D"));
|
||||||
|
|
||||||
var sim = SimCharacterComponent.CreateNakedBaseSim();
|
// Load all animations involving auskel and put them in the dictionary.
|
||||||
|
foreach (var animationAsset in contentProvider.GetAssetsOfType<ScenegraphAnimationAsset>(TypeIDs.SCENEGRAPH_ANIM))
|
||||||
|
{
|
||||||
|
var auSkelTarget = animationAsset.AnimResource.AnimTargets.FirstOrDefault(t => t.TagName.ToLower() == "auskel");
|
||||||
|
if (auSkelTarget == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_animations[animationAsset.AnimResource.ScenegraphResource.ResourceName] = animationAsset;
|
||||||
|
}
|
||||||
|
UpdateAnimationsListAndGetSelection();
|
||||||
|
|
||||||
|
_sim = SimCharacterComponent.CreateNakedBaseSim();
|
||||||
|
|
||||||
const string animationName = "a-pose-neutral-stand_anim";
|
const string animationName = "a-pose-neutral-stand_anim";
|
||||||
var anim = contentProvider.GetAsset<ScenegraphAnimationAsset>(
|
var anim = contentProvider.GetAsset<ScenegraphAnimationAsset>(
|
||||||
new ResourceKey(animationName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM));
|
new ResourceKey(animationName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM));
|
||||||
sim.AddInverseKinematicsFromAnimation(anim.AnimResource);
|
_sim.AdjustInverseKinematicWeightsForAnimation(anim.AnimResource);
|
||||||
|
|
||||||
// Add the test animation.
|
// Add the test animation.
|
||||||
var animationObj = sim.GetComponentInChildren<Animation>();
|
_animationObj = _sim.GetComponentInChildren<Animation>();
|
||||||
var clip = anim.CreateClipFromResource(sim.Scenegraph.BoneNamesToRelativePaths, sim.Scenegraph.BlendNamesToRelativePaths);
|
var clip = anim.CreateClipFromResource(_sim.Scenegraph.BoneNamesToRelativePaths, _sim.Scenegraph.BlendNamesToRelativePaths);
|
||||||
animationObj.AddClip(clip, animationName);
|
_animationObj.AddClip(clip, animationName);
|
||||||
|
|
||||||
//const string testAnimation = "a-blowHorn_anim";
|
//const string testAnimation = "a-blowHorn_anim";
|
||||||
const string testAnimation = "a2o-punchingBag-punch-start_anim";
|
const string testAnimation = "a2o-punchingBag-punch-start_anim";
|
||||||
anim = contentProvider.GetAsset<ScenegraphAnimationAsset>(
|
anim = contentProvider.GetAsset<ScenegraphAnimationAsset>(
|
||||||
new ResourceKey(testAnimation, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM));
|
new ResourceKey(testAnimation, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_ANIM));
|
||||||
clip = anim.CreateClipFromResource(sim.Scenegraph.BoneNamesToRelativePaths, sim.Scenegraph.BlendNamesToRelativePaths);
|
clip = anim.CreateClipFromResource(_sim.Scenegraph.BoneNamesToRelativePaths, _sim.Scenegraph.BlendNamesToRelativePaths);
|
||||||
animationObj.AddClip(clip, testAnimation);
|
_animationObj.AddClip(clip, testAnimation);
|
||||||
|
_sim.AdjustInverseKinematicWeightsForAnimation(anim.AnimResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
// Check what new animations match.
|
||||||
|
var anim = UpdateAnimationsListAndGetSelection();
|
||||||
|
if (anim == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Play the neutral animation for one second to reset positions to default.
|
||||||
|
_animationObj.Play("a-pose-neutral-stand_anim");
|
||||||
|
|
||||||
|
var animName = anim.AnimResource.ScenegraphResource.ResourceName;
|
||||||
|
if (_animationObj.GetClip(animName) == null)
|
||||||
|
{
|
||||||
|
var clip = anim.CreateClipFromResource(_sim.Scenegraph.BoneNamesToRelativePaths,
|
||||||
|
_sim.Scenegraph.BlendNamesToRelativePaths);
|
||||||
|
_animationObj.AddClip(clip, animName);
|
||||||
|
}
|
||||||
|
|
||||||
|
StartCoroutine(PlayClipFrameDelayed(animName, anim));
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator PlayClipFrameDelayed(string animName, ScenegraphAnimationAsset anim)
|
||||||
|
{
|
||||||
|
yield return new WaitForFixedUpdate();
|
||||||
|
|
||||||
|
_sim.AdjustInverseKinematicWeightsForAnimation(anim.AnimResource);
|
||||||
|
_animationObj.Play(animName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScenegraphAnimationAsset UpdateAnimationsListAndGetSelection()
|
||||||
|
{
|
||||||
|
var matchedAnimations = _animations.Where(pair => pair.Key.StartsWith(animationName));
|
||||||
|
var tenMatchedAnimations = matchedAnimations.Take(10).ToArray();
|
||||||
|
|
||||||
|
// Display 10 matching animations.
|
||||||
|
matchedNames = string.Join("\n", tenMatchedAnimations.Select(pair => pair.Key));
|
||||||
|
return tenMatchedAnimations.Length == 0 ? null : tenMatchedAnimations[0].Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,10 +22,14 @@ namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const double FramesPerTick = 0.03;
|
public const double FramesPerTick = 0.03;
|
||||||
|
|
||||||
|
public ScenegraphResource ScenegraphResource;
|
||||||
|
|
||||||
public AnimTarget[] AnimTargets;
|
public AnimTarget[] AnimTargets;
|
||||||
|
|
||||||
public AnimResourceConstBlock(PersistTypeInfo blockTypeInfo, AnimTarget[] animTargets) : base(blockTypeInfo)
|
public AnimResourceConstBlock(PersistTypeInfo blockTypeInfo, ScenegraphResource scenegraphResource,
|
||||||
|
AnimTarget[] animTargets) : base(blockTypeInfo)
|
||||||
{
|
{
|
||||||
|
ScenegraphResource = scenegraphResource;
|
||||||
AnimTargets = animTargets;
|
AnimTargets = animTargets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,7 +643,7 @@ namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return new AnimResourceConstBlock(blockTypeInfo, animTargets);
|
return new AnimResourceConstBlock(blockTypeInfo, resource, animTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For some reason this format pads to 4-byte boundaries sometimes...we deal with that here.
|
// For some reason this format pads to 4-byte boundaries sometimes...we deal with that here.
|
||||||
|
|
Loading…
Reference in a new issue