using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Deformations; using Unity.Entities; using Unity.Jobs; using Unity.Rendering; using Unity.Transforms; ///////////////////////////////////////////////////////////////////////////////// namespace Rukhanka { [DisableAutoCreation] [UpdateAfter(typeof(RukhankaAnimationInjectionSystemGroup))] partial struct AnimationApplicationSystem: ISystem { private EntityQuery boneObjectEntitiesWithParentQuery, boneObjectEntitiesNoParentQuery; NativeParallelHashMap> rigToSkinnedMeshRemapTables; int newRemapTablesCounter; ///////////////////////////////////////////////////////////////////////////////// [BurstCompile] public void OnCreate(ref SystemState ss) { var eqb0 = new EntityQueryBuilder(Allocator.Temp) .WithAll() .WithAllRW(); boneObjectEntitiesWithParentQuery = ss.GetEntityQuery(eqb0); var eqb1 = new EntityQueryBuilder(Allocator.Temp) .WithAll() .WithNone() .WithAllRW(); boneObjectEntitiesNoParentQuery = ss.GetEntityQuery(eqb1); var rq = new EntityQueryBuilder(Allocator.Temp) .WithAll() .Build(ref ss); ss.RequireForUpdate(rq); rigToSkinnedMeshRemapTables = new NativeParallelHashMap>(128, Allocator.Persistent); } ///////////////////////////////////////////////////////////////////////////////// [BurstCompile] public void OnDestroy(ref SystemState ss) { foreach (var kv in rigToSkinnedMeshRemapTables) kv.Value.Dispose(); rigToSkinnedMeshRemapTables.Dispose(); } ///////////////////////////////////////////////////////////////////////////////// [BurstCompile] public void OnUpdate(ref SystemState ss) { ref var runtimeData = ref SystemAPI.GetSingletonRW().ValueRW; var fillRigToSkinnedMeshRemapTablesJH = FillRigToSkinBonesRemapTableCache(ref ss, ss.Dependency); // Propagate local animated transforms to the entities with and without parents var propagateTRSToEntitiesWithParentsJH = PropagateAnimatedBonesToEntitiesTRS(ref ss, runtimeData, boneObjectEntitiesWithParentQuery, true, ss.Dependency); var propagateTRSToEntitiesNoParentsJH = PropagateAnimatedBonesToEntitiesTRS(ref ss, runtimeData, boneObjectEntitiesNoParentQuery, false, propagateTRSToEntitiesWithParentsJH); // Make corresponding skin matrices for all skinned meshes var jh = JobHandle.CombineDependencies(fillRigToSkinnedMeshRemapTablesJH, propagateTRSToEntitiesNoParentsJH); var applySkinJH = ApplySkinning(ref ss, runtimeData, jh); // Update render bounds for meshes that request this var updateRenderBoundsJH = UpdateRenderBounds(ref ss, runtimeData, ss.Dependency); ss.Dependency = JobHandle.CombineDependencies(applySkinJH, updateRenderBoundsJH); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// unsafe JobHandle FillRigToSkinBonesRemapTableCache(ref SystemState ss, JobHandle dependsOn) { var rigDefinitionComponentLookup = SystemAPI.GetComponentLookup(true); newRemapTablesCounter = 0; // Count new remap tables count var countNumberOfNewRemapTablesJob = new CountNumberOfNewRemapTablesJob() { rigDefinitionArr = rigDefinitionComponentLookup, numberOfNewRemapTables = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref newRemapTablesCounter)), rigToSkinnedMeshRemapTables = rigToSkinnedMeshRemapTables }; var countNumberOfNewRemapTablesJH = countNumberOfNewRemapTablesJob.ScheduleParallel(dependsOn); // Reserve necessary space in remap table cache var increaseRigRemapTableCapacityJob = new IncreaseRigRemapTableCapacityJob() { numberOfNewRemapTables = (int*)UnsafeUtility.AddressOf(ref newRemapTablesCounter), rigToSkinnedMeshRemapTables = rigToSkinnedMeshRemapTables }; var increaseRigRemapTableCapacityJH = increaseRigRemapTableCapacityJob.Schedule(countNumberOfNewRemapTablesJH); // Fill table cache with new tables var fillRigToSkinBonesRemapTableCacheJob = new FillRigToSkinBonesRemapTableCacheJob() { rigDefinitionArr = rigDefinitionComponentLookup, rigToSkinnedMeshRemapTables = rigToSkinnedMeshRemapTables.AsParallelWriter(), newRemapTablesCounter = (int*)UnsafeUtility.AddressOf(ref newRemapTablesCounter), }; var rv = fillRigToSkinBonesRemapTableCacheJob.ScheduleParallelByRef(increaseRigRemapTableCapacityJH); return rv; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// JobHandle UpdateRenderBounds(ref SystemState ss, in RuntimeAnimationData runtimeData, JobHandle dependsOn) { var updateSkinnedMeshBoundsJob = new UpdateSkinnedMeshBoundsJob() { worldBonePoses = runtimeData.worldSpaceBonesBuffer, rigDefLookup = SystemAPI.GetComponentLookup(true) }; var updateSkinnedMeshBoundsJH = updateSkinnedMeshBoundsJob.ScheduleParallel(dependsOn); return updateSkinnedMeshBoundsJH; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// JobHandle PropagateAnimatedBonesToEntitiesTRS(ref SystemState ss, in RuntimeAnimationData runtimeData, EntityQuery eq, bool withParents, JobHandle dependsOn) { var propagateAnimationJob = new PropagateBoneTransformToEntityTRSJob() { boneTransforms = withParents ? runtimeData.animatedBonesBuffer : runtimeData.worldSpaceBonesBuffer, postTransformMatrixLookup = SystemAPI.GetComponentLookup(), rigDefLookup = SystemAPI.GetComponentLookup(true), gpuEngineTagLookup = SystemAPI.GetComponentLookup(true) }; var jh = propagateAnimationJob.ScheduleParallel(eq, dependsOn); return jh; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// JobHandle ApplySkinning(ref SystemState ss, in RuntimeAnimationData runtimeData, JobHandle dependsOn) { var rigDefinitionComponentLookup = SystemAPI.GetComponentLookup(true); var cullAnimationsTagComponentLookup = SystemAPI.GetComponentLookup(true); var localTransformLookup = SystemAPI.GetComponentLookup(true); var parentLookup = SystemAPI.GetComponentLookup(true); var rigBoneLookup = SystemAPI.GetComponentLookup(true); var gpuAnimationEngineLookup = SystemAPI.GetComponentLookup(true); var animationApplyJob = new ApplyAnimationToSkinnedMeshJob() { boneTransforms = runtimeData.worldSpaceBonesBuffer, rigDefinitionLookup = rigDefinitionComponentLookup, rigToSkinnedMeshRemapTables = rigToSkinnedMeshRemapTables, cullAnimationsTagLookup = cullAnimationsTagComponentLookup, localTransformLookup = localTransformLookup, parentLookup = parentLookup, rigBoneLookup = rigBoneLookup, gpuAnimationEngineTagLookup = gpuAnimationEngineLookup }; var jh = animationApplyJob.ScheduleParallel(dependsOn); return jh; } } }