Files
Main/Assets/Plugins/ExternalLibs/BoneCloth/SpringBone.cs

168 lines
5.0 KiB
C#
Raw Normal View History

2025-01-25 04:38:09 +08:00
using UnityEngine;
using System.Collections;
namespace UnityChan
{
public class SpringBone : MonoBehaviour
{
//次のボーン
public Transform child;
//ボーンの向き
public Vector3 boneAxis = new Vector3 (-1.0f, 0.0f, 0.0f);
private float _defaultRadius = 0;
public float radius = 0.05f;
public float scale = 1f;
//各SpringBoneに設定されているstiffnessForceとdragForceを使用するか
public bool isUseEachBoneForceSettings = false;
//バネが戻る力
public float stiffnessForce = 0.01f;
//力の減衰力
public float dragForce = 0.4f;
public Vector3 springForce = new Vector3 (0.0f, -0.0001f, 0.0f);
public SpringCollider[] colliders;
public bool debug = true;
//Kobayashi:Thredshold Starting to activate activeRatio
public float threshold = 0.01f;
private float springLength;
private Quaternion localRotation;
private Transform trs;
private Vector3 currTipPos;
private Vector3 prevTipPos;
//Kobayashi
private Transform org;
//Kobayashi:Reference for "SpringManager" component with unitychan
private SpringManager managerRef;
private void Awake ()
{
trs = transform;
localRotation = transform.localRotation;
//Kobayashi:Reference for "SpringManager" component with unitychan
// GameObject.Find("unitychan_dynamic").GetComponent<SpringManager>();
managerRef = GetParentSpringManager (transform);
}
private SpringManager GetParentSpringManager (Transform t)
{
var springManager = t.GetComponent<SpringManager> ();
if (springManager != null)
return springManager;
if (t.parent != null) {
return GetParentSpringManager (t.parent);
}
return null;
}
private void Start ()
{
springLength = Vector3.Distance (trs.position, child.position);
currTipPos = child.position;
prevTipPos = child.position;
}
public void UpdateSpring ()
{
//Kobayashi
org = trs;
//回転をリセット
trs.localRotation = Quaternion.identity * localRotation;
float sqrDt = Time.deltaTime * Time.deltaTime;
//stiffness
Vector3 force = trs.rotation * (boneAxis * stiffnessForce) / sqrDt;
//drag
//Log("force x = {0}, y = {1} z = {2}", force);
//Log("prevTipPos x = {0}, y = {1} z = {2}", prevTipPos);
//Log("currTipPos x = {0}, y = {1} z = {2}", currTipPos);
force += (prevTipPos - currTipPos)* 2.3f / managerRef.transform.lossyScale.x * dragForce / sqrDt;
force += springForce / sqrDt;
//Log("force x = {0}, y = {1} z = {2}", force);
//前フレームと値が同じにならないように
Vector3 temp = currTipPos;
//verlet
currTipPos = (currTipPos - prevTipPos) + currTipPos + (force * sqrDt);
//長さを元に戻す
currTipPos = ((currTipPos - trs.position).normalized * springLength) + trs.position;
//衝突判定
for (int i = 0; i < colliders.Length; i++) {
float dis = Vector3.Distance(currTipPos, colliders[i].transform.position);
float radiusDis = radius + colliders[i].radius;
if (dis <= radiusDis) {
Vector3 normal = (currTipPos - colliders [i].transform.position).normalized;
currTipPos = colliders [i].transform.position + (normal * (radius + colliders [i].radius));
currTipPos = ((currTipPos - trs.position).normalized * springLength) + trs.position;
}
}
prevTipPos = temp;
//回転を適用;
Vector3 aimVector = trs.TransformDirection (boneAxis);
Quaternion aimRotation = Quaternion.FromToRotation (aimVector, currTipPos - trs.position);
//original
//trs.rotation = aimRotation * trs.rotation;
//Kobayahsi:Lerp with mixWeight
Quaternion secondaryRotation = aimRotation * trs.rotation;
trs.rotation = Quaternion.Lerp (org.rotation, secondaryRotation, managerRef.dynamicRatio);
}
private void Log(string str, Vector3 vect)
{
if (trs.name == "Bone003" && prevTipPos != currTipPos)
{
UnityEngine.Debug.LogError(string.Format(str, vect.x, vect.y, vect.z));
//UnityEngine.Debug.LogError(string.Format("dragForce = {0} stiness = {1}", dragForce, stiffnessForce));
}
}
public void SetRedius()
{
scale = 1;
if (_defaultRadius == 0)
{
_defaultRadius = radius;
}
else
{
radius = _defaultRadius;
}
if (transform.parent)
{
SetScale(transform.parent);
}
radius = scale * radius;
}
private void SetScale(Transform trans)
{
scale *= trans.localScale.x;
if (trans.parent)
{
SetScale(trans.parent);
}
}
private void OnDrawGizmos ()
{
currTipPos = child.position;
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(currTipPos, radius);
}
}
}