Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using UnityEditor;
using UnityEngine;

Expand Down Expand Up @@ -149,7 +150,7 @@ bool ShowSpringInfo()
return false;
}

var (spring, i) = found.Value;
var (spring, i, _) = found.Value;
m_showJoints = EditorGUILayout.Foldout(m_showJoints, $"Springs[{i}]({spring.Name})");
int? jointIndex = default;
// joints
Expand Down Expand Up @@ -192,27 +193,219 @@ bool ShowSpringInfo()
return jointIndex == (spring.Joints.Count - 1);
}

/// <summary>
/// (0,1,0)
/// ^ /
/// |/
/// +-->
/// 初期姿勢(T-Pose)の tail position が 0,1,0 になるように
/// joint local 空間を補正した空間である。回転 offset として angleLimitRotation(default は identity) も乗算する。
/// </summary>
/// <returns></returns>
static Quaternion calcSpringboneLimitSpace(Quaternion head, Vector3 boneAxis)
{
var jointLocalAxisSpace = Quaternion.FromToRotation(Vector3.up, boneAxis);
return head * jointLocalAxisSpace;
}

bool HandleLimitRotation(Matrix4x4 limitSpace)
{
Handles.matrix = limitSpace;
EditorGUI.BeginChangeCheck();
Quaternion rot = Handles.RotationHandle(m_target.m_angleLimitRotation, Vector3.zero);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "m_angleLimitRotation");
m_target.m_angleLimitRotation = rot;
return true;
}
else
{
return false;
}
}

static void DrawChain(Vrm10InstanceSpringBone.Spring spring)
{
Handles.color = Color.yellow;
var head = spring.Joints[0];
for (int i = 1; i < spring.Joints.Count; ++i)
{
var tail = spring.Joints[i];
if (head != null && tail != null)
{
Handles.DrawLine(head.transform.position, tail.transform.position);
}
head = tail;
}
}

void OnSceneGUI()
{
if (m_root == null)
{
return;
}

// joint(m_target) から、所属する spring を検索する。
var found = m_root.SpringBone.FindJoint(m_target);
if (!found.HasValue)
{
return;
}
// 所属 spring と joint(m_target) の index を得る
var (spring, i, j) = found.Value;

var head = spring.Joints[j].transform;
var label = string.IsNullOrEmpty(spring.Name)
? $"[{i}][{j}]{m_target.name}"
: $"[{i}]{spring.Name}[{j}]{m_target.name}";
Handles.Label(head.transform.position, label);
DrawChain(spring);

var (spring, i) = found.Value;
if (spring.Joints.Count > 0 && spring.Joints[0] != null)
if (j + 1 < spring.Joints.Count)
{
var label = $"Springs[{i}]";
if (!string.IsNullOrEmpty(spring.Name))
var _tail = spring.Joints[j + 1];
if (_tail != null)
{
label = spring.Name;
var tail = _tail.transform;
var local_axis = head.worldToLocalMatrix.MultiplyPoint(tail.position);
var limit_tail_pos = Vector3.up * local_axis.magnitude;
var limitRotation = calcSpringboneLimitSpace(head.rotation, local_axis);

if (m_target.m_anglelimitType == UniGLTF.SpringBoneJobs.AnglelimitTypes.None)
{
Tools.hidden = false;
}
else
{
Tools.hidden = true;
if (HandleLimitRotation(Matrix4x4.TRS(head.position, limitRotation, Vector3.one)))
{
if (Application.isPlaying)
{
if (m_root != null)
{
m_root.Runtime.SpringBone.SetJointLevel(m_target.transform, m_target.Blittable);
}
}
}
}

limitRotation = limitRotation * m_target.m_angleLimitRotation;

var limitSpace = Matrix4x4.TRS(head.position, limitRotation, Vector3.one);
Handles.matrix = limitSpace;
Handles.color = Color.red;
Handles.DrawLine(Vector3.zero, Vector3.right * limit_tail_pos.magnitude);
Handles.color = Color.green;
Handles.DrawLine(Vector3.zero, Vector3.up * limit_tail_pos.magnitude);

switch (m_target.m_anglelimitType)
{
case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone:
{
var s = Mathf.Sin(m_target.m_angleLimitAngle1 * 0.5f);
var c = Mathf.Cos(m_target.m_angleLimitAngle1 * 0.5f);

Handles.color = Color.cyan;
var r = Mathf.Tan(m_target.m_angleLimitAngle1 * 0.5f) * limit_tail_pos.magnitude * c;
Handles.DrawWireDisc(limit_tail_pos * c, Vector3.up, r, 1);
// o head
// r /
// |/
// -r --+-- r
// |
// -r
Handles.DrawLine(Vector3.zero, new Vector3(0, c, s) * limit_tail_pos.magnitude);
Handles.DrawLine(Vector3.zero, new Vector3(0, c, -s) * limit_tail_pos.magnitude);
Handles.DrawLine(Vector3.zero, new Vector3(s, c, 0) * limit_tail_pos.magnitude);
Handles.DrawLine(Vector3.zero, new Vector3(-s, c, 0) * limit_tail_pos.magnitude);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

少しネストが深く可読性に改善の余地があるかも。
DrawConeGizmo() 関数などの粒度で別クラスに切り分けてあげることができそう

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DrawConeGizmo() の引数のデザインに関してなんか良い案ありますか。
たぶん再利用されないと思うのだけど。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

再利用するかどうかはともかく、「再利用性の高い」コードスニペットにはなりそうです

break;
}

case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge:
{
var s = Mathf.Sin(m_target.m_angleLimitAngle1 * 0.5f);
var c = Mathf.Cos(m_target.m_angleLimitAngle1 * 0.5f);

Handles.color = Color.cyan;
Handles.DrawWireArc(Vector3.zero, Vector3.left,
new Vector3(0, c, s) * limit_tail_pos.magnitude,
m_target.m_angleLimitAngle1 * Mathf.Rad2Deg,
limit_tail_pos.magnitude
);
// yz plane
// o o head
// / \
// / \
// -r -+- r
//
Handles.DrawLine(Vector3.zero, new Vector3(0, c, s) * limit_tail_pos.magnitude);
Handles.DrawLine(Vector3.zero, new Vector3(0, c, -s) * limit_tail_pos.magnitude);
break;
}

case UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical:
{
Handles.color = Color.cyan;

var ts = Mathf.Sin(m_target.m_angleLimitAngle1 * 0.5f); // theta sin
var tc = Mathf.Cos(m_target.m_angleLimitAngle1 * 0.5f); // theta cos
var ps = Mathf.Sin(m_target.m_angleLimitAngle2 * 0.5f); // phi sin
var pc = Mathf.Cos(m_target.m_angleLimitAngle2 * 0.5f); // phi cos

// y = tc * pc
// ^ z = tc * ps
// |/
// +-> x = ts
var x = ts;
var y = tc * pc;
var z = tc * ps;

// z
// ^
// b|a
// -+->x
// c|d
var a = new Vector3(x, y, z);
var b = new Vector3(-x, y, z);
var c = new Vector3(-x, y, -z);
var d = new Vector3(x, y, -z);

Handles.DrawLine(Vector3.zero, a * limit_tail_pos.magnitude);
Handles.DrawLine(Vector3.zero, b * limit_tail_pos.magnitude);
Handles.DrawLine(Vector3.zero, c * limit_tail_pos.magnitude);
Handles.DrawLine(Vector3.zero, d * limit_tail_pos.magnitude);

// ab / cd
Handles.DrawWireArc(Vector3.zero, Vector3.Cross(a, b).normalized,
a * limit_tail_pos.magnitude,
m_target.m_angleLimitAngle1 * Mathf.Rad2Deg,
limit_tail_pos.magnitude
);
Handles.DrawWireArc(Vector3.zero, Vector3.Cross(c, d).normalized,
c * limit_tail_pos.magnitude,
m_target.m_angleLimitAngle1 * Mathf.Rad2Deg,
limit_tail_pos.magnitude
);

// bc / da
Handles.DrawWireArc(Vector3.zero, Vector3.Cross(b, c).normalized,
b * limit_tail_pos.magnitude,
Vector3.Angle(b, c),
limit_tail_pos.magnitude
);
Handles.DrawWireArc(Vector3.zero, Vector3.Cross(d, a).normalized,
d * limit_tail_pos.magnitude,
Vector3.Angle(d, a),
limit_tail_pos.magnitude
);

break;
}
}
}
Handles.Label(spring.Joints[0].transform.position, label);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,14 @@ public void DrawGizmos()
[SerializeField]
public List<Spring> Springs = new List<Spring>();

public (Spring, int)? FindJoint(VRM10SpringBoneJoint joint)
public (Spring spring, int springIndex, int jointIndex)? FindJoint(VRM10SpringBoneJoint joint)
{
for (int i = 0; i < Springs.Count; ++i)
{
if (Springs[i].Joints.Contains(joint))
var j = Springs[i].Joints.IndexOf(joint);
if (j >= 0)
{
return (Springs[i], i);
return new(Springs[i], i, j);
}
}
return default;
Expand Down