DOTS Dynamic Bones (WIP) Demo V0.8.2.1

Demo available at the link

https://github.com/Steven9Smith/DOTS-Dynamic-Bone-Demo

to use just place the 2 dll files inside your Assets/Plugins folder (this is what I do)

There are still 1 known bug(s).

  1. physics calculation glitch that causes jittering

temp solution: set Inert to > 0. This makes if so the player’s position is ignored in calculations.

-Update V0.8.1.3: Dynamic Bones calculations now work however, there seems to be an small issue with initial positions/rotations. I will be working on that next.

-Update V0.8.2: Fixed the previous issue. turns out I forgot to switch from AnimatedLocalToRoot to AnimatedLocalToWorld. The Core functionality should work now, please provide feedback and issues.

-Update V0.8.2.1: - Fixed the exclusions calculations. however I think the unexpected result of V0.8.2 should probably be a feature.

just released V0.8.1.1…I forgot to re-add the rotations after I was finished testing.

I also tried to solve the issue of calculations with a rotated axis but converting an AnimatedLocalToWorld to an AnimatedLocalToRoot is really…dumb…

@NT_Ninetails I tried adding a Dynamic Bone to my character, but it didn’t seem to work yet.
I’m getting some Burst errors that may be impeding the system to run correctly, what version of Burst are you using? I’m using Burst 1.5.6, Unity 2020.3.19f.

(0,0): Burst error BC1028: Creating a managed array `System.String[]` is not supported

at DOTSDynamicBone.DOTSDynamicBone.ConvertLocalToWorldToLocalToRoot(DOTSDynamicBone.DOTSDynamicBone* this, ref Unity.Entities.DynamicBuffer`1<DOTSDynamicBone.Particle> m_Particles, ref Unity.Entities.DynamicBuffer`1<Unity.Animation.AnimatedLocalToRoot> altr, ref Unity.Entities.DynamicBuffer`1<Unity.Animation.AnimatedLocalToWorld> altw, int start, int end)
at DOTSDynamicBone.DOTSDynamicBone.UpdateDynamicBones(DOTSDynamicBone.DOTSDynamicBone* this, float t, Unity.Core.TimeData timeData, Unity.Transforms.LocalToWorld* coreLTW, Unity.Entities.DynamicBuffer`1<Unity.Animation.AnimatedLocalToWorld>* altw, ref Unity.Entities.DynamicBuffer`1<Unity.Animation.AnimatedLocalToRoot> altr, ref Unity.Entities.DynamicBuffer`1<DOTSDynamicBone.Particle> m_Particles, int start, int end)
at DOTSDynamicBone.DOTSDynamicBone.mLateUpdate(DOTSDynamicBone.DOTSDynamicBone* this, ref Unity.Entities.DynamicBuffer`1<DOTSDynamicBone.Particle> m_Particles, Unity.Core.TimeData timeData, int start, int end, Unity.Transforms.LocalToWorld* coreLTW, Unity.Entities.DynamicBuffer`1<Unity.Animation.AnimatedLocalToWorld>* altw, Unity.Entities.DynamicBuffer`1<Unity.Animation.AnimatedLocalToRoot>* altr)
at DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0.OriginalLambdaBody(DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0* this, ref Unity.Transforms.LocalToWorld coreLTW, ref DOTSDynamicBone.DOTSDynamicBone bone, ref Unity.Entities.DynamicBuffer`1<DOTSDynamicBone.Particle> particles, ref Unity.Entities.DynamicBuffer`1<Unity.Animation.AnimatedLocalToRoot> altr, ref Unity.Entities.DynamicBuffer`1<Unity.Animation.AnimatedLocalToWorld> altw)
at DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0.IterateEntities(DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0* this, ref Unity.Entities.ArchetypeChunk chunk, ref DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0.LambdaParameterValueProviders.Runtimes runtimes)
at DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0.Execute(DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0* this, Unity.Entities.ArchetypeChunk* chunk, int chunkIndex, int firstEntityIndex)
at Unity.Entities.JobChunkExtensions.JobChunkProducer`1<DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0>.ExecuteInternal(ref Unity.Entities.JobChunkExtensions.JobChunkWrapper`1<DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0> jobWrapper, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) (at C:\Projetos\_Unity\nekosuki\Library\PackageCache\com.unity.entities@0.17.0-preview.42\Unity.Entities\IJobChunk.cs:386)
at Unity.Entities.JobChunkExtensions.JobChunkProducer`1<DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0>.Execute(ref Unity.Entities.JobChunkExtensions.JobChunkWrapper`1<DOTSDynamicBone.DynamicBoneLateUpdateSystem.DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0> jobWrapper, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) (at C:\Projetos\_Unity\nekosuki\Library\PackageCache\com.unity.entities@0.17.0-preview.42\Unity.Entities\IJobChunk.cs:353)


While compiling job: System.Void Unity.Entities.JobChunkExtensions/JobChunkProducer`1<DOTSDynamicBone.DynamicBoneLateUpdateSystem/DOTSDynamicBone.<>c__DisplayClass_OnUpdate_LambdaJob0>::Execute(Unity.Entities.JobChunkExtensions/JobChunkWrapper`1<T>&,System.IntPtr,System.IntPtr,Unity.Jobs.LowLevel.Unsafe.JobRanges&,System.Int32)
at <empty>:line 0

Ok, it didn’t seem to work before because I tried to add the DOTSDynamicBonesComponent to a specific bone of my rig (character tail bone). So, I added it to the main gameobject with the RigComponent instead, then the system worked.

But the system is twisting the tail bones in a weird way. Before, I used standard DynamicBone in the tail bone, so now I copied the same parameters from the original DynamicBone to the DOTSDynamicBone, but the results aren’t the same. (I know some parameters aren’t working yet, but still, it seems like a bug)

Also, can those Debug.Logs from ConvertLocalToWorldToLocalToRoot be disabled? (they’re killing my performance :face_with_spiral_eyes:) Or are those enabled on purpose for the demo?

7543468--932056--capture_20211003_191526_001.png

@NT_Ninetails Another odd thing is, even when all the DynamicBone parameters are zeroed out, the affected bones still keep moving/shaking wildly. I guess when the parameters are all 0, it shouldn’t even try to move the bones, right? Is that a bug?

EDIT: Actually, that also happens with standard (non-DOTS) Dynamic Bone, so I guess that’s not a bug.
I also think it would be useful to add an option to enable/disable dynamic physics on each DynamicBone element.

Oh, my bad about the debugging. I can disable that and update the files. I’ll also clean up some extra calculations…I went a little overboard on trying to fix the origin rotation issue…

Also for the twisting, could you show/tell me how the bones are setup/oriented so I can try to replicate it?

Great, thanks for the support! I’ll send you my character .fbx in a DM. :slight_smile:

As of now I do believe I got the bone translation working properly. There was a hidden calculation during the physics calculation I overlooked which always made the bones in a specific orientation no matter what the Root bone’s rotation was i.e. the root was rotated 90 deg on the X axis but the positions acted like there was no rotation. After extensive digging and searching I came across vital information:

“Unity ECS LocalToParent is not updated the same way Transforms are and must be accounted for”

So I had to change 1 line

 Matrix4x4 m0 = TransformsExtensions.GetTRSMatrix(
                        p0.m_Transform.localPosition,
                        p0.m_Transform.localRotation,
                        p0.m_Transform.localScale);

into

 Matrix4x4 m0 = TransformsExtensions.GetTRSMatrix(
                        p0.m_Transform.localPosition,
                math.mul(p0.m_Transform.localRotation, m_Core.rotation),
                        p0.m_Transform.localScale);

idk maybe it does update properly…I’ll do more test after I get rotation working…

Working on rotation now…

ooooooohhhhhhhhhhhhhhhh boyyyyyyyyyyyyyyyy, Got rotation working this morning, gonna clean up the code and post a new demo version soon. I will also perform other tests to make sure everything is in order.

I can now delete 200+ lines of test code and commented failed attempts…

cleaned up the code so now the system runs using Entities.ForEach().ScheduleParallel().
Here’s a screenshot with 250 entities running the system (pls ignore my camera system, its not done)

Ok, I just tested v0.8.2, the issues I had before are now gone (Debug.Log killing performance, weird bones rotations, etc.)
The DynamicBone features that your system got so far are working great, with nice performance too!
Thank you so much for taking your time to port DynamicBone to DOTS :smile:

Hope it doesn’t take too long to implement the other features, I’m particularly waiting for the DynamicBoneColliders and the Distrib curves, as I used them before in my character.
But of course, you can take your time with those, as the core functionality is working in DOTS and that’s already awesome :slight_smile:

I sure hope that there isn’t anything worse than the rotations and calculations issues next, I hope that there aren’t any bigger obstacles to this system :hushed:

More feedback:

  • I’d add a bool to each DynamicBone element (or something like “Update Mode → None”?), to enable/disable that bone’s dynamic physics processing. Sometimes I may add an element to the list of DynamicBones, then I copy the component to another character, but I may want to disable certain elements (without removing them from the list).

  • Your current system only works when the DOTSDynamicBonesComponent is attached to the same gameobject as the RigComponent, but standard DynamicBone used to also work even when it was attached to other gameobjects.
    Maybe the user could set the correct RigComponent in the bone’s parameters and it should work in theory, but in the current version, it doesn’t work.

I ask about this feature because I want to support a more modular DynamicBones organization, where each (root) gameobject of a dynamic part of my character (clothes, hair, tail, etc.) has its own DynamicBone list. In that way, I could prepare prefabs of clothes/hair/tail, etc., and easily swap them in my characters, without having to mess with the DynamicBones list in the RigComponent gameobject (so I don’t have to manually add/remove elements every time I change some part).

I don’t know if that’s more or less performant than having only a single DOTSDynamicBonesComponent in the RigComponent gameobject, though.

Thank you for the feedback, I can answer these questions and provide possible solutions for each.

As far as I can tell, the core functionality of the system works. So anything else added will most likely be a feature or settings (and there are a lot of possible settings I can add)

This is actually easy to implement however, I can’t say what the results will be due to calculations taking the parent entity in mind. So I you have a 3 bone system and the middle bone has no calculations on it then the last bone may look weird. But sure, I should be able to add this with little issue.

It would work but there might be a downgrade in performance due to data fetching (At least using a regualr Entities.ForEach system). The current system uses this to determine when to run the system.

 Entities
             
                    .WithBurst()
                    .ForEach((
                        ref DynamicBuffer<DOTSDynamicBone_BufferElement> bones,
                        ref DynamicBuffer<Particle> particles,
                        ref DynamicBuffer<Unity.Animation.AnimatedLocalToRoot> altr,
                        ref LocalToWorld coreLTW,
                        in DynamicBuffer<Unity.Animation.AnimatedLocalToWorld> altw) =>
                        {
...
                        })
                    .ScheduleParallel();

The Unity.Animation.AnimatedLocalToRoot and Unity.Animation.LocalToWorld data is stored on the root entity. In order to simplify the data structure and job structure we add 2 DynamicBuffers which hold all the information regarding the dynamic bones (calculations are done within the job and are Burst Compatible). In order to have the data stored on the bone entity itself it would need to acquire the LocalToWorld,AnimatedLocalToRoot, and the AnimatedLocalToWorld of the root enity. Using Entities.ForEach I only know 1 ways of doing this, using a ComponentDataFromEntity (which is slow) but I could maybe use some sort of IJobEntityBatch (I could take a look at this as there might not be a performance hit). Also with the bone entities having the data stored on them causes more allocation for DynamicBuffers, but I’m not 100% sure how this will affect performance though because I do know that I would be able to remove 2 ints from DOTSDynamicBone_BufferElement which would save some memory but I don’t know it that outweighs the accessing time.

So in short, yeah its possible but most likely there may be a performance hit which may increase linearly which each dynamic bone…maybe. But I’ll look into it

Just remember, I can’t use references so I really have to play around with which data I need, how it’s represented (to save space in the structs), and how to pass data efficiently to different places.

At least, this is my though process when working in DOTS.

Thanks for the feedback :smile:

@NT_Ninetails Thanks for the detailed explanations!

My feature request to make the system work outside of the root gameobject isn’t essential, I guess it adds a bit more complexity to the system than I thought. Anyway, I can work with using the system on the root gameobject only (also to ensure better performance), but I really appreciate the info!

About my other feature request, just to clarify (as it’s maybe a bit confusing to explain), I meant in case I have in my DOTSDynamicBonesComponent the following elements in the Bones list: (I assign each part’s root bone to the element)

  • Tail
  • Hair (back)
  • Skirt
  • BreastL
  • BreastR

What I meant is that, depending on the character, I may want to, for example, disable both Breasts’ dynamic physics, or disable the tail dynamic physics, etc.
Would that only be possible by deleting the elements from the Bones list? Or does an enable/disable toggle (on each element’s data) could be implemented for that?

Oh so you mean like attach the DynamicBone to another GameObject/Entity entirely? This is possible but would have the same concerns as mentioned before, but yeah, it’s possible. I can take a look into it.

Do you mean the Exclusions dropdown? I forgot to mention it but the Exclusion dropdown does work but it’s not 100% functional. Like those entities in the exclusions are ignored but there’s an issue with children and parents. Since the main system is working I can look into this next.

No, the feature I ask for is different/independent of the Exclusions dropdown.
I mean like, if I want to disable one of the DynamicBone configurations I set up, it seems there’s currently no way to do that without deleting the Element from the main list (and then losing the parameters that I set up to that DynamicBone configuration, curves, exclusions, etc.)

For example, imagine that these 4 elements in the list consist of DynamicBone configurations for my character’s Tail (Element 0), Skirt (Element 1), and Left/Right Breast (Elements 2 and 3)
Each element would have its parameters, its own exclusions set up, etc.

7567639--936790--capture_20211012_195702_003.png

If I wanted to disable the breasts, it seems I’d have to delete Element 2 and Element 3 from the list. I wanted a way to keep those elements in the list, but with a toggle on each element that defines if it’s going to have DynamicBone physics applied or not.

I may even want to enable/disable elements from the list at runtime, for example during cutscenes with special animations for the tail, etc.


My suggestion is that each element could have another bool above UpdateLocalToWorldTransforms, “Enable Dynamic Bone”, something like that.
Or in Update Mode, a new option “None”, which would disable dynamic physics for that bone configuration.

Yeah, it could be another GameObject/Entity. But what I mostly meant to do is attaching DynamicBone components to prefabs/GameObjects that would be children of the root GameObject with the RigComponent.
Then those DynamicBones (in child objects) could point to the root object’s RigComponent and get its entity, something like that.

This feature worked in standard non-DOTS DynamicBone asset, but I guess the Entity conversion workflow would make implementing that feature a bit more complex now?

Oh, yeah I don’t see a problem with that. Also you are free to edit the DynamicBuffer and DynamicBuffer<DOTSDynamicBone_BufferElement> during runtime…I should make a documentation…I’ll get started on that after I finish up some other things

Yeah, that’s possible. like you said, it will become a more complex however only in accessing the RigComponentData. I could treat that as a special case and make a new component from that since it requires different methods of access certain data efficently.

So I fixed exclusions by setting the excluded bones and thier children’s stiffness to 1, elasticity to 0 and damping to 0.
I will uploading the changes soon. V0.8.2.1

Update: I believe I have successfully got DOTS Dynamic Bones working fully with the exception of the DynamicBonePlaneCollider (The normal DynamicBoneCollider works). As far as colliders go I want to use the DOTS Physics system for collision since it allows for more dynamic interactions in a DOTS environment. The original system is pretty closed looped (you have to manually drag in the colliders that affect the bones for a particular DynamicBone) and I think using DOTS Physics to do queries on all bodies in a scene will look and feel nice as well. As far as the demo is concerned, I believe it is a fine stable version of the core concepts of DynamicBone and runs efficiently with burst, and as such, will be a Demo of DOTSDynamicBone.

Future Plans: After creating some samples and a tutorial video I will initially put this on the AssetStore in beta. All new or improved features will be applied to the store version of DOTSDynamicBone. Any bug fixes or efficency improvements will be applied to both the AssetStore and Demo version of DOTSDynamicBone.

As for the tutorials and documentation…expect them to be longish because the original system was a little difficult to get a good understanding in but DOTS make it a whole lot more complicated. ForExample:

In the current version of the system there is a DOTSDynamicBone Component and a IndependantDynamicBone Component. The only difference between them is where they get placed and 1 line in the Entities.ForEach systems.

DOTSDynamicBone MUST be used placed in the same component as the RigComponent. However IndependantDOTSDyanmicBone can be placed on any entity and will work as just as fine as long as you reference the right Components for conversion. Here’s the line of code if your interested (Note the Entities.ForEach is also slightly altered)

//GetLTW = ComponentDataFromEntity<LocalToWorld>();
LocalToWorld coreLTW = GetLTW[bone.m_RigComponentEntity];