Skip to content

Instantly share code, notes, and snippets.

@thelebaron
Last active May 15, 2020 21:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thelebaron/7f3a61814fa30dad049d2e7bd969f202 to your computer and use it in GitHub Desktop.
Save thelebaron/7f3a61814fa30dad049d2e7bd969f202 to your computer and use it in GitHub Desktop.
dots animation root motion experiment
using Unity.Animation;
using Unity.DataFlowGraph;
using Unity.Entities;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Serialization;
using Debug = UnityEngine.Debug;
namespace MyFirstAnimationClip
{
public struct PlayClipComponent : IComponentData
{
public bool doWalk;
public BlobAssetReference<Clip> IdleClip;
public BlobAssetReference<Clip> WalkClip;
}
public struct PlayClipStateComponent : ISystemStateComponentData
{
public NodeHandle<ComponentNode> EntityNode;
public NodeHandle<DeltaTimeNode> DeltaTimeNode;
public NodeHandle<ClipPlayerNode> ClipPlayerNode;
public NodeHandle<RootMotionNode> RootMotionNode;
public NodeHandle<ConvertLocalToWorldComponentToFloat4x4Node> LocalToWorldToFloat4x4Node;
public NodeHandle<ConvertFloat4x4ToLocalToWorldComponentNode> Float4x4ToLocalToWorldNode;
}
public class UpdateWalkSystem : SystemBase
{
protected override void OnUpdate()
{
var toggle = Input.GetKeyDown(KeyCode.W);
Entities
.WithName("blarg")
.WithBurst()
.ForEach((Entity e, ref PlayClipComponent animation) =>
{
if (toggle)
{
animation.doWalk = !animation.doWalk;
}
}).Schedule();
}
}
[UpdateBefore(typeof(PreAnimationSystemGroup))]
public class PlayClipSystem : JobComponentSystem
{
PreAnimationGraphSystem m_GraphSystem;
EndSimulationEntityCommandBufferSystem m_ECBSystem;
EntityQuery m_AnimationDataQuery;
protected override void OnCreate()
{
base.OnCreate();
m_GraphSystem = World.GetOrCreateSystem<PreAnimationGraphSystem>();
// Increase the reference count on the graph system so it knows
// that we want to use it.
m_GraphSystem.AddRef();
m_ECBSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
m_AnimationDataQuery = GetEntityQuery(new EntityQueryDesc()
{
None = new ComponentType[] { typeof(PlayClipComponent) },
All = new ComponentType[] { typeof(PlayClipStateComponent) }
});
m_GraphSystem.Set.RendererModel = NodeSet.RenderExecutionModel.Islands;
}
protected override void OnDestroy()
{
if (m_GraphSystem == null)
return;
// Clean up all our nodes in the graph
var nodes = m_GraphSystem.Set;
Entities
.WithoutBurst()
.WithStructuralChanges()
.ForEach((Entity e, ref PlayClipStateComponent data) =>
{
DestroyGraph(nodes, ref data);
}).Run();
// Decrease the reference count on the graph system so it knows
// that we are done using it.
m_GraphSystem.RemoveRef();
base.OnDestroy();
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
inputDeps.Complete();
var set = m_GraphSystem.Set;
var ecb = m_ECBSystem.CreateCommandBuffer();
// Create graph for entities that have a PlayClipComponent but no graph
Entities
.WithName("CreateGraph")
.WithNone<PlayClipStateComponent>()
.WithoutBurst()
.WithStructuralChanges()
.ForEach((Entity e, ref Rig rig, ref PlayClipComponent animation) =>
{
var state = CreateGraph(e, set, ref rig, ref animation);
ecb.AddComponent(e, state);
ecb.AddComponent(e, m_GraphSystem.TagComponent);
}).Run();
// Update graph if the animation component changed
Entities
.WithName("UpdateGraph")
.WithChangeFilter<PlayClipComponent>()
.WithoutBurst()
.ForEach((Entity e, ref PlayClipComponent animation, ref PlayClipStateComponent state) =>
{
if(animation.doWalk)
set.SendMessage(state.ClipPlayerNode, ClipPlayerNode.SimulationPorts.Clip, animation.WalkClip);
if(!animation.doWalk)
set.SendMessage(state.ClipPlayerNode, ClipPlayerNode.SimulationPorts.Clip, animation.IdleClip);
}).Run();
// Destroy graph for which the entity is missing the AnimationComponent
Entities
.WithName("DestroyGraph")
.WithNone<PlayClipComponent>()
.WithoutBurst()
.WithStructuralChanges()
.ForEach((Entity e, ref PlayClipStateComponent state) =>
{
DestroyGraph(set, ref state);
}).Run();
ecb.RemoveComponent(m_AnimationDataQuery, typeof(PlayClipStateComponent));
return default;
}
static PlayClipStateComponent CreateGraph(Entity entity, NodeSet set, ref Rig rig, ref PlayClipComponent playClip)
{
var data = new PlayClipStateComponent
{
EntityNode = set.CreateComponentNode(entity),
DeltaTimeNode = set.Create<DeltaTimeNode>(),
ClipPlayerNode = set.Create<ClipPlayerNode>(),
RootMotionNode = set.Create<RootMotionNode>(),
LocalToWorldToFloat4x4Node = set.Create<ConvertLocalToWorldComponentToFloat4x4Node>(),
Float4x4ToLocalToWorldNode = set.Create<ConvertFloat4x4ToLocalToWorldComponentNode>()
};
// Connect kernel ports - TYPE, SOURCE, DESTINATION
set.Connect(data.DeltaTimeNode, DeltaTimeNode.KernelPorts.DeltaTime, data.ClipPlayerNode, ClipPlayerNode.KernelPorts.DeltaTime);
//set.Connect(data.ClipPlayerNode, ClipPlayerNode.KernelPorts.Output, data.EntityNode); //old
set.Connect(data.ClipPlayerNode, ClipPlayerNode.KernelPorts.Output, data.RootMotionNode, RootMotionNode.KernelPorts.Input);
set.Connect(data.RootMotionNode, RootMotionNode.KernelPorts.Output, data.EntityNode);
// Root motion nodes
{
set.Connect(data.EntityNode, data.LocalToWorldToFloat4x4Node, ConvertLocalToWorldComponentToFloat4x4Node.KernelPorts.Input, NodeSet.ConnectionType.Feedback);
set.Connect(data.LocalToWorldToFloat4x4Node, ConvertLocalToWorldComponentToFloat4x4Node.KernelPorts.Output, data.RootMotionNode, RootMotionNode.KernelPorts.PrevRootX);
set.Connect(data.RootMotionNode, RootMotionNode.KernelPorts.RootX, data.Float4x4ToLocalToWorldNode, ConvertFloat4x4ToLocalToWorldComponentNode.KernelPorts.Input);
set.Connect(data.Float4x4ToLocalToWorldNode, ConvertFloat4x4ToLocalToWorldComponentNode.KernelPorts.Output, data.EntityNode);
}
// Send messages to set parameters on the ClipPlayerNode
set.SetData(data.ClipPlayerNode, ClipPlayerNode.KernelPorts.Speed, 1.0f);
set.SendMessage(data.ClipPlayerNode, ClipPlayerNode.SimulationPorts.Configuration, new ClipConfiguration { Mask = ClipConfigurationMask.LoopTime });
set.SendMessage(data.ClipPlayerNode, ClipPlayerNode.SimulationPorts.Rig, rig);
set.SendMessage(data.ClipPlayerNode, ClipPlayerNode.SimulationPorts.Clip, playClip.IdleClip);
set.SendMessage(data.RootMotionNode, RootMotionNode.SimulationPorts.Rig, rig);
set.SendMessage(data.ClipPlayerNode, ClipPlayerNode.SimulationPorts.Rig, rig); // ? do i need this?
return data;
}
static void DestroyGraph(NodeSet nodes, ref PlayClipStateComponent stateComponent)
{
nodes.Destroy(stateComponent.DeltaTimeNode);
nodes.Destroy(stateComponent.ClipPlayerNode);
nodes.Destroy(stateComponent.EntityNode);
nodes.Destroy(stateComponent.RootMotionNode);
nodes.Destroy(stateComponent.LocalToWorldToFloat4x4Node);
nodes.Destroy(stateComponent.Float4x4ToLocalToWorldNode);
}
}
[ConverterVersion("chris", 8)]
public class MyFirstAnimationClip : MonoBehaviour, IConvertGameObjectToEntity
{
[FormerlySerializedAs("Clip")] public AnimationClip Idle;
public AnimationClip Walk;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData(entity, new PlayClipComponent
{
IdleClip = ClipBuilder.AnimationClipToDenseClip(Idle),
WalkClip = ClipBuilder.AnimationClipToDenseClip(Walk)
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment