//CKeyHook _oKeyHook_ThighSpread; //--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { _nDrivePos = 0.5f * C_DrivePos; // Weaken the leg pin drive over default //=== Init Bones and Joints === CJointDriver oJointPelvis = _oBody._oActor_Pelvis._oJointExtremity; _aJoints.Add(_oJointThighBend = CJointDriver.Create(this, oJointPelvis, _sSidePrefixL+"ThighBend", 15, 3.0f, -115, 035, 000, 085, 1)); // X = Leg forward (-115) / back (35), Z = Thigh split (85) / together (20) ###BAD: Super-important thigh split needed same value for thigh together makes no sense! ###IMPROVE: 2nd joint? _aJoints.Add(_oJointThighTwist = CJointDriver.Create(this, _oJointThighBend, _sSidePrefixL+"ThighTwist", 20, 2.0f, -000, 000, 075, 000, 1)); // Y = Thigh twist -75 to 75 Ok _aJoints.Add(_oJointShin = CJointDriver.Create(this, _oJointThighTwist, _sSidePrefixL+"Shin", 10, 2.0f, -011, 155, 015, 005, 1)); // X = Knee bent (+155) or backward (-11), Y = Knee rotate -25 to 10 with compromise at 15, Z = Knee side-to-side -5 to 5 _aJoints.Add(_oJointFoot = CJointDriver.Create(this, _oJointShin, _sSidePrefixL+"Foot", 15, 1.0f, -025, 010, 020, 040, 1)); // X = Foot up (-40) and down (+75), inward -25 to +10, twist -35 to 15: ###IMPROVE: FootX not up/down!! ###IMPROVE: 2 joints? ###PROBLEM: Foot up down on Z with poor bending along down _aJoints.Add(_oJointMetatarsals = CJointDriver.Create(this, _oJointFoot, _sSidePrefixL+"Metatarsals", 20, 0.5f, -000, 000, 020, 012, 1)); // X = Metatarsals left/right = useless, Y = twist -20 to 20, Z = foot bend -12 to 12 _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, _oJointMetatarsals, _sSidePrefixL+"Toe", 20, 3.0f, -000, 000, 020, 050, 1)); // X = Toes bend backward (-45) to forward (65), Y = Toe twist -20/20, Z = meaningless ###IMPROVE: Rotate axe? ###CHECK: Toe mass?? _oJointShin._oConfJoint.targetRotation = Quaternion.Euler(-160, 0, 0); //###WEAK: Set knee default position so it can easily bend (with very week drive) //###SOON: Proper bending of knee calculations from height //=== Init Hotspot === if (_eBodySide == 0) //###IMPROVE: Rediculously long path... switch to 'search for bone' (would not be as fast tho) _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/chestLower/abdomenUpper/abdomenLower/hip/pelvis/lThighBend/lThighTwist/lShin/lFoot/lMetatarsals/lToe"), "Left Leg", true, new Vector3(0, 0, 0)); else _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/chestLower/abdomenUpper/abdomenLower/hip/pelvis/rThighBend/rThighTwist/rShin/rFoot/rMetatarsals/rToe"), "Right Leg", true, new Vector3(0, 0, 0)); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorLeg), "Leg", "Leg" + _sSidePrefixU); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot _oObj.PropAdd(EActorLeg.Thigh_Spread, "Thigh-Spread", 0, -100, 100, ""); _oObj.PropAdd(EActorLeg.Thigh_Rotate, "Thigh-Rotate", 0, -100, 100, ""); _oObj.FinishInitialization(); //_oKeyHook_ThighSpread = new CKeyHook(_oObj.PropFind(EActorLeg.Thigh_Spread), KeyCode.F, EKeyHookType.QuickMouseEdit, "Thigh Spread", -1); }
//--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { //=== Init Bones and Joints === _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, null, "chestUpper", 15, 8, -000, 000, 000, 000, 1)); //### The body's root bone... is kinematic and has no joint to a parent bone so all zeros _aJoints.Add(_oJointChestLower = CJointDriver.Create(this, _oJointExtremity, "chestLower", 15, 8, -015, 015, 010, 010, 1)); _aJoints.Add(_oJointAbdomenUpper = CJointDriver.Create(this, _oJointChestLower, "abdomenUpper", 15, 6, -035, 025, 012, 020, 1)); _aJoints.Add(_oJointAbdomenLower = CJointDriver.Create(this, _oJointAbdomenUpper, "abdomenLower", 15, 6, -040, 025, 024, 020, 1)); _aJoints.Add(_oJointHip = CJointDriver.Create(this, _oJointAbdomenLower, "hip", 15, 6, -035, 020, 015, 015, 1)); //###NOTE: Pelvis bone is in CActorPelvis for extra processing there. //###CHECK: Keep? _oJointExtremity._oRigidBody.isKinematic = (CGame.INSTANCE._GameMode == EGameModes.Configure); //###HACK ###TEMP ####REVA If play no anim just set everything to kinematic... for temp cloth exploration //###OBS? _oJointExtremity._oRigidBody.isKinematic = false; // We need to disable kinematic on bone as we're driving it with our pin! //=== Init Hotspot === _oHotSpot = CHotSpot.CreateHotspot(this, transform, "Chest", true, new Vector3(0, 0, 0), C_SizeHotSpot_BodyNodes); //_oHotSpot = CHotSpot.CreateHotspot(this, _oBody.FindBone("chestUpper"), "Chest", true, new Vector3(0, 0, 0), C_SizeHotSpot_TorsoNodes); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorChest), "Chest", "Chest"); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot _oObj.PropAdd(EActorChest.Torso_LeftRight, "Torso_LeftRight", 0, -100, 100, ""); //###BUG: Have to recalibrate to make new abdoment-centric bones look good. _oObj.PropAdd(EActorChest.Torso_UpDown, "Torso_UpDown", 0, -100, 100, ""); //###NOW###: Forced to enter crappy name because of new CProp restrictions with naming! _oObj.PropAdd(EActorChest.Torso_Twist, "Torso_Twist", 0, -100, 100, ""); _oObj.FinishInitialization(); //###PROBLEM: Base actor adds 'pinned' but chest is always pinned? //###CHECK?? _oObj.PropSet(EActorChest.Pinned, 1); // Manually set pinned to 1 on torso so body doesn't float in space when no pose is loaded (Weak that we can't set in PropAdd() due to init-time problems) if (CGame.INSTANCE.EnableIdlePoseMovement) StartCoroutine(Coroutine_ChangeRandomPose()); //###CHECK: When destroyed OK?? }
Vector3 _vecStartingPos; // Pose and rotation stored so we can return to 'configure' game mode at any time #endregion Fields #region Methods public static CJointDriver Create(CActor oActor, CJointDriver oJointDrvParent, string sNameBone, float nDriveStrengthMult, float nMass, float XL, float XH, float YHL, float ZHL, int nFinalized=0) { Transform oTransform; if (oJointDrvParent == null) oTransform = CUtility.FindChild(oActor._oBody._oBodyBase._oBonesT, sNameBone); // Finding bone when root is different. ###IMPROVE: Can be simplified to just always top bone? (e.g. Why does 'Bones' have a single top bone 'chestUpper' when the could be merged?) else oTransform = CUtility.FindChild(oJointDrvParent.transform, sNameBone); if (oTransform == null) CUtility.ThrowException("CJointDriver.Create() cannot find bone " + sNameBone); CJointDriver oJointDriver = CUtility.FindOrCreateComponent(oTransform.gameObject, typeof(CJointDriver)) as CJointDriver; oJointDriver.Initialize(oActor, oJointDrvParent, nDriveStrengthMult, nMass, XL, XH, YHL, ZHL, nFinalized!=0); return oJointDriver; }
//--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { _nDrivePos = 0.1f * C_DrivePos; // Weaken the hand drive so hand doesn't fly from pin to pin //###TUNE //_memVecRayHitInfo = new CMemAlloc<Vector3>(2); //=== Init Bones and Joints === CJointDriver oJointChestUpper = _oBody._oActor_Chest._oJointExtremity; _aJoints.Add(_oJointCollar = CJointDriver.Create(this, oJointChestUpper, _sSidePrefixL+"Collar", 30, 2.5f, -010, 050, 030, 021, 1)); // X = Collar Up/Down OK, Z has 17 back and 25 forward (avg looks ok) _aJoints.Add(_oJointShoulderBend = CJointDriver.Create(this, _oJointCollar, _sSidePrefixL+"ShldrBend", 15, 2.0f, -085, 035, 000, 110, 1)); // X = Shoulder Up/Down OK, Z = Back goes to -40, Forward to 110!!! (###IMPROVE: Another joint?) _aJoints.Add(_oJointShoulderTwist = CJointDriver.Create(this, _oJointShoulderBend, _sSidePrefixL+"ShldrTwist", 20, 1.5f, -000, 000, 080, 000, 1)); // Y = Shoulder twist goes from -95 to 80 so max. ###PROBLEM: Shimmer in high rotation! _aJoints.Add(_oJointForearmBend = CJointDriver.Create(this, _oJointShoulderTwist, _sSidePrefixL+"ForearmBend", 10, 1.5f, -020, 135, 000, 000, 1)); // X = Elbow bend from -20 to 135. ok. _aJoints.Add(_oJointForearmTwist = CJointDriver.Create(this, _oJointForearmBend, _sSidePrefixL+"ForearmTwist", 20, 1.0f, -000, 000, 080, 000, 1)); // Y = Forearm twist from -90 to 80 so max. ###IMPROVE: Could rotate the axes on the twists so we use XL/XH _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, _oJointForearmTwist, _sSidePrefixL+"Hand", 10, 0.5f, -070, 080, 010, 029, 1)); // X = Hand -down(-70) / +up (+80), Y = Hand twist +/-10, Z = Hand side-to-side -28 to +30 //ConfigFingerRoot(1, "Index"); // Thumb is handled below ###DESIGN!!! Fingers in Unity PhysX is just a no-go because of extremely poor latency... what to do????? //ConfigFingerRoot(2, "Mid"); //ConfigFingerRoot(3, "Ring"); //??? ###HACK!! Disabled man's carpal1&2 in 3dsMax so we can use same code as women's! //ConfigFingerRoot(4, "Pinky"); //CJointDriver oJointFingerBoneParent = _oJointExtremity; //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 0, "Thumb", 005f, -030f, 005f, 025f); //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 1, "Thumb", 010f, -015f, 000f, 000f); //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 2, "Thumb", 010f, -015f, 000f, 000f); //=== Init Hotspot === if (_eBodySide == 0) _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/lCollar/lShldrBend/lShldrTwist/lForearmBend/lForearmTwist/lHand"), "Left Hand", true, new Vector3(0, 0, 0)); else _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/rCollar/rShldrBend/rShldrTwist/rForearmBend/rForearmTwist/rHand"), "Right Hand", true, new Vector3(0, 0, 0)); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorArm), "Arm", "Arm" + _sSidePrefixU); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot //_oObj.PropAdd(EActorArm.HandTarget, "HandTarget", typeof(EHandTargets), (int)EHandTargets.ManualPosition, ""); _oObj.PropAdd(EActorArm.Hand_UpDown, "Hand-UpDown", 0, -100, 100, ""); _oObj.PropAdd(EActorArm.Hand_LeftRight, "Hand-LeftRight", 0, -100, 100, ""); _oObj.PropAdd(EActorArm.Hand_Twist, "Hand-Twist", 0, -100, 100, ""); //_oObj.PropAdd(EActorArm.Fingers_Close, "Fingers-Close", 0, -100, 100, "", CProp.Hide); //###BROKEN //_oObj.PropAdd(EActorArm.Fingers_Spread, "Fingers-Spread", 0, -100, 100, "", CProp.Hide); //_oObj.PropAdd(EActorArm.Fingers_ThumbPose, "Fingers-ThumbPose", typeof(EThumbPose), (int)EThumbPose.AlongsideFingers, "", CProp.Hide); //_oObj.PropAdd(EActorArm.UserControl, "User Control", 0, 0, 1, ""); _oObj.FinishInitialization(); _oHandTarget_RaycastPin = CActorArm.FindHandTarget(_oBody, EHandTargets.RaycastPin, _eBodySide == EBodySide.Right); // Find the raycast pin hand target as we use it heavily and it is reparented }
public void Initialize(CActor oActor, CJointDriver oJointDrvParent, float nDriveStrengthMult, float nMass, float XL, float XH, float YHL, float ZHL, bool bFinalized) { _oActor = oActor; _oJointDrvParent = oJointDrvParent; _nDriveStrengthMult = nDriveStrengthMult; _vecStartingPos = transform.localPosition; _quatStartingRotation = transform.localRotation; if (CGame.INSTANCE.BoneDebugMode && bFinalized == false) { // Set debug limits if in debug mode (so we can fully rotate along all axis for game-time tuning) unless bone is 'finalized' in which do apply the supplied limits _XH = _YHL = _ZHL = 177f; // Set limit angles to maximum value in bone debug mode (so runtime bone debugger can move all bones and all axis all the way) _XL = -_XH; } else { _XL = XL; _XH = XH; _YHL = YHL; _ZHL = ZHL; } //=== Create the rigid body for our bone === _oRigidBody = (Rigidbody)CUtility.FindOrCreateComponent(gameObject, typeof(Rigidbody)); //###TODO: Add a "CRigidBodyWake"??? _oRigidBody.mass = nMass; _oRigidBody.drag = 1.5f; //###TODO!! //###DESIGN: Which drag?? //###TUNE!!!!! ###IMPROVE: Different settings for arms & legs??? _oRigidBody.angularDrag = 1.5f; //###TUNE!!!! _oRigidBody.sleepThreshold = 0; // Ensure the rigid body never sleeps! //=== Process special handling needed when we are root (we are kinematic and we have no joint to parent) === if (_oJointDrvParent == null) { // If we have a null parent then we're the root and we're kinematic with no joint to anyone! _oRigidBody.isKinematic = true; } else { //=== If we have a parent then we are not kinematic and rotate by PhysX simulation === _oRigidBody.isKinematic = false; //=== Create the D6 configurable joint between our parent and us === _oConfJoint = (ConfigurableJoint)CUtility.FindOrCreateComponent(gameObject, typeof(ConfigurableJoint)); //###TODO: Add a "CRigidBodyWake"??? _oConfJoint.connectedBody = _oJointDrvParent._oRigidBody; //=== Set the joint limits as per our arguments === bool bInvertX = (_XL > _XH); //###OBS??? If the logical range is inverted we can't send this to PhysX as lowAngularXLimit MUST be < than highAngularXLimit! if (bInvertX) CUtility.ThrowException("Inverted XL / XH in bone " + gameObject.name); //###CHECK SoftJointLimit oJL = new SoftJointLimit(); //###IMPROVE: Has other fields that could be of use? oJL.limit = bInvertX ? _XH : _XL; _oConfJoint. lowAngularXLimit = oJL; // X is the high-functionality axis with separately-defined Xmin and Xmax... Y and Z only have a +/- range around zero, so we are forced to raise the lower half to match the other side oJL.limit = bInvertX ? _XL : _XH; _oConfJoint.highAngularXLimit = oJL; oJL.limit = _YHL; _oConfJoint. angularYLimit = oJL; //###NOTE! Hugely inconvenient feature of D6 joint is Y & Z must be symmetrical!! Make sure bone is oriented so X is used for the assymetrical rotation!! oJL.limit = _ZHL; _oConfJoint. angularZLimit = oJL; //=== Set joint axis defaults (before overriding some of them) === _oConfJoint.xMotion = _oConfJoint.yMotion = _oConfJoint.zMotion = ConfigurableJointMotion.Locked; _oConfJoint.angularXMotion = _oConfJoint.angularYMotion = _oConfJoint.angularZMotion = ConfigurableJointMotion.Limited; //###DESIGN? Limited vs Free? //=== Free the axis that don't need driving === ###CHECK: Safe??? if (_XL == 0f && _XH == 0f) _oConfJoint.angularXMotion = ConfigurableJointMotion.Free; // If an axis is unused set it //free to reduce PhysX workload ###CHECK: Is this ever invoked? Does it make joint fail if not all three axis driven?? if (_YHL == 0f) _oConfJoint.angularYMotion = ConfigurableJointMotion.Free; //###DESIGN: Verify unsetting! if (_ZHL == 0f) _oConfJoint.angularZMotion = ConfigurableJointMotion.Free; //###NOTE: SLERP needs all three axis by definition... But Limited of little / no use if we drive all the time (less PhysX overhead)) //=== Set the configurable joint drive strength === JointDrive oDrive = new JointDrive(); oDrive.positionSpring = _nDriveStrengthMult * CGame.INSTANCE.BoneDriveStrength; // Final spring strength is the global constant multiplied by the provided multiplier... makes it easy to adjust whole-body drive strength oDrive.positionDamper = 0; //###TODO!!!!! ###TUNE? oDrive.maximumForce = float.MaxValue; //###IMPROVE: Some reasonable force to prevent explosions?? //oDrive.mode = JointDriveMode.Position; _oConfJoint.slerpDrive = oDrive; _oConfJoint.rotationDriveMode = RotationDriveMode.Slerp; // Slerp is really the only useful option for bone driving. (Many other features of D6 joint!!!) //=== If we're a node on the right side, copy the collider defined on our twin node on the left side === if (_oActor._eBodySide == EBodySide.Right) { Transform oNodeSrc = CUtility.FindSymmetricalBodyNode(transform.gameObject); //Debug.Log("Collider copy " + oNodeSrc.name); Collider oColBaseSrc = oNodeSrc.GetComponent<Collider>(); if (oColBaseSrc.GetType() == typeof(CapsuleCollider)) { CapsuleCollider oColSrc = (CapsuleCollider)oColBaseSrc; CapsuleCollider oColDst = (CapsuleCollider)CUtility.FindOrCreateComponent(transform, typeof(CapsuleCollider)); oColDst.center = oColSrc.center; oColDst.radius = oColSrc.radius; oColDst.height = oColSrc.height; oColDst.direction = oColSrc.direction; } else if (oColBaseSrc.GetType() == typeof(BoxCollider)) { BoxCollider oColSrc = (BoxCollider)oColBaseSrc; BoxCollider oColDst = (BoxCollider)CUtility.FindOrCreateComponent(transform, typeof(BoxCollider)); oColDst.center = oColSrc.center; oColDst.size = oColSrc.size; } } } }