#if UNITY_EDITOR using UnityEditor; using UnityEngine; using RootMotion.FinalIK; public static class CCDIKRodWeightEditor { // 默认鱼竿权重曲线: // 根部硬,末端软 private static readonly AnimationCurve DefaultRodCurve = new AnimationCurve( new Keyframe(0.00f, 1.00f), new Keyframe(0.30f, 0.88f), new Keyframe(0.60f, 0.58f), new Keyframe(0.82f, 0.22f), new Keyframe(1.00f, 0.05f) ); /// /// 对当前选中物体上的 CCDIK 应用默认鱼竿权重 /// [MenuItem("Tools/FinalIK/CCDIK/Apply Rod Weights (Selected)")] public static void ApplyRodWeightsToSelected() { var go = Selection.activeGameObject; if (go == null) { Debug.LogWarning("没有选中任何 GameObject。"); return; } var ccdik = go.GetComponent(); if (ccdik == null) { Debug.LogWarning($"选中的物体 [{go.name}] 上没有 CCDIK 组件。"); return; } ApplyWeights(ccdik, DefaultRodCurve, 0.05f, 1.0f, true); } /// /// 稍微软一点的版本 /// [MenuItem("Tools/FinalIK/CCDIK/Apply Rod Weights Soft (Selected)")] public static void ApplyRodWeightsSoftToSelected() { var go = Selection.activeGameObject; if (go == null) { Debug.LogWarning("没有选中任何 GameObject。"); return; } var ccdik = go.GetComponent(); if (ccdik == null) { Debug.LogWarning($"选中的物体 [{go.name}] 上没有 CCDIK 组件。"); return; } var softCurve = new AnimationCurve( new Keyframe(0.00f, 1.00f), new Keyframe(0.25f, 0.92f), new Keyframe(0.50f, 0.72f), new Keyframe(0.75f, 0.35f), new Keyframe(1.00f, 0.10f) ); ApplyWeights(ccdik, softCurve, 0.10f, 1.0f, true); } /// /// 更硬的版本 /// [MenuItem("Tools/FinalIK/CCDIK/Apply Rod Weights Stiff (Selected)")] public static void ApplyRodWeightsStiffToSelected() { var go = Selection.activeGameObject; if (go == null) { Debug.LogWarning("没有选中任何 GameObject。"); return; } var ccdik = go.GetComponent(); if (ccdik == null) { Debug.LogWarning($"选中的物体 [{go.name}] 上没有 CCDIK 组件。"); return; } var stiffCurve = new AnimationCurve( new Keyframe(0.00f, 1.00f), new Keyframe(0.35f, 0.94f), new Keyframe(0.65f, 0.65f), new Keyframe(0.88f, 0.18f), new Keyframe(1.00f, 0.03f) ); ApplyWeights(ccdik, stiffCurve, 0.03f, 1.0f, true); } /// /// 核心逻辑: /// 第0个bone = 杆尾(高权重) /// 最后一个bone = 竿稍(低权重) /// public static void ApplyWeights(CCDIK ccdik, AnimationCurve curve, float minWeight, float maxWeight, bool logResult) { if (ccdik == null) { Debug.LogWarning("CCDIK 为空。"); return; } var solver = ccdik.solver; if (solver == null) { Debug.LogWarning("CCDIK.solver 为空。"); return; } if (solver.bones == null || solver.bones.Length == 0) { Debug.LogWarning($"[{ccdik.name}] 的 solver.bones 为空,请先正确配置 CCDIK Chain。"); return; } Undo.RecordObject(ccdik, "Apply CCDIK Rod Weights"); int count = solver.bones.Length; if (count == 1) { solver.bones[0].weight = maxWeight; EditorUtility.SetDirty(ccdik); Debug.Log($"[{ccdik.name}] 只有 1 根 bone,已设置 weight = {maxWeight:F3}"); return; } for (int i = 0; i < count; i++) { // 0 = 杆尾,1 = 竿稍 float t = 1f - (i / (float)(count - 1)); // 曲线前高后低 float curveValue = curve.Evaluate(t); // 限制范围 float weight = Mathf.Lerp(minWeight, maxWeight, curveValue); weight = Mathf.Clamp(weight, minWeight, maxWeight); solver.bones[i].weight = weight; } EditorUtility.SetDirty(ccdik); if (logResult) { Debug.Log(BuildWeightLog(ccdik)); } } private static string BuildWeightLog(CCDIK ccdik) { if (ccdik == null || ccdik.solver == null || ccdik.solver.bones == null) return "CCDIK 或 bones 无效。"; var bones = ccdik.solver.bones; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine($"[{ccdik.name}] CCDIK Rod Weights Applied"); sb.AppendLine($"Bone Count = {bones.Length}"); sb.AppendLine("Index 0 = 杆尾,Last = 竿稍"); sb.AppendLine("--------------------------------"); for (int i = 0; i < bones.Length; i++) { string boneName = bones[i].transform != null ? bones[i].transform.name : "NULL"; sb.AppendLine($"[{i}] {boneName} weight = {bones[i].weight:F3}"); } return sb.ToString(); } [MenuItem("Tools/FinalIK/CCDIK/Apply Rod Weights (Selected)", true)] [MenuItem("Tools/FinalIK/CCDIK/Apply Rod Weights Soft (Selected)", true)] [MenuItem("Tools/FinalIK/CCDIK/Apply Rod Weights Stiff (Selected)", true)] private static bool ValidateApplyRodWeights() { return Selection.activeGameObject != null && Selection.activeGameObject.GetComponent() != null; } } #endif