Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Boing Kit: Dynamic Bouncy Bones (with tech breakdown)

Discussion in 'Assets and Asset Store' started by Allen-Chou, Aug 5, 2019.

  1. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Hi, all. I've finally finished my bouncy bone tech addition to my Unity extension. I initially used Unity-Chan as my test model, but then I decided that I wanted to make my own test model, doubling as a mascot for this extension, so I began learning Blender and made UFO Bunny.



    This is a silly video I made that shows off UFO Bunny being initially stiff and becoming bouncy when the bouncy bones feature is turned on. Later on, the video also demonstrates some other applications of the core bouncy tech.

    Here is a tech breakdown of how I made the bouncy bones effects:


    Data Definition & Construction

    First off, I build a chain of bone data by specifying a root bone, referenced by the bone's Transform component. Then I perform a breadth-first search to visit all of the transform's direct and indirect children. All the transforms visited are added to an array of bone data in the visited order. This way, when I want to iterate through the bone data, I can just go through the array once from start to end, guaranteed to always process parents first and then the children. Thus, when it's a child's turn to be processed and it needs to inherit proceed data from its parent (e.g. transform, bone chain length from root, etc.), the parent's data would have already been processed earlier in the array.


    Making the Bones Bouncy

    The core bouncy logic makes use of numeric springing (Intro / Examples / More Info). It is essentially a specialized type of soft constraint. When given a target value (e.g. float, vector, etc.), a numeric spring tracks its current value closer towards the target by each simulation step, with smooth-changing velocity. For bouncy bones, the core problem is how to compute the target transforms for the bones to be sprung to.

    I model the problem using "pose stiffness" and "length stiffness", each of which can be defined as a curve, where the input is the percentage of a bone's chain length from root v.s. the entire chain length, and the output is the stiffness percentage.

    I define pose stiffness as a child bone's desire to maintain its relative transform to its parent. So for a bone with full pose stiffness, its target transform is its relative transform to its parent appendeded to its parent's current transform spring values in world space.

    As for length stiffness, I define it as a child bone's desire to maintain its distance from its parent. So for a bone with full length stiffness, its target transform will maintain the same distance away from its parent's current transform spring values. Further, during each time step, I remove a percentage equal to length stiffness from a child bone's linear velocity parallel to the vector pointing from its parent to itself, so at full stiffness, there will be no linear velocity component that would alter the distance between the two.

    With the target transforms (positions & rotations) defined, the next step is to simulate the numeric springs to track the target values. For position, it's pretty straight forward: just apply numeric springing to individual vector components. However, with rotation, it's a bit tricky. There are multiple ways to represent rotation in 3D, the most common being (1) 3x3 transform matrices, (2) axis-angle vectors (direction is rotation axis & magnitude is rotation angle), and (3) quaternions.

    At first I chose (2) axis-angle vectors, because I've been accumulating effectors in this data format (more on effector's later). So my first try on rotation spring is basically a vector spring, where the vector is the axis-angle vector that gets converted to quaternions as a final step (formula here). At first, I thought it was working alright, until I noticed occasional kinks in UFO Bunny's ear (can be observed here when she spin around). Upon further investigation, it was due to the "360-degree wrap-around problem". Basically, a target axis-angle vector of length PI (180 degree) is equivalent to its negated vector, because rotating 180 degrees around an axis is the same as rotating 180 degrees around the opposite axis. So while the logical & spatial target rotation remains the same, the underlying target vector changes drastically, shooting the numeric spring in the other direction wildly.

    I tried various way to come up with a mathematically correct way to spring quaternions, but only got as close as to figuring out how to spring a point on a 3D unit sphere surface, and I haven't been able to extend that to 4D (yet). I thought the the 3D unit sphere spring was already too computationally heavy for this task, let alone trying to extend it to 4D, so I decided to cheat by just springing individual components of quaternions as if they are 4D vectors. And, the values are normalized before being read back from the spring into quaternions. It's not ideal. The rotation angle is not sprung in a mathematically correct way. But hey, it LOOKS OKAY, and it's computationally cheap. So that is my final solution.

    You can find my code for vector & quaternion springs here.


    Effector Accumulation

    Effectors are force sources that push or pull things around. I mentioned earlier that I implement this logic using angle-axis vectors. The reasoning comes from torque accumulation in physics simulation. No matter in which order you apply a series of forces, the resulting accumulated torque is always the same. In other words, torque application is order-independent. It is done by taking the cross product each force with the vector from the center of mass to the point of force application. Adding these cross products together gives the final total torque from all forces.

    I wanted effectors to apply rotational effects in the same order-independentway, so I accumulate their rotational effects by adding together the cross products of each effector's linear velocity vector and the vector from the affected object's center to the effector's center. Once I have the final accumulated rotational effect, I convert it to a quaternion and combined with a bone's target rotation, computed via the method mentioned above.


    Transform Update

    Lastly, I have the sprung transform results, and I have to apply them to the bone's Transform component. I can't just set the Transform component's position and rotation to the sprung values, because what values can I base off of to compute new target values in the next frame? So I cache the bone's original transform (position, rotation, and scale; why scale? more on that later) at the beginning of LateUpdate, compute the target transforms, update the transform springs, set the transform values to the sprung values, so the renderer would use these values for rendering, and then restore the transform back to the cached values post-render (using the Camera.OnPostRender() delegate).


    Squash & Stretch

    I cache scale as well because there's an additional feature that alters a bone's scale for volume preservation (squash & stretch). Imagine a rubber block that's stretched to 4 times its original length in the direction of, say, its local Z axis. If nothing is done to its scale, its volume would become 4 times as large. This is where squash & stretch comes in. To maintain volume, the block needs to be shrunk in the directions perpendicular to the stretching axis, in this case, its X and Y axes. The scale value to shrink to in each perpendicular axis is the square root of the reciprocal of the stretch amount; in this case, it is 1/2 in both the local X and Y axes (4 * (1/2) * (1/2) == 1). Same thing applies when the block is squashed to 1/4 its original length, its local scale in X and Y axes would need to become 2 to maintain volume.

    I have the information of each child bone's original distance from its parent. It is compared to the distance between the sprung child bone and its parent. If the sprung distance is larger than the original, it's stretched; otherwise, it's squashed. Bones are scaled accordingly to create the sense of volume preservation.


    That's all!
    Feel free to ask if you'd like me to elaborate on certain details or explain things I forgot to mention.
    And I hope you like the video!
     
    one_one, RogDolos, pixlweaver and 2 others like this.
  2. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,450
    I love the Asset but I have one question

    As soon as I duplicate a prefab I loose the effect and get this warning:

    There should be one material data entry per instance. Instance data entries: 2, material data entries: 1.
     
  3. KenjiJU

    KenjiJU

    Joined:
    Dec 31, 2012
    Posts:
    15
    Hi. I just grabbed this yesterday and I'm having some fun with it. I'm wondering if you can help me figure out a couple things.

    I threw this on my character which has a hat with several bones. When I start running, the tail of the hat is very jumpy. What should I be looking at in particular to change this? Is there a framerate setting that needs to be changed to 60?

    I also wanted to see if this was a better solution to what I'm using for my character's chest physics, so I threw it on there too. The chest has two bones for each side and they're pointing slightly outwards, so flat collision from the spine might not be a solution for me. When walking/running, the chest sinks deep inside itself. What should I be changing so that there's drastically less of this effect? Or maybe boing bones is the wrong technique for this?

    Thank you.
     
  4. RogDolos

    RogDolos

    Joined:
    Oct 16, 2012
    Posts:
    42
    Just purchased and I'm enjoying playing around with the Boing Bones portion.

    However, I am using the Universal RP (Unity 2019.3.01f) and I have no idea how to implement the custom shader needed for Boing Fields, etc. to work with URP, or whether that would be possible at all? At a guess I'm thinking some code could be added through a custom function node in Shader Graph, but other than that I don't know exactly (I am not experienced at hand-coding shaders).

    I understand URP support hasn't been listed (or Shader Graph), but I'm hoping it's possible, or perhaps support might be added at some point?
     
    Lars-Steenhoff likes this.
  5. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Hi.

    Can you elaborate on your repro steps? Which component did you use? What are the steps did you take to construct and duplicate the prefab?

    Thanks.
     
  6. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Hi.

    As of now, the only way to get the reactor field effects on meshes in SRP is by calling the shader functions provided in your vector shaders. I am looking into making it available as a node in shader graph.
     
    dariony and Lars-Steenhoff like this.
  7. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Hi.

    Boing bones are updated via fixed update for stability reasons, so game objects that use boing boing should also update their transforms in fixed update.

    Also, I’m not sure I can picture the chest problem properly. Would you be able to provide gifs or animations showing the issues your are having?

    What would help me figure out the cause of both issues better is if you can send your project (or a stripped-down version that is the bare minimum needed to repro the issues) to me via email, so I can debug it.
     
  8. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,450
    I was able to get rid of the error, turned out the prefab was static.
    Is GPU instancing supported?
     
  9. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    You mean instancing objects with the reactor field GPU sampler component? The provided example standard materials support instancing, yes. As for custom shaders using Boing Kit’s shader functions in vertex shaders, it’s up to the custom shader to enable and support instancing.
     
  10. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,450
    Yes the standard material, thanks for confirming
     
  11. montyfi

    montyfi

    Joined:
    Aug 3, 2012
    Posts:
    548
    Any way to add bone chain to non skinned object using your asset?
    I want to animate a long plant, it's not skinned and if I add reactor - it reacts only when I touch the root of the plant. I want it to be more flexible.
     
  12. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    598
    I'm really enjoying Boing Kit! Thank-you for making it.

    How do I set up Exclusion in a bone chain?
    Adding transforms to the Exclusion array causes an error on launch.

    Code (CSharp):
    1. IndexOutOfRangeException: Index was outside the bounds of the array.
    2. BoingKit.BoingWork+Params+InstanceData.PullResults (BoingKit.BoingBones bones) (at Assets/Boing Kit/Script/BoingWork.cs:493)
    3. BoingKit.BoingWork+Params.PullResults (BoingKit.BoingBones bones) (at Assets/Boing Kit/Script/BoingWork.cs:828)
    4. BoingKit.BoingWorkAsynchronous.PullBonesResults (BoingKit.BoingEffector+Params[] aEffectorParams, System.Collections.Generic.Dictionary`2[TKey,TValue] bonesMap) (at Assets/Boing Kit/Script/BoingWorkAsynchronous.cs:291)
    5. BoingKit.BoingManager.PullBonesResults () (at Assets/Boing Kit/Script/BoingManager.cs:683)
    6. BoingKit.BoingManager.LateUpdate () (at Assets/Boing Kit/Script/BoingManager.cs:378)
    7. BoingKit.BoingManagerUpdatePump.LateUpdate () (at Assets/Boing Kit/Script/BoingManagerUpdatePump.cs:26)
     
  13. Source-technology

    Source-technology

    Joined:
    Dec 2, 2016
    Posts:
    21
    Hello, we have evaluated this plugin and appreciate your work very much.
    I want to ask if we want to use unity collision without adding collision one by one, juat automatically adding all the colliders in the scene, or 10 colliders near this bone, is this possible?
     
  14. khos

    khos

    Joined:
    May 10, 2016
    Posts:
    1,463
    Hi,

    I would like to ask if you have encountered the following behaviour, or know why this is happening:

    When I press play mode, in the scene view the boing effector/reactor works (actually copied from a demo scene), but in the game window nothing is happening, see sample video:


    Unity 2018.4.14f1 in use.
     
  15. khos

    khos

    Joined:
    May 10, 2016
    Posts:
    1,463
    Hi, wondered if anyone can comment on this? Many thanks.
     
  16. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    598
    Ever since the latest object I'm having problems with objects with gravity applied. They shake constantly, in FixedUpdate and Update mode.

    Unfortunately I don't think the developer reads this forum.
     
  17. khos

    khos

    Joined:
    May 10, 2016
    Posts:
    1,463
    Time for a refund.... no support it seems.. its a pity.
     
  18. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    @dock @montify @khos @Source-technology
    Hi! And I'm so sorry about not replying.
    Somehow Unity Forums unchecked my email notification (seems like others are experiencing the same issue). I've re-enabled the option and will check the forums every more often to make sure the email notification is actually working.

    So here are my replies to your questions:

    @dock
    1. When this exception was thrown, did you add transforms to the exclusion in edit mode, in play mode, or via script in play mode?
    2. Can you send me your project (stripped down to the essentials if it's too large) via email, so I can look at your use case? (longbunnylabs@gmail.com)

    @montify
    Sorry. The boing bones component only works with skinned mesh or transform hierarchy. I think I've seen an asset that lets you paint vertex weight and add extra bones directly in Unity with a simple UI. However, I don't think I'll have the time and manpower to include a similar feature, nor will I be able to create an in-editor skinning feature nearly as good as any existing professional 3D modeling software like Blender or Maya.

    @khos
    What is the version of Boing Kit you're using? There was an update (v1.2.12) that addresses multi-view issues in the editor. If you're already using a version as new as v1.2.12 and this issue still occurs, can you email me your project (stripped down to the essentials if the project is too large), so I can take a closer look? (longbunnylabs@gmail.com)

    @Source-technology
    Sorry. Such feature is not currently supported, but let me do some research first and see if there's anything I can do to include such feature in future updates.
     
  19. songjiekun

    songjiekun

    Joined:
    Jan 21, 2017
    Posts:
    29
    @Allen-Chou

    I have a question about the collision.
    Can i receive collision event from "boing collider" or "unity collider" collision?
     
  20. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    The boing bones component does not dispatch such events, and I intend to keep it that way, in order not to introduce extra performance overhead for the users that don't need them.

    However, you can achieve the same results by adding trigger colliders to the bones/transforms of your interest.
     
  21. Creiz

    Creiz

    Joined:
    Jun 6, 2017
    Posts:
    125
    Is this a viable replacement for dynamic bones? Did somebody use this on breasts, for example? If so, how does it look?
     
  22. atomtwist

    atomtwist

    Joined:
    Mar 20, 2013
    Posts:
    32
    Hi @Allen-Chou . I'm running into the same problem with exclusions as @dock - (same exception)
    adding joints to exclude in edit mode via inspector.

    I have a hierarchy where the arm bones are nested throughout of the body bones, but i only want to 'boing' the body bones. (see screenshot)
     

    Attached Files:

  23. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    @atomtwist
    By only "boinging" the body, what would your expected behavior be?
    Do you expect the arm roots to swing around as the the body bones bounce, but the rest of the arms maintain still relative to their arm roots?
    Or would you like the arms to stay where they would be in global coordinates as if there is no bouncy effects applied to any part of the character?
    What does your current result look like?
     
  24. Korimaru88

    Korimaru88

    Joined:
    Jul 24, 2015
    Posts:
    15
    Hi,

    Has any progress been made on this? I can't seem to get seem to get reactor field compatible materials working in URP, but that could just be my lack of experience with writing shaders.
     
  25. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Hi. Unfortunately, not yet.
    I have yet to research into shader graphs.
    Things have been crazy busy at the moment.
     
  26. zavidiy

    zavidiy

    Joined:
    Jun 5, 2017
    Posts:
    11
    Hello
    When my character simple moving in one direction bones twitches, it looks like lags. How can i fix that?
    Unity 2019.2.6
     
    Last edited: May 26, 2020
  27. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Could be that the update mode of the bones and your moving script don't match up?
    Are you running your script logic in Update or FixedUpdate?
    Can you check if the update mode of the bones matches that?

    If not, are you able to share your project so I can take a closer look?
    Preferably it's stripped down to not include the Boing Kit examples and other irrelevant assets so the size is kept low.
     
  28. ikermozos

    ikermozos

    Joined:
    Dec 5, 2019
    Posts:
    8
    Hi, Allen!

    We are setting several 'Boing Bone Collider' on our character, and we realized that when using the Capsule collider its orientation is tied to the orientation of its joint. I believe the Capsule colliders Unity comes with have an attribute for that to be changed, so the capsule does not necessarily align always to one specific axis.

    Is that possible in the Boing collider?
     
  29. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Not at the moment.
    I was not aware of such feature on the Unity collider and will look into it.
     
    ikermozos likes this.
  30. Marek_Bakalarczuk

    Marek_Bakalarczuk

    Joined:
    Dec 28, 2012
    Posts:
    112
    I want to add a object in runtime to bonechain root. But when I add it to bonechain root nothing hapening (bo boing effect).
     
  31. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    After dynamically changing bone chain structures at run-time via code, you need to call BoingBones.RescanBoingChains().
     
  32. matrixvel

    matrixvel

    Joined:
    Nov 1, 2018
    Posts:
    10
    Hi Allen, I've tried doing this in the past and I remember not being able to get objects added during runtime even after calling the rescan method. Working on a new project and this would be useful although I still can't get it to work. It's a pretty simple hierarchy of just spheres and after each is added dynamically I'm calling what I think you meant as the "RescanBoneChains" method. Would love to get this working as everything else with the bones works really nicely :)
     
  33. matrixvel

    matrixvel

    Joined:
    Nov 1, 2018
    Posts:
    10
    After taking a quick look at the Rescan method, making sure the "chainNeedsRescan" bool is always true does in fact get it working.
     
  34. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Right. The correct set of conditions for that bool can be overly complicated to be worth it.
    I'll just make the rescan method rescan all chains in the next update.
    Thanks for the catch.

    Edit: The fix is in the new update 1.2.30.
     
    Last edited: Dec 30, 2021
  35. Bubsavvy

    Bubsavvy

    Joined:
    Sep 18, 2017
    Posts:
    48
    @Allen-Chou your demo for influence-type comparison doesn't work. It's throwing the following exception :
    IndexOutOfRangeException: Index 0 is out of restricted IJobParallelFor range [32...0] in ReadWriteBuffer.
    ReadWriteBuffers are restricted to only read & write the element at the job index. You can use double buffering strategies to avoid race conditions due to reading & writing in parallel to the same elements from a job.
    Unity.Collections.NativeArray`1[T].FailOutOfRangeError (System.Int32 index) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)
    Unity.Collections.NativeArray`1[T].CheckElementReadAccess (System.Int32 index) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)
    Unity.Collections.NativeArray`1[T].get_Item (System.Int32 index) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)
    BoingKit.BoingWorkAsynchronous+ReactorJob.Execute (System.Int32 index) (at Assets/Boing Kit/Script/BoingWorkAsynchronous.cs:172)
    Unity.Jobs.IJobParallelForExtensions+ParallelForJobStruct`1[T].Execute (T& jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)

    Unity version is 2020.3.32f1
     
  36. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Hi. Thanks for the report.
    Are you referring to the All Influence Types or Influence Type Comparison example?
    Unfortunately, I was unable to repro it on a fresh package import on Unity 2020.3.32f1 on Windows 10 in either example.
    What are the versions of you OS and Boing Kit (both the one shown in package manager and the one shown in the inspector by selecting one of the object with a Boing Kit component in any example)?
    What are your repro steps (starting from how the project was created)?
     
  37. Bubsavvy

    Bubsavvy

    Joined:
    Sep 18, 2017
    Posts:
    48
    We tried adding this solution to BoingWorkAsync https://forum.unity.com/threads/err...stricted-ijobparallelfor.524827/#post-3449680 and it seems to have fixed the error, but i dont think that's the best fix because i think it locks reads and writes to the effectors which i don't think was the original intention.

    [ReadOnly, NativeDisableParallelForRestriction] public NativeArray<BoingEffector.Params> Effectors;

    Interestingly enough we also found that it requires at least 32 reactors in the scene at once before it throws the error. If we remove one it stops throwing the error.

    Windows 10 OS and Boing Kit Version 1.2.36 (latest). Its the Influence Type Comparison demo where your testing positional, rotational boing, etc. There are 4 types of boing side to side. Could it be my graphics card maybe? Maybe it doesn't support the type of method being used to manipulate vertex shaders? Not sure. I don't think that would be the case. Could be the render pipeline we are using the default. Our project is rather large and we have been working on it for the past 8 years or so. So it would be hard for me to fully reproduce. We will try a couple of things from our end on different GPUs and such and see if it works and get back if we find anything.
     
    Last edited: Apr 27, 2022
  38. Bubsavvy

    Bubsavvy

    Joined:
    Sep 18, 2017
    Posts:
    48
    Hi @Allen-Chou we figured it out. It was a conflict with the "ReadOnly" attribute. We had made a custom one a long time ago before Unity added their own in the System.Collections package i think. Sorry for the fuss. It's fixed now. Thanks for the reply.
     
  39. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,681
    @Allen-Chou Hi Allen!
    Thank you for the asset.
    I am using a simple Reactor and Effector.
    Is there a way to offset the pivot point of the Reactor?

    Currently it appears to be in the middle of the mesh, but I would like it at the base.

    Thank you
     
  40. Allen-Chou

    Allen-Chou

    Joined:
    May 20, 2013
    Posts:
    54
    Hi:

    There is no native support to offset the pivot.
    Easiest way to do that is to parent the object under another object, offset its local position, and set that new parent object as a reactor instead.