Last active
May 15, 2020 21:04
-
-
Save thelebaron/7f3a61814fa30dad049d2e7bd969f202 to your computer and use it in GitHub Desktop.
dots animation root motion experiment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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