71 lines
4.5 KiB
C#
71 lines
4.5 KiB
C#
|
|
// WL838_BowRelease.cs — 활 클립(.anim 또는 FBX)에서 「시위를 놓는 순간」을 수치로 찾는다 (에디트 모드 · 프리뷰 씬)
|
||
|
|
// run_script --file AgentScripts/WL838_BowRelease.cs --entry WL838_BowRelease.Run --args '["Assets/WL/Combat/Anim/FR/FR_Bow0.anim", ""]'
|
||
|
|
// 프레임(30 fps)마다 양손 거리(당김) · 오른손 속도 · 왼손(활팔) 앞 뻗음을 찍는다. 당김이 최대인 뒤 양손 거리가 급감하는 프레임 = 발사(Projectile) 후보.
|
||
|
|
using System.Linq;
|
||
|
|
using System.Text;
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEditor.SceneManagement;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
public static class WL838_BowRelease
|
||
|
|
{
|
||
|
|
public static string Run(string src, string clipName)
|
||
|
|
{
|
||
|
|
string pcName = WL.Character.WLCharacterSwapSettings.Resolve("Ai01");
|
||
|
|
var model = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Res_Addr/PC/" + pcName + ".prefab");
|
||
|
|
if (model == null) return "PC 프리팹 없음";
|
||
|
|
AnimationClip clip;
|
||
|
|
if (src.EndsWith(".anim")) clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(src);
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var clips = AssetDatabase.LoadAllAssetsAtPath(src).OfType<AnimationClip>().Where(c => !c.name.StartsWith("__preview")).ToArray();
|
||
|
|
clip = string.IsNullOrEmpty(clipName) ? clips.FirstOrDefault() : (clips.FirstOrDefault(c => c.name == clipName) ?? clips.FirstOrDefault(c => c.name.Contains(clipName)));
|
||
|
|
}
|
||
|
|
if (clip == null) return "클립 없음 " + src;
|
||
|
|
var scene = EditorSceneManager.NewPreviewScene();
|
||
|
|
bool animMode = false;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var go = (GameObject)PrefabUtility.InstantiatePrefab(model, scene);
|
||
|
|
go.transform.position = Vector3.zero; go.transform.rotation = Quaternion.identity;
|
||
|
|
var anim = go.GetComponentInChildren<Animator>();
|
||
|
|
if (anim == null) return "Animator 없음";
|
||
|
|
AnimationMode.StartAnimationMode(); animMode = true;
|
||
|
|
var sb = new StringBuilder();
|
||
|
|
sb.Append("clip=").Append(clip.name).Append(" len=").Append(clip.length.ToString("0.000")).Append("s human=").Append(clip.isHumanMotion).Append('\n');
|
||
|
|
sb.Append("f t norm handDist rHandSpd lHandFwd rHandFwd rHandUp\n");
|
||
|
|
int frames = Mathf.Max(2, Mathf.RoundToInt(clip.length * 30f));
|
||
|
|
Vector3 prevR = Vector3.zero; float maxDist = 0f; int maxF = -1;
|
||
|
|
var rows = new System.Collections.Generic.List<string>();
|
||
|
|
var dists = new float[frames + 1];
|
||
|
|
for (int f = 0; f <= frames; f++)
|
||
|
|
{
|
||
|
|
float t = Mathf.Min(f / 30f, clip.length);
|
||
|
|
AnimationMode.BeginSampling(); AnimationMode.SampleAnimationClip(anim.gameObject, clip, t); AnimationMode.EndSampling();
|
||
|
|
var lh = anim.GetBoneTransform(HumanBodyBones.LeftHand); var rh = anim.GetBoneTransform(HumanBodyBones.RightHand); var hips = anim.GetBoneTransform(HumanBodyBones.Hips);
|
||
|
|
if (lh == null || rh == null || hips == null) return "손/힙 본 없음";
|
||
|
|
Vector3 fwd = go.transform.forward, up = Vector3.up;
|
||
|
|
float d = Vector3.Distance(lh.position, rh.position);
|
||
|
|
dists[f] = d;
|
||
|
|
float spd = f == 0 ? 0f : Vector3.Distance(rh.position, prevR) * 30f;
|
||
|
|
prevR = rh.position;
|
||
|
|
if (d > maxDist) { maxDist = d; maxF = f; }
|
||
|
|
rows.Add(string.Format("{0,-3} {1,5:0.000} {2,5:0.00} {3,8:0.000} {4,9:0.00} {5,9:0.000} {6,9:0.000} {7,8:0.000}", f, t, t / clip.length, d, spd,
|
||
|
|
Vector3.Dot(lh.position - hips.position, fwd), Vector3.Dot(rh.position - hips.position, fwd), Vector3.Dot(rh.position - hips.position, up)));
|
||
|
|
}
|
||
|
|
foreach (var r in rows) sb.Append(r).Append('\n');
|
||
|
|
// 발사 후보 = 최대 당김 이후 양손 거리가 최대의 85% 아래로 처음 떨어지는 프레임
|
||
|
|
int rel = -1;
|
||
|
|
for (int f = maxF + 1; f <= frames; f++) if (dists[f] < maxDist * 0.85f) { rel = f; break; }
|
||
|
|
sb.Append("maxDraw f").Append(maxF).Append(" (norm ").Append((maxF / 30f / clip.length).ToString("0.00")).Append(") dist ").Append(maxDist.ToString("0.000"))
|
||
|
|
.Append(" · release candidate f").Append(rel).Append(rel >= 0 ? " (norm " + (rel / 30f / clip.length).ToString("0.00") + ")" : "");
|
||
|
|
return sb.ToString();
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
if (animMode) AnimationMode.StopAnimationMode();
|
||
|
|
EditorSceneManager.ClosePreviewScene(scene);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|