diff --git a/HarmonySrc/CinerariumGenie.cs b/HarmonySrc/CinerariumGenie.cs index e4c428d..490b750 100644 --- a/HarmonySrc/CinerariumGenie.cs +++ b/HarmonySrc/CinerariumGenie.cs @@ -51,14 +51,16 @@ namespace NecromancerTome } /// Руки (16.10: «Т-поза бесит»): плечо от вертикали вбок и вперёд, локоть согнут вперёд, градусы. /// Модель в позе покоя, аниматора нет - кости ставятся один раз при появлении. - public static float ArmOut = 12f; - public static float ArmFwd = 15f; - public static float Elbow = 35f; - /// Покой (17.10: «в покое руки нужно скрестить на груди»): плечо вниз-вперёд на CrossFwd, предплечье поперёк - /// груди к другому боку, одно на CrossLift выше другого, чтобы не проходили друг сквозь друга. Жест - из этой позы и назад. - public static bool Cross = true; + public static float ArmOut = 3f; // 17.10 в игре: «По стойке смирно» - руки прямо вдоль тела (necrogenie arms 3 0 0) + public static float ArmFwd = 0f; + public static float Elbow = 0f; + /// Покой - поза покойника (17.10): плечо вниз-вперёд на CrossFwd, предплечье вверх наискось, кисть к плечу другой + /// стороны, вынесенному вперёд на CrossDepth ширины плеч; левая рука поверх правой - ещё на CrossLift. Жест - из этой позы + /// и назад. + public static bool Cross = false; // 17.10: пока поза покойника подбирается в Blender - резервная «смирно» (Arm*) public static float CrossFwd = 25f; - public static float CrossLift = 0.12f; + public static float CrossLift = 0.15f; + public static float CrossDepth = 0.3f; static GameObject _prefab; static bool _tried; @@ -154,8 +156,7 @@ namespace NecromancerTome m.EnableKeyword("_EMISSION"); m.globalIlluminationFlags = MaterialGlobalIlluminationFlags.None; } - m.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; - SetLook(m); + SetLook(m); // смешивание, глубина и очередь - тоже там (Solid) _ghostMats[_src] = m; return m; } @@ -165,12 +166,33 @@ namespace NecromancerTome /// Своё свечение тела, доля от Tint. public static float Glow = 0.35f; + /// ВРЕМЕННО (17.10: «Временно убери им прозрачность. А то плохо видно» - пока подбирается поза рук): дух + /// непрозрачный, обычная заливка с записью глубины. Перед релизом вернуть false (BACKLOG). Консоль: necrogenie solid 0|1. + public static bool Solid = true; + static void SetLook(Material _m) { if (_m == null) { return; } + _m.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); + _m.SetInt("_DstBlend", (int)(Solid ? UnityEngine.Rendering.BlendMode.Zero : UnityEngine.Rendering.BlendMode.One)); + _m.SetInt("_ZWrite", Solid ? 1 : 0); + _m.SetOverrideTag("RenderType", Solid ? "Opaque" : "Transparent"); + _m.renderQueue = (int)(Solid ? UnityEngine.Rendering.RenderQueue.Geometry : UnityEngine.Rendering.RenderQueue.Transparent); + if (Solid) + { + if (_m.HasProperty("_Color")) + { + _m.color = new Color(Tint.r, Tint.g, Tint.b, 1f); + } + if (_m.HasProperty("_EmissionColor")) + { + _m.SetColor("_EmissionColor", new Color(Tint.r * Glow * 0.5f, Tint.g * Glow * 0.5f, Tint.b * Glow * 0.5f, 1f)); + } + return; + } if (_m.HasProperty("_Color")) { _m.color = new Color(Tint.r * Alpha, Tint.g * Alpha, Tint.b * Alpha, 1f); @@ -309,6 +331,7 @@ namespace NecromancerTome } Debug.Log("[NecromancerTome] CinerariumGenie: кости рук " + sb); } + CloseFingers(); } for (int i = 0; i < _arm.Length; i++) { @@ -331,16 +354,71 @@ namespace NecromancerTome if (_cross > 0f) { float cf = CinerariumGenie.CrossFwd * Mathf.Deg2Rad; - Vector3 crossUp = new Vector3(sign * 0.12f, -Mathf.Cos(cf), Mathf.Sin(cf)).normalized; - Vector3 crossFore = new Vector3(-sign * 0.85f, side == 0 ? CinerariumGenie.CrossLift : -CinerariumGenie.CrossLift, 0.45f).normalized; - upDir = Vector3.Slerp(upDir, crossUp, _cross); - foreDir = Vector3.Slerp(foreDir, crossFore, _cross); + 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; } } + /// Пальцы (17.10: «Пальцы можешь не растопыривать?»): в модели они веером. Указательный, безымянный и мизинец + /// поворачиваются к направлению среднего на долю FingersTogether, большой - на треть её. Пальцы - дети кисти, позы рук их + /// не трогают, поэтому ставятся один раз. + public static float FingersTogether = 0.85f; + + void CloseFingers() + { + Transform[] all = GetComponentsInChildren(true); + Dictionary bones = new Dictionary(); + 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; + } + } + } + /// Светящиеся материалы рендереров - вернуть после почернения. readonly Dictionary _glowing = new Dictionary(); @@ -560,7 +638,8 @@ namespace NecromancerTome "necrogenie glow <0-1> - body's own glow (visible at night)\n" + "necrogenie tint - body colour\n" + "necrogenie arms - arm pose, degrees: upper arm from vertical sideways and forward, elbow bend\n" + - "necrogenie cross <0|1> [fwd] [lift] - arms crossed on the chest at rest (1) or hanging (0); upper arm forward, degrees; forearm height offset\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 solid <0|1> - TEMPORARY: opaque body (1) to see the pose, or the ghostly glow (0)\n" + "necrogenie sleep - 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"; } @@ -618,6 +697,10 @@ namespace NecromancerTome 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)) @@ -628,6 +711,10 @@ namespace NecromancerTome { 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(); diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index b476c0d..928d7c0 100644 Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ