182 lines
5.8 KiB
C#
182 lines
5.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
using Thousandto.Core.Base;
|
|
using Thousandto.Core.Support;
|
|
|
|
/// <summary>
|
|
/// 骨骼布料化 -- 动作柔化
|
|
/// </summary>
|
|
public class BoneCloth : MonoBehaviour
|
|
{
|
|
public Transform m_srcRoot = null;
|
|
public Transform m_dstRoot = null;
|
|
public Particle[] m_particles = null;
|
|
|
|
//父改变
|
|
private bool m_parentChanged = false;
|
|
|
|
#region//重写MonoBehaviour方法
|
|
//每帧更新最后
|
|
private void LateUpdate()
|
|
{
|
|
if (m_parentChanged)
|
|
{
|
|
m_parentChanged = false;
|
|
ResetPose();
|
|
}
|
|
if (m_particles != null)
|
|
{
|
|
for (int i = 0; i < m_particles.Length; ++i)
|
|
{
|
|
var p = m_particles[i];
|
|
if (p.pfactor < 0.99f)
|
|
{
|
|
//根据参数进行位置插值计算
|
|
p.pos = Vector3.Lerp(p.pos, p.src.position, FixFactor(p.pfactor));
|
|
p.dst.position = p.pos;
|
|
var src_parent = p.src.parent;
|
|
var dst_parent = p.dst.parent;
|
|
if (src_parent != null && dst_parent != null)
|
|
{
|
|
//计算当前位置与父的位置距离
|
|
var src_dis = Vector3.Distance(src_parent.position, p.src.position);
|
|
var dst_dis = Vector3.Distance(dst_parent.position, p.dst.position);
|
|
if (src_dis != 0 && dst_dis != 0)
|
|
{
|
|
//计算目标位置相对父位置的方向,并根据方向重新计算目标的位置
|
|
var dst_dir = Vector3.Normalize(p.dst.position - dst_parent.position);
|
|
p.dst.position = dst_parent.position + dst_dir * (src_dis * 0.4f + dst_dis * 0.6f);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p.dst.position = p.src.position;
|
|
}
|
|
//对旋转信息进行插值计算
|
|
p.rot = Quaternion.Slerp(p.rot, p.src.rotation, FixFactor(p.rfactor));
|
|
p.dst.rotation = p.rot;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region//公共接口
|
|
//恢复原始位置
|
|
public void ResetPose()
|
|
{
|
|
if (m_particles != null)
|
|
{
|
|
for (int i = 0; i < m_particles.Length; ++i)
|
|
{
|
|
var p = m_particles[i];
|
|
p.pos = p.dst.position;
|
|
p.rot = p.dst.rotation;
|
|
p.src.position = p.pos;
|
|
p.src.rotation = p.rot;
|
|
}
|
|
}
|
|
}
|
|
//进行恢复处理
|
|
public void DoReset()
|
|
{
|
|
m_particles = null;
|
|
if (m_srcRoot != null && m_dstRoot != null)
|
|
{
|
|
var particles = new List<Particle>();
|
|
UnityHierarchyUtils.WalkHierarchy(
|
|
m_srcRoot,
|
|
t =>
|
|
{
|
|
if (t.name.StartsWith("weiba", StringComparison.CurrentCultureIgnoreCase))
|
|
{
|
|
var p = new Particle();
|
|
p.src = t;
|
|
var root = m_srcRoot;
|
|
if (root != t)
|
|
{
|
|
var h = UnityUtils.GetTransPathFrom(t, root);
|
|
var depth = UnityUtils.GetHierarchyDepthFrom(t, root);
|
|
var a = Math.Min(depth, depth_pfactors.Length - 1);
|
|
var b = Math.Min(depth, depth_rfactors.Length - 1);
|
|
p.dst = m_dstRoot.Find(h);
|
|
p.pfactor = depth_pfactors[a];
|
|
p.rfactor = depth_rfactors[b];
|
|
}
|
|
else
|
|
{
|
|
p.dst = m_dstRoot;
|
|
p.pfactor = 1.0f;
|
|
p.rfactor = 1.0f;
|
|
}
|
|
if (p.dst != null)
|
|
{
|
|
t.position = p.dst.position;
|
|
t.rotation = p.dst.rotation;
|
|
p.pos = t.position;
|
|
p.rot = t.rotation;
|
|
particles.Add(p);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
);
|
|
m_particles = particles.ToArray();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region//私有函数
|
|
private void OnTransformParentChanged()
|
|
{
|
|
m_parentChanged = true;
|
|
}
|
|
#endregion
|
|
|
|
#region//静态函数与方法
|
|
//位置参数--层次越深跟随的参数就越小
|
|
private static float[] depth_pfactors = new float[] { 1.0f, 0.5f, 0.3f, 0.2f, };
|
|
//旋转参数--层次越深跟随的参数就越小
|
|
private static float[] depth_rfactors = new float[] { 1.0f, 0.75f, 0.2f, 0.1f, };
|
|
//基础参数
|
|
private static float BaseFactor = 45;
|
|
//根据时间进行参数修正
|
|
private static float FixFactor(float factor)
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (Application.isPlaying)
|
|
{
|
|
return factor * Time.deltaTime * BaseFactor;
|
|
}
|
|
else
|
|
{
|
|
return factor;
|
|
}
|
|
#else
|
|
return factor * Time.deltaTime * BaseFactor;
|
|
#endif
|
|
}
|
|
#endregion
|
|
|
|
#region//子类定义
|
|
/// <summary>
|
|
/// 每一个部分
|
|
/// </summary>
|
|
[Serializable]
|
|
public class Particle
|
|
{
|
|
public Transform src = null;
|
|
public Transform dst = null;
|
|
public Vector3 pos = Vector3.zero;
|
|
public Quaternion rot = Quaternion.identity;
|
|
[Range(0.1f, 1.0f)]
|
|
public float pfactor = 0.1f;
|
|
[Range(0.1f, 1.0f)]
|
|
public float rfactor = 0.1f;
|
|
}
|
|
#endregion
|
|
}
|
|
|