mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-15 23:20:10 -05:00
Merge pull request #2517 from ousttrue/fix/fix_cloth_sample
[1.0][cloth] 開発版。いろいろ修正
This commit is contained in:
commit
472da49bef
|
|
@ -138,7 +138,7 @@ namespace UniVRM10.Cloth.Viewer
|
|||
var warp = childchild.gameObject.AddComponent<ClothWarpRoot>();
|
||||
// Name = name,
|
||||
// CollisionMask = mask,
|
||||
warp.BaseSettings.radius = 0.02f;
|
||||
warp.BaseSettings.Radius = 0.02f;
|
||||
// Connection = type
|
||||
transforms.Add(warp);
|
||||
break;
|
||||
|
|
@ -179,7 +179,7 @@ namespace UniVRM10.Cloth.Viewer
|
|||
if (warp != null)
|
||||
{
|
||||
// CollisionMask = mask,
|
||||
warp.BaseSettings.radius = 0.02f;
|
||||
warp.BaseSettings.Radius = 0.02f;
|
||||
// Connection = type
|
||||
transforms.Add(warp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ MonoBehaviour:
|
|||
onValueChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_IsOn: 0
|
||||
m_IsOn: 1
|
||||
--- !u!1 &153452228
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -686,6 +686,92 @@ CanvasRenderer:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 168425994}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &172483632
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 172483633}
|
||||
- component: {fileID: 172483634}
|
||||
m_Layer: 5
|
||||
m_Name: AddClothToHips
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &172483633
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 172483632}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1472853923}
|
||||
- {fileID: 1724807119}
|
||||
m_Father: {fileID: 339774397}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 162, y: 20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &172483634
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 172483632}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Highlighted
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 1472853924}
|
||||
toggleTransition: 1
|
||||
graphic: {fileID: 1236232219}
|
||||
m_Group: {fileID: 0}
|
||||
onValueChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_IsOn: 1
|
||||
--- !u!1 &175751362
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -1407,6 +1493,7 @@ RectTransform:
|
|||
- {fileID: 1767706907}
|
||||
- {fileID: 947409974}
|
||||
- {fileID: 135168672}
|
||||
- {fileID: 172483633}
|
||||
- {fileID: 2144476967}
|
||||
- {fileID: 1194499280}
|
||||
- {fileID: 153452229}
|
||||
|
|
@ -5027,6 +5114,81 @@ CanvasRenderer:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1215781541}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1236232217
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1236232218}
|
||||
- component: {fileID: 1236232220}
|
||||
- component: {fileID: 1236232219}
|
||||
m_Layer: 5
|
||||
m_Name: Checkmark
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1236232218
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1236232217}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1472853923}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1236232219
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1236232217}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10901, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!222 &1236232220
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1236232217}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1242458542
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -6228,6 +6390,82 @@ MonoBehaviour:
|
|||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_IsOn: 0
|
||||
--- !u!1 &1472853922
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1472853923}
|
||||
- component: {fileID: 1472853925}
|
||||
- component: {fileID: 1472853924}
|
||||
m_Layer: 5
|
||||
m_Name: Background
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1472853923
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1472853922}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1236232218}
|
||||
m_Father: {fileID: 172483633}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 10, y: -10}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1472853924
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1472853922}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!222 &1472853925
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1472853922}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1476033060
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -6774,6 +7012,85 @@ CanvasRenderer:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1684483641}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1724807118
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1724807119}
|
||||
- component: {fileID: 1724807121}
|
||||
- component: {fileID: 1724807120}
|
||||
m_Layer: 5
|
||||
m_Name: Label
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1724807119
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1724807118}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 172483633}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 9, y: -0.5}
|
||||
m_SizeDelta: {x: -28, y: -3}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1724807120
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1724807118}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 0
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Add cloth to Hips
|
||||
--- !u!222 &1724807121
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1724807118}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1761414315
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -7224,6 +7541,7 @@ MonoBehaviour:
|
|||
m_openModel: {fileID: 2009818433}
|
||||
m_showBoxMan: {fileID: 1767706908}
|
||||
m_useJob: {fileID: 135168673}
|
||||
m_addClothToHips: {fileID: 172483634}
|
||||
m_reconstructSprngBone: {fileID: 2144476968}
|
||||
m_resetSpringBone: {fileID: 1194499281}
|
||||
m_pauseSpringBone: {fileID: 153452230}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ namespace UniVRM10.Cloth.Viewer
|
|||
|
||||
[Header("Cloth")]
|
||||
[SerializeField] Toggle m_useJob = default;
|
||||
[SerializeField] Toggle m_addClothToHips = default;
|
||||
[SerializeField] Button m_reconstructSprngBone = default;
|
||||
[SerializeField] Button m_resetSpringBone = default;
|
||||
[SerializeField] Toggle m_pauseSpringBone = default;
|
||||
|
|
@ -61,6 +62,7 @@ namespace UniVRM10.Cloth.Viewer
|
|||
m_showBoxMan = map.Get<Toggle>("ShowBoxMan");
|
||||
|
||||
m_useJob = map.Get<Toggle>("UseJob");
|
||||
m_addClothToHips = map.Get<Toggle>("AddClothToHips");
|
||||
m_reconstructSprngBone = map.Get<Button>("ReconstcutSpringBone");
|
||||
m_resetSpringBone = map.Get<Button>("ResetSpringBone");
|
||||
m_pauseSpringBone = map.Get<Toggle>("PauseSpringBone");
|
||||
|
|
@ -402,18 +404,20 @@ namespace UniVRM10.Cloth.Viewer
|
|||
else
|
||||
{
|
||||
ClothWarpRuntimeProvider.FromVrm10(vrm,
|
||||
go => go.AddComponent<ClothWarpRoot>(),
|
||||
o => GameObject.DestroyImmediate(o));
|
||||
go => go.AddComponent<ClothWarpRoot>());
|
||||
}
|
||||
|
||||
if (animator.GetBoneTransform(HumanBodyBones.Hips) is var hips)
|
||||
if (m_addClothToHips.isOn)
|
||||
{
|
||||
var cloth = hips.GetComponent<ClothGrid>();
|
||||
if (cloth == null)
|
||||
if (animator.GetBoneTransform(HumanBodyBones.Hips) is var hips)
|
||||
{
|
||||
cloth = hips.gameObject.AddComponent<ClothGrid>();
|
||||
cloth.Reset();
|
||||
cloth.LoopIsClosed = true;
|
||||
var cloth = hips.GetComponent<ClothGrid>();
|
||||
if (cloth == null)
|
||||
{
|
||||
cloth = hips.gameObject.AddComponent<ClothGrid>();
|
||||
cloth.Reset();
|
||||
cloth.LoopIsClosed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
"references": [
|
||||
"GUID:308b348fb80d89d42a9620951b0f60db",
|
||||
"GUID:e47c917724578cc43b5506c17a27e9a0",
|
||||
"GUID:3e5d614bc16b50d41bd94c8d7444ca46"
|
||||
"GUID:3e5d614bc16b50d41bd94c8d7444ca46",
|
||||
"GUID:8d76e605759c3f64a957d63ef96ada7c",
|
||||
"GUID:5f875fdc81c40184c8333b9d63c6ddd5"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UniVRM10;
|
||||
using UniGLTF;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Components
|
||||
{
|
||||
[CustomEditor(typeof(ClothWarpRoot))]
|
||||
class WarpRootEditor : Editor
|
||||
class ClothWarpRootEditor : Editor
|
||||
{
|
||||
private ClothWarpRoot m_target;
|
||||
private Vrm10Instance m_vrm;
|
||||
private MultiColumnTreeView m_treeview;
|
||||
VisualElement m_body;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
|
|
@ -27,37 +28,20 @@ namespace UniVRM10.ClothWarp.Components
|
|||
m_vrm = m_target.GetComponentInParent<Vrm10Instance>();
|
||||
}
|
||||
|
||||
// public override void OnInspectorGUI()
|
||||
// {
|
||||
// var n = EditorUtility.GetDirtyCount(m_target.GetInstanceID());
|
||||
// base.OnInspectorGUI();
|
||||
// if (n != EditorUtility.GetDirtyCount(m_target.GetInstanceID()))
|
||||
// {
|
||||
// if (m_vrm != null)
|
||||
// {
|
||||
// if (Application.isPlaying)
|
||||
// {
|
||||
// m_vrm.Runtime.SpringBone.SetJointLevel(m_target.transform, m_target.BaseSettings);
|
||||
// foreach (var p in m_target.Particles)
|
||||
// {
|
||||
// m_vrm.Runtime.SpringBone.SetJointLevel(p.Transform, p.GetSettings(m_target.BaseSettings));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void BindColumn<T>(string title, int width, Func<T> makeVisualELmeent, Func<int, bool> enableFunc, string subpath) where T : BindableElement
|
||||
void BindColumn<T>(MultiColumnTreeView tree, string title,
|
||||
int width, Func<T> makeVisualELment,
|
||||
Func<int, bool> enableFunc, string subpath) where T : BindableElement
|
||||
{
|
||||
m_treeview.columns.Add(new Column
|
||||
{
|
||||
title = title,
|
||||
width = width,
|
||||
makeCell = makeVisualELmeent,
|
||||
bindCell = (v, i) =>
|
||||
makeCell = makeVisualELment,
|
||||
bindCell = (v, index) =>
|
||||
{
|
||||
if (v is T prop)
|
||||
{
|
||||
var i = tree.GetIdForIndex(index);
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.Append("m_particles.Array.data[");
|
||||
sb.Append(i);
|
||||
|
|
@ -85,8 +69,24 @@ namespace UniVRM10.ClothWarp.Components
|
|||
s.SetEnabled(false);
|
||||
root.Add(s);
|
||||
}
|
||||
root.Add(new PropertyField { bindingPath = nameof(ClothWarpRoot.BaseSettings) });
|
||||
root.Add(new PropertyField { bindingPath = nameof(ClothWarpRoot.Center) });
|
||||
|
||||
root.Add(new IMGUIContainer(() =>
|
||||
{
|
||||
foreach (var v in m_target.Validations)
|
||||
{
|
||||
v.DrawGUI();
|
||||
}
|
||||
}));
|
||||
|
||||
m_body = new VisualElement();
|
||||
root.Add(m_body);
|
||||
m_body.style.display = m_target.Validations.All(x => x.ErrorLevel < ErrorLevels.Warning)
|
||||
? DisplayStyle.Flex
|
||||
: DisplayStyle.None
|
||||
;
|
||||
|
||||
m_body.Add(new PropertyField { bindingPath = nameof(ClothWarpRoot.BaseSettings) });
|
||||
m_body.Add(new PropertyField { bindingPath = nameof(ClothWarpRoot.Center) });
|
||||
|
||||
// root.Add(new PropertyField { bindingPath = "m_particles" });
|
||||
{
|
||||
|
|
@ -96,35 +96,43 @@ namespace UniVRM10.ClothWarp.Components
|
|||
};
|
||||
|
||||
m_treeview = new MultiColumnTreeView();
|
||||
BindColumn("Transform", 120, () => new ObjectField(), (_) => false, "Transform");
|
||||
BindColumn("Mode", 40, () => new EnumField(), (_) => true, "Mode");
|
||||
BindColumn("stiffnessForce", 40, () => new FloatField(), isCustom, "Settings.stiffnessForce");
|
||||
BindColumn("gravityPower", 40, () => new FloatField(), isCustom, "Settings.gravityPower");
|
||||
BindColumn("gravityDir", 120, () => new Vector3Field(), isCustom, "Settings.gravityDir");
|
||||
BindColumn("dragForce", 40, () => new FloatField(), isCustom, "Settings.dragForce");
|
||||
BindColumn("radius", 40, () => new FloatField(), isCustom, "Settings.radius");
|
||||
BindColumn(m_treeview, "Transform", 120, () => new ObjectField(), (_) => false, "Transform");
|
||||
BindColumn(m_treeview, "Mode", 40, () => new EnumField(), (_) => true, "Mode");
|
||||
BindColumn(m_treeview, "Stiffness", 40, () => new FloatField(), isCustom, "Settings.Stiffness");
|
||||
BindColumn(m_treeview, "Gravity", 120, () => new Vector3Field(), isCustom, "Settings.Gravity");
|
||||
BindColumn(m_treeview, "Deceleration", 40, () => new FloatField(), isCustom, "Settings.Deceleration");
|
||||
BindColumn(m_treeview, "Radius", 40, () => new FloatField(), isCustom, "Settings.Radius");
|
||||
|
||||
m_treeview.autoExpand = true;
|
||||
m_treeview.SetRootItems(m_target.m_rootitems);
|
||||
root.Add(m_treeview);
|
||||
m_body.Add(m_treeview);
|
||||
}
|
||||
|
||||
root.Add(new PropertyField { bindingPath = nameof(ClothWarpRoot.ColliderGroups) });
|
||||
m_body.Add(new PropertyField { bindingPath = nameof(ClothWarpRoot.ColliderGroups) });
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void OnValueChanged(SerializedObject so)
|
||||
{
|
||||
Debug.Log("Name changed: " + so.targetObject.name);
|
||||
// var nameProperty = so.FindProperty("m_Name");
|
||||
if (m_vrm != null)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
m_vrm.Runtime.SpringBone.SetJointLevel(m_target.transform, m_target.BaseSettings.ToBlittableJointMutable());
|
||||
foreach (var p in m_target.Particles)
|
||||
{
|
||||
m_vrm.Runtime.SpringBone.SetJointLevel(p.Transform, p.Settings.ToBlittableJointMutable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (nameProperty.stringValue.Contains(" "))
|
||||
// _textField.style.backgroundColor = Color.red;
|
||||
// else
|
||||
// _textField.style.backgroundColor = StyleKeyword.Null;
|
||||
m_treeview.RefreshItems();
|
||||
// m_treeview.SetRootItems(m_target.m_rootitems);
|
||||
|
||||
m_body.style.display = m_target.Validations.All(x => x.ErrorLevel < ErrorLevels.Warning)
|
||||
? DisplayStyle.Flex
|
||||
: DisplayStyle.None
|
||||
;
|
||||
Repaint();
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +155,7 @@ namespace UniVRM10.ClothWarp.Components
|
|||
p = m_target.GetParticleFromTransform(p.Transform);
|
||||
var t = p.Transform;
|
||||
Handles.color = Color.green;
|
||||
Handles.SphereHandleCap(t.GetInstanceID(), t.position, t.rotation, p.Settings.radius * 2, EventType.Repaint);
|
||||
Handles.SphereHandleCap(t.GetInstanceID(), t.position, t.rotation, p.Settings.Radius * 2, EventType.Repaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using System.Linq;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UniVRM10;
|
||||
using UnityEditor.UIElements;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Components
|
||||
|
|
@ -9,60 +8,109 @@ namespace UniVRM10.ClothWarp.Components
|
|||
[CustomEditor(typeof(ClothWarpRuntimeProvider))]
|
||||
public class RotateParticleRuntimeProviderEditor : Editor
|
||||
{
|
||||
const string FROM_VRM10_MENU = "Replace VRM10 Springs to ClothWarp Warps";
|
||||
ClothWarpRuntimeProvider _target;
|
||||
Vrm10Instance _vrm;
|
||||
|
||||
[MenuItem(FROM_VRM10_MENU, true)]
|
||||
public static bool IsFromVrm10()
|
||||
void OnEnable()
|
||||
{
|
||||
var go = Selection.activeGameObject;
|
||||
if (go == null)
|
||||
_target = (ClothWarpRuntimeProvider)target;
|
||||
if (_target != null)
|
||||
{
|
||||
return false;
|
||||
_vrm = _target.GetComponent<Vrm10Instance>();
|
||||
}
|
||||
return go.GetComponent<Vrm10Instance>() != null;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
var provider = target as ClothWarpRuntimeProvider;
|
||||
if (provider == null)
|
||||
var root = new VisualElement();
|
||||
root.Bind(serializedObject);
|
||||
{
|
||||
return;
|
||||
var s = new PropertyField { bindingPath = "m_Script" };
|
||||
s.SetEnabled(false);
|
||||
root.Add(s);
|
||||
}
|
||||
var instance = provider.GetComponent<Vrm10Instance>();
|
||||
using (new EditorGUI.DisabledScope(instance == null))
|
||||
root.Add(new PropertyField { bindingPath = nameof(_target.UseJob) });
|
||||
root.Add(new PropertyField { bindingPath = nameof(_target.Warps) });
|
||||
root.Add(new PropertyField { bindingPath = nameof(_target.Cloths) });
|
||||
|
||||
{
|
||||
if (GUILayout.Button("Replace VRM10 Springs to ClothWarp Warps"))
|
||||
var setup = new Foldout { text = "Setup" };
|
||||
|
||||
var from_vrm10 = new Button { text = "Load VRM10 Springs to ClothWarp Warps" };
|
||||
setup.Add(from_vrm10);
|
||||
from_vrm10.RegisterCallback<ClickEvent>(e =>
|
||||
{
|
||||
Undo.IncrementCurrentGroup();
|
||||
Undo.SetCurrentGroupName(FROM_VRM10_MENU);
|
||||
Undo.SetCurrentGroupName("Load Vrm-1.0 Springs to ClothWarp Warps");
|
||||
var undo = Undo.GetCurrentGroup();
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(instance, "RegisterCompleteObjectUndo");
|
||||
ClothWarpRuntimeProvider.FromVrm10(instance, Undo.AddComponent<ClothWarpRoot>, Undo.DestroyObjectImmediate);
|
||||
Undo.RegisterFullObjectHierarchyUndo(instance.gameObject, "RegisterFullObjectHierarchyUndo");
|
||||
// attach ClothWarp from VRM10Instance.Springs
|
||||
ClothWarpRuntimeProvider.FromVrm10(_vrm, Undo.AddComponent<ClothWarpRoot>);
|
||||
Undo.RegisterFullObjectHierarchyUndo(_vrm.gameObject, "RegisterFullObjectHierarchyUndo");
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(provider, "RegisterCompleteObjectUndo");
|
||||
provider.Reset();
|
||||
// update ClothWarpRuntimeProvider
|
||||
Undo.RegisterCompleteObjectUndo(_target, "RegisterCompleteObjectUndo");
|
||||
_target.Reset();
|
||||
|
||||
Undo.CollapseUndoOperations(undo);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
using (new EditorGUI.DisabledScope(instance == null || !Application.isPlaying))
|
||||
{
|
||||
if (GUILayout.Button("RestoreInitialTransform"))
|
||||
var clear_vrm10_springs = new Button { text = "Clear Vrm-1.0 springs" };
|
||||
setup.Add(clear_vrm10_springs);
|
||||
clear_vrm10_springs.RegisterCallback<ClickEvent>(e =>
|
||||
{
|
||||
instance.Runtime.SpringBone.RestoreInitialTransform();
|
||||
}
|
||||
Undo.IncrementCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Clear VRM10 Srpings");
|
||||
var undo = Undo.GetCurrentGroup();
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(_vrm, "RegisterCompleteObjectUndo");
|
||||
foreach (var spring in _vrm.SpringBone.Springs)
|
||||
{
|
||||
if (spring != null)
|
||||
{
|
||||
foreach (var joint in spring.Joints)
|
||||
{
|
||||
if (joint != null)
|
||||
{
|
||||
Undo.DestroyObjectImmediate(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
spring.Joints.Clear();
|
||||
}
|
||||
_vrm.SpringBone.Springs.Clear();
|
||||
Undo.RegisterFullObjectHierarchyUndo(_vrm.gameObject, "RegisterFullObjectHierarchyUndo");
|
||||
|
||||
Undo.CollapseUndoOperations(undo);
|
||||
});
|
||||
|
||||
var reload = new Button { text = "Reload" };
|
||||
setup.Add(reload);
|
||||
reload.RegisterCallback<ClickEvent>(e =>
|
||||
{
|
||||
_target.Reset();
|
||||
});
|
||||
|
||||
root.Add(setup);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Reset"))
|
||||
{
|
||||
provider.Reset();
|
||||
// runtime: reset button
|
||||
var runtime = new Foldout { text = "Runtime" };
|
||||
root.Add(runtime);
|
||||
|
||||
var button = new Button
|
||||
{
|
||||
text = "RestoreInitialTransform",
|
||||
};
|
||||
runtime.Add(button);
|
||||
button.RegisterCallback<ClickEvent>((e) =>
|
||||
{
|
||||
_vrm.Runtime.SpringBone.RestoreInitialTransform();
|
||||
});
|
||||
}
|
||||
|
||||
base.OnInspectorGUI();
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ Base 設定を変更する場合は変える方を列挙設定できる。
|
|||
Custom と Disable を選択できる。
|
||||
|
||||
- ゆれものの根元にアタッチする
|
||||
- [ ] 子孫に HumanoidBone がある場合にアタッチ不可
|
||||
- [x] 子孫に HumanoidBone がある場合にアタッチ不可
|
||||
- [ ] 枝分かれ
|
||||
- [ ] WarpRoot らからデフォルト以外の Warp を選び出す
|
||||
- [ ] Center
|
||||
|
|
@ -126,4 +126,4 @@ WarpRoot2 o=o=o
|
|||
|
||||
### Optimize
|
||||
|
||||
- [ ] 衝突グループ(現状総当たり)
|
||||
- [x] 衝突グループ
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ namespace UniVRM10.ClothWarp
|
|||
class ClothRectList
|
||||
{
|
||||
readonly List<Transform> _particles;
|
||||
|
||||
public List<(SpringConstraint, ClothRect)> List = new();
|
||||
public readonly ClothGrid[] ClothGrids;
|
||||
public List<(int, SpringConstraint, ClothRect)> List = new();
|
||||
public readonly bool[] ClothUsedParticles;
|
||||
|
||||
public ClothRectList(List<Transform> particles, Vrm10Instance vrm)
|
||||
|
|
@ -19,15 +19,16 @@ namespace UniVRM10.ClothWarp
|
|||
_particles = particles;
|
||||
ClothUsedParticles = new bool[_particles.Count];
|
||||
|
||||
var cloths = vrm.GetComponentsInChildren<ClothGrid>();
|
||||
foreach (var cloth in cloths)
|
||||
ClothGrids = vrm.GetComponentsInChildren<ClothGrid>();
|
||||
for (int i = 0; i < ClothGrids.Length; ++i)
|
||||
{
|
||||
AddCloth(cloth, vrm);
|
||||
AddCloth(i, vrm);
|
||||
}
|
||||
}
|
||||
|
||||
void AddCloth(ClothGrid cloth, Vrm10Instance vrm)
|
||||
void AddCloth(int clothGridIndex, Vrm10Instance vrm)
|
||||
{
|
||||
var cloth = ClothGrids[clothGridIndex];
|
||||
for (int i = 1; i < cloth.Warps.Count; ++i)
|
||||
{
|
||||
var s0 = cloth.Warps[i - 1];
|
||||
|
|
@ -53,6 +54,7 @@ namespace UniVRM10.ClothWarp
|
|||
(c, d) = (d, c);
|
||||
}
|
||||
List.Add((
|
||||
clothGridIndex,
|
||||
new SpringConstraint(
|
||||
_particles.IndexOf(a),
|
||||
_particles.IndexOf(b),
|
||||
|
|
@ -91,6 +93,7 @@ namespace UniVRM10.ClothWarp
|
|||
(c, d) = (d, c);
|
||||
}
|
||||
List.Add((
|
||||
clothGridIndex,
|
||||
new SpringConstraint(
|
||||
_particles.IndexOf(a),
|
||||
_particles.IndexOf(b),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
"GUID:3e5d614bc16b50d41bd94c8d7444ca46",
|
||||
"GUID:e47c917724578cc43b5506c17a27e9a0",
|
||||
"GUID:8d76e605759c3f64a957d63ef96ada7c",
|
||||
"GUID:1cd941934d098654fa21a13f28346412"
|
||||
"GUID:1cd941934d098654fa21a13f28346412",
|
||||
"GUID:5f875fdc81c40184c8333b9d63c6ddd5"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ using UnityEngine;
|
|||
|
||||
namespace UniVRM10.ClothWarp
|
||||
{
|
||||
/// <summary>
|
||||
/// プロトタイプ。非 job
|
||||
/// </summary>
|
||||
public class ClothWarpRuntime : IVrm10SpringBoneRuntime
|
||||
{
|
||||
Vrm10Instance _vrm;
|
||||
|
|
@ -58,7 +61,7 @@ namespace UniVRM10.ClothWarp
|
|||
return Color.gray;
|
||||
}
|
||||
|
||||
public async Task InitializeAsync(Vrm10Instance vrm, IAwaitCaller awaitCaller)
|
||||
public Task InitializeAsync(Vrm10Instance vrm, IAwaitCaller awaitCaller)
|
||||
{
|
||||
_building = true;
|
||||
_vrm = vrm;
|
||||
|
|
@ -102,7 +105,7 @@ namespace UniVRM10.ClothWarp
|
|||
_clothRectCollisions = new();
|
||||
for (int i = 0; i < _clothRects.List.Count; ++i)
|
||||
{
|
||||
var (s, r) = _clothRects.List[i];
|
||||
var (grid, s, r) = _clothRects.List[i];
|
||||
_clothRectCollisions.Add(new());
|
||||
var c = _clothRectCollisions.Last();
|
||||
c.InitializeColliderSide(_newPos, _colliderGroups, r);
|
||||
|
|
@ -112,6 +115,8 @@ namespace UniVRM10.ClothWarp
|
|||
|
||||
_initialized = true;
|
||||
_building = false;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -167,7 +172,7 @@ namespace UniVRM10.ClothWarp
|
|||
// verlet 積分
|
||||
var time = new FrameTime(deltaTime);
|
||||
_list.BeginFrame(Env, time, _restPositions);
|
||||
foreach (var (spring, collision) in _clothRects.List)
|
||||
foreach (var (gridIndex, spring, collision) in _clothRects.List)
|
||||
{
|
||||
// cloth constraint
|
||||
spring.Resolve(time, _clothFactor, _list._particles);
|
||||
|
|
@ -189,7 +194,7 @@ namespace UniVRM10.ClothWarp
|
|||
|
||||
for (int j = 0; j < _clothRects.List.Count; ++j)
|
||||
{
|
||||
var (spring, rect) = _clothRects.List[j];
|
||||
var (gridIndex, spring, rect) = _clothRects.List[j];
|
||||
var collision = _clothRectCollisions[j];
|
||||
// using var prof = new ProfileSample("Collision: Cloth");
|
||||
// 頂点 abcd は同じ CollisionMask
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniGLTF.SpringBoneJobs.Blittables;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UniVRM10;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Components
|
||||
|
|
@ -17,18 +16,6 @@ namespace UniVRM10.ClothWarp.Components
|
|||
/// </summary>
|
||||
public class ClothWarpRoot : MonoBehaviour
|
||||
{
|
||||
public static BlittableJointMutable DefaultSetting()
|
||||
{
|
||||
return new BlittableJointMutable
|
||||
{
|
||||
stiffnessForce = 1.0f,
|
||||
gravityPower = 0,
|
||||
gravityDir = new Vector3(0, -1.0f, 0),
|
||||
dragForce = 0.4f,
|
||||
radius = 0.02f,
|
||||
};
|
||||
}
|
||||
|
||||
public enum ParticleMode
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -53,28 +40,28 @@ namespace UniVRM10.ClothWarp.Components
|
|||
{
|
||||
public Transform Transform;
|
||||
public ParticleMode Mode;
|
||||
public BlittableJointMutable Settings;
|
||||
public Jobs.ParticleSettings Settings;
|
||||
|
||||
public Particle(Transform t, ParticleMode mode, BlittableJointMutable settings)
|
||||
public Particle(Transform t, ParticleMode mode, Jobs.ParticleSettings settings)
|
||||
{
|
||||
Transform = t;
|
||||
Mode = mode;
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
public Particle(Transform t, BlittableJointMutable settings)
|
||||
public Particle(Transform t, Jobs.ParticleSettings settings)
|
||||
: this(t, ParticleMode.Custom, settings)
|
||||
{
|
||||
}
|
||||
|
||||
public Particle(Transform t)
|
||||
: this(t, ParticleMode.Base, DefaultSetting())
|
||||
: this(t, ParticleMode.Base, Jobs.ParticleSettings.Default)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
public BlittableJointMutable BaseSettings = DefaultSetting();
|
||||
public Jobs.ParticleSettings BaseSettings = Jobs.ParticleSettings.Default;
|
||||
|
||||
/// <summary>
|
||||
/// null のときは world root ではなく model root で処理
|
||||
|
|
@ -98,9 +85,59 @@ namespace UniVRM10.ClothWarp.Components
|
|||
// 逆引き
|
||||
Dictionary<Transform, int> m_map = new();
|
||||
|
||||
public readonly List<Validation> Validations = new();
|
||||
|
||||
bool HasHumanoidBonesInChildren(Animator animator, out Transform t)
|
||||
{
|
||||
foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones)))
|
||||
{
|
||||
if (bone == HumanBodyBones.LastBone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var b = animator.GetBoneTransform(bone);
|
||||
if (b != null)
|
||||
{
|
||||
for (var parent = b.parent; parent != null; parent = parent.parent)
|
||||
{
|
||||
if (parent == transform)
|
||||
{
|
||||
t = transform;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
m_particles = GetComponentsInChildren<Transform>().Skip(1).Select(x => new Particle(x)).ToList();
|
||||
Validations.Clear();
|
||||
if (GetComponentInParent<Animator>() is var animator)
|
||||
{
|
||||
if (HasHumanoidBonesInChildren(animator, out var t))
|
||||
{
|
||||
Validations.Add(Validation.Error(
|
||||
"アタッチできません。子孫にHumanoidBoneがあります",
|
||||
ValidationContext.Create(t)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
var backup = m_particles.ToDictionary(x => x.Transform, x => x);
|
||||
m_particles = GetComponentsInChildren<Transform>().Skip(1).Select(x =>
|
||||
{
|
||||
foreach (var particle in m_particles)
|
||||
{
|
||||
if (particle.Transform == x)
|
||||
{
|
||||
return particle;
|
||||
}
|
||||
}
|
||||
return new Particle(x);
|
||||
}).ToList();
|
||||
m_map.Clear();
|
||||
for (int i = 0; i < m_particles.Count; ++i)
|
||||
{
|
||||
|
|
@ -164,7 +201,7 @@ namespace UniVRM10.ClothWarp.Components
|
|||
}
|
||||
}
|
||||
|
||||
public void SetSettings(Transform t, BlittableJointMutable settings)
|
||||
public void SetSettings(Transform t, Jobs.ParticleSettings settings)
|
||||
{
|
||||
if (t == null) return;
|
||||
for (int i = 0; i < m_particles.Count; ++i)
|
||||
|
|
@ -182,7 +219,7 @@ namespace UniVRM10.ClothWarp.Components
|
|||
|
||||
public void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.DrawSphere(transform.position, BaseSettings.radius);
|
||||
Gizmos.DrawSphere(transform.position, BaseSettings.Radius);
|
||||
|
||||
foreach (var p in Particles)
|
||||
{
|
||||
|
|
@ -190,7 +227,7 @@ namespace UniVRM10.ClothWarp.Components
|
|||
{
|
||||
continue;
|
||||
}
|
||||
Gizmos.DrawWireSphere(p.Transform.position, p.Settings.radius);
|
||||
Gizmos.DrawWireSphere(p.Transform.position, p.Settings.Radius);
|
||||
|
||||
if (TryGetClosestParent(p.Transform, out var parent))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UniVRM10;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Components
|
||||
{
|
||||
|
|
@ -17,7 +17,7 @@ namespace UniVRM10.ClothWarp.Components
|
|||
public List<ClothGrid> Cloths = new();
|
||||
|
||||
[SerializeField]
|
||||
public bool UseJob;
|
||||
public bool UseJob = true;
|
||||
|
||||
IVrm10SpringBoneRuntime m_runtime;
|
||||
public IVrm10SpringBoneRuntime CreateSpringBoneRuntime()
|
||||
|
|
@ -45,8 +45,7 @@ namespace UniVRM10.ClothWarp.Components
|
|||
}
|
||||
|
||||
public static void FromVrm10(Vrm10Instance instance,
|
||||
Func<GameObject, ClothWarpRoot> addWarp,
|
||||
Action<UnityEngine.Object> deleteObject)
|
||||
Func<GameObject, ClothWarpRoot> addWarp)
|
||||
{
|
||||
foreach (var spring in instance.SpringBone.Springs)
|
||||
{
|
||||
|
|
@ -64,29 +63,30 @@ namespace UniVRM10.ClothWarp.Components
|
|||
var warp = root_joint.GetComponent<ClothWarpRoot>();
|
||||
if (warp == null)
|
||||
{
|
||||
// var warp = Undo.AddComponent<Warp>(root_joint);
|
||||
warp = addWarp(root_joint);
|
||||
var joints = spring.Joints.Where(x => x != null).ToArray();
|
||||
for (int i = 0; i < joints.Length; ++i)
|
||||
{
|
||||
var joint = joints[i];
|
||||
var settings = new UniGLTF.SpringBoneJobs.Blittables.BlittableJointMutable
|
||||
|
||||
// mod ?
|
||||
var stiffness = Mathf.Min(0.08f, joint.m_stiffnessForce * 0.1f);
|
||||
|
||||
var settings = new Jobs.ParticleSettings
|
||||
{
|
||||
dragForce = joint.m_dragForce,
|
||||
gravityDir = joint.m_gravityDir,
|
||||
gravityPower = joint.m_gravityPower,
|
||||
// mod
|
||||
stiffnessForce = joint.m_stiffnessForce * 6,
|
||||
Deceleration = joint.m_dragForce,
|
||||
Gravity = joint.m_gravityDir * joint.m_gravityPower,
|
||||
Stiffness = stiffness,
|
||||
};
|
||||
if (i == 0)
|
||||
{
|
||||
settings.radius = joints[0].m_jointRadius;
|
||||
settings.Radius = joints[0].m_jointRadius;
|
||||
warp.BaseSettings = settings;
|
||||
}
|
||||
else
|
||||
{
|
||||
// breaking change from vrm-1.0
|
||||
settings.radius = joints[i - 1].m_jointRadius;
|
||||
settings.Radius = joints[i - 1].m_jointRadius;
|
||||
var useInheritSettings = warp.BaseSettings.Equals(settings);
|
||||
if (useInheritSettings)
|
||||
{
|
||||
|
|
@ -97,14 +97,10 @@ namespace UniVRM10.ClothWarp.Components
|
|||
warp.SetSettings(joint.transform, settings);
|
||||
}
|
||||
}
|
||||
// Undo.DestroyObjectImmediate(joint);
|
||||
deleteObject(joint);
|
||||
}
|
||||
spring.Joints.Clear();
|
||||
warp.ColliderGroups = spring.ColliderGroups.ToList();
|
||||
}
|
||||
}
|
||||
instance.SpringBone.Springs.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,11 +7,13 @@ using Unity.Collections;
|
|||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
using UniVRM10;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Jobs
|
||||
{
|
||||
/// <summary>
|
||||
/// Job 版
|
||||
/// </summary>
|
||||
public class ClothWarpJobRuntime : IVrm10SpringBoneRuntime
|
||||
{
|
||||
Vrm10Instance _vrm;
|
||||
|
|
@ -19,12 +21,25 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
bool _building = false;
|
||||
|
||||
//
|
||||
// collider
|
||||
// colliderTransform
|
||||
//
|
||||
List<Transform> _colliderTransforms;
|
||||
TransformAccessArray _colliderTransformAccessArray;
|
||||
NativeArray<Matrix4x4> _currentColliders;
|
||||
NativeArray<BlittableCollider> _colliders;
|
||||
|
||||
//
|
||||
// collider
|
||||
//
|
||||
List<VRM10SpringBoneCollider> _colliders;
|
||||
NativeArray<BlittableCollider> _colliderInfo;
|
||||
|
||||
//
|
||||
// colliderGroup
|
||||
//
|
||||
List<VRM10SpringBoneColliderGroup> _colliderGroups;
|
||||
NativeArray<int> _colliderRef;
|
||||
NativeArray<ArrayRange> _colliderGroup;
|
||||
NativeArray<int> _colliderGroupRef;
|
||||
|
||||
//
|
||||
// particle
|
||||
|
|
@ -38,10 +53,10 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
NativeArray<Vector3> _nextPositions;
|
||||
NativeArray<Quaternion> _nextRotations;
|
||||
|
||||
NativeArray<Vector3> _strandCollision;
|
||||
NativeArray<int> _clothCollisionCount;
|
||||
NativeArray<Vector3> _clothCollisionDelta;
|
||||
NativeArray<Vector3> _forces;
|
||||
NativeArray<Vector3> _warpCollision;
|
||||
NativeArray<int> _rectCollisionCount;
|
||||
NativeArray<Vector3> _rectCollisionDelta;
|
||||
NativeArray<Vector3> _impulsiveForces;
|
||||
|
||||
//
|
||||
// warp
|
||||
|
|
@ -49,16 +64,26 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
NativeArray<WarpInfo> _warps;
|
||||
|
||||
//
|
||||
// cloth
|
||||
// cloth rect
|
||||
//
|
||||
NativeArray<bool> _clothUsedParticles;
|
||||
NativeArray<(SpringConstraint, SphereTriangle.ClothRect)> _clothRects;
|
||||
NativeArray<(int ClothGridIndex, SpringConstraint SpringConstraint, SphereTriangle.ClothRect Rect)> _clothRects;
|
||||
NativeArray<(Vector3, Vector3, Vector3, Vector3)> _clothRectResults;
|
||||
|
||||
//
|
||||
// cloth grid
|
||||
//
|
||||
NativeArray<ClothInfo> _cloths;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_colliderTransformAccessArray.isCreated) _colliderTransformAccessArray.Dispose();
|
||||
if (_currentColliders.IsCreated) _currentColliders.Dispose();
|
||||
|
||||
if (_colliderRef.IsCreated) _colliderRef.Dispose();
|
||||
if (_colliderGroup.IsCreated) _colliderGroup.Dispose();
|
||||
if (_colliderGroupRef.IsCreated) _colliderGroupRef.Dispose();
|
||||
|
||||
if (_warps.IsCreated) _warps.Dispose();
|
||||
if (_transformAccessArray.isCreated) _transformAccessArray.Dispose();
|
||||
if (_inputData.IsCreated) _inputData.Dispose();
|
||||
|
|
@ -67,15 +92,17 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
if (_prevPositions.IsCreated) _prevPositions.Dispose();
|
||||
if (_nextPositions.IsCreated) _nextPositions.Dispose();
|
||||
if (_nextRotations.IsCreated) _nextRotations.Dispose();
|
||||
if (_strandCollision.IsCreated) _strandCollision.Dispose();
|
||||
if (_clothCollisionCount.IsCreated) _clothCollisionCount.Dispose();
|
||||
if (_clothCollisionDelta.IsCreated) _clothCollisionDelta.Dispose();
|
||||
if (_forces.IsCreated) _forces.Dispose();
|
||||
if (_warpCollision.IsCreated) _warpCollision.Dispose();
|
||||
if (_rectCollisionCount.IsCreated) _rectCollisionCount.Dispose();
|
||||
if (_rectCollisionDelta.IsCreated) _rectCollisionDelta.Dispose();
|
||||
if (_impulsiveForces.IsCreated) _impulsiveForces.Dispose();
|
||||
|
||||
if (_warps.IsCreated) _warps.Dispose();
|
||||
if (_cloths.IsCreated) _cloths.Dispose();
|
||||
|
||||
if (_clothUsedParticles.IsCreated) _clothUsedParticles.Dispose();
|
||||
if (_clothRects.IsCreated) _clothRects.Dispose();
|
||||
if (_clothRectResults.IsCreated) _clothRectResults.Dispose();
|
||||
}
|
||||
|
||||
(int index, bool isNew) GetTransformIndex(Transform t,
|
||||
|
|
@ -97,6 +124,33 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
return (i, true);
|
||||
}
|
||||
|
||||
Transform GetParent(Transform t, Transform root)
|
||||
{
|
||||
for (var parent = t.parent; parent != null; parent = parent.parent)
|
||||
{
|
||||
if (_transforms.Contains(parent))
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
if (parent == root)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
int GetOrAddColliderTransform(Transform t)
|
||||
{
|
||||
var index = _colliderTransforms.IndexOf(t);
|
||||
if (index == -1)
|
||||
{
|
||||
index = _colliderTransforms.Count;
|
||||
_colliderTransforms.Add(t);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public async Task InitializeAsync(Vrm10Instance vrm, IAwaitCaller awaitCaller)
|
||||
{
|
||||
_vrm = vrm;
|
||||
|
|
@ -111,30 +165,67 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
//
|
||||
// colliders
|
||||
//
|
||||
_colliders = new();
|
||||
_colliderGroups = new();
|
||||
_colliderTransforms = new();
|
||||
List<BlittableCollider> colliders = new();
|
||||
foreach (var collider in vrm.GetComponentsInChildren<VRM10SpringBoneCollider>())
|
||||
List<BlittableCollider> colliderInfo = new();
|
||||
List<int> colliderRef = new();
|
||||
List<ArrayRange> colliderGroups = new();
|
||||
foreach (var colliderGroup in vrm.GetComponentsInChildren<VRM10SpringBoneColliderGroup>())
|
||||
{
|
||||
colliders.Add(new BlittableCollider
|
||||
if (colliderGroup == null)
|
||||
{
|
||||
offset = collider.Offset,
|
||||
radius = collider.Radius,
|
||||
tailOrNormal = collider.TailOrNormal,
|
||||
colliderType = TranslateColliderType(collider.ColliderType)
|
||||
continue;
|
||||
}
|
||||
|
||||
var startColliderRef = colliderRef.Count;
|
||||
foreach (var collider in colliderGroup.Colliders)
|
||||
{
|
||||
if (collider == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (_colliders.Contains(collider))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var colliderTransformIndex = GetOrAddColliderTransform(collider.transform);
|
||||
|
||||
colliderRef.Add(colliderInfo.Count);
|
||||
colliderInfo.Add(new BlittableCollider
|
||||
{
|
||||
offset = collider.Offset,
|
||||
radius = collider.Radius,
|
||||
tailOrNormal = collider.TailOrNormal,
|
||||
colliderType = TranslateColliderType(collider.ColliderType),
|
||||
transformIndex = colliderTransformIndex,
|
||||
});
|
||||
_colliders.Add(collider);
|
||||
}
|
||||
|
||||
_colliderGroups.Add(colliderGroup);
|
||||
colliderGroups.Add(new ArrayRange
|
||||
{
|
||||
Start = startColliderRef,
|
||||
End = colliderRef.Count,
|
||||
});
|
||||
_colliderTransforms.Add(collider.transform);
|
||||
}
|
||||
_colliderTransformAccessArray = new(_colliderTransforms.ToArray(), 128);
|
||||
_colliders = new(colliders.ToArray(), Allocator.Persistent);
|
||||
_currentColliders = new(_colliderTransforms.Count, Allocator.Persistent);
|
||||
_colliderInfo = new(colliderInfo.ToArray(), Allocator.Persistent);
|
||||
|
||||
_colliderRef = new(colliderRef.ToArray(), Allocator.Persistent);
|
||||
_colliderGroup = new(colliderGroups.ToArray(), Allocator.Persistent);
|
||||
|
||||
//
|
||||
// warps
|
||||
// warps => particles
|
||||
//
|
||||
_transforms = new();
|
||||
List<TransformInfo> info = new();
|
||||
List<Vector3> positions = new();
|
||||
List<WarpInfo> warps = new();
|
||||
List<int> colliderGroupRef = new();
|
||||
var warpSrcs = vrm.GetComponentsInChildren<Components.ClothWarpRoot>();
|
||||
for (int warpIndex = 0; warpIndex < warpSrcs.Length; ++warpIndex)
|
||||
{
|
||||
|
|
@ -145,14 +236,16 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
{
|
||||
GetTransformIndex(warp.Center, new TransformInfo
|
||||
{
|
||||
TransformType = TransformType.Center
|
||||
TransformType = TransformType.Center,
|
||||
WarpIndex = warpIndex,
|
||||
}, info, positions);
|
||||
start += 1;
|
||||
}
|
||||
|
||||
var warpRootParentTransformIndex = GetTransformIndex(warp.transform.parent, new TransformInfo
|
||||
{
|
||||
TransformType = TransformType.WarpRootParent
|
||||
TransformType = TransformType.WarpRootParent,
|
||||
WarpIndex = warpIndex,
|
||||
}, info, positions);
|
||||
Debug.Assert(warpRootParentTransformIndex.index != -1);
|
||||
if (warpRootParentTransformIndex.isNew)
|
||||
|
|
@ -166,31 +259,81 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
ParentIndex = warpRootParentTransformIndex.index,
|
||||
InitLocalPosition = vrm.DefaultTransformStates[warp.transform].LocalPosition,
|
||||
InitLocalRotation = vrm.DefaultTransformStates[warp.transform].LocalRotation,
|
||||
Settings = warp.BaseSettings,
|
||||
WarpIndex = warpIndex,
|
||||
}, info, positions);
|
||||
Debug.Assert(warpRootTransformIndex.index != -1);
|
||||
Debug.Assert(warpRootTransformIndex.isNew);
|
||||
|
||||
var parentIndex = warpRootTransformIndex.index;
|
||||
foreach (var particle in warp.Particles)
|
||||
var colliderGroupRefStart = colliderGroupRef.Count;
|
||||
if (warpRootTransformIndex.isNew)
|
||||
{
|
||||
if (particle.Transform != null && particle.Mode != Components.ClothWarpRoot.ParticleMode.Disabled)
|
||||
// var parentIndex = warpRootTransformIndex.index;
|
||||
|
||||
Func<int, int> GetFirstSiblingIndex = (parent) =>
|
||||
{
|
||||
var outputParticleTransformIndex = GetTransformIndex((Transform)particle.Transform, new TransformInfo
|
||||
for (int i = 0; i < info.Count; ++i)
|
||||
{
|
||||
TransformType = TransformType.Particle,
|
||||
ParentIndex = parentIndex,
|
||||
InitLocalPosition = vrm.DefaultTransformStates[(Transform)particle.Transform].LocalPosition,
|
||||
InitLocalRotation = vrm.DefaultTransformStates[(Transform)particle.Transform].LocalRotation,
|
||||
Settings = particle.Settings,
|
||||
}, info, positions);
|
||||
parentIndex = outputParticleTransformIndex.index;
|
||||
if (info[i].ParentIndex == parent)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new Exception();
|
||||
};
|
||||
|
||||
HashSet<int> parentIndexSet = new();
|
||||
foreach (var particle in warp.Particles)
|
||||
{
|
||||
if (particle.Transform != null && particle.Mode != Components.ClothWarpRoot.ParticleMode.Disabled)
|
||||
{
|
||||
var parentIndex = _transforms.IndexOf(GetParent(particle.Transform, warp.transform));
|
||||
BranchInfo? branch = default;
|
||||
if (parentIndexSet.Contains(parentIndex))
|
||||
{
|
||||
branch = new BranchInfo
|
||||
{
|
||||
FirstSiblingIndex = GetFirstSiblingIndex(parentIndex),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
parentIndexSet.Add(parentIndex);
|
||||
}
|
||||
|
||||
var outputParticleTransformIndex = GetTransformIndex(particle.Transform, new TransformInfo
|
||||
{
|
||||
TransformType = TransformType.Particle,
|
||||
ParentIndex = parentIndex,
|
||||
InitLocalPosition = vrm.DefaultTransformStates[particle.Transform].LocalPosition,
|
||||
InitLocalRotation = vrm.DefaultTransformStates[particle.Transform].LocalRotation,
|
||||
Settings = particle.Settings,
|
||||
WarpIndex = warpIndex,
|
||||
Branch = branch,
|
||||
}, info, positions);
|
||||
// parentIndex = outputParticleTransformIndex.index;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var group in warp.ColliderGroups)
|
||||
{
|
||||
if (group != null)
|
||||
{
|
||||
colliderGroupRef.Add(_colliderGroups.IndexOf(group));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
warps.Add(new WarpInfo
|
||||
{
|
||||
StartIndex = start,
|
||||
EndIndex = _transforms.Count,
|
||||
PrticleRange = new ArrayRange
|
||||
{
|
||||
Start = start,
|
||||
End = _transforms.Count,
|
||||
},
|
||||
ColliderGroupRefRange = new ArrayRange
|
||||
{
|
||||
Start = colliderGroupRefStart,
|
||||
End = colliderGroupRef.Count,
|
||||
},
|
||||
});
|
||||
|
||||
await awaitCaller.NextFrame();
|
||||
|
|
@ -204,18 +347,48 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
_nextPositions = new(pos.Length, Allocator.Persistent);
|
||||
_nextRotations = new(pos.Length, Allocator.Persistent);
|
||||
_info = new(info.ToArray(), Allocator.Persistent);
|
||||
_strandCollision = new(pos.Length, Allocator.Persistent);
|
||||
_clothCollisionCount = new(pos.Length, Allocator.Persistent);
|
||||
_clothCollisionDelta = new(pos.Length, Allocator.Persistent);
|
||||
_forces = new(pos.Length, Allocator.Persistent);
|
||||
_warpCollision = new(pos.Length, Allocator.Persistent);
|
||||
_rectCollisionCount = new(pos.Length, Allocator.Persistent);
|
||||
_rectCollisionDelta = new(pos.Length, Allocator.Persistent);
|
||||
_impulsiveForces = new(pos.Length, Allocator.Persistent);
|
||||
|
||||
//
|
||||
// cloths
|
||||
//
|
||||
var clothRects = new ClothRectList(_transforms, vrm);
|
||||
_clothRects = new(clothRects.List.ToArray(), Allocator.Persistent);
|
||||
_clothRectResults = new(clothRects.List.Count, Allocator.Persistent);
|
||||
_clothUsedParticles = new(clothRects.ClothUsedParticles, Allocator.Persistent);
|
||||
_building = false;
|
||||
|
||||
List<ClothInfo> cloths = new();
|
||||
foreach (var grid in clothRects.ClothGrids)
|
||||
{
|
||||
var colliderGroupRefStart = colliderGroupRef.Count;
|
||||
HashSet<VRM10SpringBoneColliderGroup> groups = new();
|
||||
foreach (var warp in grid.Warps)
|
||||
{
|
||||
foreach (var group in warp.ColliderGroups)
|
||||
{
|
||||
if (group != null && !groups.Contains(group))
|
||||
{
|
||||
groups.Add(group);
|
||||
colliderGroupRef.Add(_colliderGroups.IndexOf(group));
|
||||
}
|
||||
}
|
||||
}
|
||||
cloths.Add(new ClothInfo
|
||||
{
|
||||
ColliderGroupRefRange = new ArrayRange
|
||||
{
|
||||
Start = colliderGroupRefStart,
|
||||
End = colliderGroupRef.Count,
|
||||
},
|
||||
});
|
||||
}
|
||||
_cloths = new(cloths.ToArray(), Allocator.Persistent);
|
||||
|
||||
_colliderGroupRef = new(colliderGroupRef.ToArray(), Allocator.Persistent);
|
||||
}
|
||||
|
||||
private static BlittableColliderType TranslateColliderType(VRM10SpringBoneColliderTypes colliderType)
|
||||
|
|
@ -259,10 +432,10 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
Info = _info,
|
||||
InputData = _inputData,
|
||||
CurrentPositions = _currentPositions,
|
||||
Forces = _forces,
|
||||
ImpulsiveForces = _impulsiveForces,
|
||||
|
||||
CollisionCount = _clothCollisionCount,
|
||||
CollisionDelta = _clothCollisionDelta,
|
||||
CollisionCount = _rectCollisionCount,
|
||||
CollisionDelta = _rectCollisionDelta,
|
||||
}.Schedule(_transformAccessArray, handle);
|
||||
|
||||
// spring(cloth weft)
|
||||
|
|
@ -271,8 +444,8 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
ClothRects = _clothRects,
|
||||
CurrentPositions = _currentPositions,
|
||||
|
||||
Force = _forces,
|
||||
}.Schedule(_clothRects.Length, 128, handle);
|
||||
ImpulsiveForces = _impulsiveForces,
|
||||
}.Schedule(_clothRects.Length, 1, handle);
|
||||
|
||||
// verlet
|
||||
handle = new VerletJob
|
||||
|
|
@ -282,58 +455,86 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
CurrentTransforms = _inputData,
|
||||
PrevPositions = _prevPositions,
|
||||
CurrentPositions = _currentPositions,
|
||||
Forces = _forces,
|
||||
ImpulsiveForces = _impulsiveForces,
|
||||
|
||||
NextPositions = _nextPositions,
|
||||
NextRotations = _nextRotations,
|
||||
}.Schedule(_info.Length, 128, handle);
|
||||
}.Schedule(_info.Length, 1, handle);
|
||||
|
||||
// 親子の長さで拘束
|
||||
handle = new ParentLengthConstraintJob
|
||||
{
|
||||
Warps = _warps,
|
||||
Info = _info,
|
||||
Data = _inputData,
|
||||
NextPositions = _nextPositions,
|
||||
}.Schedule(_warps.Length, 16, handle);
|
||||
}.Schedule(_warps.Length, 1, handle);
|
||||
|
||||
// collision
|
||||
{
|
||||
var handle0 = new StrandCollisionJob
|
||||
var handle0 = new WarpCollisionJob
|
||||
{
|
||||
Colliders = _colliders,
|
||||
Colliders = _colliderInfo,
|
||||
CurrentColliders = _currentColliders,
|
||||
|
||||
Info = _info,
|
||||
NextPositions = _nextPositions,
|
||||
ClothUsedParticles = _clothUsedParticles,
|
||||
StrandCollision = _strandCollision,
|
||||
}.Schedule(_info.Length, 128, handle);
|
||||
StrandCollision = _warpCollision,
|
||||
|
||||
var handle1 = new ClothCollisionJob
|
||||
Warps = _warps,
|
||||
ColliderGroupRef = _colliderGroupRef,
|
||||
ColliderGroup = _colliderGroup,
|
||||
ColliderRef = _colliderRef,
|
||||
}.Schedule(_info.Length, 1, handle);
|
||||
|
||||
var handle1 = new RectCollisionJob
|
||||
{
|
||||
Colliders = _colliders,
|
||||
ClothRects = _clothRects,
|
||||
ClothRectResults = _clothRectResults,
|
||||
|
||||
Colliders = _colliderInfo,
|
||||
CurrentColliders = _currentColliders,
|
||||
|
||||
Info = _info,
|
||||
NextPositions = _nextPositions,
|
||||
CollisionCount = _clothCollisionCount,
|
||||
CollisionDelta = _clothCollisionDelta,
|
||||
|
||||
Cloths = _cloths,
|
||||
ColliderGroupRef = _colliderGroupRef,
|
||||
ColliderGroup = _colliderGroup,
|
||||
ColliderRef = _colliderRef,
|
||||
}.Schedule(_clothRects.Length, 1, handle);
|
||||
|
||||
handle1 = new RectCollisionReduceJob
|
||||
{
|
||||
ClothRects = _clothRects,
|
||||
}.Schedule(_clothRects.Length, 128, handle);
|
||||
ClothRectResults = _clothRectResults,
|
||||
NextPositions = _nextPositions,
|
||||
|
||||
RectCollisionCount = _rectCollisionCount,
|
||||
RectCollisionDelta = _rectCollisionDelta,
|
||||
}.Schedule(handle1);
|
||||
|
||||
handle = JobHandle.CombineDependencies(handle0, handle1);
|
||||
|
||||
handle = new CollisionApplyJob
|
||||
{
|
||||
ClothUsedParticles = _clothUsedParticles,
|
||||
StrandCollision = _strandCollision,
|
||||
ClothCollisionCount = _clothCollisionCount,
|
||||
ClothCollisionDelta = _clothCollisionDelta,
|
||||
StrandCollision = _warpCollision,
|
||||
RectCollisionCount = _rectCollisionCount,
|
||||
RectCollisionDelta = _rectCollisionDelta,
|
||||
NextPosition = _nextPositions,
|
||||
}.Schedule(_info.Length, 128, handle);
|
||||
}.Schedule(_info.Length, 1, handle);
|
||||
}
|
||||
|
||||
// 親子の長さで拘束. TODO: ApplyRotationJob と合体
|
||||
handle = new ParentLengthConstraintJob
|
||||
{
|
||||
Warps = _warps,
|
||||
Info = _info,
|
||||
Data = _inputData,
|
||||
NextPositions = _nextPositions,
|
||||
}.Schedule(_warps.Length, 1, handle);
|
||||
// NextPositions から NextRotations を作る
|
||||
handle = new ApplyRotationJob
|
||||
{
|
||||
|
|
@ -342,7 +543,7 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
CurrentTransforms = _inputData,
|
||||
NextPositions = _nextPositions,
|
||||
NextRotations = _nextRotations,
|
||||
}.Schedule(_warps.Length, 16, handle);
|
||||
}.Schedule(_warps.Length, 1, handle);
|
||||
|
||||
// output
|
||||
handle = new OutputTransformJob
|
||||
|
|
@ -362,7 +563,7 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
{
|
||||
foreach (var warp in _warps)
|
||||
{
|
||||
for (int i = warp.StartIndex; i < warp.EndIndex; ++i)
|
||||
for (int i = warp.PrticleRange.Start; i < warp.PrticleRange.End; ++i)
|
||||
{
|
||||
var p = _info[i];
|
||||
var t = _transforms[i];
|
||||
|
|
@ -392,11 +593,11 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
break;
|
||||
case TransformType.ClothWarp:
|
||||
Gizmos.color = Color.white;
|
||||
Gizmos.DrawSphere(v, info.Settings.radius);
|
||||
Gizmos.DrawSphere(v, info.Settings.Radius);
|
||||
break;
|
||||
case TransformType.Particle:
|
||||
Gizmos.color = Color.cyan;
|
||||
Gizmos.DrawWireSphere(v, info.Settings.radius);
|
||||
Gizmos.DrawWireSphere(v, info.Settings.Radius);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -408,7 +609,7 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
if (i != -1)
|
||||
{
|
||||
var info = _info[i];
|
||||
info.Settings = jointSettings;
|
||||
info.Settings.FromBlittableJointMutable(jointSettings);
|
||||
_info[i] = info;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,319 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SphereTriangle;
|
||||
using UniGLTF.SpringBoneJobs.Blittables;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Jobs
|
||||
{
|
||||
public struct InputColliderJob : IJobParallelForTransform
|
||||
{
|
||||
[WriteOnly] public NativeArray<Matrix4x4> CurrentCollider;
|
||||
|
||||
public void Execute(int colliderIndex, TransformAccess transform)
|
||||
{
|
||||
CurrentCollider[colliderIndex] = transform.localToWorldMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
public struct StrandCollisionJob : IJobParallelFor
|
||||
{
|
||||
// collider
|
||||
[ReadOnly] public NativeArray<BlittableCollider> Colliders;
|
||||
[ReadOnly] public NativeArray<Matrix4x4> CurrentColliders;
|
||||
|
||||
// particle
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[ReadOnly] public NativeArray<Vector3> NextPositions;
|
||||
[ReadOnly] public NativeArray<bool> ClothUsedParticles;
|
||||
[WriteOnly] public NativeArray<Vector3> StrandCollision;
|
||||
|
||||
public void Execute(int particleIndex)
|
||||
{
|
||||
if (!ClothUsedParticles[particleIndex])
|
||||
{
|
||||
var info = Info[particleIndex];
|
||||
var pos = NextPositions[particleIndex];
|
||||
for (int colliderIndex = 0; colliderIndex < Colliders.Length; ++colliderIndex)
|
||||
{
|
||||
var c = Colliders[colliderIndex];
|
||||
var m = CurrentColliders[colliderIndex];
|
||||
|
||||
if (c.colliderType == BlittableColliderType.Capsule)
|
||||
{
|
||||
if (TryCollideCapsuleAndSphere(m.MultiplyPoint(c.offset), m.MultiplyPoint(c.tailOrNormal), c.radius,
|
||||
pos, info.Settings.radius, out var l))
|
||||
{
|
||||
pos += l.GetDelta(c.radius);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TryCollideSphereAndSphere(m.MultiplyPoint(c.offset), c.radius,
|
||||
pos, info.Settings.radius, out var l))
|
||||
{
|
||||
pos += l.GetDelta(c.radius);
|
||||
}
|
||||
}
|
||||
StrandCollision[particleIndex] = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// collide sphere a and sphere b.
|
||||
/// move sphere b to resolved if collide.
|
||||
/// </summary>
|
||||
/// <param name="from"></param>
|
||||
/// <param name="ra"></param>
|
||||
/// <param name="to"></param>
|
||||
/// <param name="ba"></param>
|
||||
/// <param name="resolved"></param>
|
||||
/// <returns></returns>
|
||||
static bool TryCollideSphereAndSphere(
|
||||
in Vector3 from, float ra,
|
||||
in Vector3 to, float rb,
|
||||
out LineSegment resolved
|
||||
)
|
||||
{
|
||||
var d = Vector3.Distance(from, to);
|
||||
if (d > (ra + rb))
|
||||
{
|
||||
resolved = default;
|
||||
return false;
|
||||
}
|
||||
Vector3 normal = (to - from).normalized;
|
||||
resolved = new(from, from + normal * (d - rb));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// collide capsule and sphere b.
|
||||
/// move sphere b to resolved if collide.
|
||||
/// </summary>
|
||||
/// <param name="capsuleHead"></param>
|
||||
/// <param name="capsuleTail"></param>
|
||||
/// <param name="capsuleRadius"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <param name="rb"></param>
|
||||
static bool TryCollideCapsuleAndSphere(
|
||||
in Vector3 capsuleHead,
|
||||
in Vector3 capsuleTail,
|
||||
float capsuleRadius,
|
||||
in Vector3 b,
|
||||
float rb,
|
||||
out LineSegment resolved
|
||||
)
|
||||
{
|
||||
var P = (capsuleTail - capsuleHead).normalized;
|
||||
var Q = b - capsuleHead;
|
||||
var dot = Vector3.Dot(P, Q);
|
||||
if (dot <= 0)
|
||||
{
|
||||
// head側半球の球判定
|
||||
return TryCollideSphereAndSphere(capsuleHead, capsuleRadius, b, rb, out resolved);
|
||||
}
|
||||
|
||||
var t = dot / P.magnitude;
|
||||
if (t >= 1.0f)
|
||||
{
|
||||
// tail側半球の球判定
|
||||
return TryCollideSphereAndSphere(capsuleTail, capsuleRadius, b, rb, out resolved);
|
||||
}
|
||||
|
||||
// head-tail上の m_transform.position との最近点
|
||||
var p = capsuleHead + P * t;
|
||||
return TryCollideSphereAndSphere(p, capsuleRadius, b, rb, out resolved);
|
||||
}
|
||||
}
|
||||
|
||||
public struct ClothCollisionJob : IJobParallelFor
|
||||
{
|
||||
// collider
|
||||
[ReadOnly] public NativeArray<BlittableCollider> Colliders;
|
||||
[ReadOnly] public NativeArray<Matrix4x4> CurrentColliders;
|
||||
|
||||
// particle
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[ReadOnly] public NativeArray<Vector3> NextPositions;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> CollisionCount;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<Vector3> CollisionDelta;
|
||||
|
||||
// cloth
|
||||
[ReadOnly] public NativeArray<(SpringConstraint, ClothRect)> ClothRects;
|
||||
|
||||
private void CollisionMove(int particleIndex, Vector3 delta)
|
||||
{
|
||||
CollisionCount[particleIndex] += 1;
|
||||
CollisionDelta[particleIndex] += delta;
|
||||
}
|
||||
|
||||
public void Execute(int rectIndex)
|
||||
{
|
||||
var (spring, rect) = ClothRects[rectIndex];
|
||||
|
||||
// using (new ProfileSample("Rect: Prepare"))
|
||||
// _s0.BeginFrame();
|
||||
// _s1.BeginFrame();
|
||||
|
||||
var a = NextPositions[rect._a];
|
||||
var b = NextPositions[rect._b];
|
||||
var c = NextPositions[rect._c];
|
||||
var d = NextPositions[rect._d];
|
||||
var aabb = GetBoundsFrom4(a, b, c, d);
|
||||
|
||||
// d x-x c
|
||||
// |/
|
||||
// a x
|
||||
var _triangle1 = new Triangle(c, d, a);
|
||||
// x c
|
||||
// /|
|
||||
// a x-x b
|
||||
var _triangle0 = new Triangle(a, b, c);
|
||||
|
||||
for (int colliderIndex = 0; colliderIndex < Colliders.Length; ++colliderIndex)
|
||||
{
|
||||
var collider = Colliders[colliderIndex];
|
||||
var collider_matrix = CurrentColliders[colliderIndex];
|
||||
if (!aabb.Intersects(GetBounds(collider, collider_matrix)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 面の片側だけにヒットさせる
|
||||
// 行き過ぎて戻るときに素通りする
|
||||
// var p = _triangle0.Plane.ClosestPointOnPlane(col_pos);
|
||||
// var dot = Vector3.Dot(_triangle0.Plane.normal, col_pos - p);
|
||||
// if (_initialColliderNormalSide[collider] * dot < 0)
|
||||
// {
|
||||
// // 片側
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (TryCollide(collider, collider_matrix, _triangle0, out var l0))
|
||||
{
|
||||
CollisionMove(rect._a, l0.GetDelta(collider.radius));
|
||||
CollisionMove(rect._b, l0.GetDelta(collider.radius));
|
||||
CollisionMove(rect._c, l0.GetDelta(collider.radius));
|
||||
}
|
||||
if (TryCollide(collider, collider_matrix, _triangle1, out var l1))
|
||||
{
|
||||
CollisionMove(rect._c, l1.GetDelta(collider.radius));
|
||||
CollisionMove(rect._d, l1.GetDelta(collider.radius));
|
||||
CollisionMove(rect._a, l1.GetDelta(collider.radius));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool TryCollide(BlittableCollider collider, in Matrix4x4 colliderMatrix, in Triangle t, out LineSegment l)
|
||||
{
|
||||
var col_pos = colliderMatrix.MultiplyPoint(collider.offset);
|
||||
if (collider.colliderType == BlittableColliderType.Capsule)
|
||||
{
|
||||
// capsule
|
||||
var tail_pos = colliderMatrix.MultiplyPoint(collider.tailOrNormal);
|
||||
var result = TriangleCapsuleCollisionSolver.Collide(t, new LineSegment(col_pos, tail_pos), collider.radius);
|
||||
var type = result.TryGetClosest(out l);
|
||||
return type.HasValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// sphere
|
||||
return TryCollideSphere(t, col_pos, collider.radius, out l);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="triangle"></param>
|
||||
/// <param name="collider"></param>
|
||||
/// <param name="radius"></param>
|
||||
/// <returns>collider => 衝突点 への線分を返す</returns>
|
||||
static bool TryCollideSphere(in Triangle triangle, in Vector3 collider, float radius, out LineSegment l)
|
||||
{
|
||||
var p = triangle.Plane.ClosestPointOnPlane(collider);
|
||||
var distance = Vector3.Distance(p, collider);
|
||||
if (distance > radius)
|
||||
{
|
||||
l = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (triangle.IsSameSide(p))
|
||||
{
|
||||
l = new LineSegment(collider, p);
|
||||
return true;
|
||||
}
|
||||
|
||||
var (closestPoint, d) = triangle.GetClosest(collider);
|
||||
if (d > radius)
|
||||
{
|
||||
l = default;
|
||||
return false;
|
||||
}
|
||||
l = new LineSegment(collider, closestPoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Bounds GetBoundsFrom4(in Vector3 a, in Vector3 b, in Vector3 c, in Vector3 d)
|
||||
{
|
||||
var aabb = new Bounds(a, Vector3.zero);
|
||||
aabb.Encapsulate(b);
|
||||
aabb.Encapsulate(c);
|
||||
aabb.Encapsulate(d);
|
||||
return aabb;
|
||||
}
|
||||
|
||||
public static Bounds GetBounds(BlittableCollider collider, Matrix4x4 m)
|
||||
{
|
||||
switch (collider.colliderType)
|
||||
{
|
||||
case BlittableColliderType.Capsule:
|
||||
{
|
||||
var h = m.MultiplyPoint(collider.offset);
|
||||
var t = m.MultiplyPoint(collider.tailOrNormal);
|
||||
var d = h - t;
|
||||
var aabb = new Bounds((h + t) * 0.5f, new Vector3(Mathf.Abs(d.x), Mathf.Abs(d.y), Mathf.Abs(d.z)));
|
||||
aabb.Expand(collider.radius * 2);
|
||||
return aabb;
|
||||
}
|
||||
|
||||
case BlittableColliderType.Sphere:
|
||||
return new Bounds(m.MultiplyPoint(collider.offset), new Vector3(collider.radius, collider.radius, collider.radius));
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct CollisionApplyJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<bool> ClothUsedParticles;
|
||||
[ReadOnly] public NativeArray<Vector3> StrandCollision;
|
||||
[ReadOnly] public NativeArray<int> ClothCollisionCount;
|
||||
[ReadOnly] public NativeArray<Vector3> ClothCollisionDelta;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<Vector3> NextPosition;
|
||||
|
||||
public void Execute(int particleIndex)
|
||||
{
|
||||
if (ClothUsedParticles[particleIndex])
|
||||
{
|
||||
if (ClothCollisionCount[particleIndex] > 0)
|
||||
{
|
||||
NextPosition[particleIndex] += (ClothCollisionDelta[particleIndex] / ClothCollisionCount[particleIndex]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NextPosition[particleIndex] = StrandCollision[particleIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Jobs
|
||||
{
|
||||
public struct ClothInfo
|
||||
{
|
||||
public ArrayRange ColliderGroupRefRange;
|
||||
}
|
||||
|
||||
public struct InputColliderJob : IJobParallelForTransform
|
||||
{
|
||||
[WriteOnly] public NativeArray<Matrix4x4> CurrentCollider;
|
||||
|
||||
public void Execute(int colliderIndex, TransformAccess transform)
|
||||
{
|
||||
CurrentCollider[colliderIndex] = transform.localToWorldMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
public struct CollisionApplyJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<bool> ClothUsedParticles;
|
||||
[ReadOnly] public NativeArray<Vector3> StrandCollision;
|
||||
|
||||
[ReadOnly] public NativeArray<int> RectCollisionCount;
|
||||
[ReadOnly] public NativeArray<Vector3> RectCollisionDelta;
|
||||
public NativeArray<Vector3> NextPosition;
|
||||
|
||||
public void Execute(int particleIndex)
|
||||
{
|
||||
if (ClothUsedParticles[particleIndex])
|
||||
{
|
||||
var count = RectCollisionCount[particleIndex];
|
||||
if (count > 0)
|
||||
{
|
||||
// 一つの頂点が最大で近接する4つの rect で当たり判定をされる
|
||||
// 衝突結果を足して割る
|
||||
NextPosition[particleIndex] += RectCollisionDelta[particleIndex] / count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NextPosition[particleIndex] = StrandCollision[particleIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,16 +12,31 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
{
|
||||
[ReadOnly] public NativeArray<WarpInfo> Warps;
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[ReadOnly] public NativeArray<TransformData> Data;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<Vector3> NextPositions;
|
||||
public void Execute(int warpIndex)
|
||||
{
|
||||
var warp = Warps[warpIndex];
|
||||
for (int particleIndex = warp.StartIndex; particleIndex < warp.EndIndex - 1; ++particleIndex)
|
||||
for (int particleIndex = warp.PrticleRange.Start; particleIndex < warp.PrticleRange.End - 1; ++particleIndex)
|
||||
{
|
||||
// 位置を長さで拘束
|
||||
NextPositions[particleIndex + 1] = NextPositions[particleIndex] +
|
||||
(NextPositions[particleIndex + 1] - NextPositions[particleIndex]).normalized
|
||||
* Info[particleIndex + 1].InitLocalPosition.magnitude;
|
||||
var particle = Info[particleIndex + 1];
|
||||
if (particle.Branch.HasValue)
|
||||
{
|
||||
var branch = particle.Branch.Value;
|
||||
// 1番目の兄弟の情報を使う
|
||||
// 枝分かれ。特別処理
|
||||
var firstSibling = Info[branch.FirstSiblingIndex];
|
||||
var firstPosition = NextPositions[branch.FirstSiblingIndex];
|
||||
var local_d = particle.InitLocalPosition - firstSibling.InitLocalPosition;
|
||||
NextPositions[particleIndex + 1] = firstPosition + Data[particle.ParentIndex].Rotation * local_d;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 位置を長さで拘束
|
||||
NextPositions[particleIndex + 1] = NextPositions[particleIndex] +
|
||||
(NextPositions[particleIndex + 1] - NextPositions[particleIndex]).normalized
|
||||
* Info[particleIndex + 1].InitLocalPosition.magnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,21 +44,20 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
public struct WeftConstraintJob : IJobParallelFor
|
||||
{
|
||||
public float Hookean;
|
||||
FrameInfo Frame;
|
||||
[ReadOnly] public NativeArray<(SpringConstraint, ClothRect)> ClothRects;
|
||||
[ReadOnly] public NativeArray<(int, SpringConstraint, ClothRect)> ClothRects;
|
||||
[ReadOnly] public NativeArray<Vector3> CurrentPositions;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<Vector3> Force;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<Vector3> ImpulsiveForces;
|
||||
|
||||
public void Execute(int rectIndex)
|
||||
{
|
||||
var (spring, rect) = ClothRects[rectIndex];
|
||||
var (clothGridIndex, spring, rect) = ClothRects[rectIndex];
|
||||
var p0 = CurrentPositions[spring._p0];
|
||||
var p1 = CurrentPositions[spring._p1];
|
||||
var d = Vector3.Distance(p0, p1);
|
||||
var f = (d - spring._rest) * Hookean;
|
||||
var dx = (p1 - p0).normalized * f / Frame.SqDeltaTime;
|
||||
Force[spring._p0] += dx;
|
||||
Force[spring._p1] -= dx;
|
||||
var dx = (p1 - p0).normalized * f;
|
||||
ImpulsiveForces[spring._p0] += dx;
|
||||
ImpulsiveForces[spring._p1] -= dx;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +74,7 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
public void Execute(int warpIndex)
|
||||
{
|
||||
var warp = Warps[warpIndex];
|
||||
for (int particleIndex = warp.StartIndex; particleIndex < warp.EndIndex - 1; ++particleIndex)
|
||||
for (int particleIndex = warp.PrticleRange.Start; particleIndex < warp.PrticleRange.End - 1; ++particleIndex)
|
||||
{
|
||||
//回転を適用
|
||||
var p = Info[particleIndex];
|
||||
|
|
|
|||
|
|
@ -1,66 +1,52 @@
|
|||
using System;
|
||||
using UniGLTF.SpringBoneJobs.Blittables;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Jobs
|
||||
{
|
||||
public struct TransformInfo
|
||||
/// <summary>
|
||||
/// UniGLTF.SpringBoneJobs.Blittables.BlittableJointMutable と同じ。
|
||||
/// Range が違う。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct ParticleSettings
|
||||
{
|
||||
public TransformType TransformType;
|
||||
public int ParentIndex;
|
||||
public Quaternion InitLocalRotation;
|
||||
public Vector3 InitLocalPosition;
|
||||
public BlittableJointMutable Settings;
|
||||
}
|
||||
[Range(0, 1)]
|
||||
public float Stiffness;
|
||||
[Range(0, 1)]
|
||||
public float Deceleration;
|
||||
public Vector3 Gravity;
|
||||
public float Radius;
|
||||
|
||||
public struct TransformData
|
||||
{
|
||||
public Matrix4x4 ToWorld;
|
||||
public Vector3 Position => ToWorld.GetPosition();
|
||||
public Quaternion Rotation => ToWorld.rotation;
|
||||
public Matrix4x4 ToLocal;
|
||||
|
||||
public TransformData(TransformAccess t)
|
||||
public static readonly ParticleSettings Default = new ParticleSettings
|
||||
{
|
||||
ToWorld = t.localToWorldMatrix;
|
||||
ToLocal = t.worldToLocalMatrix;
|
||||
Stiffness = 0.08f,
|
||||
Gravity = new Vector3(0, -1.0f, 0),
|
||||
Deceleration = 0.4f,
|
||||
Radius = 0.02f,
|
||||
};
|
||||
|
||||
public void FromBlittableJointMutable(BlittableJointMutable src)
|
||||
{
|
||||
Stiffness = src.stiffnessForce;
|
||||
Gravity = src.gravityDir * src.gravityPower;
|
||||
Deceleration = src.dragForce;
|
||||
Radius = src.radius;
|
||||
}
|
||||
public TransformData(Transform t)
|
||||
|
||||
public BlittableJointMutable ToBlittableJointMutable()
|
||||
{
|
||||
ToWorld = t.localToWorldMatrix;
|
||||
ToLocal = t.worldToLocalMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
// [Input]
|
||||
public struct InputTransformJob : IJobParallelForTransform
|
||||
{
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[WriteOnly] public NativeArray<TransformData> InputData;
|
||||
[WriteOnly] public NativeArray<Vector3> CurrentPositions;
|
||||
|
||||
[WriteOnly] public NativeArray<int> CollisionCount;
|
||||
[WriteOnly] public NativeArray<Vector3> CollisionDelta;
|
||||
[WriteOnly] public NativeArray<Vector3> Forces;
|
||||
|
||||
public void Execute(int particleIndex, TransformAccess transform)
|
||||
{
|
||||
InputData[particleIndex] = new TransformData(transform);
|
||||
|
||||
var particle = Info[particleIndex];
|
||||
if (particle.TransformType.PositionInput())
|
||||
return new BlittableJointMutable
|
||||
{
|
||||
// only warp root position update
|
||||
CurrentPositions[particleIndex] = transform.position;
|
||||
}
|
||||
|
||||
// clear cloth
|
||||
CollisionCount[particleIndex] = 0;
|
||||
CollisionDelta[particleIndex] = Vector3.zero;
|
||||
Forces[particleIndex] = Vector3.zero;
|
||||
stiffnessForce = Stiffness,
|
||||
gravityPower = 1.0f,
|
||||
gravityDir = Gravity,
|
||||
dragForce = Deceleration,
|
||||
radius = Radius,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +55,7 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
public FrameInfo Frame;
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[ReadOnly] public NativeArray<TransformData> CurrentTransforms;
|
||||
[ReadOnly] public NativeArray<Vector3> Forces;
|
||||
[ReadOnly] public NativeArray<Vector3> ImpulsiveForces;
|
||||
[ReadOnly] public NativeArray<Vector3> CurrentPositions;
|
||||
[ReadOnly] public NativeArray<Vector3> PrevPositions;
|
||||
[WriteOnly] public NativeArray<Vector3> NextPositions;
|
||||
|
|
@ -80,18 +66,19 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
var particle = Info[particleIndex];
|
||||
if (particle.TransformType.Movable())
|
||||
{
|
||||
var parentIndex = particle.ParentIndex;
|
||||
// var parentPosition = CurrentPositions[parentIndex];
|
||||
var parent = Info[parentIndex];
|
||||
var parent = Info[particle.ParentIndex];
|
||||
var parentParentRotation = CurrentTransforms[parent.ParentIndex].Rotation;
|
||||
|
||||
var external = (particle.Settings.gravityDir * particle.Settings.gravityPower + Frame.Force) * Frame.DeltaTime;
|
||||
var local_rest = parentParentRotation * parent.InitLocalRotation * particle.InitLocalPosition;
|
||||
var world_rest = CurrentPositions[particle.ParentIndex] + local_rest;
|
||||
var resilience_force = world_rest - CurrentPositions[particleIndex];
|
||||
var velocity = (CurrentPositions[particleIndex] - PrevPositions[particleIndex]) * (1.0f - particle.Settings.Deceleration);
|
||||
|
||||
var newPosition = CurrentPositions[particleIndex]
|
||||
+ (CurrentPositions[particleIndex] - PrevPositions[particleIndex]) * (1.0f - particle.Settings.dragForce)
|
||||
+ parentParentRotation * parent.InitLocalRotation * particle.InitLocalPosition *
|
||||
particle.Settings.stiffnessForce * Frame.DeltaTime // 親の回転による子ボーンの移動目標
|
||||
+ external
|
||||
+ velocity
|
||||
+ ImpulsiveForces[particleIndex]
|
||||
+ resilience_force * particle.Settings.Stiffness
|
||||
+ (particle.Settings.Gravity + Frame.Force) * Frame.SqDeltaTime
|
||||
;
|
||||
|
||||
NextPositions[particleIndex] = newPosition;
|
||||
|
|
@ -105,19 +92,4 @@ namespace UniVRM10.ClothWarp.Jobs
|
|||
NextRotations[particleIndex] = CurrentTransforms[particleIndex].Rotation;
|
||||
}
|
||||
}
|
||||
|
||||
// [Output]
|
||||
public struct OutputTransformJob : IJobParallelForTransform
|
||||
{
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[ReadOnly] public NativeArray<Quaternion> NextRotations;
|
||||
public void Execute(int particleIndex, TransformAccess transform)
|
||||
{
|
||||
var info = Info[particleIndex];
|
||||
if (info.TransformType.Writable())
|
||||
{
|
||||
transform.rotation = NextRotations[particleIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
using System;
|
||||
using SphereTriangle;
|
||||
using UniGLTF.SpringBoneJobs.Blittables;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Jobs
|
||||
{
|
||||
public struct RectCollisionJob : IJobParallelFor
|
||||
{
|
||||
// cloth
|
||||
[ReadOnly] public NativeArray<(int, SpringConstraint, ClothRect)> ClothRects;
|
||||
[WriteOnly] public NativeArray<(Vector3, Vector3, Vector3, Vector3)> ClothRectResults;
|
||||
|
||||
// collider
|
||||
[ReadOnly] public NativeArray<BlittableCollider> Colliders;
|
||||
[ReadOnly] public NativeArray<Matrix4x4> CurrentColliders;
|
||||
|
||||
// particle
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[ReadOnly] public NativeArray<Vector3> NextPositions;
|
||||
|
||||
// collider group
|
||||
[ReadOnly] public NativeArray<ClothInfo> Cloths;
|
||||
[ReadOnly] public NativeArray<int> ColliderGroupRef;
|
||||
[ReadOnly] public NativeArray<ArrayRange> ColliderGroup;
|
||||
[ReadOnly] public NativeArray<int> ColliderRef;
|
||||
|
||||
public void Execute(int rectIndex)
|
||||
{
|
||||
var (clothGridIndex, spring, rect) = ClothRects[rectIndex];
|
||||
|
||||
var a = NextPositions[rect._a];
|
||||
var b = NextPositions[rect._b];
|
||||
var c = NextPositions[rect._c];
|
||||
var d = NextPositions[rect._d];
|
||||
var aabb = GetBoundsFrom4(a, b, c, d);
|
||||
|
||||
// d x-x c
|
||||
// |/
|
||||
// a x
|
||||
var _triangle1 = new Triangle(c, d, a);
|
||||
// x c
|
||||
// /|
|
||||
// a x-x b
|
||||
var _triangle0 = new Triangle(a, b, c);
|
||||
|
||||
var cloth = Cloths[clothGridIndex];
|
||||
|
||||
for (int groupRefIndex = cloth.ColliderGroupRefRange.Start; groupRefIndex < cloth.ColliderGroupRefRange.End; ++groupRefIndex)
|
||||
{
|
||||
var groupIndex = ColliderGroupRef[groupRefIndex];
|
||||
|
||||
var group = ColliderGroup[groupIndex];
|
||||
for (int colliderRefIndex = group.Start; colliderRefIndex < group.End; ++colliderRefIndex)
|
||||
{
|
||||
var colliderIndex = ColliderRef[colliderRefIndex];
|
||||
var collider = Colliders[colliderIndex];
|
||||
var collider_matrix = CurrentColliders[collider.transformIndex];
|
||||
if (!aabb.Intersects(GetBounds(collider, collider_matrix)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 面の片側だけにヒットさせる
|
||||
// 行き過ぎて戻るときに素通りする
|
||||
// var p = _triangle0.Plane.ClosestPointOnPlane(col_pos);
|
||||
// var dot = Vector3.Dot(_triangle0.Plane.normal, col_pos - p);
|
||||
// if (_initialColliderNormalSide[collider] * dot < 0)
|
||||
// {
|
||||
// // 片側
|
||||
// continue;
|
||||
// }
|
||||
|
||||
var abc = TryCollide(collider, collider_matrix, _triangle0, out var l0);
|
||||
var cda = TryCollide(collider, collider_matrix, _triangle1, out var l1);
|
||||
if (!Info[rect._c].TransformType.Movable())
|
||||
{
|
||||
// cloth の上端。cd が固定
|
||||
if (abc)
|
||||
{
|
||||
a += l0.GetDelta(collider.radius);
|
||||
b += l0.GetDelta(collider.radius);
|
||||
}
|
||||
else if (cda)
|
||||
{
|
||||
a += l1.GetDelta(collider.radius);
|
||||
b += l1.GetDelta(collider.radius);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (abc && cda)
|
||||
{
|
||||
a += l0.GetDelta(collider.radius);
|
||||
b += l0.GetDelta(collider.radius);
|
||||
c += l1.GetDelta(collider.radius);
|
||||
d += l1.GetDelta(collider.radius);
|
||||
}
|
||||
else if (abc)
|
||||
{
|
||||
a += l0.GetDelta(collider.radius);
|
||||
b += l0.GetDelta(collider.radius);
|
||||
c += l0.GetDelta(collider.radius);
|
||||
}
|
||||
else if (cda)
|
||||
{
|
||||
c += l1.GetDelta(collider.radius);
|
||||
d += l1.GetDelta(collider.radius);
|
||||
a += l1.GetDelta(collider.radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClothRectResults[rectIndex] = (a, b, c, d);
|
||||
}
|
||||
|
||||
static bool TryCollide(BlittableCollider collider, in Matrix4x4 colliderMatrix, in Triangle t, out LineSegment l)
|
||||
{
|
||||
var col_pos = colliderMatrix.MultiplyPoint(collider.offset);
|
||||
if (collider.colliderType == BlittableColliderType.Capsule)
|
||||
{
|
||||
// capsule
|
||||
var tail_pos = colliderMatrix.MultiplyPoint(collider.tailOrNormal);
|
||||
var result = TriangleCapsuleCollisionSolver.Collide(t, new LineSegment(col_pos, tail_pos), collider.radius);
|
||||
var type = result.TryGetClosest(out l);
|
||||
return type.HasValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// sphere
|
||||
return TryCollideSphere(t, col_pos, collider.radius, out l);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="triangle"></param>
|
||||
/// <param name="collider"></param>
|
||||
/// <param name="radius"></param>
|
||||
/// <returns>collider => 衝突点 への線分を返す</returns>
|
||||
static bool TryCollideSphere(in Triangle triangle, in Vector3 collider, float radius, out LineSegment l)
|
||||
{
|
||||
var p = triangle.Plane.ClosestPointOnPlane(collider);
|
||||
var distance = Vector3.Distance(p, collider);
|
||||
if (distance > radius)
|
||||
{
|
||||
l = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (triangle.IsSameSide(p))
|
||||
{
|
||||
l = new LineSegment(collider, p);
|
||||
return true;
|
||||
}
|
||||
|
||||
var (closestPoint, d) = triangle.GetClosest(collider);
|
||||
if (d > radius)
|
||||
{
|
||||
l = default;
|
||||
return false;
|
||||
}
|
||||
l = new LineSegment(collider, closestPoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Bounds GetBoundsFrom4(in Vector3 a, in Vector3 b, in Vector3 c, in Vector3 d)
|
||||
{
|
||||
var aabb = new Bounds(a, Vector3.zero);
|
||||
aabb.Encapsulate(b);
|
||||
aabb.Encapsulate(c);
|
||||
aabb.Encapsulate(d);
|
||||
return aabb;
|
||||
}
|
||||
|
||||
public static Bounds GetBounds(BlittableCollider collider, Matrix4x4 m)
|
||||
{
|
||||
switch (collider.colliderType)
|
||||
{
|
||||
case BlittableColliderType.Capsule:
|
||||
{
|
||||
var h = m.MultiplyPoint(collider.offset);
|
||||
var t = m.MultiplyPoint(collider.tailOrNormal);
|
||||
var d = h - t;
|
||||
var aabb = new Bounds((h + t) * 0.5f, new Vector3(Mathf.Abs(d.x), Mathf.Abs(d.y), Mathf.Abs(d.z)));
|
||||
aabb.Expand(collider.radius * 2);
|
||||
return aabb;
|
||||
}
|
||||
|
||||
case BlittableColliderType.Sphere:
|
||||
return new Bounds(m.MultiplyPoint(collider.offset), new Vector3(collider.radius, collider.radius, collider.radius));
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct RectCollisionReduceJob : IJob
|
||||
{
|
||||
[ReadOnly] public NativeArray<(int, SpringConstraint, ClothRect)> ClothRects;
|
||||
[ReadOnly] public NativeArray<(Vector3, Vector3, Vector3, Vector3)> ClothRectResults;
|
||||
[ReadOnly] public NativeArray<Vector3> NextPositions;
|
||||
|
||||
public NativeArray<int> RectCollisionCount;
|
||||
public NativeArray<Vector3> RectCollisionDelta;
|
||||
public void Execute()
|
||||
{
|
||||
for (int rectIndex = 0; rectIndex < ClothRects.Length; ++rectIndex)
|
||||
{
|
||||
var (clothGridIndex, spring, rect) = ClothRects[rectIndex];
|
||||
var (a, b, c, d) = ClothRectResults[rectIndex];
|
||||
|
||||
if (a != NextPositions[rect._a])
|
||||
{
|
||||
RectCollisionDelta[rect._a] += a - NextPositions[rect._a];
|
||||
RectCollisionCount[rect._a] += 1;
|
||||
}
|
||||
if (b != NextPositions[rect._b])
|
||||
{
|
||||
RectCollisionDelta[rect._b] += b - NextPositions[rect._b];
|
||||
RectCollisionCount[rect._b] += 1;
|
||||
}
|
||||
if (c != NextPositions[rect._c])
|
||||
{
|
||||
RectCollisionDelta[rect._c] += c - NextPositions[rect._c];
|
||||
RectCollisionCount[rect._c] += 1;
|
||||
}
|
||||
if (d != NextPositions[rect._d])
|
||||
{
|
||||
RectCollisionDelta[rect._d] += d - NextPositions[rect._d];
|
||||
RectCollisionCount[rect._d] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 127d372d227187449960f33a08791017
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Jobs
|
||||
{
|
||||
public struct BranchInfo
|
||||
{
|
||||
public int FirstSiblingIndex;
|
||||
}
|
||||
|
||||
public struct TransformInfo
|
||||
{
|
||||
public TransformType TransformType;
|
||||
public int ParentIndex;
|
||||
public Quaternion InitLocalRotation;
|
||||
public Vector3 InitLocalPosition;
|
||||
public ParticleSettings Settings;
|
||||
public int WarpIndex;
|
||||
public BranchInfo? Branch;
|
||||
}
|
||||
|
||||
public struct TransformData
|
||||
{
|
||||
public Matrix4x4 ToWorld;
|
||||
public Vector3 Position => ToWorld.GetPosition();
|
||||
public Quaternion Rotation => ToWorld.rotation;
|
||||
public Matrix4x4 ToLocal;
|
||||
|
||||
public TransformData(TransformAccess t)
|
||||
{
|
||||
ToWorld = t.localToWorldMatrix;
|
||||
ToLocal = t.worldToLocalMatrix;
|
||||
}
|
||||
public TransformData(Transform t)
|
||||
{
|
||||
ToWorld = t.localToWorldMatrix;
|
||||
ToLocal = t.worldToLocalMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
// [Input]
|
||||
public struct InputTransformJob : IJobParallelForTransform
|
||||
{
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[WriteOnly] public NativeArray<TransformData> InputData;
|
||||
[WriteOnly] public NativeArray<Vector3> CurrentPositions;
|
||||
|
||||
[WriteOnly] public NativeArray<int> CollisionCount;
|
||||
[WriteOnly] public NativeArray<Vector3> CollisionDelta;
|
||||
[WriteOnly] public NativeArray<Vector3> ImpulsiveForces;
|
||||
|
||||
public void Execute(int particleIndex, TransformAccess transform)
|
||||
{
|
||||
InputData[particleIndex] = new TransformData(transform);
|
||||
|
||||
var particle = Info[particleIndex];
|
||||
if (particle.TransformType.PositionInput())
|
||||
{
|
||||
// only warp root position update
|
||||
CurrentPositions[particleIndex] = transform.position;
|
||||
}
|
||||
|
||||
// clear cloth
|
||||
CollisionCount[particleIndex] = 0;
|
||||
CollisionDelta[particleIndex] = Vector3.zero;
|
||||
ImpulsiveForces[particleIndex] = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
// [Output]
|
||||
public struct OutputTransformJob : IJobParallelForTransform
|
||||
{
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[ReadOnly] public NativeArray<Quaternion> NextRotations;
|
||||
public void Execute(int particleIndex, TransformAccess transform)
|
||||
{
|
||||
var info = Info[particleIndex];
|
||||
if (info.TransformType.Writable())
|
||||
{
|
||||
transform.rotation = NextRotations[particleIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5f3379ab5e1202d43a95e72ece6bda3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +1,14 @@
|
|||
namespace UniVRM10.ClothWarp.Jobs
|
||||
{
|
||||
public struct ArrayRange
|
||||
{
|
||||
public int Start;
|
||||
public int End;
|
||||
}
|
||||
|
||||
public struct WarpInfo
|
||||
{
|
||||
public int StartIndex;
|
||||
public int EndIndex;
|
||||
public ArrayRange PrticleRange;
|
||||
public ArrayRange ColliderGroupRefRange;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
using SphereTriangle;
|
||||
using UniGLTF.SpringBoneJobs.Blittables;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10.ClothWarp.Jobs
|
||||
{
|
||||
public struct WarpCollisionJob : IJobParallelFor
|
||||
{
|
||||
// collider
|
||||
[ReadOnly] public NativeArray<BlittableCollider> Colliders;
|
||||
[ReadOnly] public NativeArray<Matrix4x4> CurrentColliders;
|
||||
|
||||
// particle
|
||||
[ReadOnly] public NativeArray<TransformInfo> Info;
|
||||
[ReadOnly] public NativeArray<Vector3> NextPositions;
|
||||
[ReadOnly] public NativeArray<bool> ClothUsedParticles;
|
||||
[WriteOnly] public NativeArray<Vector3> StrandCollision;
|
||||
|
||||
// collider group
|
||||
[ReadOnly] public NativeArray<WarpInfo> Warps;
|
||||
[ReadOnly] public NativeArray<int> ColliderGroupRef;
|
||||
[ReadOnly] public NativeArray<ArrayRange> ColliderGroup;
|
||||
[ReadOnly] public NativeArray<int> ColliderRef;
|
||||
|
||||
public void Execute(int particleIndex)
|
||||
{
|
||||
if (
|
||||
// cloth でない
|
||||
!ClothUsedParticles[particleIndex]
|
||||
// 枝のjointでない
|
||||
&& !Info[particleIndex].Branch.HasValue
|
||||
)
|
||||
{
|
||||
var info = Info[particleIndex];
|
||||
var pos = NextPositions[particleIndex];
|
||||
var warp = Warps[info.WarpIndex];
|
||||
|
||||
for (int groupRefIndex = warp.ColliderGroupRefRange.Start; groupRefIndex < warp.ColliderGroupRefRange.End; ++groupRefIndex)
|
||||
{
|
||||
var groupIndex = ColliderGroupRef[groupRefIndex];
|
||||
var group = ColliderGroup[groupIndex];
|
||||
for (int colliderRefIndex = group.Start; colliderRefIndex < group.End; ++colliderRefIndex)
|
||||
{
|
||||
var colliderIndex = ColliderRef[colliderRefIndex];
|
||||
var c = Colliders[colliderIndex];
|
||||
var m = CurrentColliders[c.transformIndex];
|
||||
|
||||
if (c.colliderType == BlittableColliderType.Capsule)
|
||||
{
|
||||
if (SphereSphereCollision.TryCollideCapsuleAndSphere(m.MultiplyPoint(c.offset), m.MultiplyPoint(c.tailOrNormal), c.radius,
|
||||
pos, info.Settings.Radius, out var l))
|
||||
{
|
||||
pos += l.GetDelta(c.radius);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SphereSphereCollision.TryCollideSphereAndSphere(m.MultiplyPoint(c.offset), c.radius,
|
||||
pos, info.Settings.Radius, out var l))
|
||||
{
|
||||
pos += l.GetDelta(c.radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
StrandCollision[particleIndex] = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 80e53200fa3841748ad1d1416efdd53b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -23,7 +23,7 @@ namespace UniVRM10.ClothWarp
|
|||
foreach (var particle in warp.Particles)
|
||||
{
|
||||
var child_index = _MakeAParticle(joint, env, particle.Transform,
|
||||
particle.Settings.radius, 1);
|
||||
particle.Settings.Radius, 1);
|
||||
var child = _particles[child_index];
|
||||
strand.Particles.Add(child);
|
||||
joint.Children.Add(child);
|
||||
|
|
|
|||
|
|
@ -230,19 +230,19 @@ namespace SphereTriangle
|
|||
return true;
|
||||
}
|
||||
|
||||
// public void DrawGizmos()
|
||||
// {
|
||||
// var r = Vector3.Distance(_triangle0.b, _triangle0.c) * 0.1f;
|
||||
// _DrawGizmos(_triangle0, _s0, _trinagle0Collision, r);
|
||||
// _DrawGizmos(_triangle1, _s1, _triangle1Collision, r);
|
||||
// public void DrawGizmos()
|
||||
// {
|
||||
// var r = Vector3.Distance(_triangle0.b, _triangle0.c) * 0.1f;
|
||||
// _DrawGizmos(_triangle0, _s0, _trinagle0Collision, r);
|
||||
// _DrawGizmos(_triangle1, _s1, _triangle1Collision, r);
|
||||
|
||||
// #if AABB_DEBUG
|
||||
// Gizmos.matrix = Matrix4x4.identity;
|
||||
// Gizmos.color = Color.cyan;
|
||||
// var aabb = GetBoundsFrom4(_triangle0.a, _triangle0.b, _triangle1.a, _triangle1.b);
|
||||
// Gizmos.DrawWireCube(aabb.center, aabb.size);
|
||||
// #endif
|
||||
// }
|
||||
// #if AABB_DEBUG
|
||||
// Gizmos.matrix = Matrix4x4.identity;
|
||||
// Gizmos.color = Color.cyan;
|
||||
// var aabb = GetBoundsFrom4(_triangle0.a, _triangle0.b, _triangle1.a, _triangle1.b);
|
||||
// Gizmos.DrawWireCube(aabb.center, aabb.size);
|
||||
// #endif
|
||||
// }
|
||||
|
||||
// void _DrawGizmos(in Triangle t, TriangleCapsuleCollisionSolver solver, float collision, float radius)
|
||||
// {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
using UnityEngine;
|
||||
|
||||
|
||||
namespace SphereTriangle
|
||||
{
|
||||
public static class SphereSphereCollision
|
||||
{
|
||||
/// <summary>
|
||||
/// collide sphere a and sphere b.
|
||||
/// move sphere b to resolved if collide.
|
||||
/// </summary>
|
||||
/// <param name="from"></param>
|
||||
/// <param name="ra"></param>
|
||||
/// <param name="to"></param>
|
||||
/// <param name="ba"></param>
|
||||
/// <param name="resolved"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryCollideSphereAndSphere(
|
||||
in Vector3 from, float ra,
|
||||
in Vector3 to, float rb,
|
||||
out LineSegment resolved
|
||||
)
|
||||
{
|
||||
var d = Vector3.Distance(from, to);
|
||||
if (d > (ra + rb))
|
||||
{
|
||||
resolved = default;
|
||||
return false;
|
||||
}
|
||||
Vector3 normal = (to - from).normalized;
|
||||
resolved = new(from, from + normal * (d - rb));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// collide capsule and sphere b.
|
||||
/// move sphere b to resolved if collide.
|
||||
/// </summary>
|
||||
/// <param name="capsuleHead"></param>
|
||||
/// <param name="capsuleTail"></param>
|
||||
/// <param name="capsuleRadius"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <param name="rb"></param>
|
||||
public static bool TryCollideCapsuleAndSphere(
|
||||
in Vector3 capsuleHead,
|
||||
in Vector3 capsuleTail,
|
||||
float capsuleRadius,
|
||||
in Vector3 b,
|
||||
float rb,
|
||||
out LineSegment resolved
|
||||
)
|
||||
{
|
||||
var P = (capsuleTail - capsuleHead);
|
||||
var Q = b - capsuleHead;
|
||||
var dot = Vector3.Dot(P.normalized, Q);
|
||||
if (dot <= 0)
|
||||
{
|
||||
// head側半球の球判定
|
||||
return TryCollideSphereAndSphere(capsuleHead, capsuleRadius, b, rb, out resolved);
|
||||
}
|
||||
|
||||
var t = dot / P.magnitude;
|
||||
if (t >= 1.0f)
|
||||
{
|
||||
// tail側半球の球判定
|
||||
return TryCollideSphereAndSphere(capsuleTail, capsuleRadius, b, rb, out resolved);
|
||||
}
|
||||
|
||||
// head-tail上の m_transform.position との最近点
|
||||
var p = capsuleHead + P * t;
|
||||
return TryCollideSphereAndSphere(p, capsuleRadius, b, rb, out resolved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 990d1e921d604e348ab7fd04216b01d2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user