using System; using System.Linq; using System.Collections; using System.Collections.Generic; using UnityEngine; public class RagdollControllerArtanim : MonoBehaviour //this class does exactly the symetrical of MocapControllerArtanim: it maps animations from a ragdoll to a rigged character { [SerializeField] ArticulationBody _articulationBodyRoot; //to generate an environment automatically from a rigged character and an animation (see folder ROM-extraction) public ArticulationBody ArticulationBodyRoot { set => _articulationBodyRoot = value; get => _articulationBodyRoot; } private List _articulationbodies = null; private List _targetPoseTransforms = null; private List _offsetsRB2targetPoseTransforms = null; private List _offsetsSource2RB = null; [Space(20)] //not used in [SerializeField] float _debugDistance= 0.0f; [SerializeField] bool _isGeneratedProcedurally = false; public bool IsGeneratedProcedurally { set => _isGeneratedProcedurally = value; } [SerializeField] bool _debugWithRigidBody = false; [SerializeField] Rigidbody _rigidbodyRoot; private List _rigidbodies = null; // Start is called before the first frame update public void Start() { } //this one is for the case where everything is generated procedurally void SetOffsetRB2targetPoseInProceduralWorld() { if(_targetPoseTransforms == null) _targetPoseTransforms = GetComponentsInChildren().ToList(); if(_offsetsRB2targetPoseTransforms == null) _offsetsRB2targetPoseTransforms = new List(); if(_articulationbodies == null) _articulationbodies = _articulationBodyRoot.GetComponentsInChildren().ToList(); foreach (ArticulationBody ab in _articulationbodies) { //ArticulationBody ab = _articulationbodies.First(x => x.name == abname); string[] temp = ab.name.Split(':'); //if it has another ":" in the name, it crashes miserably //string tname = temp[1]; //instead, we do: string tname = ab.name.TrimStart(temp[0].ToArray()); tname = tname.TrimStart(':'); //Debug.Log("the full name is: " + ab.name + " and the trimmed name is: " + tname); //if structure is "articulation:" + t.name, it comes from a joint: if (temp[0].Equals("articulation")) { Transform t = _targetPoseTransforms.First(x => x.name == tname); //TODO: check these days if those values are different from 0, sometimes Quaternion qoffset = ab.transform.rotation * Quaternion.Inverse(t.rotation); MappingOffset r = new MappingOffset(t, ab, Quaternion.Inverse(qoffset)); if (ab.isRoot) { r.SetAsRoot(true, _debugDistance); } _offsetsRB2targetPoseTransforms.Add(r); } } } MappingOffset SetOffsetRB2targetPose(string rbname, string tname) { //here we set up: // a. the transform of the rigged character output // b. the rigidbody of the physical character // c. the offset calculated between the rigged character INPUT, and the rigidbody if (_targetPoseTransforms == null) { _targetPoseTransforms = GetComponentsInChildren().ToList(); // Debug.Log("the number of transforms intarget pose is: " + _targetPoseTransforms.Count); } if (_offsetsRB2targetPoseTransforms == null) { _offsetsRB2targetPoseTransforms = new List(); } if (_articulationbodies == null) { if (_debugWithRigidBody) { _rigidbodies = _rigidbodyRoot.GetComponentsInChildren().ToList(); } else { _articulationbodies = _articulationBodyRoot.GetComponentsInChildren().ToList(); } } Transform rb; if (_debugWithRigidBody) { rb = _rigidbodies.First(x => x.name == rbname).transform; }else { rb = null; try { rb = _articulationbodies.First(x => x.name == rbname).transform; if (rb == null) { Debug.LogError("no rigidbody with name " + rbname); } } catch { Debug.LogError("problem with finding rigidbody with a name like: " + rbname); } } Transform t = null; try { t = _targetPoseTransforms.First(x => x.name == tname); } catch { Debug.LogError("no bone transform with name in target pose" + tname); } Transform tref = null; try { tref = _targetPoseTransforms.First(x => x.name == tname); } catch { Debug.LogError("no bone transform with name in input pose " + tname); } //from refPose to Physical body: //q_{physical_body} = q_{offset} * q_{refPose} //q_{offset} = q_{physical_body} * Quaternion.Inverse(q_{refPose}) //Quaternion qoffset = rb.transform.localRotation * Quaternion.Inverse(tref.localRotation); Quaternion qoffset = rb.transform.rotation * Quaternion.Inverse(tref.rotation); //from physical body to targetPose: //q_{target_pose} = q_{offset2} * q_{physical_body} //q_{offset2} = Quaternion.Inverse(q_{offset}) MappingOffset r; if (_debugWithRigidBody) { Rigidbody myrb = rb.GetComponent(); r = new MappingOffset(t, myrb, Quaternion.Inverse(qoffset)); r.SetAsRagdollcontrollerDebug(_debugWithRigidBody); } else { ArticulationBody myrb = rb.GetComponent(); r = new MappingOffset(t, myrb, Quaternion.Inverse(qoffset)); } _offsetsRB2targetPoseTransforms.Add(r); return r; } void MimicPhysicalChar() { try { foreach (MappingOffset o in _offsetsRB2targetPoseTransforms) { o.UpdateRotation(); } } catch { Debug.Log("not calibrated yet..."); } } private void FixedUpdate() { MimicAnimationArtanim(); } void MimicAnimationArtanim() { if (_offsetsRB2targetPoseTransforms == null) { if (_isGeneratedProcedurally) { SetOffsetRB2targetPoseInProceduralWorld(); } else { MappingOffset o = SetOffsetRB2targetPose("articulation:Hips", "mixamorig:Hips"); o.SetAsRoot(true, _debugDistance); SetOffsetRB2targetPose("articulation:Spine", "mixamorig:Spine"); SetOffsetRB2targetPose("articulation:Spine1", "mixamorig:Spine1"); SetOffsetRB2targetPose("articulation:Spine2", "mixamorig:Spine2"); SetOffsetRB2targetPose("articulation:Neck", "mixamorig:Neck"); SetOffsetRB2targetPose("head", "mixamorig:Head"); SetOffsetRB2targetPose("articulation:LeftShoulder", "mixamorig:LeftShoulder"); SetOffsetRB2targetPose("articulation:LeftArm", "mixamorig:LeftArm"); SetOffsetRB2targetPose("articulation:LeftForeArm", "mixamorig:LeftForeArm"); // SetOffsetRB2targetPose("left_hand", "mixamorig:LeftHand"); // hands do not have rigidbodies SetOffsetRB2targetPose("articulation:RightShoulder", "mixamorig:RightShoulder"); SetOffsetRB2targetPose("articulation:RightArm", "mixamorig:RightArm"); SetOffsetRB2targetPose("articulation:RightForeArm", "mixamorig:RightForeArm"); // SetOffsetRB2targetPose("right_hand", "mixamorig:RightHand"); SetOffsetRB2targetPose("articulation:LeftUpLeg", "mixamorig:LeftUpLeg"); // SetOffsetRB2targetPose("left_shin", "mixamorig:LeftLeg"); SetOffsetRB2targetPose("articulation:LeftLeg", "mixamorig:LeftLeg"); SetOffsetRB2targetPose("articulation:LeftFoot", "mixamorig:LeftFoot"); SetOffsetRB2targetPose("articulation:LeftToeBase", "mixamorig:LeftToeBase"); // SetOffsetRB2targetPose("right_left_foot", "mixamorig:LeftToeBase"); SetOffsetRB2targetPose("articulation:RightUpLeg", "mixamorig:RightUpLeg"); //SetOffsetRB2targetPose("right_shin", "mixamorig:RightLeg"); SetOffsetRB2targetPose("articulation:RightLeg", "mixamorig:RightLeg"); SetOffsetRB2targetPose("articulation:RightFoot", "mixamorig:RightFoot"); SetOffsetRB2targetPose("articulation:RightToeBase", "mixamorig:RightToeBase"); // SetOffsetRB2targetPose("left_right_foot", "mixamorig:RightToeBase"); } } else { MimicPhysicalChar(); } } }