void newMoveHead(ExternalValues externalValues, TBody tbody, ref Vector3 thatHeadEulerAngle, ref Vector3 thatHeadEulerAngleG, ref Vector3 thatEyeEulerAngle, Vector3 eyeTarget_world) { TBody that = tbody; Maid maid = tbody.maid; float paramSpeed = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.speed", 0.05f); float paramLateral = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.lateral", 60.0f); float paramAbove = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.above", 40.0f); float paramBelow = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.below", 20.0f); float paramBehind = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.behind", 170.0f); float paramOfsX = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.ofsx", 0.0f); float paramOfsY = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.ofsy", 0.0f); float paramOfsZ = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.ofsz", 0.0f); // モーションにしたがっている場合 (HeadToCamPer=0f) はオフセットをつけない paramOfsX *= that.HeadToCamPer; paramOfsY *= that.HeadToCamPer; paramOfsZ *= that.HeadToCamPer; Vector3 basePosition = that.trsNeck.position; Quaternion baseRotation = that.trsNeck.rotation; Vector3 target_local = Quaternion.Inverse(baseRotation) * (eyeTarget_world - basePosition); target_local = Quaternion.Euler(paramOfsX, 0f, paramOfsY) * target_local; Vector3 target_world = (baseRotation * target_local) + basePosition; // 顔が向くべき方向を算出 Quaternion newHeadRotation_world = CalcNewHeadRotation( paramLateral, paramAbove, paramBelow, paramBehind, baseRotation, basePosition, target_world); newHeadRotation_world = newHeadRotation_world * Quaternion.Euler(0f, paramOfsZ, 0f); // TBody.HeadToCamPer を「正面向き度合い」として加味する newHeadRotation_world = Quaternion.Slerp(that.trsHead.rotation, newHeadRotation_world, that.HeadToCamPer); float s = paramSpeed; // 前回の回転よりも差が大きすぎる場合はリセットする if (externalValues.bReset) { externalValues.bReset = false; externalValues.prevQuat = that.trsHead.rotation; s = 0f; } // モーションにしたがっている場合 (HeadToCamPer=0f) は補間しない s = Mathf.Lerp(1f, s, that.HeadToCamPer); // 実際の回転 that.trsHead.rotation = Quaternion.Slerp(externalValues.prevQuat, newHeadRotation_world, s); }
public void Callback(TBody tbody) { TBody that = tbody; if (that.trsHead == null) { return; } CameraMain mainCamera = GameMain.Instance.MainCamera; if (mainCamera == null) { return; } try { bool bParamHeadTrack = false; Maid maid = tbody.maid; if (maid != null) { bParamHeadTrack = ExSaveData.GetBool(maid, PluginName, "HEAD_TRACK", false); } Vector3 thatHeadEulerAngle = (Vector3)Helper.GetInstanceField(typeof(TBody), that, "HeadEulerAngle"); Vector3 thatHeadEulerAngleG = (Vector3)Helper.GetInstanceField(typeof(TBody), that, "HeadEulerAngleG"); Vector3 thatEyeEulerAngle = (Vector3)Helper.GetInstanceField(typeof(TBody), that, "EyeEulerAngle"); if (bParamHeadTrack) { ExternalValues externalValues = PluginHelper.GetOrAddComponent <ExternalValues>(tbody.gameObject); externalValues.tbody = tbody; newTbodyMoveHeadAndEyeCallback2(externalValues, tbody, ref thatHeadEulerAngle, ref thatHeadEulerAngleG, ref thatEyeEulerAngle); } else { originalTbodyMoveHeadAndEyeCallback2(tbody, ref thatHeadEulerAngle, ref thatHeadEulerAngleG, ref thatEyeEulerAngle); } Helper.SetInstanceField(typeof(TBody), that, "HeadEulerAngle", thatHeadEulerAngle); Helper.SetInstanceField(typeof(TBody), that, "HeadEulerAngleG", thatHeadEulerAngleG); Helper.SetInstanceField(typeof(TBody), that, "EyeEulerAngle", thatEyeEulerAngle); } catch (Exception ex) { Helper.ShowException(ex); } }
// 新しい MoveHeadAndEye void newTbodyMoveHeadAndEyeCallback2(ExternalValues externalValues, TBody tbody, ref Vector3 thatHeadEulerAngle, ref Vector3 thatHeadEulerAngleG, ref Vector3 thatEyeEulerAngle) { TBody that = tbody; Maid maid = tbody.maid; CameraMain mainCamera = GameMain.Instance.MainCamera; // eyeTarget_world:視線の目標位置(ワールド座標系) Vector3 eyeTarget_world = updateEyeTargetPos(tbody); // HeadToCamPer:最終的に顔がカメラを向く度合い // 0 なら元の頭の向き、1 ならカメラの向き if (that.boHeadToCam) { that.HeadToCamPer += Time.deltaTime * that.HeadToCamFadeSpeed; } else { that.HeadToCamPer -= Time.deltaTime * that.HeadToCamFadeSpeed; } that.HeadToCamPer = Mathf.Clamp01(that.HeadToCamPer); that.boChkEye = false; newMoveHead(externalValues, tbody, ref thatHeadEulerAngle, ref thatHeadEulerAngleG, ref thatEyeEulerAngle, eyeTarget_world); externalValues.prevQuat = that.trsHead.rotation; if (that.boMAN || that.trsEyeL == null || that.trsEyeR == null) { return; } that.boChkEye = false; { float paramEyeAng = ExSaveData.GetFloat(maid, PluginName, "EYE_ANG.angle", 0f); paramEyeAng = Mathf.Clamp(paramEyeAng, -180f, 180f); float paramSpeed = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.speed", 0.05f); float paramInside = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.inside", 60f); float paramOutside = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.outside", 60f); float paramAbove = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.above", 40f); float paramBelow = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.below", 20f); float paramBehind = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.behind", 170f); float paramOfsX = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.ofsx", 0f); float paramOfsY = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.ofsy", 0f); Vector3 targetPosition = eyeTarget_world; if (!that.boEyeToCam) { // 視線を正面に戻す eyeTarget_world = that.trsHead.TransformPoint(Vector3.up * 1000.0f); } { Transform trsEye = that.trsEyeL; Quaternion defQuat = that.quaDefEyeL * Quaternion.Euler(paramEyeAng, -paramOfsX, -paramOfsY); Quaternion prevQuat = externalValues.prevLeftEyeQuat; Transform trsParent = trsEye.parent; Quaternion newRotation_world = CalcNewEyeRotation( paramOutside, paramInside, paramBelow, paramAbove, paramBehind, trsParent.rotation, trsEye.position, eyeTarget_world ); Quaternion q = Quaternion.Inverse(trsParent.rotation) * newRotation_world; q = Quaternion.Slerp(Quaternion.identity, q, 0.2f); // 眼球モデルの中心に、眼球のトランスフォームの原点が無いため、ごまかしている q = Quaternion.Slerp(prevQuat, q, paramSpeed); prevQuat = q; trsEye.localRotation = q * defQuat; externalValues.prevLeftEyeQuat = prevQuat; } { Transform trsEye = that.trsEyeR; Quaternion defQuat = that.quaDefEyeR * Quaternion.Euler(-paramEyeAng, -paramOfsX, paramOfsY); Quaternion prevQuat = externalValues.prevRightEyeQuat; Transform trsParent = trsEye.parent; Quaternion newRotation_world = CalcNewEyeRotation( paramOutside, paramInside, paramAbove, paramBelow, paramBehind, trsParent.rotation, trsEye.position, eyeTarget_world ); Quaternion q = Quaternion.Inverse(trsParent.rotation) * newRotation_world; q = Quaternion.Slerp(Quaternion.identity, q, 0.2f); q = Quaternion.Slerp(prevQuat, q, paramSpeed); prevQuat = q; trsEye.localRotation = q * defQuat; externalValues.prevRightEyeQuat = prevQuat; } } }
void newMoveHead(ExternalValues externalValues, TBody tbody, ref Vector3 thatHeadEulerAngle, ref Vector3 thatHeadEulerAngleG, ref Vector3 thatEyeEulerAngle, Vector3 eyeTarget_world) { TBody that = tbody; Maid maid = tbody.maid; float paramSpeed = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.speed", 0.05f); float paramLateral = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.lateral", 60.0f); float paramAbove = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.above", 40.0f); float paramBelow = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.below", 20.0f); float paramBehind = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.behind", 170.0f); float paramOfsX = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.ofsx", 0.0f); float paramOfsY = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.ofsy", 0.0f); float paramOfsZ = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.ofsz", 0.0f); // 正面の角度 float frontangle = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.frontangle", 0f); Quaternion frontquaternion = Quaternion.Euler(0f, 0f, frontangle); // モーションにしたがっている場合 (HeadToCamPer=0f) はオフセットをつけない paramOfsX *= that.HeadToCamPer; paramOfsY *= that.HeadToCamPer; paramOfsZ *= that.HeadToCamPer; Vector3 basePosition = that.trsHead.position; Quaternion baseRotation = that.trsNeck.rotation * frontquaternion; Vector3 target_local = Quaternion.Inverse(baseRotation) * (eyeTarget_world - basePosition); //追従割合 Quaternion local_angle = Quaternion.FromToRotation(Vector3.up, target_local); Vector3 local_auler = local_angle.eulerAngles; float headrateup = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.headrateup", 1f); float headratedown = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.headratedown", 1f); float headratehorizon = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.headratehorizon", 1f); float dx = 0; float dy = 0; if (local_auler.x < 180f) { dx = local_auler.x * (headratehorizon - 1f); } else { dx = (local_auler.x - 360f) * (headratehorizon - 1f); } if (local_auler.z < 180f) { dy = local_auler.z * (headrateup - 1f); } else { dy = (local_auler.z - 360f) * (headratedown - 1f); } target_local = Quaternion.Euler(dx, 0f, dy) * target_local; target_local = Quaternion.Euler(paramOfsX, 0f, paramOfsY) * target_local; Vector3 target_world = (baseRotation * target_local) + basePosition; // 顔が向くべき方向を算出 Quaternion newHeadRotation_world = CalcNewHeadRotation( paramLateral, paramAbove, paramBelow, paramBehind, baseRotation, basePosition, target_world, eyeTarget_world); newHeadRotation_world = newHeadRotation_world * Quaternion.Euler(0f, paramOfsZ, 0f); // TBody.HeadToCamPer を「正面向き度合い」として加味する newHeadRotation_world = Quaternion.Slerp(that.trsHead.rotation, newHeadRotation_world, that.HeadToCamPer); // 角度 float inclinerate = ExSaveData.GetFloat(maid, PluginName, "HEAD_TRACK.inclinerate", 0f); Quaternion newHeadRotation_Local = Quaternion.Inverse(baseRotation) * newHeadRotation_world; Vector3 newHeadRotationEulerLocal = newHeadRotation_Local.eulerAngles; if (newHeadRotationEulerLocal.x > 180f) { newHeadRotationEulerLocal = new Vector3( newHeadRotationEulerLocal.x - 360f, newHeadRotationEulerLocal.y, newHeadRotationEulerLocal.z); } newHeadRotationEulerLocal = new Vector3( newHeadRotationEulerLocal.x, newHeadRotationEulerLocal.y + (newHeadRotationEulerLocal.x * inclinerate), newHeadRotationEulerLocal.z); newHeadRotation_Local = Quaternion.Euler(newHeadRotationEulerLocal); newHeadRotation_world = baseRotation * newHeadRotation_Local; float s = paramSpeed; // 前回の回転よりも差が大きすぎる場合はリセットする if (externalValues.bReset) { externalValues.bReset = false; externalValues.prevQuat = that.trsHead.rotation; s = 0f; } // モーションにしたがっている場合 (HeadToCamPer=0f) は補間しない s = Mathf.Lerp(1f, s, that.HeadToCamPer); // 実際の回転 that.trsHead.rotation = Quaternion.Slerp(externalValues.prevQuat, newHeadRotation_world, s); }
// 新しい MoveHeadAndEye void newTbodyMoveHeadAndEyeCallback2(ExternalValues externalValues, TBody tbody, ref Vector3 thatHeadEulerAngle, ref Vector3 thatHeadEulerAngleG, ref Vector3 thatEyeEulerAngle) { TBody that = tbody; Maid maid = tbody.maid; CameraMain mainCamera = GameMain.Instance.MainCamera; // eyeTarget_world:視線の目標位置(ワールド座標系) Vector3 eyeTarget_world = updateEyeTargetPos(tbody); // HeadToCamPer:最終的に顔がカメラを向く度合い // 0 なら元の頭の向き、1 ならカメラの向き if (that.boHeadToCam) { that.HeadToCamPer += Time.deltaTime * that.HeadToCamFadeSpeed; } else { that.HeadToCamPer -= Time.deltaTime * that.HeadToCamFadeSpeed; } that.HeadToCamPer = Mathf.Clamp01(that.HeadToCamPer); that.boChkEye = false; newMoveHead(externalValues, tbody, ref thatHeadEulerAngle, ref thatHeadEulerAngleG, ref thatEyeEulerAngle, eyeTarget_world); externalValues.prevQuat = that.trsHead.rotation; if (that.boMAN || that.trsEyeL == null || that.trsEyeR == null) { return; } that.boChkEye = false; if (that.boEyeToCam) { float paramEyeAng = ExSaveData.GetFloat(maid, PluginName, "EYE_ANG.angle", 0f); paramEyeAng = Mathf.Clamp(paramEyeAng, -180f, 180f); float paramSpeed = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.speed", 0.05f); float paramInside = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.inside", 60f); float paramOutside = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.outside", 60f); float paramAbove = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.above", 40f); float paramBelow = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.below", 20f); float paramBehind = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.behind", 170f); float paramOfsX = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.ofsx", 0f); float paramOfsY = ExSaveData.GetFloat(maid, PluginName, "EYE_TRACK.ofsy", 0f); Vector3 targetPosition = eyeTarget_world; { Transform trsEye = that.trsEyeL; Quaternion defQuat = that.quaDefEyeL * Quaternion.Euler(paramEyeAng, -paramOfsX, -paramOfsY); Quaternion prevQuat = externalValues.prevLeftEyeQuat; Transform trsParent = trsEye.parent; Quaternion newRotation_world = CalcNewEyeRotation( paramOutside, paramInside, paramBelow, paramAbove, paramBehind, trsParent.rotation, trsEye.position, eyeTarget_world ); Quaternion q = Quaternion.Inverse(trsParent.rotation) * newRotation_world; q = Quaternion.Slerp(Quaternion.identity, q, 0.2f); // 眼球モデルの中心に、眼球のトランスフォームの原点が無いため、ごまかしている q = Quaternion.Slerp(prevQuat, q, paramSpeed); prevQuat = q; trsEye.localRotation = q * defQuat; externalValues.prevLeftEyeQuat = prevQuat; } { Transform trsEye = that.trsEyeR; Quaternion defQuat = that.quaDefEyeR * Quaternion.Euler(-paramEyeAng, -paramOfsX, paramOfsY); Quaternion prevQuat = externalValues.prevRightEyeQuat; Transform trsParent = trsEye.parent; Quaternion newRotation_world = CalcNewEyeRotation( paramOutside, paramInside, paramAbove, paramBelow, paramBehind, trsParent.rotation, trsEye.position, eyeTarget_world ); Quaternion q = Quaternion.Inverse(trsParent.rotation) * newRotation_world; q = Quaternion.Slerp(Quaternion.identity, q, 0.2f); q = Quaternion.Slerp(prevQuat, q, paramSpeed); prevQuat = q; trsEye.localRotation = q * defQuat; externalValues.prevRightEyeQuat = prevQuat; } } }