Files
Fishing2/Assets/Scripts/Editor/Fix/CCDIKRodWeightEditor.cs
2026-04-01 23:38:21 +08:00

194 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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)
);
/// <summary>
/// 对当前选中物体上的 CCDIK 应用默认鱼竿权重
/// </summary>
[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<CCDIK>();
if (ccdik == null)
{
Debug.LogWarning($"选中的物体 [{go.name}] 上没有 CCDIK 组件。");
return;
}
ApplyWeights(ccdik, DefaultRodCurve, 0.05f, 1.0f, true);
}
/// <summary>
/// 稍微软一点的版本
/// </summary>
[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<CCDIK>();
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);
}
/// <summary>
/// 更硬的版本
/// </summary>
[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<CCDIK>();
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);
}
/// <summary>
/// 核心逻辑:
/// 第0个bone = 杆尾(高权重)
/// 最后一个bone = 竿稍(低权重)
/// </summary>
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<CCDIK>() != null;
}
}
#endif