/// <summary> /// Calibrates VRIK to the specified trackers using the VRIKTrackerCalibrator.Settings. /// </summary> /// <param name="ik">Reference to the VRIK component.</param> /// <param name="settings">Calibration settings.</param> /// <param name="headTracker">The HMD.</param> /// <param name="bodyTracker">(Optional) A tracker placed anywhere on the body of the player, preferrably close to the pelvis, on the belt area.</param> /// <param name="leftHandTracker">(Optional) A tracker or hand controller device placed anywhere on or in the player's left hand.</param> /// <param name="rightHandTracker">(Optional) A tracker or hand controller device placed anywhere on or in the player's right hand.</param> /// <param name="leftFootTracker">(Optional) A tracker placed anywhere on the ankle or toes of the player's left leg.</param> /// <param name="rightFootTracker">(Optional) A tracker placed anywhere on the ankle or toes of the player's right leg.</param> public static CalibrationData Calibrate(VRIK ik, Settings settings, Transform headTracker, Transform bodyTracker = null, Transform leftHandTracker = null, Transform rightHandTracker = null, Transform leftFootTracker = null, Transform rightFootTracker = null) { if (!ik.solver.initiated) { Debug.LogError("Can not calibrate before VRIK has initiated."); return(null); } if (headTracker == null) { Debug.LogError("Can not calibrate VRIK without the head tracker."); return(null); } CalibrationData data = new CalibrationData(); ik.solver.FixTransforms(); // Root position and rotation Vector3 headPos = headTracker.position + headTracker.rotation * Quaternion.LookRotation(settings.headTrackerForward, settings.headTrackerUp) * settings.headOffset; ik.references.root.position = new Vector3(headPos.x, ik.references.root.position.y, headPos.z); Vector3 headForward = headTracker.rotation * settings.headTrackerForward; headForward.y = 0f; ik.references.root.rotation = Quaternion.LookRotation(headForward); // Head Transform headTarget = ik.solver.spine.headTarget == null ? (new GameObject("Head Target")).transform : ik.solver.spine.headTarget; headTarget.position = headPos; headTarget.rotation = ik.references.head.rotation; headTarget.parent = headTracker; ik.solver.spine.headTarget = headTarget; // Size float sizeF = (headTarget.position.y - ik.references.root.position.y) / (ik.references.head.position.y - ik.references.root.position.y); ik.references.root.localScale *= sizeF * settings.scaleMlp; // Body if (bodyTracker != null) { Transform pelvisTarget = ik.solver.spine.pelvisTarget == null ? (new GameObject("Pelvis Target")).transform : ik.solver.spine.pelvisTarget; pelvisTarget.position = ik.references.pelvis.position; pelvisTarget.rotation = ik.references.pelvis.rotation; pelvisTarget.parent = bodyTracker; ik.solver.spine.pelvisTarget = pelvisTarget; ik.solver.spine.pelvisPositionWeight = settings.pelvisPositionWeight; ik.solver.spine.pelvisRotationWeight = settings.pelvisRotationWeight; ik.solver.plantFeet = false; ik.solver.spine.maxRootAngle = 180f; } else if (leftFootTracker != null && rightFootTracker != null) { ik.solver.spine.maxRootAngle = 0f; } // Left Hand if (leftHandTracker != null) { Transform leftHandTarget = ik.solver.leftArm.target == null ? (new GameObject("Left Hand Target")).transform : ik.solver.leftArm.target; leftHandTarget.position = leftHandTracker.position + leftHandTracker.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp) * settings.handOffset; Vector3 leftHandUp = Vector3.Cross(ik.solver.leftArm.wristToPalmAxis, ik.solver.leftArm.palmToThumbAxis); leftHandTarget.rotation = QuaTools.MatchRotation(leftHandTracker.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp), settings.handTrackerForward, settings.handTrackerUp, ik.solver.leftArm.wristToPalmAxis, leftHandUp); leftHandTarget.parent = leftHandTracker; ik.solver.leftArm.target = leftHandTarget; ik.solver.leftArm.positionWeight = 1f; ik.solver.leftArm.rotationWeight = 1f; } else { ik.solver.leftArm.positionWeight = 0f; ik.solver.leftArm.rotationWeight = 0f; } // Right Hand if (rightHandTracker != null) { Transform rightHandTarget = ik.solver.rightArm.target == null ? (new GameObject("Right Hand Target")).transform : ik.solver.rightArm.target; rightHandTarget.position = rightHandTracker.position + rightHandTracker.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp) * settings.handOffset; Vector3 rightHandUp = -Vector3.Cross(ik.solver.rightArm.wristToPalmAxis, ik.solver.rightArm.palmToThumbAxis); rightHandTarget.rotation = QuaTools.MatchRotation(rightHandTracker.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp), settings.handTrackerForward, settings.handTrackerUp, ik.solver.rightArm.wristToPalmAxis, rightHandUp); rightHandTarget.parent = rightHandTracker; ik.solver.rightArm.target = rightHandTarget; ik.solver.rightArm.positionWeight = 1f; ik.solver.rightArm.rotationWeight = 1f; } else { ik.solver.rightArm.positionWeight = 0f; ik.solver.rightArm.rotationWeight = 0f; } // Legs if (leftFootTracker != null) { CalibrateLeg(settings, leftFootTracker, ik.solver.leftLeg, (ik.references.leftToes != null ? ik.references.leftToes : ik.references.leftFoot), ik.references.root.forward, true); } if (rightFootTracker != null) { CalibrateLeg(settings, rightFootTracker, ik.solver.rightLeg, (ik.references.rightToes != null ? ik.references.rightToes : ik.references.rightFoot), ik.references.root.forward, false); } // Root controller bool addRootController = bodyTracker != null || (leftFootTracker != null && rightFootTracker != null); var rootController = ik.references.root.GetComponent <VRIKRootController>(); if (addRootController) { if (rootController == null) { rootController = ik.references.root.gameObject.AddComponent <VRIKRootController>(); } rootController.Calibrate(); } else { if (rootController != null) { GameObject.Destroy(rootController); } } // Additional solver settings ik.solver.spine.minHeadHeight = 0f; ik.solver.locomotion.weight = bodyTracker == null && leftFootTracker == null && rightFootTracker == null ? 1f : 0f; // Fill in Calibration Data data.scale = ik.references.root.localScale.y; data.head = new CalibrationData.Target(ik.solver.spine.headTarget); data.pelvis = new CalibrationData.Target(ik.solver.spine.pelvisTarget); data.leftHand = new CalibrationData.Target(ik.solver.leftArm.target); data.rightHand = new CalibrationData.Target(ik.solver.rightArm.target); data.leftFoot = new CalibrationData.Target(ik.solver.leftLeg.target); data.rightFoot = new CalibrationData.Target(ik.solver.rightLeg.target); data.leftLegGoal = new CalibrationData.Target(ik.solver.leftLeg.bendGoal); data.rightLegGoal = new CalibrationData.Target(ik.solver.rightLeg.bendGoal); data.pelvisTargetRight = rootController.pelvisTargetRight; data.pelvisPositionWeight = ik.solver.spine.pelvisPositionWeight; data.pelvisRotationWeight = ik.solver.spine.pelvisRotationWeight; return(data); }
public static IEnumerator CalibrateScaled(Transform handTrackerRoot, Transform headTrackerRoot, Transform footTrackerRoot, VRIK ik, Settings settings, Vector3 LeftHandOffset, Vector3 RightHandOffset, Transform HMDTransform, Transform PelvisTransform = null, Transform LeftHandTransform = null, Transform RightHandTransform = null, Transform LeftFootTransform = null, Transform RightFootTransform = null) { if (!ik.solver.initiated) { Debug.LogError("Can not calibrate before VRIK has initiated."); yield break; } if (HMDTransform == null) { Debug.LogError("Can not calibrate VRIK without the head tracker."); yield break; } //トラッカーのルートスケールを初期値に戻す handTrackerRoot.localScale = new Vector3(1.0f, 1.0f, 1.0f); headTrackerRoot.localScale = new Vector3(1.0f, 1.0f, 1.0f); footTrackerRoot.localScale = new Vector3(1.0f, 1.0f, 1.0f); //それぞれのトラッカーを正しいルートに移動 if (HMDTransform != null) { HMDTransform.parent = headTrackerRoot; } if (LeftHandTransform != null) { LeftHandTransform.parent = handTrackerRoot; } if (RightHandTransform != null) { RightHandTransform.parent = handTrackerRoot; } if (PelvisTransform != null) { PelvisTransform.parent = footTrackerRoot; } if (LeftFootTransform != null) { LeftFootTransform.parent = footTrackerRoot; } if (RightFootTransform != null) { RightFootTransform.parent = footTrackerRoot; } //コントローラーの場合手首までのオフセットを追加 if (LeftHandOffset == Vector3.zero) { var offset = new GameObject("LeftWristOffset"); offset.transform.parent = LeftHandTransform; offset.transform.localPosition = new Vector3(-0.04f, 0.04f, -0.15f); offset.transform.localRotation = Quaternion.Euler(60, 0, 90); offset.transform.localScale = Vector3.one; LeftHandTransform = offset.transform; } if (RightHandOffset == Vector3.zero) { var offset = new GameObject("RightWristOffset"); offset.transform.parent = RightHandTransform; offset.transform.localPosition = new Vector3(0.04f, 0.04f, -0.15f); offset.transform.localRotation = Quaternion.Euler(60, 0, -90); offset.transform.localScale = Vector3.one; RightHandTransform = offset.transform; } // モデルのポジションを手と手の中心位置に移動 var centerposition = Vector3.Lerp(LeftHandTransform.position, RightHandTransform.position, 0.5f); ik.references.root.position = new Vector3(centerposition.x, ik.references.root.position.y, centerposition.z); yield return(new WaitForEndOfFrame()); //それぞれのトラッカーに手のオフセットを適用 //トラッカーの角度は 0,-90,-90 が正位置(手の甲に付けてLED部を外側に向けたとき) //トラッカー zをマイナス方向に動かすとトラッカーの底面に向かって進む //角度補正LookAt(左手なら右のトラッカーに向けた)後 zを+方向は体中心(左手なら右手の方向)に向かって進む //xを-方向は体の正面に向かって進む //先にトラッカー底面に向かってのオフセットを両手に適用する var leftWrist = new GameObject("LeftWristOffset").transform; leftWrist.parent = LeftHandTransform; leftWrist.localPosition = new Vector3(0, 0, -LeftHandOffset.y); leftWrist.localRotation = Quaternion.Euler(Vector3.zero); var rightWrist = new GameObject("RightWristOffset").transform; rightWrist.parent = RightHandTransform; rightWrist.localPosition = new Vector3(0, 0, -RightHandOffset.y); rightWrist.localRotation = Quaternion.Euler(Vector3.zero); //お互いのトラッカー同士を向き合わせてオフセットを適用する leftWrist.LookAt(rightWrist ?? RightHandTransform); leftWrist.localPosition += leftWrist.localRotation * new Vector3(0, 0, LeftHandOffset.z); rightWrist.LookAt(leftWrist ?? LeftHandTransform); rightWrist.localPosition += rightWrist.localRotation * new Vector3(0, 0, RightHandOffset.z); //両手のxをマイナス方向が正面なので体を回転させる Vector3 hmdForwardAngle = leftWrist.rotation * new Vector3(-1, 0, 0); hmdForwardAngle.y = 0f; ik.references.root.rotation = Quaternion.LookRotation(hmdForwardAngle); //回転した分トラッカーも回転させる if (LeftHandOffset != Vector3.zero) // Vector3 (IsEnable, ToTrackerBottom, ToBodySide) { leftWrist.eulerAngles = new Vector3(0, -90, 90); //トラッカー補正後の角度 leftWrist.RotateAround(leftWrist.position, Vector3.up, ik.references.root.rotation.eulerAngles.y); //体の回転分を引く LeftHandTransform = leftWrist; } if (RightHandOffset != Vector3.zero) // Vector3 (IsEnable, ToTrackerBottom, ToBodySide) { rightWrist.eulerAngles = new Vector3(180, -90, 90); //トラッカー補正後の角度 rightWrist.RotateAround(rightWrist.position, Vector3.up, ik.references.root.rotation.eulerAngles.y); //体の回転分を引く RightHandTransform = rightWrist; } yield return(new WaitForEndOfFrame()); //モデルを手の高さで比較してスケールアップさせる //なるべく現実の身長に近づけて現実のコントローラー座標とのずれをなくす //ずれが大きいとexternalcamera.cfgとの合成時に手がずれすぎておかしくなる var modelHandHeight = (ik.references.leftHand.position.y + ik.references.rightHand.position.y) / 2f; var realHandHeight = (LeftHandTransform.position.y + RightHandTransform.position.y) / 2f; var hscale = realHandHeight / modelHandHeight; ik.references.root.localScale = new Vector3(hscale, hscale, hscale); //VRMモデルのコライダーがスケールについてこないため、すべて再設定 var springBoneColiderGroups = ik.references.root.GetComponentsInChildren <VRM.VRMSpringBoneColliderGroup>(); foreach (var springBoneColiderGroup in springBoneColiderGroups) { foreach (var colider in springBoneColiderGroup.Colliders) { colider.Offset *= hscale; colider.Radius *= hscale; } } // 手のトラッカー全体のスケールを手の位置に合わせる var modelHandDistance = Vector3.Distance(ik.references.leftHand.position, ik.references.rightHand.position); var realHandDistance = Vector3.Distance(LeftHandTransform.position, RightHandTransform.position); var wscale = modelHandDistance / realHandDistance; modelHandHeight = (ik.references.leftHand.position.y + ik.references.rightHand.position.y) / 2f; realHandHeight = (LeftHandTransform.position.y + RightHandTransform.position.y) / 2f; hscale = modelHandHeight / realHandHeight; handTrackerRoot.localScale = new Vector3(wscale, hscale, wscale); // モデルのポジションを再度手と手の中心位置に移動 centerposition = Vector3.Lerp(LeftHandTransform.position, RightHandTransform.position, 0.5f); ik.references.root.position = new Vector3(centerposition.x, ik.references.root.position.y, centerposition.z); //hmdForwardAngle = HMDTransform.rotation * settings.headTrackerForward; //hmdForwardAngle.y = 0f; ik.references.root.rotation = Quaternion.LookRotation(hmdForwardAngle); // 頭のトラッカー全体のスケールを頭の位置に合わせる var modelHeadHeight = ik.references.head.position.y; var realHeadHeight = HMDTransform.position.y; var headHscale = modelHeadHeight / realHeadHeight; headTrackerRoot.localScale = new Vector3(wscale, hscale, wscale); // 腰のトラッカー全体のスケールを腰の位置に合わせる if (PelvisTransform != null) { var modelPelvisHeight = ik.references.pelvis.position.y; var realPelvisHeight = PelvisTransform.position.y; var pelvisHscale = modelPelvisHeight / realPelvisHeight; footTrackerRoot.localScale = new Vector3(wscale, pelvisHscale, wscale); } //腰の子に膝のBendGoal設定用 var bendGoalTarget = new GameObject("BendGoalTarget"); bendGoalTarget.transform.parent = ik.references.pelvis; bendGoalTarget.transform.localScale = Vector3.one; bendGoalTarget.transform.localPosition = new Vector3(0, 0, 1); //正面1m bendGoalTarget.transform.localRotation = Quaternion.Euler(Vector3.zero); yield return(new WaitForEndOfFrame()); //yield break; // Head Transform hmdAdjusterTransform = ik.solver.spine.headTarget == null ? (new GameObject("hmdAdjuster")).transform : ik.solver.spine.headTarget; hmdAdjusterTransform.parent = HMDTransform; hmdAdjusterTransform.position = ik.references.head.position; //HMDTransform.position + HMDTransform.rotation * Quaternion.LookRotation(settings.headTrackerForward, settings.headTrackerUp) * settings.headOffset; //hmdAdjusterTransform.localPosition = new Vector3(0, hmdAdjusterTransform.localPosition.y, -0.15f); hmdAdjusterTransform.rotation = ik.references.head.rotation; ik.solver.spine.headTarget = hmdAdjusterTransform; ik.solver.spine.headClampWeight = 0.38f; // Body if (PelvisTransform != null) { Transform pelvisAdjusterTransform = ik.solver.spine.pelvisTarget == null ? (new GameObject("pelvisAdjuster")).transform : ik.solver.spine.pelvisTarget; pelvisAdjusterTransform.parent = PelvisTransform; pelvisAdjusterTransform.position = ik.references.pelvis.position; pelvisAdjusterTransform.rotation = ik.references.pelvis.rotation; ik.solver.spine.pelvisTarget = pelvisAdjusterTransform; ik.solver.spine.pelvisPositionWeight = 1f; ik.solver.spine.pelvisRotationWeight = 1f; ik.solver.plantFeet = false; ik.solver.spine.neckStiffness = 0f; ik.solver.spine.maxRootAngle = 180f; } else if (LeftFootTransform != null && RightFootTransform != null) { ik.solver.spine.maxRootAngle = 0f; } yield return(new WaitForEndOfFrame()); // Left Hand if (LeftHandTransform != null) { Transform leftHandAdjusterTransform = ik.solver.leftArm.target == null ? (new GameObject("leftHandAdjuster")).transform : ik.solver.leftArm.target; leftHandAdjusterTransform.parent = LeftHandTransform; leftHandAdjusterTransform.position = LeftHandTransform.position + LeftHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp) * settings.handOffset; Vector3 leftHandUp = Vector3.Cross(ik.solver.leftArm.wristToPalmAxis, ik.solver.leftArm.palmToThumbAxis); leftHandAdjusterTransform.rotation = QuaTools.MatchRotation(LeftHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp), settings.handTrackerForward, settings.handTrackerUp, ik.solver.leftArm.wristToPalmAxis, leftHandUp); ik.solver.leftArm.target = leftHandAdjusterTransform; } else { ik.solver.leftArm.positionWeight = 0f; ik.solver.leftArm.rotationWeight = 0f; } // Right Hand if (RightHandTransform != null) { Transform rightHandAdjusterTransform = ik.solver.rightArm.target == null ? (new GameObject("rightHandAdjuster")).transform : ik.solver.rightArm.target; rightHandAdjusterTransform.parent = RightHandTransform; rightHandAdjusterTransform.position = RightHandTransform.position + RightHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp) * settings.handOffset; Vector3 rightHandUp = -Vector3.Cross(ik.solver.rightArm.wristToPalmAxis, ik.solver.rightArm.palmToThumbAxis); rightHandAdjusterTransform.rotation = QuaTools.MatchRotation(RightHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp), settings.handTrackerForward, settings.handTrackerUp, ik.solver.rightArm.wristToPalmAxis, rightHandUp); ik.solver.rightArm.target = rightHandAdjusterTransform; } else { ik.solver.rightArm.positionWeight = 0f; ik.solver.rightArm.rotationWeight = 0f; } // Legs if (LeftFootTransform != null) { CalibrateLeg(settings, LeftFootTransform, ik.solver.leftLeg, (ik.references.leftToes != null ? ik.references.leftToes : ik.references.leftFoot), hmdForwardAngle, ik.references.root.forward, true); } if (RightFootTransform != null) { CalibrateLeg(settings, RightFootTransform, ik.solver.rightLeg, (ik.references.rightToes != null ? ik.references.rightToes : ik.references.rightFoot), hmdForwardAngle, ik.references.root.forward, false); } ik.solver.leftLeg.bendGoal = bendGoalTarget.transform; ik.solver.leftLeg.bendGoalWeight = 1.0f; ik.solver.rightLeg.bendGoal = bendGoalTarget.transform; ik.solver.rightLeg.bendGoalWeight = 1.0f; // Root controller bool addRootController = PelvisTransform != null || (LeftFootTransform != null && RightFootTransform != null); var rootController = ik.references.root.GetComponent <VRIKRootController>(); if (addRootController) { if (rootController == null) { rootController = ik.references.root.gameObject.AddComponent <VRIKRootController>(); } rootController.pelvisTarget = ik.solver.spine.pelvisTarget; rootController.leftFootTarget = ik.solver.leftLeg.target; rootController.rightFootTarget = ik.solver.rightLeg.target; rootController.Calibrate(); } else { if (rootController != null) { GameObject.Destroy(rootController); } } // Additional solver settings ik.solver.spine.minHeadHeight = 0f; ik.solver.locomotion.weight = PelvisTransform == null && LeftFootTransform == null && RightFootTransform == null ? 1f : 0f; }
/// <summary> /// Calibrates VRIK to the specified trackers using the VRIKTrackerCalibrator.Settings. /// </summary> /// <param name="ik">Reference to the VRIK component.</param> /// <param name="settings">Calibration settings.</param> /// <param name="HMDTransform">The HMD.</param> /// <param name="PelvisTransform">(Optional) A tracker placed anywhere on the body of the player, preferrably close to the pelvis, on the belt area.</param> /// <param name="LeftHandTransform">(Optional) A tracker or hand controller device placed anywhere on or in the player's left hand.</param> /// <param name="RightHandTransform">(Optional) A tracker or hand controller device placed anywhere on or in the player's right hand.</param> /// <param name="LeftFootTransform">(Optional) A tracker placed anywhere on the ankle or toes of the player's left leg.</param> /// <param name="RightFootTransform">(Optional) A tracker placed anywhere on the ankle or toes of the player's right leg.</param> public static void Calibrate(VRIK ik, Settings settings, Transform HMDTransform, Transform PelvisTransform = null, Transform LeftHandTransform = null, Transform RightHandTransform = null, Transform LeftFootTransform = null, Transform RightFootTransform = null) { if (!ik.solver.initiated) { Debug.LogError("Can not calibrate before VRIK has initiated."); return; } if (HMDTransform == null) { Debug.LogError("Can not calibrate VRIK without the head tracker."); return; } // Head Transform hmdAdjusterTransform = ik.solver.spine.headTarget == null ? (new GameObject("hmdAdjuster")).transform : ik.solver.spine.headTarget; hmdAdjusterTransform.parent = HMDTransform; hmdAdjusterTransform.position = HMDTransform.position + HMDTransform.rotation * Quaternion.LookRotation(settings.headTrackerForward, settings.headTrackerUp) * settings.headOffset; hmdAdjusterTransform.rotation = ik.references.head.rotation; ik.solver.spine.headTarget = hmdAdjusterTransform; // Size float sizeF = hmdAdjusterTransform.position.y / ik.references.head.position.y; ik.references.root.localScale = Vector3.one * sizeF; // Root position and rotation ik.references.root.position = new Vector3(hmdAdjusterTransform.position.x, ik.references.root.position.y, hmdAdjusterTransform.position.z); Vector3 hmdForwardAngle = HMDTransform.rotation * settings.headTrackerForward; hmdForwardAngle.y = 0f; ik.references.root.rotation = Quaternion.LookRotation(hmdForwardAngle); // Body if (PelvisTransform != null) { Transform pelvisAdjusterTransform = ik.solver.spine.pelvisTarget == null ? (new GameObject("pelvisAdjuster")).transform : ik.solver.spine.pelvisTarget; pelvisAdjusterTransform.parent = PelvisTransform; pelvisAdjusterTransform.position = ik.references.pelvis.position; pelvisAdjusterTransform.rotation = ik.references.pelvis.rotation; ik.solver.spine.pelvisTarget = pelvisAdjusterTransform; ik.solver.spine.pelvisPositionWeight = 1f; ik.solver.spine.pelvisRotationWeight = 1f; ik.solver.plantFeet = false; ik.solver.spine.neckStiffness = 0f; ik.solver.spine.maxRootAngle = 180f; } else if (LeftFootTransform != null && RightFootTransform != null) { ik.solver.spine.maxRootAngle = 0f; } // Left Hand if (LeftHandTransform != null) { Transform leftHandAdjusterTransform = ik.solver.leftArm.target == null ? (new GameObject("leftHandAdjuster")).transform : ik.solver.leftArm.target; leftHandAdjusterTransform.parent = LeftHandTransform; leftHandAdjusterTransform.position = LeftHandTransform.position + LeftHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp) * settings.handOffset; Vector3 leftHandUp = Vector3.Cross(ik.solver.leftArm.wristToPalmAxis, ik.solver.leftArm.palmToThumbAxis); leftHandAdjusterTransform.rotation = QuaTools.MatchRotation(LeftHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp), settings.handTrackerForward, settings.handTrackerUp, ik.solver.leftArm.wristToPalmAxis, leftHandUp); ik.solver.leftArm.target = leftHandAdjusterTransform; } else { ik.solver.leftArm.positionWeight = 0f; ik.solver.leftArm.rotationWeight = 0f; } // Right Hand if (RightHandTransform != null) { Transform rightHandAdjusterTransform = ik.solver.rightArm.target == null ? (new GameObject("rightHandAdjuster")).transform : ik.solver.rightArm.target; rightHandAdjusterTransform.parent = RightHandTransform; rightHandAdjusterTransform.position = RightHandTransform.position + RightHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp) * settings.handOffset; Vector3 rightHandUp = -Vector3.Cross(ik.solver.rightArm.wristToPalmAxis, ik.solver.rightArm.palmToThumbAxis); rightHandAdjusterTransform.rotation = QuaTools.MatchRotation(RightHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp), settings.handTrackerForward, settings.handTrackerUp, ik.solver.rightArm.wristToPalmAxis, rightHandUp); ik.solver.rightArm.target = rightHandAdjusterTransform; } else { ik.solver.rightArm.positionWeight = 0f; ik.solver.rightArm.rotationWeight = 0f; } // Legs if (LeftFootTransform != null) { CalibrateLeg(settings, LeftFootTransform, ik.solver.leftLeg, (ik.references.leftToes != null ? ik.references.leftToes : ik.references.leftFoot), hmdForwardAngle, ik.references.root.forward, true); } if (RightFootTransform != null) { CalibrateLeg(settings, RightFootTransform, ik.solver.rightLeg, (ik.references.rightToes != null ? ik.references.rightToes : ik.references.rightFoot), hmdForwardAngle, ik.references.root.forward, false); } // Root controller bool addRootController = PelvisTransform != null || (LeftFootTransform != null && RightFootTransform != null); var rootController = ik.references.root.GetComponent <VRIKRootController>(); if (addRootController) { if (rootController == null) { rootController = ik.references.root.gameObject.AddComponent <VRIKRootController>(); } rootController.pelvisTarget = ik.solver.spine.pelvisTarget; rootController.leftFootTarget = ik.solver.leftLeg.target; rootController.rightFootTarget = ik.solver.rightLeg.target; rootController.Calibrate(); } else { if (rootController != null) { GameObject.Destroy(rootController); } } // Additional solver settings ik.solver.spine.minHeadHeight = 0f; ik.solver.locomotion.weight = PelvisTransform == null && LeftFootTransform == null && RightFootTransform == null ? 1f : 0f; }
public static IEnumerator CalibrateScaled(Transform handTrackerRoot, Transform headTrackerRoot, Transform footTrackerRoot, VRIK ik, Settings settings, Transform HMDTransform, Transform PelvisTransform = null, Transform LeftHandTransform = null, Transform RightHandTransform = null, Transform LeftFootTransform = null, Transform RightFootTransform = null) { if (!ik.solver.initiated) { Debug.LogError("Can not calibrate before VRIK has initiated."); yield break; } if (HMDTransform == null) { Debug.LogError("Can not calibrate VRIK without the head tracker."); yield break; } //トラッカーのルートスケールを初期値に戻す handTrackerRoot.localScale = new Vector3(1.0f, 1.0f, 1.0f); headTrackerRoot.localScale = new Vector3(1.0f, 1.0f, 1.0f); footTrackerRoot.localScale = new Vector3(1.0f, 1.0f, 1.0f); // モデルのポジションを手と手の中心位置に移動 var centerposition = Vector3.Lerp(LeftHandTransform.position, RightHandTransform.position, 0.5f); ik.references.root.position = new Vector3(centerposition.x, ik.references.root.position.y, centerposition.z); Vector3 hmdForwardAngle = HMDTransform.rotation * settings.headTrackerForward; hmdForwardAngle.y = 0f; ik.references.root.rotation = Quaternion.LookRotation(hmdForwardAngle); yield return(new WaitForEndOfFrame()); //モデルを手の高さで比較してスケールアップさせる //なるべく現実の身長に近づけて現実のコントローラー座標とのずれをなくす //ずれが大きいとexternalcamera.cfgとの合成時に手がずれすぎておかしくなる var modelHandHeight = (ik.references.leftHand.position.y + ik.references.rightHand.position.y) / 2f; var realHandHeight = (LeftHandTransform.position.y + RightHandTransform.position.y) / 2f; var hscale = realHandHeight / modelHandHeight; ik.references.root.localScale = new Vector3(hscale, hscale, hscale); // 手のトラッカー全体のスケールを手の位置に合わせる var modelHandDistance = Vector3.Distance(ik.references.leftHand.position, ik.references.rightHand.position); var realHandDistance = Vector3.Distance(LeftHandTransform.position, RightHandTransform.position); var wscale = modelHandDistance / realHandDistance; modelHandHeight = (ik.references.leftHand.position.y + ik.references.rightHand.position.y) / 2f; realHandHeight = (LeftHandTransform.position.y + RightHandTransform.position.y) / 2f; hscale = modelHandHeight / realHandHeight; handTrackerRoot.localScale = new Vector3(wscale, hscale, wscale); // モデルのポジションを再度手と手の中心位置に移動 centerposition = Vector3.Lerp(LeftHandTransform.position, RightHandTransform.position, 0.5f); ik.references.root.position = new Vector3(centerposition.x, ik.references.root.position.y, centerposition.z); hmdForwardAngle = HMDTransform.rotation * settings.headTrackerForward; hmdForwardAngle.y = 0f; ik.references.root.rotation = Quaternion.LookRotation(hmdForwardAngle); // 頭のトラッカー全体のスケールを頭の位置に合わせる var modelHeadHeight = ik.references.head.position.y; var realHeadHeight = HMDTransform.position.y; var headHscale = modelHeadHeight / realHeadHeight; headTrackerRoot.localScale = new Vector3(wscale, hscale, wscale); // 腰のトラッカー全体のスケールを腰の位置に合わせる if (PelvisTransform != null) { var modelPelvisHeight = ik.references.pelvis.position.y; var realPelvisHeight = PelvisTransform.position.y; var pelvisHscale = modelPelvisHeight / realPelvisHeight; footTrackerRoot.localScale = new Vector3(wscale, pelvisHscale, wscale); } yield return(new WaitForEndOfFrame()); //yield break; // Head Transform hmdAdjusterTransform = ik.solver.spine.headTarget == null ? (new GameObject("hmdAdjuster")).transform : ik.solver.spine.headTarget; hmdAdjusterTransform.parent = HMDTransform; hmdAdjusterTransform.position = ik.references.head.position; //HMDTransform.position + HMDTransform.rotation * Quaternion.LookRotation(settings.headTrackerForward, settings.headTrackerUp) * settings.headOffset; //hmdAdjusterTransform.localPosition = new Vector3(0, hmdAdjusterTransform.localPosition.y, -0.15f); hmdAdjusterTransform.rotation = ik.references.head.rotation; ik.solver.spine.headTarget = hmdAdjusterTransform; ik.solver.spine.headClampWeight = 0.38f; // Body if (PelvisTransform != null) { Transform pelvisAdjusterTransform = ik.solver.spine.pelvisTarget == null ? (new GameObject("pelvisAdjuster")).transform : ik.solver.spine.pelvisTarget; pelvisAdjusterTransform.parent = PelvisTransform; pelvisAdjusterTransform.position = ik.references.pelvis.position; pelvisAdjusterTransform.rotation = ik.references.pelvis.rotation; ik.solver.spine.pelvisTarget = pelvisAdjusterTransform; ik.solver.spine.pelvisPositionWeight = 1f; ik.solver.spine.pelvisRotationWeight = 1f; ik.solver.plantFeet = false; ik.solver.spine.neckStiffness = 0f; ik.solver.spine.maxRootAngle = 180f; } else if (LeftFootTransform != null && RightFootTransform != null) { ik.solver.spine.maxRootAngle = 0f; } // Left Hand if (LeftHandTransform != null) { Transform leftHandAdjusterTransform = ik.solver.leftArm.target == null ? (new GameObject("leftHandAdjuster")).transform : ik.solver.leftArm.target; leftHandAdjusterTransform.parent = LeftHandTransform; leftHandAdjusterTransform.position = LeftHandTransform.position + LeftHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp) * settings.handOffset; Vector3 leftHandUp = Vector3.Cross(ik.solver.leftArm.wristToPalmAxis, ik.solver.leftArm.palmToThumbAxis); leftHandAdjusterTransform.rotation = QuaTools.MatchRotation(LeftHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp), settings.handTrackerForward, settings.handTrackerUp, ik.solver.leftArm.wristToPalmAxis, leftHandUp); ik.solver.leftArm.target = leftHandAdjusterTransform; } else { ik.solver.leftArm.positionWeight = 0f; ik.solver.leftArm.rotationWeight = 0f; } // Right Hand if (RightHandTransform != null) { Transform rightHandAdjusterTransform = ik.solver.rightArm.target == null ? (new GameObject("rightHandAdjuster")).transform : ik.solver.rightArm.target; rightHandAdjusterTransform.parent = RightHandTransform; rightHandAdjusterTransform.position = RightHandTransform.position + RightHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp) * settings.handOffset; Vector3 rightHandUp = -Vector3.Cross(ik.solver.rightArm.wristToPalmAxis, ik.solver.rightArm.palmToThumbAxis); rightHandAdjusterTransform.rotation = QuaTools.MatchRotation(RightHandTransform.rotation * Quaternion.LookRotation(settings.handTrackerForward, settings.handTrackerUp), settings.handTrackerForward, settings.handTrackerUp, ik.solver.rightArm.wristToPalmAxis, rightHandUp); ik.solver.rightArm.target = rightHandAdjusterTransform; } else { ik.solver.rightArm.positionWeight = 0f; ik.solver.rightArm.rotationWeight = 0f; } // Legs if (LeftFootTransform != null) { CalibrateLeg(settings, LeftFootTransform, ik.solver.leftLeg, (ik.references.leftToes != null ? ik.references.leftToes : ik.references.leftFoot), ik.references.root.forward, true); } if (RightFootTransform != null) { CalibrateLeg(settings, RightFootTransform, ik.solver.rightLeg, (ik.references.rightToes != null ? ik.references.rightToes : ik.references.rightFoot), ik.references.root.forward, false); } // Root controller bool addRootController = PelvisTransform != null || (LeftFootTransform != null && RightFootTransform != null); var rootController = ik.references.root.GetComponent <VRIKRootController>(); if (addRootController) { if (rootController == null) { rootController = ik.references.root.gameObject.AddComponent <VRIKRootController>(); } rootController.pelvisTarget = ik.solver.spine.pelvisTarget; rootController.leftFootTarget = ik.solver.leftLeg.target; rootController.rightFootTarget = ik.solver.rightLeg.target; rootController.Calibrate(); } else { if (rootController != null) { GameObject.Destroy(rootController); } } // Additional solver settings ik.solver.spine.minHeadHeight = 0f; ik.solver.locomotion.weight = PelvisTransform == null && LeftFootTransform == null && RightFootTransform == null ? 1f : 0f; }