123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- using GpuEcsAnimationBaker.Engine.Data;
- using Unity.Burst;
- using Unity.Collections;
- using Unity.Entities;
- using Unity.Mathematics;
- using UnityEngine;
- namespace GPUECSAnimationBaker.Engine.AnimatorSystem
- {
- [BurstCompile]
- public partial struct GpuEcsAnimatorSystem : ISystem
- {
- [BurstCompile]
- public void OnUpdate(ref SystemState state)
- {
- EndSimulationEntityCommandBufferSystem.Singleton ecbSystem =
- SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
- EntityCommandBuffer.ParallelWriter ecb = ecbSystem.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter();
- float deltaTime = SystemAPI.Time.DeltaTime;
- state.Dependency = new GpuEcsAnimatorJob()
- {
- ecb = ecb,
- deltaTime = deltaTime
- }.ScheduleParallel(state.Dependency);
- }
- [BurstCompile]
- private partial struct GpuEcsAnimatorJob : IJobEntity
- {
- public EntityCommandBuffer.ParallelWriter ecb;
- [ReadOnly] public float deltaTime;
- public void Execute(
- ref GpuEcsAnimatorShaderDataComponent gpuEcsAnimatorShaderData,
- ref GpuEcsAnimatorTransitionInfoComponent gpuEcsAnimatorTransitionInfo,
- ref GpuEcsAnimatorStateComponent gpuEcsAnimatorState,
- ref GpuEcsAnimatorInitializedComponent gpuEcsAnimatorInitialized,
- ref DynamicBuffer<GpuEcsCurrentAttachmentAnchorBufferElement> gpuEcsCurrentAttachmentAnchors,
- ref GpuEcsAnimatorControlStateComponent gpuEcsAnimatorControlState,
- ref DynamicBuffer<GpuEcsAnimatorEventBufferElement> gpuEcsAnimatorEventBuffer,
- in GpuEcsAnimatorControlComponent gpuEcsAnimatorControl,
- in GpuEcsAnimationDataComponent gpuEcsAnimationData,
- in DynamicBuffer<GpuEcsAnimationDataBufferElement> gpuEcsAnimationDataBuffer,
- in DynamicBuffer<GpuEcsAnimationEventOccurenceBufferElement> gpuEcsAnimationEventOccurenceBuffer,
- in DynamicBuffer<GpuEcsAttachmentAnchorDataBufferElement> gpuEcsAttachmentAnchorData,
- [ChunkIndexInQuery] int sortKey, Entity gpuEcsAnimatorEntity)
- {
- gpuEcsAnimatorEventBuffer.Clear();
- if (!gpuEcsAnimatorInitialized.initialized )
- {
- // We switch immediately to the first animation, no transition
- gpuEcsAnimatorTransitionInfo = new GpuEcsAnimatorTransitionInfoComponent()
- {
- current = gpuEcsAnimatorControl.animatorInfo,
- blendPreviousToCurrent = 1f
- };
- gpuEcsAnimatorState = new GpuEcsAnimatorStateComponent()
- {
- currentNormalizedTime = gpuEcsAnimatorControl.startNormalizedTime,
- stoppedPrevious = false,
- stoppedCurrent = false
- };
- gpuEcsAnimatorInitialized.initialized = true;
- }
- else if(gpuEcsAnimatorControl.animatorInfo.animationID != gpuEcsAnimatorTransitionInfo.current.animationID)
- {
- // A new animation (or animation combination) has been started, so we need to do a transition
- // from the old one to the new
- gpuEcsAnimatorTransitionInfo = new GpuEcsAnimatorTransitionInfoComponent()
- {
- current = gpuEcsAnimatorControl.animatorInfo,
- previous = gpuEcsAnimatorTransitionInfo.current,
- blendPreviousToCurrent = 0f
- };
- gpuEcsAnimatorState = new GpuEcsAnimatorStateComponent()
- {
- previousNormalizedTime = gpuEcsAnimatorState.currentNormalizedTime,
- stoppedPrevious = gpuEcsAnimatorState.stoppedCurrent,
- currentNormalizedTime = gpuEcsAnimatorControl.startNormalizedTime,
- stoppedCurrent = false,
- };
- }
- else
- {
- // The same animation (or animation combination) is still running, but the parameters might have changed
- // (blendPrimaryToSecondary or speedFactor)
- gpuEcsAnimatorTransitionInfo.current = gpuEcsAnimatorControl.animatorInfo;
- }
- GpuEcsAnimatorControlStates controlState = gpuEcsAnimatorControlState.state;
- if (gpuEcsAnimatorControlState.state == GpuEcsAnimatorControlStates.Start)
- gpuEcsAnimatorState.stoppedCurrent = false;
- else if (gpuEcsAnimatorControlState.state == GpuEcsAnimatorControlStates.Stop)
- gpuEcsAnimatorState.stoppedCurrent = true;
- gpuEcsAnimatorControlState.state = GpuEcsAnimatorControlStates.KeepCurrentState;
- if (!gpuEcsAnimatorState.stoppedCurrent)
- {
- UpdateAnimatorState(ref gpuEcsAnimatorState.currentNormalizedTime, ref gpuEcsAnimatorState.stoppedCurrent,
- ref gpuEcsAnimatorEventBuffer,
- gpuEcsAnimatorTransitionInfo.current, controlState, gpuEcsAnimationDataBuffer, gpuEcsAnimationEventOccurenceBuffer,
- out float primaryBlendFactor, out float primaryTransitionToNextFrame, out int primaryFrameIndex,
- out float secondaryBlendFactor, out float secondaryTransitionToNextFrame, out int secondaryFrameIndex,
- sortKey, gpuEcsAnimatorEntity, forPrevious: false);
- if (gpuEcsAnimatorTransitionInfo.blendPreviousToCurrent >= 1f)
- {
- gpuEcsAnimatorShaderData.shaderData = new float4x4(
- primaryBlendFactor, primaryTransitionToNextFrame, primaryFrameIndex, 0,
- secondaryBlendFactor, secondaryTransitionToNextFrame, secondaryFrameIndex, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0);
- //Apply attachment anchor transforms
- for (int attachmentAnchorIndex = 0; attachmentAnchorIndex < gpuEcsAnimationData.nbrOfAttachmentAnchors; attachmentAnchorIndex++)
- {
- int baseIndex = gpuEcsAnimationData.totalNbrOfFrames * attachmentAnchorIndex;
- gpuEcsCurrentAttachmentAnchors[attachmentAnchorIndex] = new GpuEcsCurrentAttachmentAnchorBufferElement()
- {
- currentTransform = LerpBlend(gpuEcsAttachmentAnchorData, baseIndex,
- primaryFrameIndex, secondaryFrameIndex,
- primaryTransitionToNextFrame, secondaryTransitionToNextFrame,
- secondaryBlendFactor)
- };
- }
- }
- else
- {
- if (gpuEcsAnimatorControl.transitionSpeed == 0) gpuEcsAnimatorTransitionInfo.blendPreviousToCurrent = 1f;
- else
- {
- gpuEcsAnimatorTransitionInfo.blendPreviousToCurrent += deltaTime / gpuEcsAnimatorControl.transitionSpeed;
- if (gpuEcsAnimatorTransitionInfo.blendPreviousToCurrent > 1f) gpuEcsAnimatorTransitionInfo.blendPreviousToCurrent = 1f;
- }
- float previousToCurrent = gpuEcsAnimatorTransitionInfo.blendPreviousToCurrent;
- float currentToPrevious = 1f - previousToCurrent;
- UpdateAnimatorState(ref gpuEcsAnimatorState.previousNormalizedTime, ref gpuEcsAnimatorState.stoppedPrevious,
- ref gpuEcsAnimatorEventBuffer,
- gpuEcsAnimatorTransitionInfo.previous, controlState, gpuEcsAnimationDataBuffer, gpuEcsAnimationEventOccurenceBuffer,
- out float previousPrimaryBlendFactor, out float previousPrimaryTransitionToNextFrame, out int previousPrimaryFrameIndex,
- out float previousSecondaryBlendFactor, out float previousSecondaryTransitionToNextFrame, out int previousSecondaryFrameIndex,
- sortKey, gpuEcsAnimatorEntity, forPrevious: true);
- gpuEcsAnimatorShaderData.shaderData = new float4x4(
- previousToCurrent * primaryBlendFactor, primaryTransitionToNextFrame, primaryFrameIndex, 0,
- previousToCurrent * secondaryBlendFactor, secondaryTransitionToNextFrame, secondaryFrameIndex, 0,
- currentToPrevious * previousPrimaryBlendFactor, previousPrimaryTransitionToNextFrame, previousPrimaryFrameIndex, 0,
- currentToPrevious * previousSecondaryBlendFactor, previousSecondaryTransitionToNextFrame, previousSecondaryFrameIndex, 0);
- for (int attachmentAnchorIndex = 0; attachmentAnchorIndex < gpuEcsAnimationData.nbrOfAttachmentAnchors; attachmentAnchorIndex++)
- {
- int baseIndex = gpuEcsAnimationData.totalNbrOfFrames * attachmentAnchorIndex;
- float4x4 current = LerpBlend(gpuEcsAttachmentAnchorData, baseIndex,
- primaryFrameIndex, secondaryFrameIndex,
- primaryTransitionToNextFrame, secondaryTransitionToNextFrame,
- secondaryBlendFactor);
- float4x4 previous = LerpBlend(gpuEcsAttachmentAnchorData, baseIndex,
- previousPrimaryFrameIndex, previousSecondaryFrameIndex,
- previousPrimaryTransitionToNextFrame, previousSecondaryTransitionToNextFrame,
- previousSecondaryBlendFactor);
- gpuEcsCurrentAttachmentAnchors[attachmentAnchorIndex] = new GpuEcsCurrentAttachmentAnchorBufferElement()
- {
- currentTransform = LerpTransform(previous, current, previousToCurrent)
- };
- }
- }
- }
- }
-
- private float4x4 LerpBlend(in DynamicBuffer<GpuEcsAttachmentAnchorDataBufferElement> gpuEcsAttachmentAnchorData,
- int baseIndex, int frameIndexA, int frameIndexB,
- float frameIndexATransitionToNextFrame, float frameIndexBTransitionToNextFrame,
- float t)
- {
- float4x4 result;
- if (t == 0)
- result = LerpNextFrame(gpuEcsAttachmentAnchorData, baseIndex, frameIndexA, frameIndexATransitionToNextFrame);
- else if(t == 1f)
- result = LerpNextFrame(gpuEcsAttachmentAnchorData, baseIndex, frameIndexB, frameIndexBTransitionToNextFrame);
- else
- {
- float4x4 primary = LerpNextFrame(gpuEcsAttachmentAnchorData, baseIndex, frameIndexA, frameIndexATransitionToNextFrame);
- float4x4 secondary = LerpNextFrame(gpuEcsAttachmentAnchorData, baseIndex, frameIndexB, frameIndexBTransitionToNextFrame);
- result = LerpTransform(primary, secondary, t);
- }
- return result;
- }
- private float4x4 LerpNextFrame(in DynamicBuffer<GpuEcsAttachmentAnchorDataBufferElement> gpuEcsAttachmentAnchorData,
- int baseIndex, int frameIndex, float transitionToNextFrame)
- {
- return LerpTransform(
- gpuEcsAttachmentAnchorData[baseIndex + frameIndex].anchorTransform,
- gpuEcsAttachmentAnchorData[baseIndex + frameIndex + 1].anchorTransform,
- transitionToNextFrame
- );
- }
- private float4x4 LerpTransform(float4x4 valueA, float4x4 valueB, float t)
- {
- float3 posA = new float3(valueA.c3.x, valueA.c3.y, valueA.c3.z);
- quaternion rotA = new quaternion(valueA);
- float3 posB = new float3(valueB.c3.x, valueB.c3.y, valueB.c3.z);
- quaternion rotB = new quaternion(valueB);
- float3 pos = math.lerp(posA, posB, t);
- Quaternion rot = math.slerp(rotA, rotB, t);
- return float4x4.TRS(pos, rot, new float3(1f, 1f, 1f));
- }
- private void UpdateAnimatorState(ref float normalizedTime, ref bool stopped,
- ref DynamicBuffer<GpuEcsAnimatorEventBufferElement> gpuEcsAnimatorEventBuffer,
- AnimatorInfo animatorInfo,
- in GpuEcsAnimatorControlStates controlState,
- in DynamicBuffer<GpuEcsAnimationDataBufferElement> gpuEcsAnimationDataBuffer,
- in DynamicBuffer<GpuEcsAnimationEventOccurenceBufferElement> gpuEcsAnimationEventOccurenceBuffer,
- out float primaryBlendFactor, out float primaryTransitionToNextFrame, out int primaryFrameIndex,
- out float secondaryBlendFactor, out float secondaryTransitionToNextFrame, out int secondaryFrameIndex,
- in int sortKey, Entity gpuEcsAnimatorEntity, bool forPrevious)
- {
- GpuEcsAnimationDataBufferElement animationData = gpuEcsAnimationDataBuffer[animatorInfo.animationID];
- if (animationData.nbrOfInBetweenSamples == 1)
- {
- float blendSpeedAdjustment = 1f;
- UpdateAnimationNormalizedTime(ref normalizedTime, ref stopped, ref gpuEcsAnimatorEventBuffer, animatorInfo, controlState,
- gpuEcsAnimationEventOccurenceBuffer, animationData, blendSpeedAdjustment,
- out float transitionToNextFrame, out int relativeFrameIndex, sortKey, gpuEcsAnimatorEntity, forPrevious);
- primaryBlendFactor = 1;
- primaryTransitionToNextFrame = transitionToNextFrame;
- primaryFrameIndex = animationData.startFrameIndex + relativeFrameIndex;
- secondaryBlendFactor = 0;
- secondaryTransitionToNextFrame = 0;
- secondaryFrameIndex = 0;
- }
- else
- {
- float endBlend = (float)(animationData.nbrOfInBetweenSamples - 1);
- float currentBlendSetFloat = animatorInfo.blendFactor * endBlend;
- int currentBlendSet = (int)math.floor(currentBlendSetFloat);
- float transitionToNextSet = currentBlendSetFloat - (float)currentBlendSet;
-
- float blendSpeedAdjustment = animatorInfo.blendFactor * animationData.blendTimeCorrection + (1f - animatorInfo.blendFactor);
- UpdateAnimationNormalizedTime(ref normalizedTime, ref stopped, ref gpuEcsAnimatorEventBuffer, animatorInfo, controlState,
- gpuEcsAnimationEventOccurenceBuffer, animationData, blendSpeedAdjustment,
- out float transitionToNextFrame, out int relativeFrameIndex, sortKey, gpuEcsAnimatorEntity, forPrevious);
- primaryBlendFactor = 1f - transitionToNextSet;
- primaryTransitionToNextFrame = transitionToNextFrame;
- primaryFrameIndex = animationData.startFrameIndex + currentBlendSet * animationData.nbrOfFramesPerSample + relativeFrameIndex;
- secondaryBlendFactor = transitionToNextSet;
- secondaryTransitionToNextFrame = transitionToNextFrame;
- secondaryFrameIndex = animationData.startFrameIndex + (currentBlendSet + 1) * animationData.nbrOfFramesPerSample + relativeFrameIndex;
- }
- }
- private void UpdateAnimationNormalizedTime(ref float normalizedTime, ref bool stopped,
- ref DynamicBuffer<GpuEcsAnimatorEventBufferElement> gpuEcsAnimatorEventBuffer,
- AnimatorInfo animatorInfo, in GpuEcsAnimatorControlStates controlState,
- in DynamicBuffer<GpuEcsAnimationEventOccurenceBufferElement> gpuEcsAnimationEventOccurenceBuffer,
- GpuEcsAnimationDataBufferElement animationData, float blendSpeedAdjustment,
- out float transitionToNextFrame, out int relativeFrameIndex, int sortKey, Entity gpuEcsAnimatorEntity, bool forPrevious)
- {
- int endFrame = animationData.nbrOfFramesPerSample - 1;
- float animationLength = (float)endFrame / GlobalConstants.SampleFrameRate;
- float currentTime = normalizedTime * animationLength;
- if(!stopped) currentTime += deltaTime * animatorInfo.speedFactor * blendSpeedAdjustment;
- float normalizedTimeLastUpdate = normalizedTime;
- normalizedTime = currentTime / animationLength;
-
- for (int eventOccurencId = animationData.startEventOccurenceId; eventOccurencId < animationData.startEventOccurenceId + animationData.nbrOfEventOccurenceIds; eventOccurencId++)
- {
- GpuEcsAnimationEventOccurenceBufferElement occurence = gpuEcsAnimationEventOccurenceBuffer[eventOccurencId];
- if (normalizedTimeLastUpdate < occurence.eventNormalizedTime && normalizedTime > occurence.eventNormalizedTime)
- {
- //Trigger event
- gpuEcsAnimatorEventBuffer.Add(new GpuEcsAnimatorEventBufferElement()
- {
- animationId = animatorInfo.animationID,
- eventId = occurence.eventId
- });
- }
- }
- if (!forPrevious && (animationData.loop || controlState == GpuEcsAnimatorControlStates.Start))
- {
- while (normalizedTime >= 1f) normalizedTime -= 1f;
- }
- else
- {
- if (normalizedTime >= 1f)
- {
- normalizedTime = 1f;
- stopped = true;
- }
- }
- if (normalizedTime == 1f)
- {
- relativeFrameIndex = endFrame - 1;
- transitionToNextFrame = 1f;
- }
- else
- {
- float relativeFrameIndexFloat = normalizedTime * (float)endFrame;
- relativeFrameIndex = (int)math.floor(relativeFrameIndexFloat);
- transitionToNextFrame = relativeFrameIndexFloat - (float)relativeFrameIndex;
- }
- }
- }
- }
- }
|