Search Unity

PuppetMaster - Advanced Character Physics Tool [RELEASED]

Discussion in 'Assets and Asset Store' started by Partel-Lang, Oct 1, 2015.

  1. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    @Partel-Lang

    So I just implemented chained relationships between the various muscles.

    The behaviour is -much- better than using kinship distance. Much better.

    I also see why you avoided it, the difficulty is that you need to do astar (or similar) across all muscles and you need to do this from puppetbehaviour, associating the overriden values against muscles in puppetmaster. Normally this operation would be most comfortable in puppetmaster itself, but since the individual overrides live in puppetbehaviour, it is extra cumbersome.

    I was going to share the code, but since I needed to use astar to calculate the paths from each muscle to each muscle, the code grew to be hundreds of lines.

    After you do astar, the rest is very easy - but unless you want to hardcode the paths from muscle to muscle, it must be done with a pathfinding algo or similar calculation or else it will never work.

    I guess this is why you excluded it... but... the behaviour can be very much improved with proper relationship weighting between limbs.
    ___________

    Also, when are you finally going to start working on 'self balancing puppet' - it is obviously the next step to do leg movement to balance :D
     
    Last edited: Jan 18, 2017
  2. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    The unpinning logic during death sequence:
    Code (csharp):
    1.  
    2.           float mW = muscles[0].state.muscleWeightMlp;
    3.  
    4.           while (mW > stateSettings.deadMuscleWeight) {
    5.             mW = Mathf.Max(mW - Time.deltaTime * (range / stateSettings.killDuration), stateSettings.deadMuscleWeight);
    6.  
    7.             foreach (Muscle m in muscles) m.state.muscleWeightMlp = mW;
    8.  
    9.             yield return null;
    10.           }
    11.  
    I believe this produces incorrect results, especially when used in conjunction with behaviourpuppet, as an impact from behaviour puppet can loosen muscle weight at the impact point (unpinned muscle weight multiplier). If the parent mult isn't 1, then it's certainly possible that hips can have a higher muscle weight multiplier than other limbs - so the ragdoll will tighten after being loose during a killing sequence.

    It is possible that this isn't a bug - as my codebase has deviated a bit, and I may have introduced problems here, but I am fairly certain the above logic isn't correct.
     
  3. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hi,
    Pinning is basically just moving the rigidbodies to their targets in world space using AddForce commands. The rest is handled by the muscles actuating the joints. If you set pin weight to 0, the muscles will still be working and animating the ragdoll so it will be lying on the ground still moving it's limbs around like you said. To completely kill the ragdoll, set Muscle Weight to 0 in PuppetMaster or set it's State to Dead.

    Hey, I'll try to answer your questions..
    First, the best way to get BehaviourPuppet in a state that should work nicely on a stock puppet is to copy it from the pilot in "Melee" or "Puppet Extended" demo and just paste it under yours. They have no direct references to anything so it will be fine. I'm planning to add a "Reset To Defaults" button too sometime in the future.

    About the unpinning...
    I'm not powing unpin by kinship degree, that would indeed propagate the value of 1 to everything regardless of kinship distance, I am powing the unpin falloff.
    So if the head gets hit, and head "Unpin Parents" weight is 1, all bones get unpinned by that same value, which is what you probably don't want, but it's just a possibility.
    If "Unpin Parents" is 0.5, the chest will get unpin * 0.5 = 0.5, the spine will get unpin * 0.5 * 0.5 = 0.25 and hips will get unpin * 0.5 * 0.5 * 0.5 = 0.125. So it's kind of an exponential falloff there based on kinship degree.

    Technically we could come up with all kinds of models for that, even biometrically correct ones, but keep in mind that there can be hundreds of collisions that need to be processed by that model in each simulation step, so performance really is the main criteria here, which is why I chose this system of using precalculated kinship degrees, it's fast.

    I'd be very interested in seeing how your astar method behaves though, as you said it was looking much better. :)

    I'll take a look at that dead muscle weight thing, might be a bug indeed.

    About balancing puppets, the next version of PM will include a Stagger behaviour. It will try to maintain balance by adjusting ankle joints, then makes some procedural staggering steps if it is pushed out of balance.

    Cheers,
    Pärtel
     
    tapawafo likes this.
  4. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Again though, if these falloffs are 1, the entire puppet destabilizes.

    I liked the kinship precalculation, so I followed form, I do not use astar at runtime, I just use it to precalculate the chained kinship unpin falloff.

    Code (csharp):
    1.  
    2.  
    3.     private void MapPuppetKinship() {
    4.       for (int i = 0; i < puppetMaster.muscles.Length; i++) {
    5.         Muscle a = puppetMaster.muscles[i];
    6.         a.kinshipMultipliers = new Muscle.Kin[puppetMaster.muscles.Length];
    7.         a.kinshipMultipliers[i] = new Muscle.Kin(){Name="Self", Weight = 1};
    8.  
    9.         for (int z = 0; z < puppetMaster.muscles.Length; z++) {
    10.           Muscle b = puppetMaster.muscles[z];
    11.           if (a == b) { continue; }
    12.           // astar to map the muscle tree
    13.           var path = PuppetMusclePathCalculator.GetPath(puppetMaster, i, z, true);
    14.           float chained_unpin = 1;
    15.           // start at 1 since we include origin in path
    16.           for (int path_depth = 1; path_depth < path.MuscleIndexPath.Count; path_depth++){
    17.             int prev_idx = path.MuscleIndexPath[path_depth - 1];
    18.             int path_idx = path.MuscleIndexPath[path_depth];
    19.             Muscle path_muscle = puppetMaster.muscles[path_idx];
    20.      
    21.             bool is_parent = path_muscle.childFlags[prev_idx];
    22.  
    23.             var props = GetProps(path_muscle.props.group);
    24.             float unpin = is_parent ? props.unpinParents : props.unpinChildren;
    25.             chained_unpin *= unpin;
    26.           }
    27.  
    28.           a.kinshipMultipliers[z] = new Muscle.Kin(){Name = b.props.group.ToString(), Weight = chained_unpin };
    29.         }
    30.       }
    31.     }
    32.  
    Obviously mapping all muscles to all muscles should be done in editor not at runtime! This code isn't optimal either, but it's precalculated so it doesn't really matter.

    The real problem is the feet and legs. If you chain the relationships, then you can set the leg's child unpin to 0 or .1, minimizing foot unpin. For example, when dealing with the head, you will often want a high parent unpin if you want the arms to unpin from impact. But having a high parent unpin here will also affect the legs and feet. If you use a .8 or ,9, then the feet can unpin at like .25, which is quite a lot!

    If you're modelling falling over when running into an object on the ground this isn't so bad. When modelling impacts that are not knockdowns, it can make a large difference. The feet and legs will often need to be treated very differently from the upper body.

    EDIT: it's worth noting that the animations I use for impacts and hurt include quite a lot of foot movement. The animation includes stagger. So if the legs start to unpin too much, the result can be crazy very fast, with legs flopping around like a clown. This is an example of when it's very important to keep leg pinned.
     
    Last edited: Jan 20, 2017
  5. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Also, I really liked how you designed behaviour puppet with no references, so it can be reused. I suggest something similar for the muscle configuration for puppetmaster. So that users can copy muscle config from one puppet to another and keep consistent settings (as long as the hierarchy is the same order). Or perhaps map the muscle settings to mecanim bones, so that they can be shared.

    This makes a big difference for user quality, since keeping the settings consistent across different characters can be error magnet.
     
  6. TommiH

    TommiH

    Joined:
    Jan 14, 2008
    Posts:
    253
    Thanks for the response! However, I tried setting the muscle weight to 0, and setting the mode to Dead, and it still animates...
     
  7. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Look at the examples, it will show how the settings work. Switching mode to dead should drop pinning and switch to muscle strength and fade this out over time (depending on the death settings).

    If you experiment with examples, it should be clear after a bit.

    Just open an example - like the boxer example, and mode the pin and muscle weight sliders around, it will start to make sense. You can also switch to dead/alive and see how this works.

    EDIT: The examples are very well set up, but you need to really look at how the settings work in the examples. Make sure to look at readme component in each.
     
    Last edited: Jan 20, 2017
    Partel-Lang likes this.
  8. nubdev

    nubdev

    Joined:
    Mar 30, 2013
    Posts:
    87
    Hey I am having some issues after coming back to PM - using puppet master with the navmesh agent specifically
    I've browsed the support documentation and this thread a bit but am unable to find a solution:

    A puppet has a navmesh agent on its root parent. When it loses balance, it disables the agent (tried both turning it off and setting its speed to 0) and then enables it once it regains balance. The problem is the puppet moves away from the agent when it loses balance, and ends up getting up in an offset position. This screws with AI that are targeting the puppet as they move towards the agent position instead of the puppet.

    I feel as though I have dealt with this problem before yet I cannot remember / figure out how to fix this.
    Any help is appreciated, thanks
     
  9. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    https://docs.unity3d.com/ScriptReference/AI.NavMeshAgent-nextPosition.html

    there are a lot of different configs for navmeshagent so how exactly you fix this will depend on your project
     
    Partel-Lang likes this.
  10. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey, thanks again for your valuable feedback!

    I see what you mean. Actually, I'm thinking why not make a Damage Map for each muscle, complete with Scene View visualization and editing tools. It would be difficult to maintain the zero reference policy, but I'll probably figure something out. Added that to the todo list.

    Hey,
    Another great idea, I just made a PuppetMasterHumanoidConfig ScriptableObject that does just that. Will be added to the next version, PM me if you need it right away.

    Thanks again,

    Cheers,
    Pärtel
     
  11. leevermeulen

    leevermeulen

    Joined:
    Sep 17, 2014
    Posts:
    6
    I remember seeing a demo/video of PuppetMaster being used on a quadruped dog - is that available anywhere?
     
  12. Telojuri94

    Telojuri94

    Joined:
    Jan 25, 2017
    Posts:
    7
    Hi Partel,
    First of all, congratulations for your plugin. It's so usefull and well-implemented.
    Mi question it's about the props. As you can see, the dummy have a sword. All the pins weights are at 1 (PuppetMaster's muscles array), included the prop's. Also, all the angular motions of the joint Prop/Hand are locked.
    I want to have the sword more strong, not so easy to move. I've tried increasing and decreasing the Solver Iterations Count variable.
    Is there any way to makes the behaviour of the prop being similar of the muscles?



    Thank you for your work!
     
  13. nubdev

    nubdev

    Joined:
    Mar 30, 2013
    Posts:
    87
  14. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey,
    I just have this video of setting up a dog with PM.

    Hey,
    It is only muscle spring that is maintaining that prop's rotation, the pin is only at the hand, so it only keeps the hand in place. If you check out the "Prop Melee" in Melee demo, it uses an additional pin in the middle of the prop to make use of pinning to make the prop stronger.

    Best,
    Pärtel
     
  15. wilco3d

    wilco3d

    Joined:
    Feb 15, 2015
    Posts:
    6
    Hi Partel,

    I'm using PuppetMaster along with Opsive's TPC. It's generally working great, quite impressed by how much better and natural my animations are looking.

    I just have 2 issues I wondered if you could point me in the right direction.

    1) Although it's smooth in Gameview in Unity, when I do a build - whenever the ragdoll takes over (e.g. when falling to the ground or getting back up) it's very jittery, like loads of little movements - hard to explain but it looks like its glitching? is there particular settings I should be playing with which would fix this?

    2) 90% of the time collisions work perfectly, but sometimes when a collision occurs the ragdoll goes flying off at 10000mph straight out the screen, do you have any idea why this might be happening or how I could fix it?

    Thank you!
     
  16. chaneya

    chaneya

    Joined:
    Jan 12, 2010
    Posts:
    416
    I'm interested in hearing from Partel on this number 2 issue as well. This happens to me infrequently but still it's a game breaker that I'll have to ultimately provide a solution for it. Every now and then during combat between PuppetMaster characters, for no apparent reason, they just go shooting off into space. It's infrequent enough that I haven't been able to isolate exactly what is going on when it happens.

    I would love to see a built in solution for limiting Ragdoll Rigidbody Velocity so just in case this sort of thing happens there is a built in check to try and prevent it.

    Thanks
    Allan
     
  17. Robray

    Robray

    Joined:
    Oct 11, 2015
    Posts:
    6
    Hi,
    I'm having a weird behaviour with puppet master that I can't understand. In the demo scenes, when you move the animated skeleton, the ragdoll puppet follow it perfectly but with my own prefab, when I do so, there are forces applied to the puppet. I mean, the quicker I move it, the more acceleration there is, limbs are going back and forth like they are on springs.
    The only difference I could notice is that my character doesn't have a humanoid rig but I don't know if this is really it.

    Does anyone know what could be the problem here ?
     
  18. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey,
    1) Is the jitter also visible when you look at the puppet in the Scene View, I mean without camera motion?
    If it's not, it's the camera updating that is out of sync with the physics.
    If it is, try disabling angular limits and internal collisions in PuppetMaster, might be that either one of those does not allow for the range of motion that is required by the animation.

    2) Most character controllers apply supernatural accelerations to characters when changing running direction or jumping. If you could visualize the center of mass of real physical humans, you'd see it's acceleration is always very smooth and slow, which is why it takes so much time and effort to change direction when we run. Slow acceleration is not however what is considered fun and responsive in terms of character controllers in video games, so they always accelerate many times faster than what would be physically possible. It will require major pinning forces to be applied on the ragdoll to keep up with that acceleration. When a puppet collides with something at that point and is unpinned, those forces will not be counterbalanced by the subsequent supernatural deacceleration of the character controller and that will shoot the puppet off to space. You are probably seeing this problem when you collide with something right after jumping or changing movement direction.

    I added
    Code (CSharp):
    1. public float maxRigidbodyVelocity = 10f;
    to BehaviourPuppet.cs.
    Then in BehaviourPuppetStateSwitching.cs, at line 59 this:
    Code (CSharp):
    1. if (maxRigidbodyVelocity != Mathf.Infinity) {
    2.                         m.rigidbody.velocity = Vector3.ClampMagnitude(m.rigidbody.velocity, maxRigidbodyVelocity);
    3.                     }
    Try a smaller value if the problem doesn't go away.

    Hey, please see the answer above.

    Hey,
    Perhaps the mass of the rigidbodies in the ragdolls is different? Mass has a big effect on how the puppet solves, so even if PuppetMaster settings are the same, it will look quite different. If that's not it, could you package up that puppet for me to take a closer look at?

    Best,
    Pärtel
     
  19. Robray

    Robray

    Joined:
    Oct 11, 2015
    Posts:
    6
    Nevermind, it was a silly mistake. I changed the pin weight on some muscles individually and forgot to reset the values that made the whole ragdoll wobbly. But thanks for the quick reply :).
     
  20. wilco3d

    wilco3d

    Joined:
    Feb 15, 2015
    Posts:
    6
    Thanks for the reply Partel.

    1) I managed to fix the jitter by changing the Solver Iteration Count to 1 - not sure if that points to a deeper cause of the problem that I'm just masking? Internal collisions and angular limits were disabled already.

    2) That didn't seem to make a difference. I even tried limiting the rigidbody velocity in an update method on my characters, but that didn't work either which is strange. Maybe ill PM you a video so you can see what I mean - might be obvious if you saw how they were reacting.
     
  21. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    I'm having an issue where when my character gets up she has a rotation which isn't corrected. She get up fine but she is rotated by some angle. This is probably due to me rotating the parent somewhere when I have the puppet behaviors turned off. This issue is quickly corrected by taking a couple of steps but it doesn't look very nice until you take those steps. I'm wondering if there's a way to correct this before it becomes a problem or if I can force the correction that happens automatically when my character takes a couple of steps.
     
  22. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey,
    What do you have for fixed time step in the Time manager? If it's higher than the default, it can cause jitter
    I'll continue working on that velocity issue with you in PM.

    Hey,
    You should disable all movement/rotation of the character controller while behaviourPuppet.state != BehaviourPuppet.State.Puppet;
    Moving/rotating the target root needs to be entirely controlled by BehaviourPuppet while the puppet is unpinned or getting up.

    Cheers,
    Pärtel
     
  23. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    @Partel-Lang
    I've done much more work with puppetmaster. I have some thoughts and comments on possible improvements.

    The main thing is behaviourpuppet - I feel that a lot of the functionality here (damage, unpin, etc) should be moved to puppetmaster proper. The state switching / get up logic and stuff should be separate.

    As a user, the muscle unpin weighting and logic in behaviourpuppet is a really important, core usage of puppetmaster.

    Different games will have very different needs in terms of behaviours or behaviour switching - and more demanding users may want to use an entirely different system for changing animation logic. But the weighted unpinning is very useful across many different use cases, and is really much more general.

    You also must have felt this when you added musclecollisionbroadcaster to muscle. Muscle is initialized by puppetmaster but musclecollisionbroadcaster is initialized by behaviourpuppet - a clear sign that some of behaviourpuppet's functionality should really be in puppetmaster.

    I recommend moving this logic out of behaviourpuppet and into puppetmaster core. I think many users will benefit from this. It will also make it easier to understand puppetmaster, as I personally found the behaviour broadcasting to be counter-intuitive - since disabled behaviours receive callbacks (mostly for the unpin logic in behaviourpuppet i think).

    PS: The more I work with puppetmaster, the more I appreciate your work. There are small problems here and there, but your core structure is very good. Example: I really liked the 'state' and 'props' object and have begun using similar patterns often in my own code.
     
  24. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey,
    Thanks for the feedback, very useful!

    You might be right, I mean as much as I have used PM myself, there have been times when I needed a "lighter" version of BehaviourPuppet, or just the damage/recovery functionality of it. For example when you need to be able to touch characters in VR without them falling over or anything.

    I have a vague idea of a concept of "damage maps", that could be added directly to the muscles, something you could visualize and edit in Scene View with some gizmos.

    The main problem with that is how to easily transfer that data from puppet to puppet so you wouldn't have to set them up manually each time. Perhaps I can add them to the PuppetMaster Humanoid Config that will be introduced by PM 0.6.

    Anyway, I'll give it some thought, thanks!
    Cheers,
    Pärtel
     
    frosted likes this.
  25. nazbee

    nazbee

    Joined:
    Oct 5, 2016
    Posts:
    9
    Hi,

    Is it possible to create an extra ragdoll limb using the Biped Ragdoll Creator? I followed your dog quadruped tutorial, but you didn't specify how to setup a tail. Im trying it on a cat model but the workflow isnt clear to me
     
  26. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey,
    Sorry, BipedRagdollCreator does not support additional limbs yet. You'll need to add that tail manually, but you can use RagdollEditor for easier setup of colliders and joint limits.

    Best,
    Pärtel
     
  27. nazbee

    nazbee

    Joined:
    Oct 5, 2016
    Posts:
    9
    Ok, thanks. No problem, Ill try to get it working manually
     
  28. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,079
    Hi, my character sliding on the ground really fast. I don't use any character controller I move my character only with animations.
     
  29. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Did you mean when it has lost balance and fallen on the ground? Does it just seem to have no friction at all?
     
  30. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,079
    Solved, thanks. It was an issue with layer collision matrix.
     
    Last edited: Feb 17, 2017
  31. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    When my character's arm is broken I use this code to ragdoll it:
    puppetMaster.RemoveMuscleRecursive(associatedMuscle.joint, true, true, MuscleRemoveMode.Numb);

    But that code destructively removes joints. How do I reenable my joints when I use a healthkit or otherwise no longer want the arm numb?
     
  32. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    Please correct me if I'm wrong, but under Joint and Muscle Settings, Muscle Spring is set to Position Spring as a Configurable Joint. This is "The spring torque that rotates the joint towards its target position. This is only used when the drive mode is set to Position or Position and Velocity."

    So position spring is a torque value?

    Does this mean every muscle has the same strength, equal to whatever "Muscle Spring" is set to? That seems wrong if so.

    I'm also trying to figure out what is a meaningful value for muscle spring.

    Suppose I want a value that represents a human strong enough to maintain 30 kg with his arm outstretched. The length of an average human arm is 63.5 centimeters. The weight of a human arm is 5.3% of the total body weight. For a 90.7 KG (200 LB) bodybuilder, this is 4.80KG. So I want enough torque to resist gravity on a 34.8 KG object with a length of .635 meters.

    In this case
    Torque = arm length * force * sin(90)
    Where force = mass * acceleration
    And acceleration = 9.81 m/s^2

    So that would be :
    .635 * 34.8 * 9.81 =216.78138 if my formula is right.
     
  33. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    I have a helper EditorWindow to create AI characters. I have it kind of working, but want to double check this is the correct approach. I'm concerned because your own code uses SerializedProperty so my own value changes may be getting overwritten, and I'm getting a warning sometimes as well.

    Creating a BipedRagdoll, step 1
    Code (CSharp):
    1.  
    2. BipedRagdollCreator bipedRagdollCreator = modelGameObject.AddComponent<BipedRagdollCreator>();
    3. bipedRagdollCreator.options.weight = modelWeightKg;
    4. bipedRagdollCreator.options.spine = true;
    5. bipedRagdollCreator.canBuild = true;
    6.  
    (I have to wait one frame, otherwise BipedRagdollCreator.Create fails due to invalid references)

    Creating a BipedRagdoll, step 2

    Code (CSharp):
    1. BipedRagdollCreator bipedRagdollCreator = modelGameObject.GetComponent<BipedRagdollCreator>();
    2. if (bipedRagdollCreator.references.IsValid())
    3. {
    4.     BipedRagdollCreator.Create(bipedRagdollCreator.references, bipedRagdollCreator.options);
    5.     UnityEngine.Object.DestroyImmediate(bipedRagdollCreator);
    6. }
    Creating PuppetMaster
    Code (CSharp):
    1.  
    2. PuppetMaster pm = PuppetMaster.SetUp(modelGameObject.transform, characterControllerLayer, ragdollLayer);
    3.  
    Creating FullBodyBipedIK
    Code (CSharp):
    1. Animator targetAnimator = modelGameObject.GetComponentInChildren<Animator>();
    2. GameObject workingObject = targetAnimator.gameObject;
    3. RootMotion.FinalIK.FullBodyBipedIK fullBodyBipedIk = workingObject.AddComponent<RootMotion.FinalIK.FullBodyBipedIK>();
    4. // Copied from [ContextMenu("Auto-detect References")]
    5. RootMotion.BipedReferences references = new BipedReferences();
    6. BipedReferences.AutoDetectReferences(ref references, workingObject.transform, new BipedReferences.AutoDetectParams(true, false));
    7. fullBodyBipedIk.solver.rootNode = IKSolverFullBodyBiped.DetectRootNodeBone(references);
    8. fullBodyBipedIk.solver.SetToReferences(references, fullBodyBipedIk.solver.rootNode);
    Creating AIMIK
    Code (CSharp):
    1. Animator targetAnimator = modelGameObject.GetComponentInChildren<Animator>();
    2. GameObject workingObject = targetAnimator.gameObject;
    3.  
    4. Transform spineTransform;
    5. Transform chestTransform;
    6. Transform shoulderTransform;
    7. Transform upperArmTransform;
    8.  
    9. spineTransform = targetAnimator.GetBoneTransform(HumanBodyBones.Spine);
    10. chestTransform = targetAnimator.GetBoneTransform(HumanBodyBones.Chest);
    11. if (rightHanded)
    12. shoulderTransform = targetAnimator.GetBoneTransform(HumanBodyBones.RightShoulder);
    13. else
    14. shoulderTransform = targetAnimator.GetBoneTransform(HumanBodyBones.LeftShoulder);
    15. if (rightHanded)
    16. upperArmTransform = targetAnimator.GetBoneTransform(HumanBodyBones.RightUpperArm);
    17. else
    18. upperArmTransform = targetAnimator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
    19.  
    20. AimIK aimIk = workingObject.AddComponent<RootMotion.FinalIK.AimIK>();
    21. aimIk.GetIKSolver().Initiate(targetAnimator.gameObject.transform);
    22. if (spineTransform != null)
    23. {
    24.     aimIk.solver.AddBone(spineTransform);
    25. }
    26. else if (chestTransform != null)
    27. {
    28.     aimIk.solver.AddBone(chestTransform);
    29. }
    30. if (shoulderTransform != null)
    31. {
    32.     aimIk.solver.AddBone(shoulderTransform);
    33. }
    34. if (upperArmTransform != null && upperArmTransform != shoulderTransform)
    35. {
    36.     aimIk.solver.AddBone(upperArmTransform);
    37. }
    38.  
    39. // Have to do it this way because AddBone resets the weights
    40. if (spineTransform != null)
    41. {
    42.     aimIk.solver.GetPoint(spineTransform).weight = .8f;
    43. }
    44. else if (chestTransform != null)
    45. {
    46.     aimIk.solver.GetPoint(chestTransform).weight = .8f;
    47. }
    48. if (shoulderTransform != null)
    49. {
    50.     aimIk.solver.GetPoint(shoulderTransform).weight = .2f;
    51. }
    52. if (upperArmTransform != null && upperArmTransform != shoulderTransform)
    53. {
    54.     aimIk.solver.GetPoint(upperArmTransform).weight = .2f;
    55. }
     
  34. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    Would you mind elaborating on what Pin Weight, Pin Pow, and Pin Distance Falloff means in more detail? I understand that Pin Weight adds a force so that the puppet matches the animation. But how much force? Does 1 mean it always adds enough force to match the animation no matter what the Muscle Weight is, so if the value is 1 then muscle weight has no effect? I see in the code that PinPow is the power the pin is raised to, but I don't understand under what condition this happens. Lastly, I don't know what Pin Distance Falloff means in units. 10 seems to be the default, but is that 10 meters? And if it's a distance then does that mean the pin force scales between 0 to 10 raised to PinPow?
     
  35. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    My understanding of how things work is
    A. PuppetMaster reads puppetMaster.targetRoot.position to determine where to place the puppet
    B. PuppetMaster rotates joints on the target animation, and moves the puppet to puppetMaster.targetRoot.position
    C. If the puppet is knocked around by large forces, it's up to the user to match the targetRoot position to the puppet position.

    For example, suppose my puppet rolls down a hill, I don't know about it so my puppetMaster.targetRoot stays at the top of the hill from my own user code. After the puppet stops rolling it warps back to the top of the hill. This is what happens with my setup.

    Looking at "Behavior Puppet" to see how you deal with this. you have an unpinned state that you enter when the puppet is knocked down. After trying to get back up, you directly set puppetMaster.targetRoot.position so the warping doesn't happen.
    Code (CSharp):
    1. puppetMaster.targetRoot.position = puppetMaster.muscles[0].rigidbody.position;
    However, this solution hides small changes to the puppet position. Either the puppet warps to the animated target position, or you warp the animated target to the puppet when the puppet is knocked down.

    What would really be helpful is if there was some callback after the puppet has processed changes to its own transform, and I could apply that same transform delta to my targetRoot. Then I don't have to deal with warping and will be able to reflect small changes to position.

    Is there such a thing, and is my understanding otherwise correct?

    Thanks in advance.
     
    wisniowy88 likes this.
  36. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey,
    In that case just set pin and muscle weights to 0 for the muscles of that limbs (muscle.props.pinWeight, muscle.psops.muscleWeight), will be very easy to reset them to 1.

    Yes, I have not applied any biometrics for that, yet at least. But you can do it if you set muscle spring to the value of the strongest muscle, then adjust each individual muscle's muscleWeight, that is basically just a multiplied for it's muscle spring.

    Seems legit. As for waiting for a frame for bipedragdollcreator, you can fill in it's references manually using
    Code (CSharp):
    1. public static BipedRagdollReferences FromAvatar(Animator animator)
    Actually it's all in just 9 lines of code in Muscle.cs starting from line 602
    private void Pin(float pinWeightMaster, float pinPow, float pinDistanceFalloff)

    Pinning is not a force actually, it just changes rigidbody.velocity to whatever the vector is towards it's target, pinWeight is basically just a multiplier for that. pin pow can be understood as pinWeight = Mathf.Pow(pinWeight, pinPow), it is used to make the effect of blending pin weight in/out more even, as otherwise it would be too snappy.

    Pin distance falloff divides the pinning effect by 1f + positionOffset.sqrMagnitude * pinDistanceFalloff;
    positionOffset is the vector from the rigidbody to it's target.

    It's more like:
    A. PuppetMaster reads the positions/rotations of all target bones
    B. PuppetMaster updates joint target rotations, pins all rigidbodies to their target positions

    PuppetMaster never adjusts the position of the targetRoot. It is only done by BehaviourPuppet if it is used.
    The way BehaviourPuppet does it is move the targetRoot to the hips rigidbody, store the pose of the ragdoll and blend from that pose to the animation in "Blend To Animation Time" so the transition is smooth. What did you mean by small changes to the puppet positions?

    Best,
    Pärtel
     
    RakNet likes this.
  37. corpsepile

    corpsepile

    Joined:
    Aug 14, 2016
    Posts:
    8
    @Partel-Lang
    Hey, just bought PuppetMaster and for starters, it's amazing!
    I've only been poking around with it for a few days but had a question for you.
    I'm trying to create an instance where my character is moving while being animated (mainly legs and lower body) but still being able to have his arms move independently (by input). I've seen some projects in this forum with that effect, so I know it's possible, just not entirely sure where to start. I'm guessing I need to "unpin" the arms but not sure the best way to go about doing so, or even how to do it correctly. (I'm relatively new to all of this.)
    Thanks!
     
  38. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    Hey, thanks for the quick response!

    That was my first approach but it acted differently from numbing the joint. As I recall, when I numbed the joint the arm hung naturally by the side of the character. If I set the weights to 0, the arm swung around wildly as if it had little mass.

    It looks like if the pin weight is one, the pin power is one, the pin distance falloff is zero, then the velocity will be such that the position matches over the next frame.

    Pin weight is linear
    Pin power reduces reduces the pinning force by raising it to a power
    The distance falloff divides the pin force by the the position offset squared * the distance falloff.

    Can I suggest pinPow and pinDistance falloff be replaced by an AnimationCurve instead? The Y axis is 0 to 1, and is linear between no offset, and apply the full offset, over the next frame. The X axis is distance.

    Code (CSharp):
    1.  
    2. float w = pinWeightMaster * props.pinWeight * state.pinWeightMlp;
    3. Vector3 displacement = positionOffset + offset;
    4. w *= curve.Evaluate(displacement)
    5. Vector3 p = (displacement) / Time.fixedDeltaTime;
    6. Vector3 force = -rigidbody.velocity + p;
    7. force *= w;
    8. rigidbody.velocity += force;
    9.  
    I'd like to request this feature. It would be useful to define during puppet setup. It would also save the effort of having to store these proportions.
     
  39. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    If you don't need puppetmaster to act on the arms at all, you can set the pin weight and muscle weight to 0. If you want it to act on the puppet, but not to update your animation, you can set the mapping weight to 0.

    You do this under "Individual Muscle Settings" in the puppet. You'd have to do it numerous times, once for each part of the arm.

    As in my post two above this I wrote an editor script to setup the puppet for me. In the script I do these kinds of updates. Otherwise it is unmaintainable to update the settings by hand for every character in my game.

    Feel free to message me if you have questions about PuppetMaster. I don't know everything but I'd spent many hours now trying to figure it out and might save you the same effort.
     
    Partel-Lang likes this.
  40. corpsepile

    corpsepile

    Joined:
    Aug 14, 2016
    Posts:
    8

    Hey thanks for offering to help!
    I think I tried what you're suggesting but it didn't produce the result I thought it would.
    As in, the Rigidbodies of my character were free to move, however the physical mesh/model was still pinned to the TargetRoot. I may have done something wrong though. Let me take another look later today and I may have some questions later.
    Thanks again!
     
  41. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    Suppose the following:

    1. My GameObject, the animation, and the puppet are at 0,0,0.
    2. I pause the player and move my GameObject +1 on the z axis. Now the game object and animation are at 0,0,1 while the puppet is at 0,0,0.
    3. The next frame, PuppetMaster will move the animation to 0,0,0 because of MappingWeight . The GameObject remains at 0,0,1
    4. Press next a few times, the puppet will eventually move to 0,0,1 because of pinning force.

    In this case, I know from step 2 that I am the one who moved the GameObject. But in code, in step 3 there is no way to tell who is right without additional information.

    Scenario 1: The GameObject took a step 1 meter forward
    Correct outcome: The puppet should move to that position

    Scenario 2: The puppet was knocked backwards due to physics 1 meter.
    Correct outcome: The GameObject should be moved to the puppet position

    This is a fundamental problem where there are two different data sources (the GameObject position and the puppet position) both of which can change independently (gameplay vs. dynamics) but are supposed to stay in synch.

    I need some kind of way for the GameObject to know what changes occured to the Puppet due to dynamics, so I can apply any corresponding transformations to the GameObject.

     
  42. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hi Defkron and thanks!
    Depends on what exactly you need to do with the arms. If you need to hang on to some handles physically, you should unpin them and link the hand rigidbodies to the handles with a Joint. If you need to interact with something, it would be best to use IK on the target rig. You can use Unity's built in IK if you have a humanoid or Final-IK to modify the pose that the ragdoll is targeting.

    Hey, about numbing the joint, you can set muscle weight to a very low value and add some muscle damper to reduce that swing. There is a problem with the current version, it will not use damper on the joint if muscle weight is 0, but it has been fixed for the next version.

    About using an AnimationCurve we could use that instead of pin pow, where time is pin weight and value is the multiplier for it, but distance faloff would require another curve. I remember considering that, but I chose to use float values for max performance, it takes time to evaluate curves and it needs to be done for each muscle in each fixed update. I've been also thinking about hiding pin pow, it's difficult to understand and doesn't really change all that much.

    This is how PM updates..
    With Animator update mode Normal:

    1. FixedUpdate - muscle target rotations and positions are updated
    2. PhysX simulation step
    4. Mecanim updates
    5. LateUpdate - reading the animation for the next frame, mapping the character to the ragdoll (writing)

    With Animator update mode AnimatePhysics:

    1. FixedUpdate - Mecanim is updated, reading the animation, muscle target rotations and positions are updated
    2. PhysX simulation step
    3. LateUpdate - mapping the character to the ragdoll (writing)

    So if you need to keep something in sync with the bones of the character, you only need to know when to do it.
    PuppetMaster has an OnWrite delegate, which is called each time PM is done with mapping the character to the ragdoll, so if you use that, you'll know the bones at that time are exactly where you see them on screen.

    There is also OnRead, which you can use to read the transforms of the bones as they are animated, without the effect of PuppetMaster.

    And finally, the ragdoll hierarchy is moved only physically, it is not mapped to anything (unless in Kinematic mode), so you can read rigidbody.velocity to know how much a part of it has moved.

    Cheers,
    Pärtel
     
  43. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    Is this generally correct, with animator mode normal?

    1. FixedUpdate - PhysX updates the ragdoll
    2. Mechanim updates
    3. Late update: Read the new animation state from step 2. Set the animation to the ragdoll. Write to the ragdoll the animation state PuppetMaster just read.

    To read my position: Use "ThirdPersonPuppet -> Character Controller -> Animation Controller -> Pilot -> Pelvis." The reason I need to do that is the Pelvis gets updated to reflect physics update to the puppet, where the Character Controller's game object does not.

    To modify my position (Option 1): Modify anything higher up in the read hierarchy. I cannot write to the Pelvis game object, because Mechanim is called after Update() and will overwrite any changes I make.

    To modify my position (Option 2):Modify the pelvis in OnRead(), which is called after Mechanim, but before PuppetMaster reads it.

    Is there another solution? I would really like to just have a single game object I can use gameobject.transform.position on and have that be the position of the hips, and be able to read/write to that in Update(). All my existing scripts assume this, as well as other assets that I use.

    CharacterController.png

     
    Last edited: Feb 22, 2017
  44. chaneya

    chaneya

    Joined:
    Jan 12, 2010
    Posts:
    416
    Partel,

    I found a compatibility problem between PuppetMaster and FinalIK. The problem occurs when you have a PuppetMaster character that also uses Full Body Biped IK and you switch the PuppetMaster State to Frozen.

    The character loses balance as expected but instead of staying dead, as soon as the Behavior Puppet behaviors and PuppetMaster ragdolls are disabled, the character instantly goes into T-Pose.

    Here is how to recreate the problem in a clean install:
    Unity 5.5.1
    1. Create New Project, Import Puppet Master, Import Final IK, extract Puppet Master Integration package for FinalIK
    2. Open the Melee Demo in Puppet Master/Demos
    3. Choose the Third Person Puppet and add a Full Body Biped IK component to Third Person Puppet/Character Controller gameobject.
    4. Press Play and change the Third Person Puppet/Pilot PuppetMaster State to Frozen.

    Thanks for the help.

    Allan
     
  45. Telojuri94

    Telojuri94

    Joined:
    Jan 25, 2017
    Posts:
    7
    Hi Partel,
    I've to change onTime the pinWeight of some muscles. Actually i'm doing it like this:
    puppetMaster.muscles[8].props.pinWeight = 0.0f;
    but now I have implemented the removal of muscles, so the muscles array changes.
    Is there any way to know on which index of the muscles array is a concrete muscle?

    Thank you
     
  46. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey,
    1. PhysX updates the ragdoll after FixedUpdate, not in it.
    3. The last part is not true, PM will not write to the ragdoll the animation state PM just read. It will set target positions/rotations for the muscles in the next FixedUpdate. It will only move the ragdoll to the character when in Kinematic mode, otherwise the ragdoll is moved only by physical forces.

    There is really no simple solution other than Option 2 to modify the position. Unfortunately the execution order of event functions is fixed in Unity so I can't just make PuppetMaster.Update() like I have ik.solver.Update() in FIK. I can not change when PhysX updates, that's why PuppetMaster's update functions are spread around the whole update cycle of Unity.

    Hey,
    Just uncheck "Fix Transforms" on FBBIK or disable FBBIK when you freeze the puppet. Freezing a puppet disables animation on it, so if FBBIK fixes transforms to their default state, there's nothing overwriting it.

    Hey,
    If it's a humanoid, you could use
    Code (CSharp):
    1. GetMuscleIndex(HumanBodyBones humanBodyBone)
    There's also
    Code (CSharp):
    1. GetMuscleIndex(Transform target)
    if you have a reference to the target bone.
    There are some other methods that can all be found in PuppetMasterMuscleAPI.cs or in the Script Reference.

    Best,
    Pärtel
     
  47. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    Sometimes when I start Unity I get:
    "Biped references were auto-detected on a FullBodyBipedIK component that was added in runtime. Note that this only happens in the Editor and if the GameObject is selected (for quick and convenient debugging). If you want to add FullBodyBipedIK dynamically in runtime via script, you will have to use BipedReferences.AutodetectReferences() for automatic biped detection."

    But I'm already doing that

    Code (CSharp):
    1.  
    2. GameObject workingObject = targetAnimator.gameObject;
    3.             RootMotion.FinalIK.FullBodyBipedIK fullBodyBipedIk = workingObject.AddComponent<RootMotion.FinalIK.FullBodyBipedIK>();
    4.  
    5.             // Copied from [ContextMenu("Auto-detect References")]
    6.             RootMotion.BipedReferences references = new BipedReferences();
    7.             BipedReferences.AutoDetectReferences(ref references, workingObject.transform, new BipedReferences.AutoDetectParams(true, false));
    8.             fullBodyBipedIk.solver.rootNode = IKSolverFullBodyBiped.DetectRootNodeBone(references);
    9.             fullBodyBipedIk.solver.SetToReferences(references, fullBodyBipedIk.solver.rootNode);
    10.  

     
  48. Alfonso_CJ

    Alfonso_CJ

    Joined:
    Nov 19, 2015
    Posts:
    35
    Are there any Scripts that allows the PuppetBots to walk along a nav mesh path and avoid Obstacles?
     
    Last edited: Feb 27, 2017
  49. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Hey,
    Instead of the last 2 lines, write
    Code (CSharp):
    1.  fullBodyBipedIk.SetReferences(references, null);
    Full code sample in the User Manual FBBIK page.

    Just add a NavMeshAgent to the character as you normally would.

    Cheers,
    Pärtel
     
  50. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    I suspect the "Dual Rig" setup of Puppet Master is fundamentally a flawed design. Pärtel, I've read your forum feedback carefully and spent hours studying the code and I still don't see how to resolve this.

    The design:
    There are two positions, the animated position and the puppet
    The animated position may be updated by gameplay code
    The puppet position may be updated by internal forces (pinning) or external forces (physics collisions).
    PuppetMaster tries to match up the positions by having the puppet follow the animated position. This can lag behind the animated position, sometimes substantially.

    The problem:
    What happens if an external force moves the puppet away from the animated position? Once the external force dissipates, the internal force (pinning) moves the puppet back to the animated position. This is clearly undesirable. If my puppet rolls down a hill, he should not reach the bottom and then slide back up. In practice this doesn't always happen because of the pin force falloff, but you can see similar behavior on a smaller scale.

    I've tried to fix this in many ways, and none work in all circumstances.
    Set the animated character position to the puppet position every frame.
    Try to move the puppet, rather than the animated character.
    Set the animated character position to the puppet position when the puppet falls down.

    The Unity engine doesn't have this same problem because there is only one position for a rigid body. If the rigid body moves due to physics, so does the game object. If the game object moves, so does the rigid body.