Дух урны: смирно - поза покоя модели
Смирно (pose_attention.json) запечено в позу покоя при выгрузке FBX; там же новые кости пальцев, веса кисти и хребет. Код больше не ставит руки и пальцы в покое - жест уводит руки из позы модели и возвращает. Поза покойника (cross) и сведение пальцев кодом убраны. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f040ebdc62
commit
fcc8bd9d7d
+21
-117
@@ -51,18 +51,11 @@ namespace NecromancerTome
|
||||
}
|
||||
return (pl.GetPosition() - Origin.position - _scenePos).sqrMagnitude > SleepDistance * SleepDistance;
|
||||
}
|
||||
/// <summary>Руки (16.10: «Т-поза бесит»): плечо от вертикали вбок и вперёд, локоть согнут вперёд, градусы.
|
||||
/// Модель в позе покоя, аниматора нет - кости ставятся один раз при появлении.</summary>
|
||||
public static float ArmOut = 3f; // 17.10 в игре: «По стойке смирно» - руки прямо вдоль тела (necrogenie arms 3 0 0)
|
||||
public static float ArmFwd = 0f;
|
||||
/// <summary>Руки в жесте: плечо от вертикали вбок, локоть согнут вперёд, градусы. Покой - «смирно» (18.10: «Всё Смирно и
|
||||
/// будет позой для бездельничающих некротехов») запечён в позу покоя модели (pose_attention.json при выгрузке FBX),
|
||||
/// аниматора нет - без жеста кости не трогаются.</summary>
|
||||
public static float ArmOut = 3f;
|
||||
public static float Elbow = 0f;
|
||||
/// <summary>Покой - поза покойника (17.10): плечо вниз-вперёд на CrossFwd, предплечье вверх наискось, кисть к плечу другой
|
||||
/// стороны, вынесенному вперёд на CrossDepth ширины плеч; левая рука поверх правой - ещё на CrossLift. Жест - из этой позы
|
||||
/// и назад.</summary>
|
||||
public static bool Cross = false; // 17.10: пока поза покойника подбирается в Blender - резервная «смирно» (Arm*)
|
||||
public static float CrossFwd = 25f;
|
||||
public static float CrossLift = 0.15f;
|
||||
public static float CrossDepth = 0.3f;
|
||||
|
||||
static GameObject _prefab;
|
||||
static bool _tried;
|
||||
@@ -301,15 +294,15 @@ namespace NecromancerTome
|
||||
Quaternion[] _armRest;
|
||||
static bool _armLogged;
|
||||
|
||||
/// <summary>Опустить руки из позы покоя: направление плеча и предплечья задаётся в осях модели (вперёд - +Z),
|
||||
/// поворот - от текущего направления кости к нужному, так что оси самих костей значения не имеют.</summary>
|
||||
/// <summary>Покой - руки в позе модели («смирно»).</summary>
|
||||
public void Pose()
|
||||
{
|
||||
Pose(CinerariumGenie.ArmFwd, CinerariumGenie.Elbow, CinerariumGenie.Elbow, CinerariumGenie.Cross ? 1f : 0f);
|
||||
Pose(0f, CinerariumGenie.Elbow, CinerariumGenie.Elbow);
|
||||
}
|
||||
|
||||
/// <summary>_cross - доля скрещённой позы (1 - руки на груди, 0 - опущены/жест), направления смешиваются.</summary>
|
||||
void Pose(float _fwd, float _elbowL, float _elbowR, float _cross)
|
||||
/// <summary>Жест долей _w от покоя: плечо вперёд на GestureFwd, направление плеча и предплечья задаётся в осях модели
|
||||
/// (вперёд - +Z), поворот - от текущего направления кости к нужному, так что оси самих костей значения не имеют.</summary>
|
||||
void Pose(float _w, float _elbowL, float _elbowR)
|
||||
{
|
||||
if (_arm == null)
|
||||
{
|
||||
@@ -337,7 +330,6 @@ namespace NecromancerTome
|
||||
}
|
||||
Debug.Log("[NecromancerTome] CinerariumGenie: кости рук " + sb);
|
||||
}
|
||||
CloseFingers();
|
||||
}
|
||||
for (int i = 0; i < _arm.Length; i++)
|
||||
{
|
||||
@@ -346,6 +338,10 @@ namespace NecromancerTome
|
||||
_arm[i].localRotation = _armRest[i];
|
||||
}
|
||||
}
|
||||
if (_w <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int side = 0; side < 2; side++)
|
||||
{
|
||||
Transform up = _arm[side * 3], fore = _arm[side * 3 + 1], hand = _arm[side * 3 + 2];
|
||||
@@ -354,74 +350,11 @@ namespace NecromancerTome
|
||||
continue;
|
||||
}
|
||||
float sign = Mathf.Sign(transform.InverseTransformPoint(up.position).x);
|
||||
float o = CinerariumGenie.ArmOut * Mathf.Deg2Rad, f = _fwd * Mathf.Deg2Rad;
|
||||
float o = CinerariumGenie.ArmOut * Mathf.Deg2Rad, f = GestureFwd * Mathf.Deg2Rad;
|
||||
Vector3 upDir = new Vector3(sign * Mathf.Sin(o), -Mathf.Cos(o) * Mathf.Cos(f), Mathf.Sin(f)).normalized;
|
||||
Vector3 foreDir = Vector3.RotateTowards(upDir, Vector3.forward, (side == 0 ? _elbowL : _elbowR) * Mathf.Deg2Rad, 0f);
|
||||
if (_cross > 0f)
|
||||
{
|
||||
float cf = CinerariumGenie.CrossFwd * Mathf.Deg2Rad;
|
||||
upDir = Vector3.Slerp(upDir, new Vector3(0f, -Mathf.Cos(cf), Mathf.Sin(cf)), _cross).normalized;
|
||||
}
|
||||
up.rotation = Quaternion.FromToRotation(fore.position - up.position, transform.TransformDirection(upDir)) * up.rotation;
|
||||
Transform otherUp = _arm[(1 - side) * 3];
|
||||
if (_cross > 0f && otherUp != null)
|
||||
{
|
||||
// Кисть - к плечу другой стороны (17.10: «Ладонь правой руки прижимается к левому плечу. Левая рука идёт
|
||||
// поверх правой и прижимает ладонь к правому плечу»): цель - сустав другого плеча, вынесенный вперёд на
|
||||
// толщину груди; левая (side 0) - ещё на CrossLift вперёд, поверх правой. Доли - от ширины плеч.
|
||||
float width = Vector3.Distance(up.position, otherUp.position);
|
||||
Vector3 target = otherUp.position + transform.forward * width * (CinerariumGenie.CrossDepth + (side == 0 ? CinerariumGenie.CrossLift : 0f));
|
||||
Vector3 want = transform.InverseTransformDirection(target - fore.position).normalized;
|
||||
foreDir = Vector3.Slerp(foreDir, want, _cross).normalized;
|
||||
}
|
||||
fore.rotation = Quaternion.FromToRotation(hand.position - fore.position, transform.TransformDirection(foreDir)) * fore.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Пальцы (17.10: «Пальцы можешь не растопыривать?»): в модели они веером. Указательный, безымянный и мизинец
|
||||
/// поворачиваются к направлению среднего на долю FingersTogether, большой - на треть её. Пальцы - дети кисти, позы рук их
|
||||
/// не трогают, поэтому ставятся один раз.</summary>
|
||||
public static float FingersTogether = 0.85f;
|
||||
|
||||
void CloseFingers()
|
||||
{
|
||||
Transform[] all = GetComponentsInChildren<Transform>(true);
|
||||
Dictionary<string, Transform> bones = new Dictionary<string, Transform>();
|
||||
foreach (string side in new[] { "Left", "Right" })
|
||||
{
|
||||
foreach (string finger in new[] { "Index", "Middle", "Ring", "Pinky", "Thumb" })
|
||||
{
|
||||
for (int j = 1; j <= 2; j++)
|
||||
{
|
||||
string key = side + "Hand" + finger + j;
|
||||
foreach (Transform t in all)
|
||||
{
|
||||
if (t.name.EndsWith(key))
|
||||
{
|
||||
bones[key] = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (string side in new[] { "Left", "Right" })
|
||||
{
|
||||
if (!bones.TryGetValue(side + "HandMiddle1", out Transform m1) || !bones.TryGetValue(side + "HandMiddle2", out Transform m2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Vector3 mid = m2.position - m1.position;
|
||||
foreach (string finger in new[] { "Index", "Ring", "Pinky", "Thumb" })
|
||||
{
|
||||
if (!bones.TryGetValue(side + "Hand" + finger + "1", out Transform f1) || !bones.TryGetValue(side + "Hand" + finger + "2", out Transform f2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Vector3 cur = f2.position - f1.position;
|
||||
float k = finger == "Thumb" ? FingersTogether / 3f : FingersTogether;
|
||||
f1.rotation = Quaternion.FromToRotation(cur, Vector3.Slerp(cur, mid, k)) * f1.rotation;
|
||||
}
|
||||
up.rotation = Quaternion.Slerp(Quaternion.identity, Quaternion.FromToRotation(fore.position - up.position, transform.TransformDirection(upDir)), _w) * up.rotation;
|
||||
fore.rotation = Quaternion.Slerp(Quaternion.identity, Quaternion.FromToRotation(hand.position - fore.position, transform.TransformDirection(foreDir)), _w) * fore.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,9 +409,8 @@ namespace NecromancerTome
|
||||
{
|
||||
if (_w > 0f)
|
||||
{
|
||||
float wave = Mathf.Sin(_t * Mathf.PI * 2f * 1.5f) * GestureWave * _w;
|
||||
Pose(Mathf.Lerp(CinerariumGenie.ArmFwd, GestureFwd, _w), CinerariumGenie.Elbow + 15f * _w + wave, CinerariumGenie.Elbow + 15f * _w - wave,
|
||||
CinerariumGenie.Cross ? 1f - _w : 0f);
|
||||
float wave = Mathf.Sin(_t * Mathf.PI * 2f * 1.5f) * GestureWave;
|
||||
Pose(_w, CinerariumGenie.Elbow + 15f + wave, CinerariumGenie.Elbow + 15f - wave);
|
||||
_gesturing = true;
|
||||
}
|
||||
else if (_gesturing)
|
||||
@@ -643,8 +575,7 @@ namespace NecromancerTome
|
||||
"necrogenie alpha <0-1> - body brightness (the body adds light, it is not alpha-blended)\n" +
|
||||
"necrogenie glow <0-1> - body's own glow (visible at night)\n" +
|
||||
"necrogenie tint <r> <g> <b> - body colour\n" +
|
||||
"necrogenie arms <out> <fwd> <elbow> - arm pose, degrees: upper arm from vertical sideways and forward, elbow bend\n" +
|
||||
"necrogenie cross <0|1> [fwd] [lift] [depth] - rest pose: hands on the opposite shoulders, left over right (1) or hanging (0); upper arm forward, degrees; left forearm over the right and chest depth, shares of shoulder width\n" +
|
||||
"necrogenie arms <out> [elbow] - gesture arms, degrees: upper arm from vertical sideways, elbow bend (rest pose 'attention' is the model's own)\n" +
|
||||
"necrogenie solid <0|1> - TEMPORARY: opaque body (1) to see the pose, or the ghostly glow (0)\n" +
|
||||
"necrogenie sleep <m> - spirits and threads freeze when the player is farther (work goes on)\n" +
|
||||
"necrogenie hide|show - hide all spirits (weak PCs, video), work goes on";
|
||||
@@ -690,42 +621,15 @@ namespace NecromancerTome
|
||||
break;
|
||||
case "arms":
|
||||
CinerariumGenie.ArmOut = v;
|
||||
if (_params.Count >= 3 && float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float af))
|
||||
{
|
||||
CinerariumGenie.ArmFwd = af;
|
||||
}
|
||||
if (_params.Count >= 4 && float.TryParse(_params[3], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float ae))
|
||||
if (_params.Count >= 3 && float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float ae))
|
||||
{
|
||||
CinerariumGenie.Elbow = ae;
|
||||
}
|
||||
foreach (CinerariumGenieMotion m in CinerariumGenie.Live)
|
||||
{
|
||||
m.Pose();
|
||||
}
|
||||
break;
|
||||
case "solid":
|
||||
CinerariumGenie.Solid = v != 0f;
|
||||
CinerariumGenie.ApplyAlpha();
|
||||
break;
|
||||
case "cross":
|
||||
CinerariumGenie.Cross = v != 0f;
|
||||
if (_params.Count >= 3 && float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float cf))
|
||||
{
|
||||
CinerariumGenie.CrossFwd = cf;
|
||||
}
|
||||
if (_params.Count >= 4 && float.TryParse(_params[3], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float cl))
|
||||
{
|
||||
CinerariumGenie.CrossLift = cl;
|
||||
}
|
||||
if (_params.Count >= 5 && float.TryParse(_params[4], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float cd))
|
||||
{
|
||||
CinerariumGenie.CrossDepth = cd;
|
||||
}
|
||||
foreach (CinerariumGenieMotion m in CinerariumGenie.Live)
|
||||
{
|
||||
m.Pose();
|
||||
}
|
||||
break;
|
||||
case "tint":
|
||||
if (_params.Count >= 4 &&
|
||||
float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float g) &&
|
||||
@@ -744,7 +648,7 @@ namespace NecromancerTome
|
||||
", bob " + CinerariumGenie.BobHeight.ToString("F2") + " / " + CinerariumGenie.BobPeriod.ToString("F1") + " s, alpha " +
|
||||
CinerariumGenie.Alpha.ToString("F2") + ", glow " + CinerariumGenie.Glow.ToString("F2") + ", tint " +
|
||||
CinerariumGenie.Tint.r.ToString("F2") + " " + CinerariumGenie.Tint.g.ToString("F2") + " " + CinerariumGenie.Tint.b.ToString("F2") + ", arms " + CinerariumGenie.ArmOut.ToString("F0") + " " +
|
||||
CinerariumGenie.ArmFwd.ToString("F0") + " " + CinerariumGenie.Elbow.ToString("F0") + ", sleep " + CinerariumGenie.SleepDistance.ToString("F0") + " m" + (CinerariumGenie.Hidden ? ", HIDDEN" : "") + "; spirits on screen: " + CinerariumGenie.Live.Count);
|
||||
CinerariumGenie.Elbow.ToString("F0") + ", sleep " + CinerariumGenie.SleepDistance.ToString("F0") + " m" + (CinerariumGenie.Hidden ? ", HIDDEN" : "") + "; spirits on screen: " + CinerariumGenie.Live.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user