RotateParticleSpringboneRuntimeProvider

This commit is contained in:
ousttrue 2024-11-07 19:18:00 +09:00
parent b0d6087272
commit 9cca2a3c99
6 changed files with 250 additions and 275 deletions

View File

@ -567,11 +567,7 @@ namespace UniVRM10.Cloth.Viewer
awaitCaller: m_useAsync.enabled ? (IAwaitCaller)new RuntimeOnlyAwaitCaller() : (IAwaitCaller)new ImmediateCaller(),
materialGenerator: GetVrmMaterialDescriptorGenerator(true),
vrmMetaInformationCallback: m_texts.UpdateMeta,
springboneRuntime: new RotateParticle.RotateParticleSpringboneRuntime((instance) =>
{
var autoSetup = instance.transform.gameObject.AddComponent<RotateParticle.HumanoidAutoSetup>();
autoSetup.Reset();
}));
springboneRuntime: new RotateParticle.RotateParticleSpringboneRuntime());
if (cancellationToken.IsCancellationRequested)
{
UnityObjectDestroyer.DestroyRuntimeOrEditor(vrm10Instance.gameObject);

View File

@ -1,233 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using SphereTriangle;
using UnityEngine;
namespace RotateParticle
{
public class HumanoidAutoSetup : MonoBehaviour
{
static (string group, HumanBodyBones head, HumanBodyBones tail, float radius)[] Capsules = new[]
{
("Leg", HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg, 0.06f),
("Leg", HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot, 0.05f),
("Leg", HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg, 0.06f),
("Leg", HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot, 0.05f),
("Arm", HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm, 0.03f),
("Arm", HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand, 0.03f),
("Arm", HumanBodyBones.LeftHand, HumanBodyBones.LeftMiddleProximal, 0.02f),
("Arm", HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm, 0.03f),
("Arm", HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand, 0.03f),
("Arm", HumanBodyBones.RightHand, HumanBodyBones.RightMiddleProximal, 0.02f),
};
T GetOrAddComponent<T>() where T : Component
{
var t = GetComponent<T>();
if (t != null)
{
return t;
}
return gameObject.AddComponent<T>();
}
bool TryAddGroup(CollisionGroupMask mask, string name, Animator animator, HumanBodyBones humanBone, string[] targets, StrandConnectionType type,
out StrandGroup group)
{
var bone = animator.GetBoneTransform(humanBone);
if (bone == null)
{
Debug.LogWarning($"{humanBone} not found");
group = default;
return false;
}
List<Transform> transforms = new();
foreach (Transform child in bone)
{
foreach (var target in targets)
{
if (child.name.ToLower().Contains(target.ToLower()))
{
transforms.Add(child);
break;
}
}
}
if (transforms.Count == 0)
{
Debug.LogWarning($"{string.Join(',', targets)} not found");
group = default;
return false;
}
group = new StrandGroup
{
Name = name,
CollisionMask = mask,
DefaultStrandRaius = 0.02f,
Connection = type
};
group.Roots.AddRange(transforms);
// sort
group.Roots.Sort(new TransformSort(bone.position));
return true;
}
bool TryAddGroupChildChild(CollisionGroupMask mask, string name, Animator animator, HumanBodyBones humanBone,
string[] targets, string[] excludes,
StrandConnectionType type,
bool sort,
out StrandGroup group)
{
var bone = animator.GetBoneTransform(humanBone);
if (bone == null)
{
Debug.LogWarning($"{humanBone} not found");
group = default;
return false;
}
List<Transform> transforms = new();
foreach (Transform child in bone)
{
foreach (Transform childchild in child)
{
if (excludes.Any(x => childchild.name.ToLower().Contains(x.ToLower())))
{
continue;
}
foreach (var target in targets)
{
if (childchild.name.ToLower().Contains(target.ToLower()))
{
transforms.Add(childchild);
break;
}
}
}
}
if (transforms.Count == 0)
{
Debug.LogWarning($"{string.Join(',', targets)} not found");
group = default;
return false;
}
group = new StrandGroup
{
Name = name,
CollisionMask = mask,
DefaultStrandRaius = 0.02f,
Connection = type
};
group.Roots.AddRange(transforms);
// sort
if (sort)
{
group.Roots.Sort(new TransformSort(bone.position));
}
return true;
}
public void Reset()
{
var animator = GetComponent<Animator>();
if (animator == null)
{
Debug.LogWarning("no animator");
return;
}
var avatar = animator.avatar;
if (!avatar.isHuman)
{
Debug.LogWarning("not humanoid");
return;
}
var system = GetOrAddComponent<RotateParticleSystem>();
system.Env.DragForce = 0.6f;
system.Env.Stiffness = 0.07f;
foreach (var (group, head, tail, radius) in Capsules)
{
system.AddColliderIfNotExists(group,
animator.GetBoneTransform(head), animator.GetBoneTransform(tail), radius);
}
// skirt
{
if (TryAddGroup(CollisionGroupMask.Group01, "Skirt", animator, HumanBodyBones.Hips, new[] { "skirt", "スカート", "スカート" }, StrandConnectionType.ClothLoop,
out var g))
{
system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group01, "Skirt", animator, HumanBodyBones.Hips, new[] { "skirt", "スカート", "スカート" }, new string[]{}, StrandConnectionType.ClothLoop, false,
out var g))
{
system._strandGroups.Add(g);
}
}
{
if (TryAddGroup(CollisionGroupMask.Group02, "髪", animator, HumanBodyBones.Head, new[] { "髪", "hair" }, StrandConnectionType.Strand,
out var g))
{
system._strandGroups.Add(g);
}
}
{
if (TryAddGroup(CollisionGroupMask.Group01, "裾", animator, HumanBodyBones.Hips, new[] { "裾" }, StrandConnectionType.Cloth,
out var g))
{
system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group02, "左袖", animator, HumanBodyBones.LeftUpperArm, new[] { "袖" }, new[] { "ひじ袖" }, StrandConnectionType.ClothLoop,
false,
out var g))
{
system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group02, "左ひじ袖", animator, HumanBodyBones.LeftLowerArm, new[] { "袖" }, new string[] { }, StrandConnectionType.ClothLoop,
false,
out var g))
{
system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group02, "右袖", animator, HumanBodyBones.RightUpperArm, new[] { "袖" }, new[] { "ひじ袖" }, StrandConnectionType.ClothLoop,
false,
out var g))
{
system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group02, "右ひじ袖", animator, HumanBodyBones.RightLowerArm, new[] { "袖" }, new string[] { }, StrandConnectionType.ClothLoop,
false,
out var g))
{
system._strandGroups.Add(g);
}
}
{
if (TryAddGroup(CollisionGroupMask.Group01 | CollisionGroupMask.Group02, "マント", animator, HumanBodyBones.Chest, new[] { "マント" }, StrandConnectionType.Cloth,
out var g))
{
system._strandGroups.Add(g);
}
}
}
}
}

View File

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using SphereTriangle;
using UniGLTF;
using UniGLTF.SpringBoneJobs.Blittables;
using UnityEngine;
@ -13,31 +16,246 @@ namespace RotateParticle
/// </summary>
public class RotateParticleSpringboneRuntime : IVrm10SpringBoneRuntime
{
Action<Vrm10Instance> _setup;
public RotateParticleSpringboneRuntime(Action<Vrm10Instance> setup)
{
_setup = setup;
}
RotateParticleSystem _system;
public void Dispose()
{
}
public Task InitializeAsync(Vrm10Instance instance, IAwaitCaller awaitCaller)
public async Task InitializeAsync(Vrm10Instance instance, IAwaitCaller awaitCaller)
{
if (_setup != null)
{
_setup(instance);
}
var system = instance.GetComponent<RotateParticleSystem>();
system.Initialize();
await awaitCaller.NextFrame();
// if (_setup != null)
// {
// _setup(instance);
// }
return Task.CompletedTask;
var animator = instance.GetComponent<Animator>();
if (animator == null)
{
Debug.LogWarning("no animator");
return;
}
var avatar = animator.avatar;
if (!avatar.isHuman)
{
Debug.LogWarning("not humanoid");
return;
}
_system = new RotateParticleSystem();
_system.Env.DragForce = 0.6f;
_system.Env.Stiffness = 0.07f;
foreach (var (group, head, tail, radius) in Capsules)
{
_system.AddColliderIfNotExists(group,
animator.GetBoneTransform(head), animator.GetBoneTransform(tail), radius);
}
// skirt
{
if (TryAddGroup(CollisionGroupMask.Group01, "Skirt", animator, HumanBodyBones.Hips, new[] { "skirt", "スカート", "スカート" }, StrandConnectionType.ClothLoop,
out var g))
{
_system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group01, "Skirt", animator, HumanBodyBones.Hips, new[] { "skirt", "スカート", "スカート" }, new string[] { }, StrandConnectionType.ClothLoop, false,
out var g))
{
_system._strandGroups.Add(g);
}
}
{
if (TryAddGroup(CollisionGroupMask.Group02, "髪", animator, HumanBodyBones.Head, new[] { "髪", "hair" }, StrandConnectionType.Strand,
out var g))
{
_system._strandGroups.Add(g);
}
}
{
if (TryAddGroup(CollisionGroupMask.Group01, "裾", animator, HumanBodyBones.Hips, new[] { "裾" }, StrandConnectionType.Cloth,
out var g))
{
_system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group02, "左袖", animator, HumanBodyBones.LeftUpperArm, new[] { "袖" }, new[] { "ひじ袖" }, StrandConnectionType.ClothLoop,
false,
out var g))
{
_system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group02, "左ひじ袖", animator, HumanBodyBones.LeftLowerArm, new[] { "袖" }, new string[] { }, StrandConnectionType.ClothLoop,
false,
out var g))
{
_system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group02, "右袖", animator, HumanBodyBones.RightUpperArm, new[] { "袖" }, new[] { "ひじ袖" }, StrandConnectionType.ClothLoop,
false,
out var g))
{
_system._strandGroups.Add(g);
}
}
{
if (TryAddGroupChildChild(CollisionGroupMask.Group02, "右ひじ袖", animator, HumanBodyBones.RightLowerArm, new[] { "袖" }, new string[] { }, StrandConnectionType.ClothLoop,
false,
out var g))
{
_system._strandGroups.Add(g);
}
}
{
if (TryAddGroup(CollisionGroupMask.Group01 | CollisionGroupMask.Group02, "マント", animator, HumanBodyBones.Chest, new[] { "マント" }, StrandConnectionType.Cloth,
out var g))
{
_system._strandGroups.Add(g);
}
}
_system.Initialize();
}
static (string group, HumanBodyBones head, HumanBodyBones tail, float radius)[] Capsules = new[]
{
("Leg", HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg, 0.06f),
("Leg", HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot, 0.05f),
("Leg", HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg, 0.06f),
("Leg", HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot, 0.05f),
("Arm", HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm, 0.03f),
("Arm", HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand, 0.03f),
("Arm", HumanBodyBones.LeftHand, HumanBodyBones.LeftMiddleProximal, 0.02f),
("Arm", HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm, 0.03f),
("Arm", HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand, 0.03f),
("Arm", HumanBodyBones.RightHand, HumanBodyBones.RightMiddleProximal, 0.02f),
};
// T GetOrAddComponent<T>() where T : Component
// {
// var t = GetComponent<T>();
// if (t != null)
// {
// return t;
// }
// return gameObject.AddComponent<T>();
// }
bool TryAddGroup(CollisionGroupMask mask, string name, Animator animator, HumanBodyBones humanBone, string[] targets, StrandConnectionType type,
out StrandGroup group)
{
var bone = animator.GetBoneTransform(humanBone);
if (bone == null)
{
Debug.LogWarning($"{humanBone} not found");
group = default;
return false;
}
List<Transform> transforms = new();
foreach (Transform child in bone)
{
foreach (var target in targets)
{
if (child.name.ToLower().Contains(target.ToLower()))
{
transforms.Add(child);
break;
}
}
}
if (transforms.Count == 0)
{
// Debug.LogWarning($"{string.Join(',', targets)} not found");
group = default;
return false;
}
group = new StrandGroup
{
Name = name,
CollisionMask = mask,
DefaultStrandRaius = 0.02f,
Connection = type
};
group.Roots.AddRange(transforms);
// sort
group.Roots.Sort(new TransformSort(bone.position));
return true;
}
bool TryAddGroupChildChild(CollisionGroupMask mask, string name, Animator animator, HumanBodyBones humanBone,
string[] targets, string[] excludes,
StrandConnectionType type,
bool sort,
out StrandGroup group)
{
var bone = animator.GetBoneTransform(humanBone);
if (bone == null)
{
Debug.LogWarning($"{humanBone} not found");
group = default;
return false;
}
List<Transform> transforms = new();
foreach (Transform child in bone)
{
foreach (Transform childchild in child)
{
if (excludes.Any(x => childchild.name.ToLower().Contains(x.ToLower())))
{
continue;
}
foreach (var target in targets)
{
if (childchild.name.ToLower().Contains(target.ToLower()))
{
transforms.Add(childchild);
break;
}
}
}
}
if (transforms.Count == 0)
{
// Debug.LogWarning($"{string.Join(',', targets)} not found");
group = default;
return false;
}
group = new StrandGroup
{
Name = name,
CollisionMask = mask,
DefaultStrandRaius = 0.02f,
Connection = type
};
group.Roots.AddRange(transforms);
// sort
if (sort)
{
group.Roots.Sort(new TransformSort(bone.position));
}
return true;
}
public void Process()
{
_system.Process(Time.deltaTime);
}
public bool ReconstructSpringBone()

View File

@ -0,0 +1,13 @@
using UnityEngine;
using UniVRM10;
namespace RotateParticle
{
public class RotateParticleSpringboneRuntimeProvider : MonoBehaviour, IVrm10SpringBoneRuntimeProvider
{
public IVrm10SpringBoneRuntime CreateSpringBoneRuntime()
{
return new RotateParticleSpringboneRuntime();
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: f2c23a62e016b3244b286404bc339540
guid: de8d095eee60f134ebd9ccaa9efcc01e
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -7,8 +7,8 @@ using UnityEngine;
namespace RotateParticle
{
[DisallowMultipleComponent]
public class RotateParticleSystem : MonoBehaviour
[Serializable]
public class RotateParticleSystem
{
// TODO: param to _strandGroups
[SerializeField]
@ -24,7 +24,6 @@ namespace RotateParticle
public float _clothFactor = 0.5f;
// runtime
bool _initialized = false;
List<Strand> _strands = new List<Strand>();
public ParticleList _list = new();
public List<(SpringConstraint, ClothRectCollision)> _clothRects = new();
@ -176,7 +175,6 @@ namespace RotateParticle
public void Initialize()
{
_initialized = true;
foreach (var g in _strandGroups)
{
if (g.Roots?.Count == 0)
@ -205,14 +203,6 @@ namespace RotateParticle
}
}
void Start()
{
if (!_initialized)
{
Initialize();
}
}
/// <summary>
/// すべての Particle を Init 状態にする。
/// Verlet の Prev を現在地に更新する(速度0)。
@ -225,15 +215,6 @@ namespace RotateParticle
}
}
public void Update()
{
if (Time.deltaTime == 0)
{
return;
}
Process(Time.deltaTime);
}
public void Process(float deltaTime)
{
using var profile = new ProfileSample("RotateParticle");
@ -345,7 +326,7 @@ namespace RotateParticle
}
}
void OnDrawGizmos()
public void DrawGizmos()
{
_list.DrawGizmos();