Modify: 매지카클로스2 스크립트 최신화
This commit is contained in:
parent
60f8e6dc25
commit
3f3d799879
@ -1,6 +1,6 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-4012764583101539669
|
||||
--- !u!114 &-3443301767334639713
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
|
||||
@ -9,6 +9,13 @@ namespace MagicaCloth2
|
||||
{
|
||||
public Vector3 eulers = new Vector3(0, 90, 0);
|
||||
public Space space = Space.World;
|
||||
public enum UpdateMode
|
||||
{
|
||||
Update,
|
||||
FixedUpdate,
|
||||
}
|
||||
[SerializeField]
|
||||
private UpdateMode updateMode = UpdateMode.Update;
|
||||
|
||||
[SerializeField]
|
||||
[Range(0.1f, 5.0f)]
|
||||
@ -19,11 +26,23 @@ namespace MagicaCloth2
|
||||
|
||||
private float time = 0;
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (updateMode == UpdateMode.FixedUpdate)
|
||||
UpdatePosition(Time.fixedDeltaTime);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (updateMode == UpdateMode.Update)
|
||||
UpdatePosition(Time.deltaTime);
|
||||
}
|
||||
|
||||
void UpdatePosition(float dtime)
|
||||
{
|
||||
if (useSin)
|
||||
{
|
||||
time += Time.deltaTime;
|
||||
time += dtime;
|
||||
float ang = (time % interval) / interval * Mathf.PI * 2.0f;
|
||||
var t = Mathf.Sin(ang);
|
||||
if (space == Space.World)
|
||||
@ -33,7 +52,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.Rotate(eulers * Time.deltaTime, space);
|
||||
transform.Rotate(eulers * dtime, space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,10 +124,7 @@ namespace MagicaCloth2
|
||||
return;
|
||||
|
||||
// カメラターゲットポジション
|
||||
if (cameraTarget)
|
||||
{
|
||||
cameraTargetPos = cameraTarget.position;
|
||||
}
|
||||
cameraTargetPos = cameraTarget ? cameraTarget.position : transform.position;
|
||||
|
||||
// 補間
|
||||
cameraDist = Mathf.SmoothDamp(cameraDist, setCameraDist, ref cameraDistVelocity, cameraDistHokanTime);
|
||||
@ -147,13 +144,13 @@ namespace MagicaCloth2
|
||||
Vector3 pos = q * v;
|
||||
|
||||
// ターゲットポジション
|
||||
Vector3 tarpos = cameraTargetPos + cameraTargetOffset;
|
||||
Vector3 tarpos = cameraTargetPos + transform.TransformVector(cameraTargetOffset);
|
||||
Vector3 fixpos = tarpos + pos;
|
||||
cameraTransform.localPosition = fixpos;
|
||||
cameraTransform.position = fixpos;
|
||||
|
||||
// 回転確定
|
||||
Vector3 relativePos = tarpos - cameraTransform.position;
|
||||
Quaternion rot = Quaternion.LookRotation(relativePos);
|
||||
Quaternion rot = Quaternion.LookRotation(relativePos, transform.up);
|
||||
cameraTransform.rotation = rot;
|
||||
}
|
||||
|
||||
@ -182,8 +179,8 @@ namespace MagicaCloth2
|
||||
}
|
||||
else if (moveMode == MoveMode.Free)
|
||||
{
|
||||
Vector3 offset = cameraTransform.up * -speed.y * moveSpeed;
|
||||
offset += cameraTransform.right * -speed.x * moveSpeed;
|
||||
Vector3 offset = transform.InverseTransformDirection(cameraTransform.up) * -speed.y * moveSpeed;
|
||||
offset += transform.InverseTransformDirection(cameraTransform.right) * -speed.x * moveSpeed;
|
||||
|
||||
cameraTargetOffset += offset;
|
||||
}
|
||||
@ -207,7 +204,7 @@ namespace MagicaCloth2
|
||||
/// <param name="screenVelocity"></param>
|
||||
private void OnTouchMove(int fid, Vector2 screenPos, Vector2 screenVelocity, Vector2 cmVelocity)
|
||||
{
|
||||
screenVelocity *= Time.deltaTime * 60.0f;
|
||||
screenVelocity *= SpeedAdjustment();
|
||||
|
||||
if (fid == 2)
|
||||
{
|
||||
@ -225,6 +222,8 @@ namespace MagicaCloth2
|
||||
|
||||
private void OnDoubleTouchMove(int fid, Vector2 screenPos, Vector2 screenVelocity, Vector2 cmVelocity)
|
||||
{
|
||||
screenVelocity *= SpeedAdjustment();
|
||||
|
||||
if (SimpleInputManager.Instance.GetTouchCount() >= 3)
|
||||
updateOffset(screenVelocity);
|
||||
}
|
||||
@ -236,9 +235,15 @@ namespace MagicaCloth2
|
||||
/// <param name="speedcm"></param>
|
||||
private void OnTouchPinch(float speedscr, float speedcm)
|
||||
{
|
||||
//if (Mathf.Abs(speedcm) > 1.0f)
|
||||
speedcm *= SpeedAdjustment();
|
||||
|
||||
if (SimpleInputManager.Instance.GetTouchCount() < 3)
|
||||
updateZoom(speedcm);
|
||||
}
|
||||
|
||||
private float SpeedAdjustment()
|
||||
{
|
||||
return Time.deltaTime * 60.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,6 +233,7 @@ namespace MagicaCloth2
|
||||
sdata.colliderCollisionConstraint.mode = ColliderCollisionConstraint.Mode.Point;
|
||||
|
||||
// setup collider
|
||||
// UpperLeg L
|
||||
var lobj = new GameObject("CapsuleCollider_L");
|
||||
lobj.transform.SetParent(gameObjectContainer.GetGameObject("Character1_LeftUpLeg").transform);
|
||||
lobj.transform.localPosition = new Vector3(0.0049f, 0.0f, -0.0832f);
|
||||
@ -240,17 +241,10 @@ namespace MagicaCloth2
|
||||
var colliderL = lobj.AddComponent<MagicaCapsuleCollider>();
|
||||
colliderL.direction = MagicaCapsuleCollider.Direction.Z;
|
||||
colliderL.SetSize(0.082f, 0.094f, 0.3f);
|
||||
|
||||
var robj = new GameObject("CapsuleCollider_R");
|
||||
robj.transform.SetParent(gameObjectContainer.GetGameObject("Character1_RightUpLeg").transform);
|
||||
robj.transform.localPosition = new Vector3(-0.0049f, 0.0f, -0.0832f);
|
||||
robj.transform.localEulerAngles = new Vector3(0.23f, -16.376f, -0.028f);
|
||||
var colliderR = robj.AddComponent<MagicaCapsuleCollider>();
|
||||
colliderR.direction = MagicaCapsuleCollider.Direction.Z;
|
||||
colliderR.SetSize(0.082f, 0.094f, 0.3f);
|
||||
|
||||
// UpperLeg R (Symmetry)
|
||||
colliderL.symmetryMode = ColliderSymmetryMode.AutomaticHumanBody;
|
||||
colliderL.UpdateParameters(); // Required when changing parameters.
|
||||
sdata.colliderCollisionConstraint.colliderList.Add(colliderL);
|
||||
sdata.colliderCollisionConstraint.colliderList.Add(colliderR);
|
||||
|
||||
// start build
|
||||
cloth.BuildAndRun();
|
||||
|
||||
@ -105,6 +105,8 @@ namespace MagicaCloth2
|
||||
//=========================================================================================
|
||||
protected override void InitSingleton()
|
||||
{
|
||||
SimpleInput.Init();
|
||||
|
||||
// スクリーン情報
|
||||
CalcScreenDpi();
|
||||
|
||||
@ -188,7 +190,7 @@ namespace MagicaCloth2
|
||||
|
||||
public int GetTouchCount()
|
||||
{
|
||||
return Input.touchCount;
|
||||
return SimpleInput.touchCount;
|
||||
}
|
||||
|
||||
public bool IsUI()
|
||||
@ -199,7 +201,7 @@ namespace MagicaCloth2
|
||||
if (mobilePlatform)
|
||||
{
|
||||
// モバイル用タッチ入力
|
||||
return EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId);
|
||||
return EventSystem.current.IsPointerOverGameObject(SimpleInput.GetTouch(0).fingerId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -214,7 +216,7 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
private void UpdateMobile()
|
||||
{
|
||||
int count = Input.touchCount;
|
||||
int count = SimpleInput.touchCount;
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
@ -223,7 +225,7 @@ namespace MagicaCloth2
|
||||
// バックボタン
|
||||
if (Application.platform == RuntimePlatform.Android)
|
||||
{
|
||||
if (Input.GetKey(KeyCode.Escape) && lastTime + 0.2f < Time.time)
|
||||
if (SimpleInput.GetKey(KeyCode.Escape) && lastTime + 0.2f < Time.time)
|
||||
{
|
||||
lastTime = Time.time;
|
||||
if (OnBackButton != null)
|
||||
@ -239,7 +241,7 @@ namespace MagicaCloth2
|
||||
// メイン
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Touch touch = Input.GetTouch(i);
|
||||
Touch touch = SimpleInput.GetTouch(i);
|
||||
int fid = touch.fingerId;
|
||||
|
||||
// フィンガーIDが0と1以外は無視する
|
||||
@ -289,7 +291,7 @@ namespace MagicaCloth2
|
||||
int setcnt = 0;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
Touch t = Input.GetTouch(j);
|
||||
Touch t = SimpleInput.GetTouch(j);
|
||||
if (mainFingerId == t.fingerId)
|
||||
{
|
||||
t1pos = t.position;
|
||||
@ -497,7 +499,7 @@ namespace MagicaCloth2
|
||||
private void UpdateMouse()
|
||||
{
|
||||
// BackSpace を Android 端末のバックボタンに割り当てる
|
||||
if (Input.GetKeyDown(KeyCode.Backspace))
|
||||
if (SimpleInput.GetKeyDown(KeyCode.Backspace))
|
||||
{
|
||||
if (OnBackButton != null)
|
||||
OnBackButton();
|
||||
@ -507,7 +509,7 @@ namespace MagicaCloth2
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
// マウスボタンダウン
|
||||
if (Input.GetMouseButtonDown(i))
|
||||
if (SimpleInput.GetMouseButtonDown(i))
|
||||
{
|
||||
if (IsUI())
|
||||
continue;
|
||||
@ -519,46 +521,46 @@ namespace MagicaCloth2
|
||||
mouseDown[i] = true;
|
||||
|
||||
// 入力位置を記録
|
||||
downPos[i] = Input.mousePosition;
|
||||
mouseOldMovePos[i] = Input.mousePosition;
|
||||
downPos[i] = SimpleInput.mousePosition;
|
||||
mouseOldMovePos[i] = SimpleInput.mousePosition;
|
||||
if (i == 0)
|
||||
flickDownPos[i] = Input.mousePosition;
|
||||
flickDownPos[i] = SimpleInput.mousePosition;
|
||||
|
||||
// タッチダウンイベント発行
|
||||
if (OnTouchDown != null)
|
||||
OnTouchDown(i, Input.mousePosition);
|
||||
OnTouchDown(i, SimpleInput.mousePosition);
|
||||
}
|
||||
|
||||
// マウスボタンアップ
|
||||
if (Input.GetMouseButtonUp(i) && mouseDown[i])
|
||||
if (SimpleInput.GetMouseButtonUp(i) && mouseDown[i])
|
||||
{
|
||||
mouseDown[i] = false;
|
||||
|
||||
// フリック判定
|
||||
if (i == 0)
|
||||
{
|
||||
CheckFlic(i, mouseOldMovePos[i], Input.mousePosition, flickDownPos[i], flickDownTime[i]);
|
||||
CheckFlic(i, mouseOldMovePos[i], SimpleInput.mousePosition, flickDownPos[i], flickDownTime[i]);
|
||||
}
|
||||
|
||||
mouseOldMovePos[i] = Vector2.zero;
|
||||
|
||||
// タッチアップイベント
|
||||
if (OnTouchUp != null)
|
||||
OnTouchUp(i, Input.mousePosition);
|
||||
OnTouchUp(i, SimpleInput.mousePosition);
|
||||
|
||||
// タップ判定
|
||||
float distcm = Vector2.Distance(downPos[0], Input.mousePosition) / screenDpc;
|
||||
float distcm = Vector2.Distance(downPos[0], SimpleInput.mousePosition) / screenDpc;
|
||||
if (distcm <= tapRadiusCm)
|
||||
{
|
||||
if (OnTouchTap != null)
|
||||
OnTouchTap(i, Input.mousePosition);
|
||||
OnTouchTap(i, SimpleInput.mousePosition);
|
||||
}
|
||||
}
|
||||
|
||||
// 移動
|
||||
if (mouseDown[i])
|
||||
{
|
||||
Vector2 spos = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
|
||||
Vector2 spos = new Vector2(SimpleInput.mousePosition.x, SimpleInput.mousePosition.y);
|
||||
Vector2 delta = spos - mouseOldMovePos[i];
|
||||
|
||||
if (spos != mouseOldMovePos[i])
|
||||
@ -569,10 +571,10 @@ namespace MagicaCloth2
|
||||
|
||||
// 移動通知(現在スクリーン座標、速度(スクリーン比率/s)、速度(cm/s))
|
||||
if (OnTouchMove != null)
|
||||
OnTouchMove(i, Input.mousePosition, CalcScreenRatioVector(delta) / Time.deltaTime, speedcm);
|
||||
OnTouchMove(i, SimpleInput.mousePosition, CalcScreenRatioVector(delta) / Time.deltaTime, speedcm);
|
||||
}
|
||||
|
||||
mouseOldMovePos[i] = Input.mousePosition;
|
||||
mouseOldMovePos[i] = SimpleInput.mousePosition;
|
||||
|
||||
// フリックダウン位置更新
|
||||
flickDownPos[i] = (flickDownPos[i] + spos) * 0.5f;
|
||||
@ -582,7 +584,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
// ピンチイン/アウト
|
||||
float w = Input.GetAxis("Mouse ScrollWheel");
|
||||
float w = SimpleInput.GetMouseScrollWheel();
|
||||
if (Mathf.Abs(w) > 0.01f)
|
||||
{
|
||||
// モバイル入力とスケール感を合わせるために係数を掛ける
|
||||
|
||||
BIN
Assets/External/MagicaCloth2/Example (Can be deleted)/DemoScenes/CoreRP/UnityChanKAGURA_CoreRP.unity
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Example (Can be deleted)/DemoScenes/CoreRP/UnityChanKAGURA_CoreRP.unity
(Stored with Git LFS)
vendored
Binary file not shown.
@ -1,5 +1,18 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-8535022332011870411
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
--- !u!114 &-5755898939291106094
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
@ -116,16 +129,3 @@ Material:
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Tiling: {r: 1, g: 1, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
--- !u!114 &3484866536248413851
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
|
||||
@ -1,5 +1,18 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-2691252781391532706
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
@ -116,16 +129,3 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 0
|
||||
--- !u!114 &8408605057506184450
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
|
||||
@ -1,5 +1,18 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-7295792319158048354
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
--- !u!114 &-4086932747498456647
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
@ -13,19 +26,6 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 0
|
||||
--- !u!114 &-164983938586400980
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-4330475528230009683
|
||||
--- !u!114 &-3407187510348448959
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
|
||||
@ -13,19 +13,6 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 0
|
||||
--- !u!114 &-1058601315364651215
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
@ -129,3 +116,16 @@ Material:
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Tiling: {r: 1, g: 1, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
--- !u!114 &5988508712152931550
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-8786398318607239453
|
||||
--- !u!114 &-178249263625412926
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
|
||||
@ -1,18 +1,5 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-6925851060112298428
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
@ -116,6 +103,19 @@ Material:
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Tiling: {r: 1, g: 1, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
--- !u!114 &1491462379427701739
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
--- !u!114 &6265247899772061283
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
|
||||
@ -116,7 +116,7 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 0
|
||||
--- !u!114 &9070933888469703597
|
||||
--- !u!114 &7169070195589252005
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
|
||||
BIN
Assets/External/MagicaCloth2/Example (Can be deleted)/UnityChan/SD_Kohaku_chanz/Utc_sum_humanoid (Body).prefab
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Example (Can be deleted)/UnityChan/SD_Kohaku_chanz/Utc_sum_humanoid (Body).prefab
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Example (Can be deleted)/UnityChan/SD_Kohaku_chanz/Utc_sum_humanoid (Hair).prefab
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Example (Can be deleted)/UnityChan/SD_Kohaku_chanz/Utc_sum_humanoid (Hair).prefab
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Example (Can be deleted)/UnityChan/UnityChanKAGURA/UnityCHanKAGURA_MC2.prefab
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Example (Can be deleted)/UnityChan/UnityChanKAGURA/UnityCHanKAGURA_MC2.prefab
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_Accessory.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_Accessory.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_Cape.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_Cape.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_FrontHair.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_FrontHair.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_HardSpring.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_HardSpring.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_LongHair.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_LongHair.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_MiddleSpring.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_MiddleSpring.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_ShortHair.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_ShortHair.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_Skirt.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_Skirt.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_SoftSpring.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_SoftSpring.json
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_Tail.json
(Stored with Git LFS)
vendored
BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_Tail.json
(Stored with Git LFS)
vendored
Binary file not shown.
@ -19,5 +19,11 @@ namespace MagicaCloth2
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gizmo display state.
|
||||
/// </summary>
|
||||
public bool IsGizmoVisible { get; set; }
|
||||
protected virtual void OnDrawGizmos() => IsGizmoVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// 重力方向(ワールド空間)
|
||||
/// </summary>
|
||||
public float3 gravityDirection;
|
||||
public float3 worldGravityDirection;
|
||||
|
||||
/// <summary>
|
||||
/// 初期姿勢での重力の減衰率(0.0 ~ 1.0)
|
||||
@ -63,6 +63,9 @@ namespace MagicaCloth2
|
||||
public float rotationalInterpolation;
|
||||
public float rootRotation;
|
||||
|
||||
// カリング(Culling)
|
||||
public CullingSettings.CullingParams culling;
|
||||
|
||||
// 慣性制約(Inertia)
|
||||
public InertiaConstraint.InertiaConstraintParams inertiaConstraint;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
@ -16,20 +17,31 @@ namespace MagicaCloth2
|
||||
{
|
||||
public MagicaCloth cloth { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 同期中の参照クロス。これは同期階層の最上位のクロスを指す
|
||||
/// </summary>
|
||||
public MagicaCloth SyncTopCloth { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状態フラグ(0 ~ 31)
|
||||
/// </summary>
|
||||
public const int State_Valid = 0;
|
||||
public const int State_Enable = 1;
|
||||
public const int State_ParameterDirty = 2;
|
||||
public const int State_InitComplete = 3;
|
||||
public const int State_Build = 4;
|
||||
public const int State_Running = 5;
|
||||
public const int State_DisableAutoBuild = 6;
|
||||
public const int State_CullingInvisible = 7; // チームデータの同フラグのコピー
|
||||
public const int State_CullingKeep = 8; // チームデータの同フラグのコピー
|
||||
public const int State_SkipWriting = 9; // 書き込み停止(ストップモーション用)
|
||||
public const int State_SkipWritingDirty = 10; // 書き込み停止フラグ更新サイン
|
||||
//public const int State_ParameterDirty = 2;
|
||||
public const int State_InitSuccess = 3;
|
||||
public const int State_InitComplete = 4;
|
||||
public const int State_Build = 5;
|
||||
public const int State_Running = 6;
|
||||
public const int State_DisableAutoBuild = 7;
|
||||
public const int State_CameraCullingInvisible = 8; // チームデータの同フラグのコピー
|
||||
public const int State_CameraCullingKeep = 9; // チームデータの同フラグのコピー
|
||||
public const int State_SkipWriting = 10; // 書き込み停止(ストップモーション用)
|
||||
//public const int State_SkipWritingDirty = 11; // 書き込み停止フラグ更新サイン
|
||||
public const int State_UsePreBuild = 12; // PreBuildを利用
|
||||
public const int State_DistanceCullingInvisible = 13; // チームデータの同フラグのコピー
|
||||
public const int State_UpdateTangent = 14; // 接線の更新
|
||||
public const int State_Component = 15; // コンポーネントの有効状態
|
||||
public const int State_Verification = 16; // 検証結果による有効状態
|
||||
|
||||
/// <summary>
|
||||
/// 現在の状態
|
||||
@ -45,7 +57,7 @@ namespace MagicaCloth2
|
||||
/// レンダー情報へのハンドル
|
||||
/// (レンダラーのセットアップデータ)
|
||||
/// </summary>
|
||||
List<int> renderHandleList = new List<int>();
|
||||
internal List<int> renderHandleList = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// BoneClothのセットアップデータ
|
||||
@ -58,8 +70,11 @@ namespace MagicaCloth2
|
||||
public class RenderMeshInfo
|
||||
{
|
||||
public int renderHandle;
|
||||
public VirtualMesh renderMesh;
|
||||
public VirtualMeshContainer renderMeshContainer;
|
||||
public DataChunk mappingChunk;
|
||||
//public DataChunk renderMeshPositionAndNormalChunk;
|
||||
//public DataChunk renderMeshTangentChunk;
|
||||
public int renderDataWorkIndex;
|
||||
}
|
||||
internal List<RenderMeshInfo> renderMeshInfoList = new List<RenderMeshInfo>();
|
||||
|
||||
@ -96,6 +111,11 @@ namespace MagicaCloth2
|
||||
internal ResultCode result;
|
||||
public ResultCode Result => result;
|
||||
|
||||
/// <summary>
|
||||
/// 初期化データ参照結果
|
||||
/// </summary>
|
||||
public ResultCode InitDataResult { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cloth Type
|
||||
/// </summary>
|
||||
@ -120,18 +140,15 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// プロキシメッシュ
|
||||
/// </summary>
|
||||
public VirtualMesh ProxyMesh { get; private set; } = null;
|
||||
public VirtualMeshContainer ProxyMeshContainer { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// コライダーリスト
|
||||
/// コライダーが格納されるインデックスは他のデータのインデックスと一致している
|
||||
/// 登録中のコライダー
|
||||
/// int2 (メインコライダー・ローカルインデックス, シンメトリーコライダー・ローカルインデックス)
|
||||
/// メインコライダーのインデックス0はあり得る
|
||||
/// シンメトリーコライダーのインデックス0はシンメトリーが存在しないことを示す
|
||||
/// </summary>
|
||||
internal List<ColliderComponent> colliderList = new List<ColliderComponent>();
|
||||
|
||||
/// <summary>
|
||||
/// コライダー配列数
|
||||
/// </summary>
|
||||
internal int ColliderCapacity => colliderList.Count;
|
||||
internal Dictionary<ColliderComponent, int2> colliderDict = new Dictionary<ColliderComponent, int2>();
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
@ -156,14 +173,37 @@ namespace MagicaCloth2
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// カリング用対象アニメーター
|
||||
/// 連動アニメーター
|
||||
/// ・カリング
|
||||
/// ・更新モード
|
||||
/// </summary>
|
||||
internal Animator cullingAnimator = null;
|
||||
internal Animator interlockingAnimator = null;
|
||||
|
||||
/// <summary>
|
||||
/// カリング用アニメーター配下のレンダラーリスト
|
||||
/// </summary>
|
||||
internal List<Renderer> cullingAnimatorRenderers = new List<Renderer>();
|
||||
internal List<Renderer> interlockingAnimatorRenderers = new List<Renderer>();
|
||||
|
||||
/// <summary>
|
||||
/// 現在アンカーとして設定されているTransformのインスタンスID
|
||||
/// </summary>
|
||||
internal int anchorTransformId = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 現在距離カリングの参照として設定されているオブジェクトのインスタンスID
|
||||
/// </summary>
|
||||
internal int distanceReferenceObjectId = 0;
|
||||
|
||||
/// <summary>
|
||||
/// コンポーネントの登録TransformIndex
|
||||
/// tdata.componentTransformIndexのコピー
|
||||
/// </summary>
|
||||
//internal int componentTransformIndex = 0;
|
||||
|
||||
internal Animator cameraCullingAnimator = null;
|
||||
internal List<Renderer> cameraCullingRenderers = null;
|
||||
internal CullingSettings.CameraCullingMode cameraCullingMode;
|
||||
internal bool cameraCullingOldInvisible = false;
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
@ -171,12 +211,12 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
volatile object lockObject = new object();
|
||||
volatile object lockState = new object();
|
||||
//volatile object lockState = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 初期化待機カウンター
|
||||
/// </summary>
|
||||
volatile int suspendCounter = 0;
|
||||
//volatile int suspendCounter = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 破棄フラグ
|
||||
@ -195,7 +235,7 @@ namespace MagicaCloth2
|
||||
|
||||
public BitField32 GetStateFlag()
|
||||
{
|
||||
lock (lockState)
|
||||
//lock (lockState)
|
||||
{
|
||||
// copy
|
||||
var state = stateFlag;
|
||||
@ -205,7 +245,7 @@ namespace MagicaCloth2
|
||||
|
||||
public bool IsState(int state)
|
||||
{
|
||||
lock (lockState)
|
||||
//lock (lockState)
|
||||
{
|
||||
return stateFlag.IsSet(state);
|
||||
}
|
||||
@ -213,16 +253,19 @@ namespace MagicaCloth2
|
||||
|
||||
public void SetState(int state, bool sw)
|
||||
{
|
||||
lock (lockState)
|
||||
//lock (lockState)
|
||||
{
|
||||
stateFlag.SetBits(state, sw);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValid() => IsState(State_Valid);
|
||||
public bool IsCullingInvisible() => IsState(State_CullingInvisible);
|
||||
public bool IsCullingKeep() => IsState(State_CullingKeep);
|
||||
public bool IsRunning() => IsState(State_Running);
|
||||
public bool IsCameraCullingInvisible() => IsState(State_CameraCullingInvisible);
|
||||
public bool IsCameraCullingKeep() => IsState(State_CameraCullingKeep);
|
||||
public bool IsDistanceCullingInvisible() => IsState(State_DistanceCullingInvisible);
|
||||
public bool IsSkipWriting() => IsState(State_SkipWriting);
|
||||
public bool IsUpdateTangent() => IsState(State_UpdateTangent);
|
||||
|
||||
public bool IsEnable
|
||||
{
|
||||
@ -240,7 +283,7 @@ namespace MagicaCloth2
|
||||
{
|
||||
if (IsValid() == false || TeamId == 0)
|
||||
return false;
|
||||
return ProxyMesh?.IsSuccess ?? false;
|
||||
return ProxyMeshContainer?.shareVirtualMesh?.IsSuccess ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,7 +335,7 @@ namespace MagicaCloth2
|
||||
continue;
|
||||
|
||||
// 仮想メッシュ破棄
|
||||
info.renderMesh?.Dispose();
|
||||
info.renderMeshContainer?.Dispose();
|
||||
}
|
||||
renderMeshInfoList.Clear();
|
||||
renderMeshInfoList = null;
|
||||
@ -310,13 +353,24 @@ namespace MagicaCloth2
|
||||
boneClothSetupData = null;
|
||||
|
||||
// プロキシメッシュ破棄
|
||||
ProxyMesh?.Dispose();
|
||||
ProxyMesh = null;
|
||||
ProxyMeshContainer?.Dispose();
|
||||
ProxyMeshContainer = null;
|
||||
|
||||
colliderList.Clear();
|
||||
colliderDict.Clear();
|
||||
|
||||
cullingAnimator = null;
|
||||
cullingAnimatorRenderers.Clear();
|
||||
interlockingAnimator = null;
|
||||
interlockingAnimatorRenderers.Clear();
|
||||
|
||||
// PreBuildデータ解除
|
||||
MagicaManager.PreBuild?.UnregisterPreBuildData(cloth?.GetSerializeData2()?.preBuildData.GetSharePreBuildData());
|
||||
|
||||
// 作業バッファ破棄
|
||||
SyncTopCloth = null;
|
||||
int compId = cloth.GetInstanceID();
|
||||
MagicaManager.Team.comp2SuspendCounterMap.Remove(compId);
|
||||
MagicaManager.Team.comp2TeamIdMap.Remove(compId);
|
||||
MagicaManager.Team.comp2SyncPartnerCompMap.Remove(compId);
|
||||
MagicaManager.Team.comp2SyncTopCompMap.Remove(compId);
|
||||
|
||||
// 完全破棄フラグ
|
||||
isDestoryInternal = true;
|
||||
@ -329,23 +383,44 @@ namespace MagicaCloth2
|
||||
|
||||
internal void IncrementSuspendCounter()
|
||||
{
|
||||
lock (lockObject)
|
||||
//suspendCounter++;
|
||||
var tm = MagicaManager.Team;
|
||||
int compId = cloth.GetInstanceID();
|
||||
if (tm.comp2SuspendCounterMap.TryGetValue(compId, out int cnt))
|
||||
{
|
||||
suspendCounter++;
|
||||
cnt++;
|
||||
//tm.comp2SuspendCounterMap.Add(compId, cnt);
|
||||
tm.comp2SuspendCounterMap[compId] = cnt;
|
||||
}
|
||||
else
|
||||
tm.comp2SuspendCounterMap.Add(compId, 1);
|
||||
}
|
||||
|
||||
internal void DecrementSuspendCounter()
|
||||
{
|
||||
lock (lockObject)
|
||||
//suspendCounter--;
|
||||
var tm = MagicaManager.Team;
|
||||
int compId = cloth.GetInstanceID();
|
||||
if (tm.comp2SuspendCounterMap.TryGetValue(compId, out int cnt))
|
||||
{
|
||||
suspendCounter--;
|
||||
cnt--;
|
||||
if (cnt > 0)
|
||||
//tm.comp2SuspendCounterMap.Add(compId, cnt);
|
||||
tm.comp2SuspendCounterMap[compId] = cnt;
|
||||
else
|
||||
tm.comp2SuspendCounterMap.Remove(compId);
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetSuspendCounter()
|
||||
{
|
||||
return suspendCounter;
|
||||
//return suspendCounter;
|
||||
var tm = MagicaManager.Team;
|
||||
int compId = cloth.GetInstanceID();
|
||||
if (tm.comp2SuspendCounterMap.TryGetValue(compId, out int cnt))
|
||||
return cnt;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
public RenderMeshInfo GetRenderMeshInfo(int index)
|
||||
@ -364,16 +439,22 @@ namespace MagicaCloth2
|
||||
public void GetUsedTransform(HashSet<Transform> transformSet)
|
||||
{
|
||||
cloth.SerializeData.GetUsedTransform(transformSet);
|
||||
cloth.serializeData2.GetUsedTransform(transformSet);
|
||||
clothTransformRecord?.GetUsedTransform(transformSet);
|
||||
boneClothSetupData?.GetUsedTransform(transformSet);
|
||||
renderHandleList.ForEach(handle => MagicaManager.Render.GetRendererData(handle).GetUsedTransform(transformSet));
|
||||
customSkinningBoneRecords.ForEach(rd => rd.GetUsedTransform(transformSet));
|
||||
normalAdjustmentTransformRecord?.GetUsedTransform(transformSet);
|
||||
|
||||
// nullを除外する
|
||||
if (transformSet.Contains(null))
|
||||
transformSet.Remove(null);
|
||||
}
|
||||
|
||||
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
|
||||
{
|
||||
cloth.SerializeData.ReplaceTransform(replaceDict);
|
||||
cloth.serializeData2.ReplaceTransform(replaceDict);
|
||||
clothTransformRecord?.ReplaceTransform(replaceDict);
|
||||
boneClothSetupData?.ReplaceTransform(replaceDict);
|
||||
renderHandleList.ForEach(handle => MagicaManager.Render.GetRendererData(handle).ReplaceTransform(replaceDict));
|
||||
@ -386,7 +467,44 @@ namespace MagicaCloth2
|
||||
// ここではフラグのみ更新する
|
||||
// 実際の更新はチームのAlwaysTeamUpdate()で行われる
|
||||
SetState(State_SkipWriting, sw);
|
||||
SetState(State_SkipWritingDirty, true);
|
||||
//SetState(State_SkipWritingDirty, true);
|
||||
MagicaManager.Team.skipWritingDirtyList.Add(this);
|
||||
}
|
||||
|
||||
internal ClothUpdateMode GetClothUpdateMode()
|
||||
{
|
||||
switch (cloth.SerializeData.updateMode)
|
||||
{
|
||||
case ClothUpdateMode.Normal:
|
||||
case ClothUpdateMode.UnityPhysics:
|
||||
case ClothUpdateMode.Unscaled:
|
||||
return cloth.SerializeData.updateMode;
|
||||
case ClothUpdateMode.AnimatorLinkage:
|
||||
if (interlockingAnimator)
|
||||
{
|
||||
switch (interlockingAnimator.updateMode)
|
||||
{
|
||||
case AnimatorUpdateMode.Normal:
|
||||
return ClothUpdateMode.Normal;
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
case AnimatorUpdateMode.Fixed:
|
||||
return ClothUpdateMode.UnityPhysics;
|
||||
#else
|
||||
case AnimatorUpdateMode.AnimatePhysics:
|
||||
return ClothUpdateMode.UnityPhysics;
|
||||
#endif
|
||||
case AnimatorUpdateMode.UnscaledTime:
|
||||
return ClothUpdateMode.Unscaled;
|
||||
default:
|
||||
Develop.DebugLogWarning($"[{cloth.name}] Unknown Animator UpdateMode:{interlockingAnimator.updateMode}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ClothUpdateMode.Normal;
|
||||
default:
|
||||
Develop.LogError($"[{cloth.name}] Unknown Cloth Update Mode:{cloth.SerializeData.updateMode}");
|
||||
return ClothUpdateMode.Normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,56 @@
|
||||
// Magica Cloth 2.
|
||||
// Copyright (c) 2023 MagicaSoft.
|
||||
// https://magicasoft.jp
|
||||
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
{
|
||||
public partial class ClothProcess
|
||||
{
|
||||
public ResultCode GenerateStatusCheck()
|
||||
{
|
||||
ResultCode result = new ResultCode();
|
||||
|
||||
// スケール値チェック
|
||||
var scl = cloth.transform.lossyScale;
|
||||
if (Mathf.Approximately(scl.x, 0.0f) || Mathf.Approximately(scl.y, 0.0f) || Mathf.Approximately(scl.z, 0.0f))
|
||||
{
|
||||
// スケール値がゼロ
|
||||
result.SetError(Define.Result.Init_ScaleIsZero);
|
||||
}
|
||||
else if (scl.x < 0.0f || scl.y < 0.0f || scl.z < 0.0f)
|
||||
{
|
||||
// 負のスケール
|
||||
// 負のスケールでの初期化は、事前構築もしくは初期化データありの場合許可する
|
||||
var sdata2 = cloth.GetSerializeData2();
|
||||
if (sdata2.preBuildData.UsePreBuild() || (sdata2.initData?.HasData() ?? false))
|
||||
{
|
||||
// ただし許可されるのは一軸フリップのみ
|
||||
int flipCount = (scl.x < 0.0f ? 1 : 0) + (scl.y < 0.0f ? 1 : 0) + (scl.z < 0.0f ? 1 : 0);
|
||||
if (flipCount != 1)
|
||||
{
|
||||
result.SetError(Define.Result.Init_NegativeScale);
|
||||
}
|
||||
}
|
||||
else
|
||||
result.SetError(Define.Result.Init_NegativeScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
float diff1 = Mathf.Abs(1.0f - scl.x / scl.y);
|
||||
float diff2 = Mathf.Abs(1.0f - scl.x / scl.z);
|
||||
const float diffTolerance = 0.01f; // 誤差(1%)
|
||||
if (diff1 > diffTolerance || diff2 > diffTolerance)
|
||||
{
|
||||
// 一様スケールではない
|
||||
result.SetWarning(Define.Result.Init_NonUniformScale);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal bool GenerateInitialization()
|
||||
{
|
||||
result.SetProcess();
|
||||
|
||||
@ -29,6 +29,13 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public List<Renderer> sourceRenderers = new List<Renderer>();
|
||||
|
||||
/// <summary>
|
||||
/// Write target to mesh in MeshCloth.
|
||||
/// [OK] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
public ClothMeshWriteMode meshWriteMode = ClothMeshWriteMode.PositionAndNormal;
|
||||
|
||||
public enum PaintMode
|
||||
{
|
||||
Manual = 0,
|
||||
@ -55,6 +62,14 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public List<Texture2D> paintMaps = new List<Texture2D>();
|
||||
|
||||
/// <summary>
|
||||
/// The UV channel that references the paint map.
|
||||
/// [NG] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
[Range(0, 7)]
|
||||
public int paintMapUvChannel = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Root bone list used in BoneCloth.
|
||||
/// [NG] Runtime changes.
|
||||
@ -92,7 +107,7 @@ namespace MagicaCloth2
|
||||
/// [OK] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
public ClothUpdateMode updateMode = ClothUpdateMode.Normal;
|
||||
public ClothUpdateMode updateMode = ClothUpdateMode.AnimatorLinkage;
|
||||
|
||||
/// <summary>
|
||||
/// Blend ratio between initial pose and animation pose.
|
||||
@ -180,7 +195,7 @@ namespace MagicaCloth2
|
||||
/// [OK] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
[System.NonSerialized]
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float blendWeight = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -11,8 +11,14 @@ namespace MagicaCloth2
|
||||
/// Parts that cannot be exported externally.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ClothSerializeData2 : IDataValidate, IValid
|
||||
public class ClothSerializeData2 : IDataValidate, IValid, ITransform
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialization Data.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public ClothInitSerializeData initData = new ClothInitSerializeData();
|
||||
|
||||
/// <summary>
|
||||
/// 頂点ペイントデータ
|
||||
/// vertex paint data.
|
||||
@ -26,8 +32,23 @@ namespace MagicaCloth2
|
||||
/// Transform and vertex attribute dictionary data.
|
||||
/// When creating BoneCloth/BoneSpring at runtime, you can store Transform and vertex attribute pairs in this dictionary and use it instead of vertex paint data.
|
||||
/// </summary>
|
||||
[System.NonSerialized]
|
||||
public Dictionary<Transform, VertexAttribute> boneAttributeDict = new Dictionary<Transform, VertexAttribute>();
|
||||
|
||||
/// <summary>
|
||||
/// Rendererに対応する頂点属性データ
|
||||
/// 実行時にMeshClothを構築する場合に、このリストにレンダラーごとのメッシュ頂点数分の頂点属性を格納することでセレクションデータの代わりにすることができます
|
||||
/// Vertex attribute data corresponding to the Renderer.
|
||||
/// When constructing MeshCloth at runtime, you can substitute selection data by storing vertex attributes in this list for the number of mesh vertices per renderer.
|
||||
/// </summary>
|
||||
[System.NonSerialized]
|
||||
public List<VertexAttribute[]> vertexAttributeList = new List<VertexAttribute[]>();
|
||||
|
||||
/// <summary>
|
||||
/// PreBuild Data.
|
||||
/// </summary>
|
||||
public PreBuildSerializeData preBuildData = new PreBuildSerializeData();
|
||||
|
||||
//=========================================================================================
|
||||
public ClothSerializeData2()
|
||||
{
|
||||
@ -57,5 +78,17 @@ namespace MagicaCloth2
|
||||
int hash = 0;
|
||||
return hash;
|
||||
}
|
||||
|
||||
public void GetUsedTransform(HashSet<Transform> transformSet)
|
||||
{
|
||||
initData.GetUsedTransform(transformSet);
|
||||
preBuildData.GetUsedTransform(transformSet);
|
||||
}
|
||||
|
||||
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
|
||||
{
|
||||
initData.ReplaceTransform(replaceDict);
|
||||
preBuildData.ReplaceTransform(replaceDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,6 +44,11 @@ namespace MagicaCloth2
|
||||
return false;
|
||||
if (rootBones.Count(x => x != null) == 0)
|
||||
return false;
|
||||
if (rootBones.Distinct().Count() != rootBones.Count)
|
||||
{
|
||||
verificationResult.SetError(Define.Result.SerializeData_DuplicateRootBone);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case ClothProcess.ClothType.MeshCloth:
|
||||
if (sourceRenderers == null || sourceRenderers.Count == 0)
|
||||
@ -57,6 +62,11 @@ namespace MagicaCloth2
|
||||
verificationResult.SetError(Define.Result.SerializeData_Over31Renderers);
|
||||
return false;
|
||||
}
|
||||
if (sourceRenderers.Distinct().Count() != sourceRenderers.Count)
|
||||
{
|
||||
verificationResult.SetError(Define.Result.SerializeData_DuplicateRenderer);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@ -107,10 +117,12 @@ namespace MagicaCloth2
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
const int NullHash = -3910836;
|
||||
|
||||
int hash = 0;
|
||||
hash += (int)clothType;
|
||||
foreach (var ren in sourceRenderers)
|
||||
hash += ren?.GetInstanceID() ?? 0;
|
||||
hash += ren?.GetInstanceID() ?? NullHash;
|
||||
foreach (var t in rootBones)
|
||||
{
|
||||
var stack = new Stack<Transform>(30);
|
||||
@ -119,7 +131,10 @@ namespace MagicaCloth2
|
||||
{
|
||||
var t2 = stack.Pop();
|
||||
if (t2 == null)
|
||||
{
|
||||
hash += NullHash;
|
||||
continue;
|
||||
}
|
||||
hash += t2.GetInstanceID();
|
||||
hash += t2.localPosition.GetHashCode();
|
||||
hash += t2.localRotation.GetHashCode();
|
||||
@ -142,6 +157,7 @@ namespace MagicaCloth2
|
||||
hash += map.isReadable ? 1 : 0;
|
||||
}
|
||||
}
|
||||
hash += paintMapUvChannel * 123;
|
||||
hash += colliderCollisionConstraint.GetHashCode();
|
||||
|
||||
return hash;
|
||||
@ -158,7 +174,7 @@ namespace MagicaCloth2
|
||||
|
||||
//cparams.solverFrequency = Define.System.SolverFrequency;
|
||||
cparams.gravity = clothType == ClothProcess.ClothType.BoneSpring ? 0.0f : gravity; // BoneSpring has no gravity.
|
||||
cparams.gravityDirection = gravityDirection;
|
||||
cparams.worldGravityDirection = gravityDirection;
|
||||
cparams.gravityFalloff = gravityFalloff;
|
||||
cparams.stablizationTimeAfterReset = stablizationTimeAfterReset;
|
||||
cparams.blendWeight = blendWeight;
|
||||
@ -169,6 +185,7 @@ namespace MagicaCloth2
|
||||
cparams.rotationalInterpolation = rotationalInterpolation;
|
||||
cparams.rootRotation = rootRotation;
|
||||
|
||||
cparams.culling.Convert(cullingSettings);
|
||||
cparams.inertiaConstraint.Convert(inertiaConstraint);
|
||||
cparams.tetherConstraint.Convert(tetherConstraint, clothType);
|
||||
cparams.distanceConstraint.Convert(distanceConstraint, clothType);
|
||||
@ -187,8 +204,10 @@ namespace MagicaCloth2
|
||||
{
|
||||
ClothProcess.ClothType clothType;
|
||||
List<Renderer> sourceRenderers;
|
||||
ClothMeshWriteMode meshWriteMode;
|
||||
PaintMode paintMode;
|
||||
List<Texture2D> paintMaps;
|
||||
int paintMapUvChannel;
|
||||
List<Transform> rootBones;
|
||||
RenderSetupData.BoneConnectionMode connectionMode;
|
||||
float rotationalInterpolation;
|
||||
@ -204,9 +223,9 @@ namespace MagicaCloth2
|
||||
MagicaCloth synchronization;
|
||||
float stablizationTimeAfterReset;
|
||||
float blendWeight;
|
||||
CullingSettings.CameraCullingMode cullingMode;
|
||||
CullingSettings.CameraCullingMethod cullingMethod;
|
||||
List<Renderer> cullingRenderers;
|
||||
CullingSettings cullingSetting;
|
||||
Transform anchor;
|
||||
float anchorInertia;
|
||||
|
||||
internal TempBuffer(ClothSerializeData sdata)
|
||||
{
|
||||
@ -217,8 +236,10 @@ namespace MagicaCloth2
|
||||
{
|
||||
clothType = sdata.clothType;
|
||||
sourceRenderers = new List<Renderer>(sdata.sourceRenderers);
|
||||
meshWriteMode = sdata.meshWriteMode;
|
||||
paintMode = sdata.paintMode;
|
||||
paintMaps = new List<Texture2D>(sdata.paintMaps);
|
||||
paintMapUvChannel = sdata.paintMapUvChannel;
|
||||
rootBones = new List<Transform>(sdata.rootBones);
|
||||
connectionMode = sdata.connectionMode;
|
||||
rotationalInterpolation = sdata.rotationalInterpolation;
|
||||
@ -234,17 +255,19 @@ namespace MagicaCloth2
|
||||
synchronization = sdata.selfCollisionConstraint.syncPartner;
|
||||
stablizationTimeAfterReset = sdata.stablizationTimeAfterReset;
|
||||
blendWeight = sdata.blendWeight;
|
||||
cullingMode = sdata.cullingSettings.cameraCullingMode;
|
||||
cullingMethod = sdata.cullingSettings.cameraCullingMethod;
|
||||
cullingRenderers = new List<Renderer>(sdata.cullingSettings.cameraCullingRenderers);
|
||||
cullingSetting = sdata.cullingSettings.Clone();
|
||||
anchor = sdata.inertiaConstraint.anchor;
|
||||
anchorInertia = sdata.inertiaConstraint.anchorInertia;
|
||||
}
|
||||
|
||||
internal void Pop(ClothSerializeData sdata)
|
||||
{
|
||||
sdata.clothType = clothType;
|
||||
sdata.sourceRenderers = sourceRenderers;
|
||||
sdata.meshWriteMode = meshWriteMode;
|
||||
sdata.paintMode = paintMode;
|
||||
sdata.paintMaps = paintMaps;
|
||||
sdata.paintMapUvChannel = paintMapUvChannel;
|
||||
sdata.rootBones = rootBones;
|
||||
sdata.connectionMode = connectionMode;
|
||||
sdata.rotationalInterpolation = rotationalInterpolation;
|
||||
@ -260,9 +283,9 @@ namespace MagicaCloth2
|
||||
sdata.selfCollisionConstraint.syncPartner = synchronization;
|
||||
sdata.stablizationTimeAfterReset = stablizationTimeAfterReset;
|
||||
sdata.blendWeight = blendWeight;
|
||||
sdata.cullingSettings.cameraCullingMode = cullingMode;
|
||||
sdata.cullingSettings.cameraCullingMethod = cullingMethod;
|
||||
sdata.cullingSettings.cameraCullingRenderers = cullingRenderers;
|
||||
sdata.cullingSettings = cullingSetting;
|
||||
sdata.inertiaConstraint.anchor = anchor;
|
||||
sdata.inertiaConstraint.anchorInertia = anchorInertia;
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,6 +348,7 @@ namespace MagicaCloth2
|
||||
sourceRenderers = new List<Renderer>(sdata.sourceRenderers);
|
||||
paintMode = sdata.paintMode;
|
||||
paintMaps = new List<Texture2D>(sdata.paintMaps);
|
||||
paintMapUvChannel = sdata.paintMapUvChannel;
|
||||
rootBones = new List<Transform>(sdata.rootBones);
|
||||
connectionMode = sdata.connectionMode;
|
||||
rotationalInterpolation = sdata.rotationalInterpolation;
|
||||
@ -404,5 +428,17 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsBoneSpring() => clothType == ClothProcess.ClothType.BoneSpring;
|
||||
|
||||
public int GetUvChannel()
|
||||
{
|
||||
switch (paintMode)
|
||||
{
|
||||
case PaintMode.Texture_Fixed_Move:
|
||||
case PaintMode.Texture_Fixed_Move_Limit:
|
||||
return paintMapUvChannel;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,5 +23,14 @@ namespace MagicaCloth2
|
||||
/// Updates are independent of Unity's Time.timeScale.
|
||||
/// </summary>
|
||||
Unscaled = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Automatically set from linked animator.
|
||||
/// 連動アニメーターから自動設定する
|
||||
/// - Animator.UpdateMode.Normal -> Normal
|
||||
/// - Animator.UpdateMode.AnimatePhysics -> UnityPhysics
|
||||
/// - Animator.UpdateMode.UnscaledTime -> Unscaled
|
||||
/// </summary>
|
||||
AnimatorLinkage = 10,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,12 @@
|
||||
// Copyright (c) 2023 MagicaSoft.
|
||||
// https://magicasoft.jp
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
{
|
||||
public abstract class ColliderComponent : ClothBehaviour, IDataValidate
|
||||
public abstract class ColliderComponent : ClothBehaviour, IDataValidate, ITransform
|
||||
{
|
||||
/// <summary>
|
||||
/// トランスフォームからの中心ローカルオフセット
|
||||
@ -23,6 +24,17 @@ namespace MagicaCloth2
|
||||
[SerializeField]
|
||||
protected Vector3 size;
|
||||
|
||||
/// <summary>
|
||||
/// シンメトリーモード
|
||||
/// Symmetry mode.
|
||||
/// </summary>
|
||||
public ColliderSymmetryMode symmetryMode = ColliderSymmetryMode.None;
|
||||
|
||||
/// <summary>
|
||||
/// シンメトリーの接続対象
|
||||
/// Symmetry connection target.
|
||||
/// </summary>
|
||||
public Transform symmetryTarget = null;
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
@ -42,6 +54,16 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
private HashSet<int> teamIdSet = new HashSet<int>();
|
||||
|
||||
/// <summary>
|
||||
/// 現在登録中のシンメトリーモード
|
||||
/// </summary>
|
||||
public ColliderSymmetryMode? ActiveSymmetryMode { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 現在登録中のシンメトリーターゲット
|
||||
/// </summary>
|
||||
public Transform ActiveSymmetryTarget { get; private set; }
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// Get collider size.
|
||||
@ -52,26 +74,30 @@ namespace MagicaCloth2
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual Vector3 GetSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
public virtual Vector3 GetSize() => size;
|
||||
|
||||
public void SetSize(Vector3 size)
|
||||
{
|
||||
this.size = size;
|
||||
}
|
||||
public void SetSize(Vector3 size) => this.size = size;
|
||||
|
||||
public void SetSizeX(float size) => this.size.x = size;
|
||||
public void SetSizeY(float size) => this.size.y = size;
|
||||
public void SetSizeZ(float size) => this.size.z = size;
|
||||
|
||||
/// <summary>
|
||||
/// スケール値を取得
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public float GetScale()
|
||||
public virtual float GetScale()
|
||||
{
|
||||
// X軸のみを見る
|
||||
return transform.lossyScale.x;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 方向の逆転(基本的にカプセルコライダー用)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool IsReverseDirection() => false;
|
||||
|
||||
/// <summary>
|
||||
/// チームへのコライダー登録通知
|
||||
/// </summary>
|
||||
@ -85,9 +111,11 @@ namespace MagicaCloth2
|
||||
/// チームからのコライダー解除通知
|
||||
/// </summary>
|
||||
/// <param name="teamId"></param>
|
||||
internal void Exit(int teamId)
|
||||
/// <returns>利用者0ならtrue</returns>
|
||||
internal bool Exit(int teamId)
|
||||
{
|
||||
teamIdSet.Remove(teamId);
|
||||
return teamIdSet.Count == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -101,15 +129,269 @@ namespace MagicaCloth2
|
||||
// パラメータの検証
|
||||
DataValidate();
|
||||
|
||||
// Symmetry更新
|
||||
// シンメトリーは削除もしくは追加がある。またTransformが変更される場合もある
|
||||
var oldActiveSymmetryMode = ActiveSymmetryMode;
|
||||
var oldActiveSymmetryTarget = ActiveSymmetryTarget;
|
||||
SetActiveSymmetryMode(firstOnly: false); // 最新の状態に更新
|
||||
bool changeSymmetry = oldActiveSymmetryMode != ActiveSymmetryMode || oldActiveSymmetryTarget != ActiveSymmetryTarget;
|
||||
|
||||
// 反映
|
||||
foreach (int teamId in teamIdSet)
|
||||
{
|
||||
MagicaManager.Collider.UpdateParameters(this, teamId);
|
||||
MagicaManager.Collider.UpdateParameters(this, teamId, changeSymmetry);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 現在の状態から適切なシンメトリーモードとそのターゲットTransformを計算して返す
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ColliderSymmetryMode CalcSymmetryMode(out Transform symmetryParent)
|
||||
{
|
||||
symmetryParent = symmetryTarget;
|
||||
|
||||
// 親
|
||||
var parent = transform.parent;
|
||||
if (parent == null)
|
||||
return ColliderSymmetryMode.None;
|
||||
|
||||
switch (symmetryMode)
|
||||
{
|
||||
case ColliderSymmetryMode.None:
|
||||
return ColliderSymmetryMode.None;
|
||||
case ColliderSymmetryMode.AutomaticHumanBody:
|
||||
case ColliderSymmetryMode.AutomaticTarget:
|
||||
break;
|
||||
case ColliderSymmetryMode.X_Symmetry:
|
||||
case ColliderSymmetryMode.Y_Symmetry:
|
||||
case ColliderSymmetryMode.Z_Symmetry:
|
||||
case ColliderSymmetryMode.XYZ_Symmetry:
|
||||
// ターゲットnullの場合は親
|
||||
if (symmetryParent == null)
|
||||
symmetryParent = parent;
|
||||
return symmetryMode;
|
||||
default:
|
||||
Develop.LogError("Unknown symmetry mode.");
|
||||
return ColliderSymmetryMode.None;
|
||||
}
|
||||
|
||||
// Automatic
|
||||
Animator ani = symmetryMode == ColliderSymmetryMode.AutomaticHumanBody ? gameObject.GetComponentInParent<Animator>(true) : null;
|
||||
|
||||
// 対象Transform
|
||||
// AutomaticではSymmetryTargetは無視される
|
||||
var target = symmetryMode == ColliderSymmetryMode.AutomaticTarget ? symmetryTarget : null;
|
||||
if (target == null && ani)
|
||||
{
|
||||
// 自動判定
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.Hips, HumanBodyBones.Hips);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.LeftUpperLeg, HumanBodyBones.RightUpperLeg);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.RightUpperLeg, HumanBodyBones.LeftUpperLeg);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.LeftLowerLeg, HumanBodyBones.RightLowerLeg);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.RightLowerLeg, HumanBodyBones.LeftLowerLeg);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.LeftFoot, HumanBodyBones.RightFoot);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.RightFoot, HumanBodyBones.LeftFoot);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.Spine, HumanBodyBones.Spine);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.Chest, HumanBodyBones.Chest);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.Neck, HumanBodyBones.Neck);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.Head, HumanBodyBones.Head);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.LeftShoulder, HumanBodyBones.RightShoulder);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.RightShoulder, HumanBodyBones.LeftShoulder);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.LeftUpperArm, HumanBodyBones.RightUpperArm);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.RightUpperArm, HumanBodyBones.LeftUpperArm);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.LeftLowerArm, HumanBodyBones.RightLowerArm);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.RightLowerArm, HumanBodyBones.LeftLowerArm);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.LeftHand, HumanBodyBones.RightHand);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.RightHand, HumanBodyBones.LeftHand);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.LeftToes, HumanBodyBones.RightToes);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.RightToes, HumanBodyBones.LeftToes);
|
||||
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.Jaw, HumanBodyBones.Jaw);
|
||||
GetHumanoidSymmetryBone(ref target, parent, ani, HumanBodyBones.UpperChest, HumanBodyBones.UpperChest);
|
||||
}
|
||||
if (target == null)
|
||||
target = parent;
|
||||
symmetryParent = target;
|
||||
|
||||
// 親が同一かどうか
|
||||
bool sameParent = target == parent;
|
||||
|
||||
// 各軸
|
||||
var x = parent.right;
|
||||
var y = parent.up;
|
||||
var z = parent.forward;
|
||||
var sx = target.right;
|
||||
var sy = target.up;
|
||||
var sz = target.forward;
|
||||
|
||||
// ベクトルの方向性情報
|
||||
// Animatorがある場合はAnimatorから、ない場合は共通の親Transformから、それでも無い場合はワールドX軸
|
||||
Vector3 H = Vector3.right;
|
||||
if (ani)
|
||||
H = ani.transform.right;
|
||||
else
|
||||
{
|
||||
var commonParent = FindCommonParent(transform, symmetryParent);
|
||||
if (commonParent)
|
||||
{
|
||||
//Debug.Log($"Find common parent:{commonParent.name}");
|
||||
H = commonParent.right;
|
||||
}
|
||||
}
|
||||
|
||||
float xdot = Mathf.Abs(Vector3.Dot(H, x));
|
||||
float ydot = Mathf.Abs(Vector3.Dot(H, y));
|
||||
float zdot = Mathf.Abs(Vector3.Dot(H, z));
|
||||
|
||||
bool xsign = Vector3.Dot(x, sx) >= 0.0f;
|
||||
bool ysign = Vector3.Dot(y, sy) >= 0.0f;
|
||||
bool zsign = Vector3.Dot(z, sz) >= 0.0f;
|
||||
|
||||
if (xdot > ydot && xdot > zdot)
|
||||
{
|
||||
// (X)
|
||||
if (sameParent)
|
||||
return ColliderSymmetryMode.X_Symmetry;
|
||||
if (Vector3.Dot(H, x) * Vector3.Dot(H, sx) > 0.0f)
|
||||
{
|
||||
if (ysign == false && zsign == false)
|
||||
return ColliderSymmetryMode.XYZ_Symmetry;
|
||||
else
|
||||
return ColliderSymmetryMode.X_Symmetry;
|
||||
}
|
||||
else if (zsign)
|
||||
return ColliderSymmetryMode.Y_Symmetry;
|
||||
else
|
||||
return ColliderSymmetryMode.Z_Symmetry;
|
||||
}
|
||||
else if (ydot > xdot && ydot > zdot)
|
||||
{
|
||||
// (Y)
|
||||
if (sameParent)
|
||||
return ColliderSymmetryMode.Y_Symmetry;
|
||||
if (Vector3.Dot(H, y) * Vector3.Dot(H, sy) > 0.0f)
|
||||
{
|
||||
if (xsign == false && zsign == false)
|
||||
return ColliderSymmetryMode.XYZ_Symmetry;
|
||||
else
|
||||
return ColliderSymmetryMode.Y_Symmetry;
|
||||
}
|
||||
else if (zsign)
|
||||
return ColliderSymmetryMode.X_Symmetry;
|
||||
else
|
||||
return ColliderSymmetryMode.Z_Symmetry;
|
||||
}
|
||||
else
|
||||
{
|
||||
// (Z)
|
||||
if (sameParent)
|
||||
return ColliderSymmetryMode.Z_Symmetry;
|
||||
if (Vector3.Dot(H, z) * Vector3.Dot(H, sz) > 0.0f)
|
||||
{
|
||||
if (xsign == false && ysign == false)
|
||||
return ColliderSymmetryMode.XYZ_Symmetry;
|
||||
else
|
||||
return ColliderSymmetryMode.Z_Symmetry;
|
||||
}
|
||||
else if (xsign)
|
||||
return ColliderSymmetryMode.Y_Symmetry;
|
||||
else
|
||||
return ColliderSymmetryMode.X_Symmetry;
|
||||
}
|
||||
}
|
||||
|
||||
bool GetHumanoidSymmetryBone(ref Transform target, Transform parent, Animator ani, HumanBodyBones src, HumanBodyBones dst)
|
||||
{
|
||||
var bone = ani.GetBoneTransform(src);
|
||||
if (bone && parent == bone)
|
||||
{
|
||||
var bone2 = ani.GetBoneTransform(dst);
|
||||
if (bone2)
|
||||
{
|
||||
target = bone2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// at/btの共通の親を返す。無い場合はnull。
|
||||
/// </summary>
|
||||
/// <param name="at"></param>
|
||||
/// <param name="bt"></param>
|
||||
/// <returns></returns>
|
||||
Transform FindCommonParent(Transform at, Transform bt)
|
||||
{
|
||||
if (at == null || bt == null)
|
||||
return null;
|
||||
|
||||
// ハッシュセットでatの親を格納
|
||||
var atParents = new HashSet<Transform>(16);
|
||||
Transform current = at;
|
||||
while (current != null)
|
||||
{
|
||||
atParents.Add(current);
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
// btの親をチェック
|
||||
current = bt;
|
||||
while (current != null)
|
||||
{
|
||||
if (atParents.Contains(current))
|
||||
return current;
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 現在のシンメトリー設定に基づいて、シンメトリーのモードと対象を決定する
|
||||
/// </summary>
|
||||
internal void SetActiveSymmetryMode(bool firstOnly)
|
||||
{
|
||||
if (ActiveSymmetryMode.HasValue == false || firstOnly == false)
|
||||
{
|
||||
ActiveSymmetryMode = CalcSymmetryMode(out var target);
|
||||
ActiveSymmetryTarget = target;
|
||||
}
|
||||
}
|
||||
|
||||
public int UseTeamCount => teamIdSet.Count;
|
||||
|
||||
//=========================================================================================
|
||||
public void GetUsedTransform(HashSet<Transform> transformSet)
|
||||
{
|
||||
if (symmetryTarget)
|
||||
transformSet.Add(symmetryTarget);
|
||||
}
|
||||
|
||||
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
|
||||
{
|
||||
if (symmetryTarget)
|
||||
{
|
||||
int id = symmetryTarget.GetInstanceID();
|
||||
if (id != 0 && replaceDict.ContainsKey(id))
|
||||
symmetryTarget = replaceDict[id];
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
protected virtual void Start()
|
||||
{
|
||||
SetActiveSymmetryMode(firstOnly: true);
|
||||
}
|
||||
|
||||
protected virtual void OnValidate()
|
||||
@ -138,11 +420,15 @@ namespace MagicaCloth2
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
// コライダーを削除する
|
||||
foreach (int teamId in teamIdSet)
|
||||
if (teamIdSet.Count > 0)
|
||||
{
|
||||
var teamList = teamIdSet.ToList();
|
||||
foreach (int teamId in teamList)
|
||||
{
|
||||
MagicaManager.Collider.RemoveCollider(this, teamId);
|
||||
}
|
||||
teamIdSet.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,12 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public Direction direction = Direction.X;
|
||||
|
||||
/// <summary>
|
||||
/// Reverse direction.
|
||||
/// 方向を逆転させる
|
||||
/// </summary>
|
||||
public bool reverseDirection = false;
|
||||
|
||||
/// <summary>
|
||||
/// 半径をStart/End別々に設定
|
||||
/// Set radius separately for Start/End.
|
||||
@ -86,12 +92,14 @@ namespace MagicaCloth2
|
||||
/// <returns></returns>
|
||||
public Vector3 GetLocalDir()
|
||||
{
|
||||
float rev = reverseDirection ? -1 : 1;
|
||||
|
||||
if (direction == Direction.X)
|
||||
return Vector3.right;
|
||||
return Vector3.right * rev;
|
||||
else if (direction == Direction.Y)
|
||||
return Vector3.up;
|
||||
return Vector3.up * rev;
|
||||
else
|
||||
return Vector3.forward;
|
||||
return Vector3.forward * rev;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -108,6 +116,12 @@ namespace MagicaCloth2
|
||||
return Vector3.up;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 方向の逆転(基本的にカプセルコライダー用)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool IsReverseDirection() => reverseDirection;
|
||||
|
||||
public override void DataValidate()
|
||||
{
|
||||
size.x = Mathf.Max(size.x, 0.001f);
|
||||
|
||||
@ -3,9 +3,7 @@
|
||||
// https://magicasoft.jp
|
||||
using System;
|
||||
using System.Text;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
@ -188,14 +186,6 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
NativeArray<float> lengthBuffer;
|
||||
NativeArray<float3> localPosBuffer;
|
||||
NativeArray<quaternion> localRotBuffer;
|
||||
NativeArray<quaternion> rotationBuffer;
|
||||
NativeArray<float3> restorationVectorBuffer;
|
||||
|
||||
|
||||
//=========================================================================================
|
||||
public AngleConstraint()
|
||||
{
|
||||
@ -203,149 +193,46 @@ namespace MagicaCloth2
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lengthBuffer.DisposeSafe();
|
||||
localPosBuffer.DisposeSafe();
|
||||
localRotBuffer.DisposeSafe();
|
||||
rotationBuffer.DisposeSafe();
|
||||
restorationVectorBuffer.DisposeSafe();
|
||||
}
|
||||
|
||||
internal void WorkBufferUpdate()
|
||||
{
|
||||
int pcnt = MagicaManager.Simulation.ParticleCount;
|
||||
lengthBuffer.Resize(pcnt, options: NativeArrayOptions.UninitializedMemory);
|
||||
localPosBuffer.Resize(pcnt, options: NativeArrayOptions.UninitializedMemory);
|
||||
localRotBuffer.Resize(pcnt, options: NativeArrayOptions.UninitializedMemory);
|
||||
rotationBuffer.Resize(pcnt, options: NativeArrayOptions.UninitializedMemory);
|
||||
restorationVectorBuffer.Resize(pcnt, options: NativeArrayOptions.UninitializedMemory);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($"[AngleConstraint]");
|
||||
sb.AppendLine($" -lengthBuffer:{(lengthBuffer.IsCreated ? lengthBuffer.Length : 0)}");
|
||||
sb.AppendLine($" -localPosBuffer:{(localPosBuffer.IsCreated ? localPosBuffer.Length : 0)}");
|
||||
sb.AppendLine($" -localRotBuffer:{(localRotBuffer.IsCreated ? localRotBuffer.Length : 0)}");
|
||||
sb.AppendLine($" -rotationBuffer:{(rotationBuffer.IsCreated ? rotationBuffer.Length : 0)}");
|
||||
sb.AppendLine($" -restorationVectorBuffer:{(restorationVectorBuffer.IsCreated ? restorationVectorBuffer.Length : 0)}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 制約の解決
|
||||
/// </summary>
|
||||
/// <param name="clothBase"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
internal unsafe JobHandle SolverConstraint(JobHandle jobHandle)
|
||||
{
|
||||
var tm = MagicaManager.Team;
|
||||
var sm = MagicaManager.Simulation;
|
||||
var vm = MagicaManager.VMesh;
|
||||
|
||||
// 角度復元と角度制限を1つに統合したもの
|
||||
// 復元/制限ともにほぼMC1の移植。
|
||||
// 他のアルゴリズムを散々テストした結果、MC1の動きが一番映えるという結論に至る。
|
||||
// 微調整および堅牢性を上げるために反復回数を増やしている。
|
||||
var job = new AngleConstraintJob()
|
||||
{
|
||||
simulationPower = MagicaManager.Time.SimulationPower,
|
||||
|
||||
stepBaseLineIndexArray = sm.processingStepBaseLine.Buffer,
|
||||
|
||||
teamDataArray = tm.teamDataArray.GetNativeArray(),
|
||||
parameterArray = tm.parameterArray.GetNativeArray(),
|
||||
|
||||
attributes = vm.attributes.GetNativeArray(),
|
||||
vertexDepths = vm.vertexDepths.GetNativeArray(),
|
||||
vertexParentIndices = vm.vertexParentIndices.GetNativeArray(),
|
||||
baseLineStartDataIndices = vm.baseLineStartDataIndices.GetNativeArray(),
|
||||
baseLineDataCounts = vm.baseLineDataCounts.GetNativeArray(),
|
||||
baseLineData = vm.baseLineData.GetNativeArray(),
|
||||
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
frictionArray = sm.frictionArray.GetNativeArray(),
|
||||
|
||||
stepBasicPositionBuffer = sm.stepBasicPositionBuffer,
|
||||
stepBasicRotationBuffer = sm.stepBasicRotationBuffer,
|
||||
|
||||
lengthBufferArray = lengthBuffer,
|
||||
localPosBufferArray = localPosBuffer,
|
||||
localRotBufferArray = localRotBuffer,
|
||||
rotationBufferArray = rotationBuffer,
|
||||
restorationVectorBufferArray = restorationVectorBuffer,
|
||||
};
|
||||
jobHandle = job.Schedule(sm.processingStepBaseLine.GetJobSchedulePtr(), 2, jobHandle);
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct AngleConstraintJob : IJobParallelForDefer
|
||||
{
|
||||
public float4 simulationPower;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> stepBaseLineIndexArray;
|
||||
|
||||
// Solver
|
||||
//=========================================================================================
|
||||
internal static void SolverConstraint(
|
||||
DataChunk chunk,
|
||||
in float4 simulationPower,
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ClothParameters> parameterArray;
|
||||
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
// vmesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> vertexDepths;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> vertexParentIndices;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ushort> baseLineStartDataIndices;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ushort> baseLineDataCounts;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ushort> baseLineData;
|
||||
|
||||
ref NativeArray<VertexAttribute> attributes,
|
||||
ref NativeArray<float> vertexDepths,
|
||||
ref NativeArray<int> vertexParentIndices,
|
||||
ref NativeArray<ushort> baseLineStartDataIndices,
|
||||
ref NativeArray<ushort> baseLineDataCounts,
|
||||
ref NativeArray<ushort> baseLineData,
|
||||
// particle
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> frictionArray;
|
||||
|
||||
// temp
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> stepBasicPositionBuffer;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<quaternion> stepBasicRotationBuffer;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float> lengthBufferArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> localPosBufferArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<quaternion> localRotBufferArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<quaternion> rotationBufferArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> restorationVectorBufferArray;
|
||||
|
||||
// ベースラインごと
|
||||
public void Execute(int index)
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
ref NativeArray<float3> velocityPosArray,
|
||||
ref NativeArray<float> frictionArray,
|
||||
// buffer
|
||||
ref NativeArray<float3> stepBasicPositionBuffer,
|
||||
ref NativeArray<quaternion> stepBasicRotationBuffer,
|
||||
// buffer2
|
||||
ref NativeArray<float> lengthBufferArray,
|
||||
ref NativeArray<float3> localPosBufferArray,
|
||||
ref NativeArray<quaternion> localRotBufferArray,
|
||||
ref NativeArray<quaternion> rotationBufferArray,
|
||||
ref NativeArray<float3> restorationVectorBufferArray
|
||||
)
|
||||
{
|
||||
uint pack = (uint)stepBaseLineIndexArray[index];
|
||||
int teamId = DataUtility.Unpack32Hi(pack);
|
||||
int bindex = DataUtility.Unpack32Low(pack);
|
||||
|
||||
// チームは有効であることが保証されている
|
||||
var tdata = teamDataArray[teamId];
|
||||
var param = parameterArray[teamId];
|
||||
var angleParam = param.angleConstraint;
|
||||
if (angleParam.useAngleLimit == false && angleParam.useAngleRestoration == false)
|
||||
return;
|
||||
@ -354,9 +241,6 @@ namespace MagicaCloth2
|
||||
int p_start = tdata.particleChunk.startIndex;
|
||||
int v_start = tdata.proxyCommonChunk.startIndex;
|
||||
|
||||
int start = baseLineStartDataIndices[bindex];
|
||||
int dcnt = baseLineDataCounts[bindex];
|
||||
|
||||
bool useAngleLimit = angleParam.useAngleLimit;
|
||||
bool useAngleRestoration = angleParam.useAngleRestoration;
|
||||
|
||||
@ -371,6 +255,15 @@ namespace MagicaCloth2
|
||||
//float gravity = param.gravity;
|
||||
//float3 gravityVector = gravity > Define.System.Epsilon ? param.gravityDirection : 0;
|
||||
|
||||
// ベースラインごと
|
||||
//int bindex = tdata.baseLineChunk.startIndex;
|
||||
int bindex = tdata.baseLineChunk.startIndex + chunk.startIndex;
|
||||
//for (int a = 0; a < tdata.baseLineChunk.dataLength; a++, bindex++)
|
||||
for (int a = 0; a < chunk.dataLength; a++, bindex++)
|
||||
{
|
||||
int start = baseLineStartDataIndices[bindex];
|
||||
int dcnt = baseLineDataCounts[bindex];
|
||||
|
||||
// バッファリング
|
||||
int dataIndex = start + d_start;
|
||||
for (int i = 0; i < dcnt; i++, dataIndex++)
|
||||
@ -402,8 +295,21 @@ namespace MagicaCloth2
|
||||
|
||||
// 親からの基本姿勢
|
||||
var bv = bpos - pbpos;
|
||||
Develop.Assert(math.length(bv) > 0.0f);
|
||||
var v = math.normalize(bv);
|
||||
float bvlen = math.length(bv);
|
||||
if (vlen < Define.System.Epsilon || bvlen < Define.System.Epsilon)
|
||||
{
|
||||
// length=0
|
||||
//Debug.Log($"NG1");
|
||||
//エッジ長0対処
|
||||
lengthBufferArray[pindex] = 0;
|
||||
localPosBufferArray[pindex] = 0;
|
||||
localRotBufferArray[pindex] = quaternion.identity;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Develop.Assert(math.length(bv) > 0.0f);
|
||||
//var v = math.normalize(bv);
|
||||
var v = bv / bvlen;
|
||||
var ipq = math.inverse(pbrot);
|
||||
float3 localPos = math.mul(ipq, v);
|
||||
quaternion localRot = math.mul(ipq, brot);
|
||||
@ -412,12 +318,14 @@ namespace MagicaCloth2
|
||||
localPosBufferArray[pindex] = localPos;
|
||||
localRotBufferArray[pindex] = localRot;
|
||||
}
|
||||
}
|
||||
|
||||
if (useAngleRestoration)
|
||||
{
|
||||
// 復元ベクトル
|
||||
float3 rv = bpos - pbpos;
|
||||
restorationVectorBufferArray[pindex] = rv;
|
||||
//Debug.Log($"[{pindex}] rv:{rv}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -478,19 +386,46 @@ namespace MagicaCloth2
|
||||
|
||||
// 現在のベクトル
|
||||
float3 v = cpos - ppos;
|
||||
float vlen = math.length(v);
|
||||
if (vlen < Define.System.Epsilon)
|
||||
{
|
||||
//エッジ長0対処
|
||||
//Debug.Log($"NG2");
|
||||
goto EndAngleLimit;
|
||||
}
|
||||
|
||||
// 復元すべきベクトル
|
||||
float3 tv = math.mul(prot, localPos);
|
||||
float tvlen = math.length(tv);
|
||||
if (tvlen < Define.System.Epsilon)
|
||||
{
|
||||
//エッジ長0対処
|
||||
//Debug.Log($"NG3");
|
||||
float3 add = ppos - cpos;
|
||||
nextPosArray[pindex] = ppos;
|
||||
velocityPosArray[pindex] = velocityPosArray[pindex] + add;
|
||||
rotationBufferArray[pindex] = math.mul(prot, localRot);
|
||||
goto EndAngleLimit;
|
||||
}
|
||||
|
||||
v /= vlen;
|
||||
tv /= tvlen;
|
||||
|
||||
// ベクトル長修正
|
||||
float vlen = math.length(v);
|
||||
float blen = lengthBufferArray[pindex];
|
||||
vlen = math.lerp(vlen, blen, 0.5f); // 計算前の距離に徐々に近づける
|
||||
Develop.Assert(vlen > 0.0f);
|
||||
v = math.normalize(v) * vlen;
|
||||
if (blen < Define.System.Epsilon || vlen < Define.System.Epsilon)
|
||||
{
|
||||
//エッジ長0対処
|
||||
//Debug.Log($"NG4");
|
||||
goto EndAngleLimit;
|
||||
}
|
||||
//Develop.Assert(vlen > 0.0f);
|
||||
//v = math.normalize(v) * vlen;
|
||||
v = v * vlen;
|
||||
|
||||
// ベクトル角度クランプ
|
||||
float maxAngleDeg = angleParam.limitCurveData.EvaluateCurve(cdepth);
|
||||
float maxAngleDeg = angleParam.limitCurveData.MC2EvaluateCurve(cdepth);
|
||||
float maxAngleRad = math.radians(maxAngleDeg);
|
||||
float angle = MathUtility.Angle(v, tv);
|
||||
float3 rv = v;
|
||||
@ -537,12 +472,23 @@ namespace MagicaCloth2
|
||||
|
||||
// 回転補正
|
||||
v = cpos - ppos;
|
||||
vlen = math.length(v);
|
||||
if (vlen < Define.System.Epsilon)
|
||||
{
|
||||
//エッジ長0対処
|
||||
//Debug.Log($"NG5");
|
||||
goto EndAngleLimit;
|
||||
}
|
||||
v /= vlen;
|
||||
var nrot = math.mul(prot, localRot);
|
||||
var q = MathUtility.FromToRotation(tv, v);
|
||||
//var q = MathUtility.FromToRotation(tv, v);
|
||||
var q = MathUtility.FromToRotationWithoutNormalize(tv, v);
|
||||
nrot = math.mul(q, nrot);
|
||||
rotationBufferArray[pindex] = nrot;
|
||||
}
|
||||
|
||||
EndAngleLimit:
|
||||
|
||||
//=====================================================
|
||||
// Angle Restoration
|
||||
//=====================================================
|
||||
@ -550,14 +496,31 @@ namespace MagicaCloth2
|
||||
{
|
||||
//Debug.Log($"pindex:{pindex}, p_pindex:{p_pindex}");
|
||||
|
||||
// 現在のベクトル
|
||||
float3 v = cpos - ppos;
|
||||
|
||||
// 復元すべきベクトル
|
||||
float3 tv = restorationVectorBufferArray[pindex];
|
||||
float tvlen = math.length(tv);
|
||||
if (tvlen < Define.System.Epsilon)
|
||||
{
|
||||
//エッジ長0対処
|
||||
//Debug.Log($"NG6");
|
||||
float3 add = ppos - cpos;
|
||||
nextPosArray[pindex] = ppos;
|
||||
velocityPosArray[pindex] = velocityPosArray[pindex] + add;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 現在のベクトル
|
||||
float3 v = cpos - ppos;
|
||||
float vlen = math.length(v);
|
||||
if (vlen < Define.System.Epsilon)
|
||||
{
|
||||
//エッジ長0対処
|
||||
//Debug.Log($"NG7");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 復元力
|
||||
float restorationStiffness = angleParam.restorationStiffness.EvaluateCurveClamp01(cdepth);
|
||||
float restorationStiffness = angleParam.restorationStiffness.MC2EvaluateCurveClamp01(cdepth);
|
||||
restorationStiffness = math.saturate(restorationStiffness * simulationPower.w);
|
||||
|
||||
//int _pindex = indexBuffer[i] + p_start;
|
||||
@ -567,7 +530,7 @@ namespace MagicaCloth2
|
||||
restorationStiffness *= gravityFalloff;
|
||||
|
||||
// 球面線形補間
|
||||
var q = MathUtility.FromToRotation(v, tv, restorationStiffness);
|
||||
var q = MathUtility.FromToRotationWithoutNormalize(v / vlen, tv / tvlen, restorationStiffness);
|
||||
float3 rv = math.mul(q, v);
|
||||
|
||||
// 回転中心割合
|
||||
@ -607,6 +570,25 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// バッファクリア
|
||||
bindex = tdata.baseLineChunk.startIndex + chunk.startIndex;
|
||||
for (int a = 0; a < chunk.dataLength; a++, bindex++)
|
||||
{
|
||||
int start = baseLineStartDataIndices[bindex];
|
||||
int dcnt = baseLineDataCounts[bindex];
|
||||
|
||||
int dataIndex = start + d_start;
|
||||
for (int i = 0; i < dcnt; i++, dataIndex++)
|
||||
{
|
||||
int l_index = baseLineData[dataIndex];
|
||||
int pindex = p_start + l_index;
|
||||
|
||||
lengthBufferArray[pindex] = 0;
|
||||
localPosBufferArray[pindex] = 0;
|
||||
restorationVectorBufferArray[pindex] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
@ -113,6 +111,11 @@ namespace MagicaCloth2
|
||||
|
||||
public void GetUsedTransform(HashSet<Transform> transformSet)
|
||||
{
|
||||
colliderList.ForEach(x =>
|
||||
{
|
||||
if (x)
|
||||
x.GetUsedTransform(transformSet);
|
||||
});
|
||||
foreach (var t in collisionBones)
|
||||
{
|
||||
if (t)
|
||||
@ -122,6 +125,11 @@ namespace MagicaCloth2
|
||||
|
||||
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
|
||||
{
|
||||
colliderList.ForEach(x =>
|
||||
{
|
||||
if (x)
|
||||
x.ReplaceTransform(replaceDict);
|
||||
});
|
||||
for (int i = 0; i < collisionBones.Count; i++)
|
||||
{
|
||||
var t = collisionBones[i];
|
||||
@ -184,9 +192,6 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
NativeArray<int> tempFrictionArray;
|
||||
NativeArray<int> tempNormalArray;
|
||||
|
||||
//=========================================================================================
|
||||
public ColliderCollisionConstraint()
|
||||
{
|
||||
@ -195,211 +200,69 @@ namespace MagicaCloth2
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
tempFrictionArray.DisposeSafe();
|
||||
tempNormalArray.DisposeSafe();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作業バッファ更新
|
||||
/// </summary>
|
||||
internal void WorkBufferUpdate()
|
||||
{
|
||||
int cnt = MagicaManager.Team.edgeColliderCollisionCount;
|
||||
if (cnt == 0)
|
||||
return;
|
||||
|
||||
int pcnt = MagicaManager.Simulation.ParticleCount;
|
||||
tempFrictionArray.Resize(pcnt);
|
||||
tempNormalArray.Resize(pcnt * 3);
|
||||
//if (tempFrictionArray.IsCreated == false || tempFrictionArray.Length < pcnt)
|
||||
//{
|
||||
// if (tempFrictionArray.IsCreated)
|
||||
// tempFrictionArray.Dispose();
|
||||
// tempFrictionArray = new NativeArray<int>(pcnt, Allocator.Persistent);
|
||||
//}
|
||||
//if (tempNormalArray.IsCreated == false || tempNormalArray.Length < pcnt * 3)
|
||||
//{
|
||||
// if (tempNormalArray.IsCreated)
|
||||
// tempNormalArray.Dispose();
|
||||
// tempNormalArray = new NativeArray<int>(pcnt * 3, Allocator.Persistent);
|
||||
//}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($"[ColliderCollisionConstraint]");
|
||||
sb.AppendLine($" -tempFrictionArray:{(tempFrictionArray.IsCreated ? tempFrictionArray.Length : 0)}");
|
||||
sb.AppendLine($" -tempNormalArray:{(tempNormalArray.IsCreated ? tempNormalArray.Length : 0)}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 制約の解決
|
||||
/// </summary>
|
||||
/// <param name="clothBase"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
unsafe internal JobHandle SolverConstraint(JobHandle jobHandle)
|
||||
{
|
||||
var tm = MagicaManager.Team;
|
||||
var sm = MagicaManager.Simulation;
|
||||
var vm = MagicaManager.VMesh;
|
||||
var cm = MagicaManager.Collider;
|
||||
|
||||
// Point
|
||||
var job = new PointColliderCollisionConstraintJob()
|
||||
{
|
||||
stepParticleIndexArray = sm.processingStepParticle.Buffer,
|
||||
|
||||
teamDataArray = tm.teamDataArray.GetNativeArray(),
|
||||
parameterArray = tm.parameterArray.GetNativeArray(),
|
||||
|
||||
attributes = vm.attributes.GetNativeArray(),
|
||||
vertexDepths = vm.vertexDepths.GetNativeArray(),
|
||||
|
||||
teamIdArray = sm.teamIdArray.GetNativeArray(),
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
frictionArray = sm.frictionArray.GetNativeArray(),
|
||||
collisionNormalArray = sm.collisionNormalArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
basePosArray = sm.basePosArray.GetNativeArray(),
|
||||
|
||||
colliderFlagArray = cm.flagArray.GetNativeArray(),
|
||||
colliderWorkDataArray = cm.workDataArray.GetNativeArray(),
|
||||
};
|
||||
jobHandle = job.Schedule(sm.processingStepParticle.GetJobSchedulePtr(), 32, jobHandle);
|
||||
|
||||
// Edge
|
||||
if (tm.edgeColliderCollisionCount > 0)
|
||||
{
|
||||
var job2 = new EdgeColliderCollisionConstraintJob()
|
||||
{
|
||||
stepEdgeCollisionIndexArray = sm.processingStepEdgeCollision.Buffer,
|
||||
|
||||
teamDataArray = tm.teamDataArray.GetNativeArray(),
|
||||
parameterArray = tm.parameterArray.GetNativeArray(),
|
||||
|
||||
attributes = vm.attributes.GetNativeArray(),
|
||||
vertexDepths = vm.vertexDepths.GetNativeArray(),
|
||||
edgeTeamIdArray = vm.edgeTeamIdArray.GetNativeArray(),
|
||||
edges = vm.edges.GetNativeArray(),
|
||||
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
frictionArray = sm.frictionArray.GetNativeArray(),
|
||||
collisionNormalArray = sm.collisionNormalArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
|
||||
colliderFlagArray = cm.flagArray.GetNativeArray(),
|
||||
colliderWorkDataArray = cm.workDataArray.GetNativeArray(),
|
||||
|
||||
countArray = sm.countArray,
|
||||
sumArray = sm.sumArray,
|
||||
tempFrictionArray = tempFrictionArray,
|
||||
tempNormalArray = tempNormalArray,
|
||||
};
|
||||
jobHandle = job2.Schedule(sm.processingStepEdgeCollision.GetJobSchedulePtr(), 32, jobHandle);
|
||||
|
||||
// 集計
|
||||
var job3 = new SolveEdgeBufferAndClearJob()
|
||||
{
|
||||
jobParticleIndexList = sm.processingStepParticle.Buffer,
|
||||
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
frictionArray = sm.frictionArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
collisionNormalArray = sm.collisionNormalArray.GetNativeArray(),
|
||||
|
||||
countArray = sm.countArray,
|
||||
sumArray = sm.sumArray,
|
||||
tempFrictionArray = tempFrictionArray,
|
||||
tempNormalArray = tempNormalArray,
|
||||
};
|
||||
jobHandle = job3.Schedule(sm.processingStepParticle.GetJobSchedulePtr(), 32, jobHandle);
|
||||
}
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
// Point Solver
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// Pointコライダー衝突判定
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
struct PointColliderCollisionConstraintJob : IJobParallelForDefer
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> stepParticleIndexArray;
|
||||
|
||||
internal static void SolverPointConstraint(
|
||||
DataChunk chunk,
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ClothParameters> parameterArray;
|
||||
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
// vmesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> vertexDepths;
|
||||
|
||||
ref NativeArray<VertexAttribute> attributes,
|
||||
ref NativeArray<float> vertexDepths,
|
||||
// particle
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<short> teamIdArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float> frictionArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> collisionNormalArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> basePosArray;
|
||||
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
ref NativeArray<float> frictionArray,
|
||||
ref NativeArray<float3> collisionNormalArray,
|
||||
ref NativeArray<float3> velocityPosArray,
|
||||
ref NativeArray<float3> basePosArray,
|
||||
// collider
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ExBitFlag8> colliderFlagArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ColliderManager.WorkData> colliderWorkDataArray;
|
||||
|
||||
// ステップ実行パーティクルごと
|
||||
public void Execute(int index)
|
||||
ref NativeArray<ExBitFlag16> colliderFlagArray,
|
||||
ref NativeArray<ColliderManager.WorkData> colliderWorkDataArray
|
||||
)
|
||||
{
|
||||
// このパーティクルは有効であることが保証されている
|
||||
int pindex = stepParticleIndexArray[index];
|
||||
int teamId = teamIdArray[pindex];
|
||||
var tdata = teamDataArray[teamId];
|
||||
if (tdata.colliderCount == 0)
|
||||
if (tdata.UseColliderCount == 0)
|
||||
return;
|
||||
if (param.colliderCollisionConstraint.mode != Mode.Point)
|
||||
return;
|
||||
if (chunk.IsValid == false)
|
||||
return;
|
||||
|
||||
// パラメータ
|
||||
var param = parameterArray[teamId];
|
||||
|
||||
// モード判定
|
||||
var mode = param.colliderCollisionConstraint.mode;
|
||||
if (mode != Mode.Point)
|
||||
return;
|
||||
bool isSpring = tdata.IsSpring;
|
||||
|
||||
// ■Point
|
||||
// パーティクルごと
|
||||
//int pindex = tdata.particleChunk.startIndex;
|
||||
//int vindex = tdata.proxyCommonChunk.startIndex;
|
||||
int pindex = tdata.particleChunk.startIndex + chunk.startIndex;
|
||||
int vindex = tdata.proxyCommonChunk.startIndex + chunk.startIndex;
|
||||
//for (int k = 0; k < tdata.particleChunk.dataLength; k++, pindex++, vindex++)
|
||||
for (int k = 0; k < chunk.dataLength; k++, pindex++, vindex++)
|
||||
{
|
||||
// パーティクル情報
|
||||
var nextPos = nextPosArray[pindex];
|
||||
int l_index = pindex - tdata.particleChunk.startIndex;
|
||||
int vindex = tdata.proxyCommonChunk.startIndex + l_index;
|
||||
var attr = attributes[vindex];
|
||||
if (attr.IsInvalid() || attr.IsDisableCollision())
|
||||
return;
|
||||
continue;
|
||||
if (attr.IsMove() == false && tdata.IsSpring == false) // スプリング利用時は固定頂点も通す
|
||||
return;
|
||||
continue;
|
||||
float depth = vertexDepths[vindex];
|
||||
|
||||
// BoneSpringでは自動的にソフトコライダーとなる
|
||||
bool isSpring = tdata.IsSpring;
|
||||
var basePos = isSpring ? basePosArray[pindex] : float3.zero; // ソフトコライダーのみbasePosが必要
|
||||
|
||||
// パーティクル半径
|
||||
float radius = math.max(param.radiusCurveData.EvaluateCurve(depth), 0.0001f); // safe;
|
||||
float radius = math.max(param.radiusCurveData.MC2EvaluateCurve(depth), 0.0001f); // safe;
|
||||
|
||||
// チームスケール倍率
|
||||
radius *= tdata.scaleRatio;
|
||||
@ -426,7 +289,7 @@ namespace MagicaCloth2
|
||||
aabb.Expand(cfr);
|
||||
|
||||
// BoneSpringでの最大押し出し距離
|
||||
float maxLength = isSpring ? math.max(param.colliderCollisionConstraint.limitDistance.EvaluateCurve(depth), 0.0001f) * tdata.scaleRatio : -1; // チームスケール倍率
|
||||
float maxLength = isSpring ? math.max(param.colliderCollisionConstraint.limitDistance.MC2EvaluateCurve(depth), 0.0001f) * tdata.scaleRatio : -1; // チームスケール倍率
|
||||
|
||||
// チーム内のコライダーをループ
|
||||
int cindex = tdata.colliderChunk.startIndex;
|
||||
@ -447,7 +310,6 @@ namespace MagicaCloth2
|
||||
{
|
||||
case ColliderManager.ColliderType.Sphere:
|
||||
// ソフトコライダーはSphereのみ
|
||||
//dist = PointSphereColliderDetection(ref _nextPos, basePos, radius, aabb, cwork, maxLength, out n);
|
||||
dist = PointSphereColliderDetection(ref _nextPos, basePos, radius, aabb, cwork, isSpring, maxLength, out n);
|
||||
break;
|
||||
case ColliderManager.ColliderType.CapsuleX_Center:
|
||||
@ -473,6 +335,7 @@ namespace MagicaCloth2
|
||||
addPos += (_nextPos - nextPos);
|
||||
addN += n;
|
||||
addCnt++;
|
||||
//Debug.Log($"Collision!");
|
||||
}
|
||||
|
||||
// コライダーに一定距離近づいている場合(動摩擦/静止摩擦が影響する)
|
||||
@ -531,17 +394,18 @@ namespace MagicaCloth2
|
||||
velocityPosArray[pindex] = velocityPosArray[pindex] + addPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Point球衝突判定
|
||||
/// </summary>
|
||||
/// <param name="nextpos"></param>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="radius"></param>
|
||||
/// <param name="cindex"></param>
|
||||
/// <param name="friction"></param>
|
||||
/// <returns></returns>
|
||||
float PointSphereColliderDetection(ref float3 nextpos, in float3 basePos, float radius, in AABB aabb, in ColliderManager.WorkData cwork, bool isSpring, float maxLength, out float3 normal)
|
||||
static float PointSphereColliderDetection(
|
||||
ref float3 nextpos,
|
||||
in float3 basePos,
|
||||
float radius,
|
||||
in AABB aabb,
|
||||
in ColliderManager.WorkData cwork,
|
||||
bool isSpring,
|
||||
float maxLength,
|
||||
out float3 normal
|
||||
)
|
||||
{
|
||||
// ★たとえ接触していなくともコライダーまでの距離と法線を返さなければならない!
|
||||
normal = 0;
|
||||
@ -599,15 +463,12 @@ namespace MagicaCloth2
|
||||
return dist;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Point平面衝突判定(無限平面)
|
||||
/// </summary>
|
||||
/// <param name="nextpos"></param>
|
||||
/// <param name="radius"></param>
|
||||
/// <param name="cindex"></param>
|
||||
/// <param name="normal"></param>
|
||||
/// <returns></returns>
|
||||
float PointPlaneColliderDetction(ref float3 nextpos, float radius, in ColliderManager.WorkData cwork, out float3 normal)
|
||||
static float PointPlaneColliderDetction(
|
||||
ref float3 nextpos,
|
||||
float radius,
|
||||
in ColliderManager.WorkData cwork,
|
||||
out float3 normal
|
||||
)
|
||||
{
|
||||
// ★たとえ接触していなくともコライダーまでの距離と法線を返さなければならない!
|
||||
|
||||
@ -625,17 +486,13 @@ namespace MagicaCloth2
|
||||
return MathUtility.IntersectPointPlaneDist(cpos + n * radius, n, nextpos, out nextpos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pointカプセル衝突判定
|
||||
/// </summary>
|
||||
/// <param name="nextpos"></param>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="radius"></param>
|
||||
/// <param name="cindex"></param>
|
||||
/// <param name="dir"></param>
|
||||
/// <param name="friction"></param>
|
||||
/// <returns></returns>
|
||||
float PointCapsuleColliderDetection(ref float3 nextpos, float radius, in AABB aabb, in ColliderManager.WorkData cwork, out float3 normal)
|
||||
static float PointCapsuleColliderDetection(
|
||||
ref float3 nextpos,
|
||||
float radius,
|
||||
in AABB aabb,
|
||||
in ColliderManager.WorkData cwork,
|
||||
out float3 normal
|
||||
)
|
||||
{
|
||||
// ★たとえ接触していなくともコライダーまでの距離と法線を返さなければならない!
|
||||
normal = 0;
|
||||
@ -681,92 +538,65 @@ namespace MagicaCloth2
|
||||
// 平面衝突判定と押し出し
|
||||
return MathUtility.IntersectPointPlaneDist(c, n, nextpos, out nextpos);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// Edgeコライダー衝突判定
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
unsafe struct EdgeColliderCollisionConstraintJob : IJobParallelForDefer
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> stepEdgeCollisionIndexArray;
|
||||
|
||||
// Edge Solver
|
||||
//=========================================================================================
|
||||
internal unsafe static void SolverEdgeConstraint(
|
||||
DataChunk chunk,
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ClothParameters> parameterArray;
|
||||
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
// vmesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> vertexDepths;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<short> edgeTeamIdArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int2> edges;
|
||||
|
||||
ref NativeArray<VertexAttribute> attributes,
|
||||
ref NativeArray<float> vertexDepths,
|
||||
ref NativeArray<int2> edges,
|
||||
// particle
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float> frictionArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> collisionNormalArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
// collider
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ExBitFlag8> colliderFlagArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ColliderManager.WorkData> colliderWorkDataArray;
|
||||
|
||||
// output
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> countArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> sumArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> tempFrictionArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> tempNormalArray;
|
||||
|
||||
// ステップ実行エッジごと
|
||||
public void Execute(int index)
|
||||
ref NativeArray<ExBitFlag16> colliderFlagArray,
|
||||
ref NativeArray<ColliderManager.WorkData> colliderWorkDataArray,
|
||||
// buffer2
|
||||
ref NativeArray<float3> tempVectorBufferA,
|
||||
ref NativeArray<float3> tempVectorBufferB,
|
||||
ref NativeArray<int> tempCountBuffer,
|
||||
ref NativeArray<float> tempFloatBufferA
|
||||
)
|
||||
{
|
||||
// このエッジは有効であることが保証されている
|
||||
int eindex = stepEdgeCollisionIndexArray[index];
|
||||
int teamId = edgeTeamIdArray[eindex];
|
||||
var tdata = teamDataArray[teamId];
|
||||
if (tdata.colliderCount == 0)
|
||||
if (tdata.UseColliderCount == 0)
|
||||
return;
|
||||
if (param.colliderCollisionConstraint.mode != Mode.Edge)
|
||||
return;
|
||||
if (chunk.IsValid == false)
|
||||
return;
|
||||
|
||||
// パラメータ
|
||||
var param = parameterArray[teamId];
|
||||
// ■Edge
|
||||
int* vecAPt = (int*)tempVectorBufferA.GetUnsafePtr();
|
||||
int* vecBPt = (int*)tempVectorBufferB.GetUnsafePtr();
|
||||
int* cntPt = (int*)tempCountBuffer.GetUnsafePtr();
|
||||
int* floatPt = (int*)tempFloatBufferA.GetUnsafePtr();
|
||||
|
||||
// モード判定
|
||||
var mode = param.colliderCollisionConstraint.mode;
|
||||
if (mode != Mode.Edge)
|
||||
return;
|
||||
|
||||
// エッジ情報
|
||||
// ■計算
|
||||
// エッジごと
|
||||
int vstart = tdata.proxyCommonChunk.startIndex;
|
||||
//int eindex = tdata.proxyEdgeChunk.startIndex;
|
||||
int eindex = tdata.proxyEdgeChunk.startIndex + chunk.startIndex;
|
||||
//for (int k = 0; k < tdata.proxyEdgeChunk.dataLength; k++, eindex++)
|
||||
for (int k = 0; k < chunk.dataLength; k++, eindex++)
|
||||
{
|
||||
// エッジ情報
|
||||
int2 edge = edges[eindex];
|
||||
int2 vE = edge + vstart;
|
||||
var attrE0 = attributes[vE.x];
|
||||
var attrE1 = attributes[vE.y];
|
||||
// 両方とも固定なら不要
|
||||
if (attrE0.IsMove() == false && attrE1.IsMove() == false)
|
||||
return;
|
||||
continue;
|
||||
int pstart = tdata.particleChunk.startIndex;
|
||||
int2 pE = edge + pstart;
|
||||
float3x2 nextPosE = new float3x2(nextPosArray[pE.x], nextPosArray[pE.y]);
|
||||
float2 depthE = new float2(vertexDepths[vE.x], vertexDepths[vE.y]);
|
||||
float2 radiusE = new float2(param.radiusCurveData.EvaluateCurve(depthE.x), param.radiusCurveData.EvaluateCurve(depthE.y));
|
||||
float2 radiusE = new float2(param.radiusCurveData.MC2EvaluateCurve(depthE.x), param.radiusCurveData.MC2EvaluateCurve(depthE.y));
|
||||
|
||||
// チームスケール倍率
|
||||
radiusE *= tdata.scaleRatio;
|
||||
@ -781,12 +611,6 @@ namespace MagicaCloth2
|
||||
float3 collisionNormal = 0;
|
||||
float3 n = 0;
|
||||
|
||||
// 書き込みポインタ
|
||||
int* cntPt = (int*)countArray.GetUnsafePtr();
|
||||
int* sumPt = (int*)sumArray.GetUnsafePtr();
|
||||
int* frictionPt = (int*)tempFrictionArray.GetUnsafePtr();
|
||||
int* normalPt = (int*)tempNormalArray.GetUnsafePtr();
|
||||
|
||||
// エッジAABB
|
||||
var aabbE = new AABB(nextPosE.c0 - radiusE.x, nextPosE.c0 + radiusE.x);
|
||||
var aabbE1 = new AABB(nextPosE.c1 - radiusE.y, nextPosE.c1 + radiusE.y);
|
||||
@ -868,8 +692,8 @@ namespace MagicaCloth2
|
||||
addPos *= t;
|
||||
|
||||
// 書き戻し
|
||||
InterlockUtility.AddFloat3(pE.x, addPos.c0, cntPt, sumPt);
|
||||
InterlockUtility.AddFloat3(pE.y, addPos.c1, cntPt, sumPt);
|
||||
InterlockUtility.AddFloat3(pE.x, addPos.c0, cntPt, vecAPt);
|
||||
InterlockUtility.AddFloat3(pE.y, addPos.c1, cntPt, vecAPt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -881,20 +705,99 @@ namespace MagicaCloth2
|
||||
var friction = 1.0f - math.saturate(mindist / cfr);
|
||||
|
||||
// 大きい場合のみ上書き
|
||||
InterlockUtility.Max(pE.x, friction, frictionPt);
|
||||
InterlockUtility.Max(pE.y, friction, frictionPt);
|
||||
InterlockUtility.Max(pE.x, friction, floatPt);
|
||||
InterlockUtility.Max(pE.y, friction, floatPt);
|
||||
|
||||
// 摩擦用接触法線平均化
|
||||
//Develop.Assert(math.length(collisionNormal) > 0.0f);
|
||||
collisionNormal = math.normalize(collisionNormal);
|
||||
|
||||
// 接触法線集計(すべて加算する)
|
||||
InterlockUtility.AddFloat3(pE.x, collisionNormal, normalPt);
|
||||
InterlockUtility.AddFloat3(pE.y, collisionNormal, normalPt);
|
||||
InterlockUtility.AddFloat3(pE.x, collisionNormal, vecBPt);
|
||||
InterlockUtility.AddFloat3(pE.y, collisionNormal, vecBPt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float EdgeSphereColliderDetection(ref float3x2 nextPosE, in float2 radiusE, in AABB aabbE, float cfr, in ColliderManager.WorkData cwork, out float3 normal)
|
||||
internal unsafe static void SumEdgeConstraint(
|
||||
DataChunk chunk,
|
||||
// team
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
// particle
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
ref NativeArray<float> frictionArray,
|
||||
ref NativeArray<float3> collisionNormalArray,
|
||||
// buffer2
|
||||
ref NativeArray<float3> tempVectorBufferA,
|
||||
ref NativeArray<float3> tempVectorBufferB,
|
||||
ref NativeArray<int> tempCountBuffer,
|
||||
ref NativeArray<float> tempFloatBufferA
|
||||
)
|
||||
{
|
||||
if (tdata.UseColliderCount == 0)
|
||||
return;
|
||||
if (param.colliderCollisionConstraint.mode != Mode.Edge)
|
||||
return;
|
||||
if (chunk.IsValid == false)
|
||||
return;
|
||||
|
||||
// ■Edge
|
||||
int* vecAPt = (int*)tempVectorBufferA.GetUnsafePtr();
|
||||
int* vecBPt = (int*)tempVectorBufferB.GetUnsafePtr();
|
||||
int* cntPt = (int*)tempCountBuffer.GetUnsafePtr();
|
||||
int* floatPt = (int*)tempFloatBufferA.GetUnsafePtr();
|
||||
|
||||
// ■集計
|
||||
// パーティクルごと
|
||||
//int pindex = tdata.particleChunk.startIndex;
|
||||
//int vindex = tdata.proxyCommonChunk.startIndex;
|
||||
int pindex = tdata.particleChunk.startIndex + chunk.startIndex;
|
||||
int vindex = tdata.proxyCommonChunk.startIndex + chunk.startIndex;
|
||||
//for (int k = 0; k < tdata.particleChunk.dataLength; k++, pindex++, vindex++)
|
||||
for (int k = 0; k < chunk.dataLength; k++, pindex++, vindex++)
|
||||
{
|
||||
// nextpos
|
||||
int count = tempCountBuffer[pindex];
|
||||
if (count > 0)
|
||||
{
|
||||
float3 add = InterlockUtility.ReadAverageFloat3(pindex, cntPt, vecAPt);
|
||||
|
||||
// 書き出し
|
||||
nextPosArray[pindex] = nextPosArray[pindex] + add;
|
||||
}
|
||||
|
||||
// friction
|
||||
float f = InterlockUtility.ReadFloat(pindex, floatPt);
|
||||
if (f > 0.0f && f > frictionArray[pindex])
|
||||
{
|
||||
frictionArray[pindex] = f;
|
||||
}
|
||||
|
||||
// collision normal
|
||||
float3 n = InterlockUtility.ReadFloat3(pindex, vecBPt);
|
||||
if (math.lengthsq(n) > 0.0f)
|
||||
{
|
||||
n = math.normalize(n);
|
||||
collisionNormalArray[pindex] = n;
|
||||
}
|
||||
|
||||
// バッファクリア
|
||||
tempVectorBufferA[pindex] = 0;
|
||||
tempVectorBufferB[pindex] = 0;
|
||||
tempCountBuffer[pindex] = 0;
|
||||
tempFloatBufferA[pindex] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static float EdgeSphereColliderDetection(
|
||||
ref float3x2 nextPosE,
|
||||
in float2 radiusE,
|
||||
in AABB aabbE,
|
||||
float cfr,
|
||||
in ColliderManager.WorkData cwork,
|
||||
out float3 normal
|
||||
)
|
||||
{
|
||||
// ★たとえ接触していなくともコライダーまでの距離と法線を返さなければならない!
|
||||
normal = 0;
|
||||
@ -989,7 +892,14 @@ namespace MagicaCloth2
|
||||
return -C;
|
||||
}
|
||||
|
||||
float EdgeCapsuleColliderDetection(ref float3x2 nextPosE, in float2 radiusE, in AABB aabbE, float cfr, in ColliderManager.WorkData cwork, out float3 normal)
|
||||
static float EdgeCapsuleColliderDetection(
|
||||
ref float3x2 nextPosE,
|
||||
in float2 radiusE,
|
||||
in AABB aabbE,
|
||||
float cfr,
|
||||
in ColliderManager.WorkData cwork,
|
||||
out float3 normal
|
||||
)
|
||||
{
|
||||
// ★たとえ接触していなくともコライダーまでの距離と法線を返さなければならない!
|
||||
normal = 0;
|
||||
@ -1021,10 +931,37 @@ namespace MagicaCloth2
|
||||
|
||||
// 押出法線
|
||||
var v = cA - cB;
|
||||
Develop.Assert(math.length(v) > 0.0f);
|
||||
float3 n = math.normalize(v);
|
||||
float3 n = v / clen;
|
||||
normal = n;
|
||||
|
||||
#if !MC2_DISABLE_EDGE_COLLISION_EXTENSION
|
||||
// ★カプセル半径を考慮した補正
|
||||
// これまでのエッジ-カプセル判定はカプセルの半径が始点と終点で同じであることが前提となっていた
|
||||
// そのためカプセルの始点と終点の半径が異なると間違った衝突判定が行われてしまい、それが原因で大きな振動が発生していた
|
||||
// (これはBoneClothのようにカプセルエッジよりメッシュエッジのほうが長い場合に顕著になる)
|
||||
// そこで始点と終点の半径が異なる場合は、最初の計算の最近接点方向からカプセルエッジを半径分シフトし、
|
||||
// それをもとに再度エッジ-エッジ判定を行うように修正した
|
||||
// これは完璧ではないがおおよそ理想的な判定を行うようになり、また振動の問題も大幅に解決できる
|
||||
// (ただし小刻みな振動はまだ発生することがある)
|
||||
if (sr != er)
|
||||
{
|
||||
// 押し出し法線方向にカプセル半径を考慮してカプセルの中心線をシフトさせる
|
||||
float3 soldpos2 = soldpos + n * sr;
|
||||
float3 eoldpos2 = eoldpos + n * er;
|
||||
|
||||
// この線分で再び最近接点(s/t)を計算する
|
||||
MathUtility.ClosestPtSegmentSegment2(nextPosE.c0, nextPosE.c1, soldpos2, eoldpos2, out s, out t);
|
||||
|
||||
// 最終的にはこのシフト後のsとtを利用するように結果を書き換える
|
||||
cA = math.lerp(nextPosE.c0, nextPosE.c1, s);
|
||||
cB = math.lerp(soldpos, eoldpos, t);
|
||||
v = cA - cB;
|
||||
clen = math.length(v);
|
||||
n = v / clen;
|
||||
normal = n;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 変位
|
||||
float3 dB0 = spos - soldpos;
|
||||
float3 dB1 = epos - eoldpos;
|
||||
@ -1094,7 +1031,12 @@ namespace MagicaCloth2
|
||||
return -C;
|
||||
}
|
||||
|
||||
float EdgePlaneColliderDetection(ref float3x2 nextPosE, in float2 radiusE, in ColliderManager.WorkData cwork, out float3 normal)
|
||||
static float EdgePlaneColliderDetection(
|
||||
ref float3x2 nextPosE,
|
||||
in float2 radiusE,
|
||||
in ColliderManager.WorkData cwork,
|
||||
out float3 normal
|
||||
)
|
||||
{
|
||||
// ★たとえ接触していなくともコライダーまでの距離と法線を返さなければならない!
|
||||
|
||||
@ -1115,82 +1057,4 @@ namespace MagicaCloth2
|
||||
return math.min(dist0, dist1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// エッジコライダーコリジョン結果の集計
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
struct SolveEdgeBufferAndClearJob : IJobParallelForDefer
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> jobParticleIndexList;
|
||||
|
||||
// particle
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float> frictionArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> collisionNormalArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
|
||||
// aggregate
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> countArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> sumArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> tempFrictionArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> tempNormalArray;
|
||||
|
||||
// ステップ有効パーティクルごと
|
||||
public void Execute(int index)
|
||||
{
|
||||
int pindex = jobParticleIndexList[index];
|
||||
|
||||
// nextpos
|
||||
int count = countArray[pindex];
|
||||
int dataIndex = pindex * 3;
|
||||
if (count > 0)
|
||||
{
|
||||
float3 add = InterlockUtility.ReadAverageFloat3(pindex, countArray, sumArray);
|
||||
|
||||
// 書き出し
|
||||
nextPosArray[pindex] = nextPosArray[pindex] + add;
|
||||
|
||||
// 速度影響
|
||||
//float attn = param.colliderCollisionConstraint.colliderVelocityAttenuation;
|
||||
//float attn = Define.System.ColliderCollisionVelocityAttenuation;
|
||||
//velocityPosArray[pindex] = velocityPosArray[pindex] + add * attn;
|
||||
|
||||
// バッファクリア
|
||||
countArray[pindex] = 0;
|
||||
sumArray[dataIndex] = 0;
|
||||
sumArray[dataIndex + 1] = 0;
|
||||
sumArray[dataIndex + 2] = 0;
|
||||
}
|
||||
|
||||
// friction
|
||||
float f = InterlockUtility.ReadFloat(pindex, tempFrictionArray);
|
||||
if (f > 0.0f && f > frictionArray[pindex])
|
||||
{
|
||||
frictionArray[pindex] = f;
|
||||
tempFrictionArray[pindex] = 0;
|
||||
}
|
||||
|
||||
// collision normal
|
||||
float3 n = InterlockUtility.ReadFloat3(pindex, tempNormalArray);
|
||||
if (math.lengthsq(n) > 0.0f)
|
||||
{
|
||||
n = math.normalize(n);
|
||||
collisionNormalArray[pindex] = n;
|
||||
tempNormalArray[dataIndex] = 0;
|
||||
tempNormalArray[dataIndex + 1] = 0;
|
||||
tempNormalArray[dataIndex + 2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,9 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
@ -85,9 +83,10 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// 制約データ
|
||||
/// </summary>
|
||||
internal class ConstraintData : IValid
|
||||
[System.Serializable]
|
||||
public class ConstraintData : IValid
|
||||
{
|
||||
internal ResultCode result;
|
||||
public ResultCode result;
|
||||
|
||||
public uint[] indexArray;
|
||||
public ushort[] dataArray;
|
||||
@ -151,7 +150,7 @@ namespace MagicaCloth2
|
||||
/// 制約データの作成
|
||||
/// </summary>
|
||||
/// <param name="cbase"></param>
|
||||
internal static ConstraintData CreateData(VirtualMesh proxyMesh, in ClothParameters parameters)
|
||||
public static ConstraintData CreateData(VirtualMesh proxyMesh, in ClothParameters parameters)
|
||||
{
|
||||
var constraintData = new ConstraintData();
|
||||
|
||||
@ -216,7 +215,7 @@ namespace MagicaCloth2
|
||||
for (int l = 0; l < ecnt; l++)
|
||||
{
|
||||
int2 edge = proxyMesh.edges[l];
|
||||
var tset = proxyMesh.edgeToTriangles.ToFixedList128Bytes(edge);
|
||||
var tset = proxyMesh.edgeToTriangles.MC2ToFixedList128Bytes(edge);
|
||||
int tcnt = tset.Length;
|
||||
if (tcnt < 2)
|
||||
continue;
|
||||
@ -377,103 +376,34 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 制約の解決
|
||||
/// </summary>
|
||||
/// <param name="clothBase"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
unsafe internal JobHandle SolverConstraint(JobHandle jobHandle)
|
||||
{
|
||||
var tm = MagicaManager.Team;
|
||||
var sm = MagicaManager.Simulation;
|
||||
var vm = MagicaManager.VMesh;
|
||||
|
||||
var job = new DistanceConstraintJob()
|
||||
{
|
||||
simulationPower = MagicaManager.Time.SimulationPower,
|
||||
|
||||
stepParticleIndexArray = sm.processingStepParticle.Buffer,
|
||||
|
||||
teamDataArray = tm.teamDataArray.GetNativeArray(),
|
||||
parameterArray = tm.parameterArray.GetNativeArray(),
|
||||
|
||||
attributes = vm.attributes.GetNativeArray(),
|
||||
depthArray = vm.vertexDepths.GetNativeArray(),
|
||||
|
||||
teamIdArray = sm.teamIdArray.GetNativeArray(),
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
basePosArray = sm.basePosArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
frictionArray = sm.frictionArray.GetNativeArray(),
|
||||
|
||||
//stepBasicPositionBuffer = sm.stepBasicPositionBuffer,
|
||||
|
||||
indexArray = indexArray.GetNativeArray(),
|
||||
dataArray = dataArray.GetNativeArray(),
|
||||
distanceArray = distanceArray.GetNativeArray(),
|
||||
};
|
||||
jobHandle = job.Schedule(sm.processingStepParticle.GetJobSchedulePtr(), 32, jobHandle);
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 距離制約の解決
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
struct DistanceConstraintJob : IJobParallelForDefer
|
||||
{
|
||||
public float4 simulationPower;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> stepParticleIndexArray;
|
||||
|
||||
// Solver
|
||||
//=========================================================================================
|
||||
internal static void SolverConstraint(
|
||||
DataChunk chunk,
|
||||
float4 simulationPower,
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ClothParameters> parameterArray;
|
||||
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
// vmesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> depthArray;
|
||||
|
||||
ref NativeArray<VertexAttribute> attributes,
|
||||
ref NativeArray<float> depthArray,
|
||||
// particle
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<short> teamIdArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> basePosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> frictionArray;
|
||||
|
||||
// buffer
|
||||
//[Unity.Collections.ReadOnly]
|
||||
//public NativeArray<float3> stepBasicPositionBuffer;
|
||||
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
ref NativeArray<float3> basePosArray,
|
||||
ref NativeArray<float3> velocityPosArray,
|
||||
ref NativeArray<float> frictionArray,
|
||||
// constrants
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<uint> indexArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ushort> dataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> distanceArray;
|
||||
|
||||
// ステップ有効パーティクルごと
|
||||
public void Execute(int index)
|
||||
ref NativeArray<uint> indexArray,
|
||||
ref NativeArray<ushort> dataArray,
|
||||
ref NativeArray<float> distanceArray
|
||||
)
|
||||
{
|
||||
// pindexのチームは有効であることが保証されている
|
||||
int pindex = stepParticleIndexArray[index];
|
||||
|
||||
int teamId = teamIdArray[pindex];
|
||||
var tdata = teamDataArray[teamId];
|
||||
var parameter = parameterArray[teamId];
|
||||
var sc = tdata.distanceStartChunk;
|
||||
var dc = tdata.distanceDataChunk;
|
||||
if (sc.dataLength == 0)
|
||||
return;
|
||||
int c_start = sc.startIndex;
|
||||
int d_start = dc.startIndex;
|
||||
|
||||
// 復元を基本姿勢で行うかアニメーション後の姿勢で行うかの判定
|
||||
float blendRatio = tdata.animationPoseRatio;
|
||||
@ -481,20 +411,20 @@ namespace MagicaCloth2
|
||||
// スケール倍率
|
||||
float scl = tdata.InitScale * tdata.scaleRatio;
|
||||
|
||||
bool isSpring = tdata.IsSpring;
|
||||
|
||||
// パーティクルごと
|
||||
int p_start = tdata.particleChunk.startIndex;
|
||||
int l_index = pindex - p_start;
|
||||
|
||||
var sc = tdata.distanceStartChunk;
|
||||
var dc = tdata.distanceDataChunk;
|
||||
|
||||
if (sc.dataLength == 0)
|
||||
return;
|
||||
|
||||
int c_start = sc.startIndex;
|
||||
int d_start = dc.startIndex;
|
||||
int pindex = p_start + chunk.startIndex;
|
||||
//int pindex = p_start;
|
||||
int v_start = tdata.proxyCommonChunk.startIndex;
|
||||
int vindex = v_start + l_index;
|
||||
|
||||
int vindex = v_start + chunk.startIndex;
|
||||
//int vindex = v_start;
|
||||
int dataIndex = chunk.startIndex;
|
||||
//int dataIndex = 0;
|
||||
//for (int k = 0; k < tdata.particleChunk.dataLength; k++, pindex++, vindex++, dataIndex++)
|
||||
for (int k = 0; k < chunk.dataLength; k++, pindex++, vindex++, dataIndex++)
|
||||
{
|
||||
// パーティクル情報
|
||||
var nextPos = nextPosArray[pindex];
|
||||
var attr = attributes[vindex];
|
||||
@ -502,36 +432,31 @@ namespace MagicaCloth2
|
||||
float friction = frictionArray[pindex];
|
||||
|
||||
if (attr.IsInvalid())
|
||||
return;
|
||||
continue;
|
||||
|
||||
// Spring利用中は固定も通す
|
||||
bool isSpring = tdata.IsSpring;
|
||||
if (attr.IsDontMove() && isSpring == false)
|
||||
return;
|
||||
continue;
|
||||
|
||||
// 固定点の重量
|
||||
float fixMass = isSpring ? 10.0f : 50.0f;
|
||||
|
||||
// 重量
|
||||
// BoneSpringでは固定点の重量加算を行わない
|
||||
//float invMass = MathUtility.CalcInverseMass(friction, depth, attr.IsDontMove() && isSpring == false);
|
||||
float invMass = MathUtility.CalcInverseMass(friction, depth, attr.IsDontMove(), fixMass);
|
||||
//float invMass = isSpring && attr.IsDontMove() ? 1.0f / 2.0f : MathUtility.CalcInverseMass(friction, depth, attr.IsDontMove());
|
||||
|
||||
// 基本剛性
|
||||
float stiffness = parameter.distanceConstraint.restorationStiffness.EvaluateCurveClamp01(depth);
|
||||
//stiffness *= simulationPower;
|
||||
//stiffness *= (simulationPower * simulationPower);
|
||||
float stiffness = param.distanceConstraint.restorationStiffness.MC2EvaluateCurveClamp01(depth);
|
||||
stiffness *= simulationPower.y;
|
||||
|
||||
var pack = indexArray[c_start + l_index];
|
||||
//var pack = indexArray[c_start + k];
|
||||
var pack = indexArray[c_start + dataIndex];
|
||||
DataUtility.Unpack12_20(pack, out int dcnt, out int dstart);
|
||||
|
||||
if (dcnt > 0)
|
||||
{
|
||||
// 基準座標を切り替え
|
||||
float3 basePos = basePosArray[pindex];
|
||||
//float3 basicPos = stepBasicPositionBuffer[pindex];
|
||||
|
||||
float3 addPos = 0;
|
||||
int addCnt = 0;
|
||||
@ -550,22 +475,18 @@ namespace MagicaCloth2
|
||||
int tvindex = v_start + t_l_index;
|
||||
var t_nextPos = nextPosArray[tpindex];
|
||||
float3 t_basePos = basePosArray[tpindex];
|
||||
//float3 t_basicPos = stepBasicPositionBuffer[tpindex];
|
||||
float t_depth = depthArray[tvindex];
|
||||
float t_friction = frictionArray[tpindex];
|
||||
var t_attr = attributes[tvindex];
|
||||
|
||||
// 重量
|
||||
// BoneSpringでは固定点の重量加算を行わない
|
||||
//float t_invMass = MathUtility.CalcInverseMass(t_friction, t_depth, t_attr.IsDontMove() && isSpring == false);
|
||||
float t_invMass = MathUtility.CalcInverseMass(t_friction, t_depth, t_attr.IsDontMove(), fixMass);
|
||||
//float t_invMass = isSpring && t_attr.IsDontMove() ? 1.0f / 2.0f : MathUtility.CalcInverseMass(t_friction, t_depth, t_attr.IsDontMove());
|
||||
|
||||
// 復元する長さ
|
||||
// !Distance制約は初期化時に保存した距離を見るようにしないと駄目
|
||||
// フラグにより初期値かアニメーション後の姿勢かを切り替える
|
||||
float restLength = math.lerp(math.abs(restDist) * scl, math.distance(basePos, t_basePos), blendRatio);
|
||||
//float restLength = math.distance(basicPos, t_basicPos);
|
||||
|
||||
var v = t_nextPos - nextPos;
|
||||
|
||||
@ -595,7 +516,7 @@ namespace MagicaCloth2
|
||||
nextPosArray[pindex] = nextPos;
|
||||
|
||||
// 速度影響
|
||||
float attn = parameter.distanceConstraint.velocityAttenuation;
|
||||
float attn = param.distanceConstraint.velocityAttenuation;
|
||||
velocityPosArray[pindex] = velocityPosArray[pindex] + addPos * attn;
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +39,28 @@ namespace MagicaCloth2
|
||||
[System.Serializable]
|
||||
public class SerializeData : IDataValidate
|
||||
{
|
||||
/// <summary>
|
||||
/// Anchor that cancels inertia.
|
||||
/// Anchor translation and rotation are excluded from simulation.
|
||||
/// This is useful if your character rides a vehicle.
|
||||
/// 慣性を打ち消すアンカー
|
||||
/// アンカーの移動と回転はシミュレーションから除外されます
|
||||
/// これはキャラクターが乗り物に乗る場合に便利です
|
||||
/// [OK] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
public Transform anchor;
|
||||
|
||||
/// <summary>
|
||||
/// Anchor Influence (0.0 ~ 1.0)
|
||||
/// アンカーの影響(0.0 ~ 1.0)
|
||||
/// [OK] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float anchorInertia;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// World Influence (0.0 ~ 1.0).
|
||||
/// ワールド移動影響(0.0 ~ 1.0)
|
||||
@ -49,6 +71,15 @@ namespace MagicaCloth2
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float worldInertia;
|
||||
|
||||
/// <summary>
|
||||
/// World Influence Smoothing (0.0 ~ 1.0).
|
||||
/// ワールド移動影響平滑化(0.0 ~ 1.0)
|
||||
/// [OK] Runtime changes.
|
||||
/// [OK] Export/Import with Presets
|
||||
/// </summary>
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float movementInertiaSmoothing;
|
||||
|
||||
/// <summary>
|
||||
/// World movement speed limit (m/s).
|
||||
/// ワールド移動速度制限(m/s)
|
||||
@ -144,7 +175,12 @@ namespace MagicaCloth2
|
||||
|
||||
public SerializeData()
|
||||
{
|
||||
anchor = null;
|
||||
anchorInertia = 0.0f;
|
||||
worldInertia = 1.0f;
|
||||
//movementInertiaSmoothing = 0.65f; // ->0.0524
|
||||
//movementInertiaSmoothing = 0.5f; // ->0.13375
|
||||
movementInertiaSmoothing = 0.4f;
|
||||
movementSpeedLimit = new CheckSliderSerializeData(true, 5.0f);
|
||||
rotationSpeedLimit = new CheckSliderSerializeData(true, 720.0f);
|
||||
localInertia = 1.0f;
|
||||
@ -162,7 +198,10 @@ namespace MagicaCloth2
|
||||
{
|
||||
return new SerializeData()
|
||||
{
|
||||
anchor = anchor,
|
||||
anchorInertia = anchorInertia,
|
||||
worldInertia = worldInertia,
|
||||
movementInertiaSmoothing = movementInertiaSmoothing,
|
||||
movementSpeedLimit = movementSpeedLimit.Clone(),
|
||||
rotationSpeedLimit = rotationSpeedLimit.Clone(),
|
||||
localInertia = localInertia,
|
||||
@ -179,7 +218,9 @@ namespace MagicaCloth2
|
||||
|
||||
public void DataValidate()
|
||||
{
|
||||
anchorInertia = Mathf.Clamp01(anchorInertia);
|
||||
worldInertia = Mathf.Clamp01(worldInertia);
|
||||
movementInertiaSmoothing = Mathf.Clamp01(movementInertiaSmoothing);
|
||||
movementSpeedLimit.DataValidate(0.0f, Define.System.MaxMovementSpeedLimit);
|
||||
rotationSpeedLimit.DataValidate(0.0f, Define.System.MaxRotationSpeedLimit);
|
||||
localInertia = Mathf.Clamp01(localInertia);
|
||||
@ -195,18 +236,30 @@ namespace MagicaCloth2
|
||||
|
||||
public struct InertiaConstraintParams
|
||||
{
|
||||
/// <summary>
|
||||
/// アンカー影響率(0.0 ~ 1.0)
|
||||
/// </summary>
|
||||
public float anchorInertia;
|
||||
|
||||
/// <summary>
|
||||
/// ワールド慣性影響(0.0 ~ 1.0)
|
||||
/// </summary>
|
||||
public float worldInertia;
|
||||
|
||||
/// <summary>
|
||||
/// ワールド慣性スムージング率(0.0 ~ 1.0)
|
||||
/// </summary>
|
||||
public float movementInertiaSmoothing;
|
||||
|
||||
/// <summary>
|
||||
/// ワールド移動速度制限(m/s)
|
||||
/// 無制限時は(-1)
|
||||
/// </summary>
|
||||
public float movementSpeedLimit;
|
||||
|
||||
/// <summary>
|
||||
/// ワールド回転速度制限(deg/s)
|
||||
/// 無制限時は(-1)
|
||||
/// </summary>
|
||||
public float rotationSpeedLimit;
|
||||
|
||||
@ -258,7 +311,9 @@ namespace MagicaCloth2
|
||||
|
||||
public void Convert(SerializeData sdata)
|
||||
{
|
||||
anchorInertia = sdata.anchorInertia;
|
||||
worldInertia = sdata.worldInertia;
|
||||
movementInertiaSmoothing = sdata.movementInertiaSmoothing;
|
||||
movementSpeedLimit = sdata.movementSpeedLimit.GetValue(-1);
|
||||
rotationSpeedLimit = sdata.rotationSpeedLimit.GetValue(-1);
|
||||
localInertia = sdata.localInertia;
|
||||
@ -277,8 +332,26 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// センタートランスフォームのデータ
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public struct CenterData
|
||||
{
|
||||
/// <summary>
|
||||
/// 現在のアンカー姿勢
|
||||
/// </summary>
|
||||
public float3 anchorPosition;
|
||||
public quaternion anchorRotation;
|
||||
|
||||
/// <summary>
|
||||
/// 前フレームのアンカー姿勢
|
||||
/// </summary>
|
||||
public float3 oldAnchorPosition;
|
||||
public quaternion oldAnchorRotation;
|
||||
|
||||
/// <summary>
|
||||
/// アンカー空間でのコンポーネントのローカル座標
|
||||
/// </summary>
|
||||
public float3 anchorComponentLocalPosition;
|
||||
|
||||
/// <summary>
|
||||
/// 参照すべきセンタートランスフォームインデックス
|
||||
/// 同期時は同期先チームのもにになる
|
||||
@ -290,12 +363,14 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public float3 componentWorldPosition;
|
||||
public quaternion componentWorldRotation;
|
||||
public float3 componentWorldScale;
|
||||
|
||||
/// <summary>
|
||||
/// 前フレームのコンポーネント姿勢
|
||||
/// </summary>
|
||||
public float3 oldComponentWorldPosition;
|
||||
public quaternion oldComponentWorldRotation;
|
||||
public float3 oldComponentWorldScale;
|
||||
|
||||
/// <summary>
|
||||
/// 現フレームのコンポーネント移動量
|
||||
@ -329,7 +404,7 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public float3 nowWorldPosition;
|
||||
public quaternion nowWorldRotation;
|
||||
public float3 nowWorldScale; // ※現在未使用
|
||||
//public float3 nowWorldScale; // ※現在未使用
|
||||
|
||||
/// <summary>
|
||||
/// 前回ステップでの姿勢
|
||||
@ -395,10 +470,26 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public float3 initLocalGravityDirection;
|
||||
|
||||
/// <summary>
|
||||
/// スムージングされた現在のワールド慣性速度ベクトル
|
||||
/// </summary>
|
||||
public float3 smoothingVelocity; // (m/s)
|
||||
|
||||
/// <summary>
|
||||
/// マイナススケールによる反転を打ち消すための変換マトリックス
|
||||
/// センター空間
|
||||
/// </summary>
|
||||
public float4x4 negativeScaleMatrix;
|
||||
|
||||
internal void Initialize()
|
||||
{
|
||||
anchorRotation = quaternion.identity;
|
||||
oldAnchorRotation = quaternion.identity;
|
||||
|
||||
componentWorldRotation = quaternion.identity;
|
||||
componentWorldScale = 1;
|
||||
oldComponentWorldRotation = quaternion.identity;
|
||||
oldComponentWorldScale = 1;
|
||||
frameComponentShiftRotation = quaternion.identity;
|
||||
|
||||
frameWorldRotation = quaternion.identity;
|
||||
@ -412,6 +503,7 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// 制約データ
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintData
|
||||
{
|
||||
public ResultCode result;
|
||||
@ -450,7 +542,7 @@ namespace MagicaCloth2
|
||||
/// 制約データの作成
|
||||
/// </summary>
|
||||
/// <param name="cbase"></param>
|
||||
internal static ConstraintData CreateData(VirtualMesh proxyMesh, in ClothParameters parameters)
|
||||
public static ConstraintData CreateData(VirtualMesh proxyMesh, in ClothParameters parameters)
|
||||
{
|
||||
var constraintData = new ConstraintData();
|
||||
|
||||
@ -489,7 +581,7 @@ namespace MagicaCloth2
|
||||
// 初期センター姿勢からローカル重力方向を算出する
|
||||
var rot = MathUtility.ToRotation(math.normalize(nor), math.normalize(tan));
|
||||
var irot = math.inverse(rot);
|
||||
localGravityDirection = math.mul(irot, parameters.gravityDirection);
|
||||
localGravityDirection = math.mul(irot, parameters.worldGravityDirection);
|
||||
}
|
||||
constraintData.initLocalGravityDirection = localGravityDirection;
|
||||
|
||||
@ -519,12 +611,13 @@ namespace MagicaCloth2
|
||||
|
||||
// 初期化時のローカル重力方向
|
||||
cdata.initLocalGravityDirection = cprocess.inertiaConstraintData.initLocalGravityDirection;
|
||||
//Debug.Log($"[{cprocess.TeamId}] initLocalGravityDirection:{cdata.initLocalGravityDirection}");
|
||||
|
||||
// 固定点リスト
|
||||
var c = new DataChunk();
|
||||
if (cprocess.ProxyMesh.CenterFixedPointCount > 0)
|
||||
if (cprocess.ProxyMeshContainer.shareVirtualMesh.CenterFixedPointCount > 0)
|
||||
{
|
||||
c = fixedArray.AddRange(cprocess.ProxyMesh.centerFixedList);
|
||||
c = fixedArray.AddRange(cprocess.ProxyMeshContainer.shareVirtualMesh.centerFixedList);
|
||||
}
|
||||
tdata.fixedDataChunk = c;
|
||||
}
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
// Copyright (c) 2023 MagicaSoft.
|
||||
// https://magicasoft.jp
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
@ -134,97 +132,45 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 制約の解決
|
||||
/// </summary>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
unsafe internal JobHandle SolverConstraint(JobHandle jobHandle)
|
||||
{
|
||||
var tm = MagicaManager.Team;
|
||||
var sm = MagicaManager.Simulation;
|
||||
var vm = MagicaManager.VMesh;
|
||||
|
||||
var job = new MotionConstraintJob()
|
||||
{
|
||||
stepParticleIndexArray = sm.processingStepMotionParticle.Buffer,
|
||||
|
||||
teamDataArray = tm.teamDataArray.GetNativeArray(),
|
||||
parameterArray = tm.parameterArray.GetNativeArray(),
|
||||
|
||||
attributes = vm.attributes.GetNativeArray(),
|
||||
vertexDepths = vm.vertexDepths.GetNativeArray(),
|
||||
|
||||
teamIdArray = sm.teamIdArray.GetNativeArray(),
|
||||
basePosArray = sm.basePosArray.GetNativeArray(),
|
||||
baseRotArray = sm.baseRotArray.GetNativeArray(),
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
frictionArray = sm.frictionArray.GetNativeArray(),
|
||||
collisionNormalArray = sm.collisionNormalArray.GetNativeArray(),
|
||||
};
|
||||
jobHandle = job.Schedule(sm.processingStepMotionParticle.GetJobSchedulePtr(), 32, jobHandle);
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct MotionConstraintJob : IJobParallelForDefer
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> stepParticleIndexArray;
|
||||
|
||||
// Solver
|
||||
//=========================================================================================
|
||||
internal static void SolverConstraint(
|
||||
DataChunk chunk,
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ClothParameters> parameterArray;
|
||||
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
// vmesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> vertexDepths;
|
||||
|
||||
ref NativeArray<VertexAttribute> attributes,
|
||||
ref NativeArray<float> vertexDepths,
|
||||
// particle
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<short> teamIdArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> basePosArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<quaternion> baseRotArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float> frictionArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> collisionNormalArray;
|
||||
|
||||
|
||||
public void Execute(int index)
|
||||
ref NativeArray<float3> basePosArray,
|
||||
ref NativeArray<quaternion> baseRotArray,
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
ref NativeArray<float3> velocityPosArray,
|
||||
ref NativeArray<float> frictionArray,
|
||||
ref NativeArray<float3> collisionNormalArray
|
||||
)
|
||||
{
|
||||
// pindexのチームは有効であることが保証されている
|
||||
int pindex = stepParticleIndexArray[index];
|
||||
|
||||
int teamId = teamIdArray[pindex];
|
||||
var tdata = teamDataArray[teamId];
|
||||
var param = parameterArray[teamId];
|
||||
var motionParam = param.motionConstraint;
|
||||
var normalAxis = param.normalAxis;
|
||||
if (motionParam.useMaxDistance == false && motionParam.useBackstop == false)
|
||||
if (param.motionConstraint.useMaxDistance == false && param.motionConstraint.useBackstop == false)
|
||||
return;
|
||||
|
||||
int p_start = tdata.particleChunk.startIndex;
|
||||
int l_index = pindex - p_start;
|
||||
int v_start = tdata.proxyCommonChunk.startIndex;
|
||||
int vindex = v_start + l_index;
|
||||
// stiffness
|
||||
float stiffness = param.motionConstraint.stiffness;
|
||||
|
||||
float backstopRadius = param.motionConstraint.backstopRadius;
|
||||
|
||||
// パーティクルごと
|
||||
//int pindex = tdata.particleChunk.startIndex;
|
||||
//int vindex = tdata.proxyCommonChunk.startIndex;
|
||||
int pindex = tdata.particleChunk.startIndex + chunk.startIndex;
|
||||
int vindex = tdata.proxyCommonChunk.startIndex + chunk.startIndex;
|
||||
//for (int k = 0; k < tdata.particleChunk.dataLength; k++, pindex++, vindex++)
|
||||
for (int k = 0; k < chunk.dataLength; k++, pindex++, vindex++)
|
||||
{
|
||||
// 移動パーティクルのみ
|
||||
var attr = attributes[vindex];
|
||||
if (attr.IsMove() == false)
|
||||
return;
|
||||
continue;
|
||||
|
||||
var nextPos = nextPosArray[pindex];
|
||||
var basePos = basePosArray[pindex];
|
||||
@ -233,17 +179,13 @@ namespace MagicaCloth2
|
||||
// !MaxDistanceとBackstop制約は常にアニメーション姿勢(basePose)から計算されるので注意!
|
||||
// !そのためAnimationBlendRatioは影響しない。
|
||||
|
||||
// stiffness
|
||||
float stiffness = motionParam.stiffness;
|
||||
|
||||
// 適用頂点属性チェック
|
||||
if (attr.IsMotion())
|
||||
{
|
||||
var opos = nextPos;
|
||||
|
||||
// パーティクル半径
|
||||
float radius = math.max(param.radiusCurveData.EvaluateCurve(depth), 0.0001f); // safe
|
||||
//radius *= tdata.scaleRatio;
|
||||
float radius = math.max(param.radiusCurveData.MC2EvaluateCurve(depth), 0.0001f); // safe
|
||||
|
||||
// 摩擦影響距離
|
||||
float cfr = radius * 1.0f;
|
||||
@ -256,7 +198,7 @@ namespace MagicaCloth2
|
||||
//=========================================================
|
||||
var baseRot = baseRotArray[pindex];
|
||||
float3 dir = math.up();
|
||||
switch (normalAxis)
|
||||
switch (param.normalAxis)
|
||||
{
|
||||
case ClothNormalAxis.Right:
|
||||
dir = math.right();
|
||||
@ -282,9 +224,9 @@ namespace MagicaCloth2
|
||||
//=========================================================
|
||||
// Max Distance
|
||||
//=========================================================
|
||||
if (motionParam.useMaxDistance)
|
||||
if (param.motionConstraint.useMaxDistance)
|
||||
{
|
||||
float maxDistance = motionParam.maxDistanceCurveData.EvaluateCurve(depth);
|
||||
float maxDistance = param.motionConstraint.maxDistanceCurveData.MC2EvaluateCurve(depth);
|
||||
//var cen = basePos + dir * (motionParam.maxDistanceOffset * maxDistance);
|
||||
var cen = basePos;
|
||||
var v = MathUtility.ClampVector(nextPos - cen, maxDistance);
|
||||
@ -294,10 +236,9 @@ namespace MagicaCloth2
|
||||
//=========================================================
|
||||
// Backstop
|
||||
//=========================================================
|
||||
if (motionParam.useBackstop)
|
||||
if (param.motionConstraint.useBackstop)
|
||||
{
|
||||
float backstopRadius = motionParam.backstopRadius;
|
||||
float backstopDistance = motionParam.backstopDistanceCurveData.EvaluateCurve(depth);
|
||||
float backstopDistance = param.motionConstraint.backstopDistanceCurveData.MC2EvaluateCurve(depth);
|
||||
if (backstopRadius > 0.0f)
|
||||
{
|
||||
// バックストップは法線逆方向
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,6 @@
|
||||
// https://magicasoft.jp
|
||||
|
||||
using System;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
@ -127,11 +126,5 @@ namespace MagicaCloth2
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
unsafe internal JobHandle SolverConstraint(JobHandle jobHandle)
|
||||
{
|
||||
return jobHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
// Copyright (c) 2023 MagicaSoft.
|
||||
// https://magicasoft.jp
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
@ -32,7 +30,7 @@ namespace MagicaCloth2
|
||||
|
||||
public SerializeData()
|
||||
{
|
||||
distanceCompression = 0.9f;
|
||||
distanceCompression = 0.4f;
|
||||
}
|
||||
|
||||
public void DataValidate()
|
||||
@ -85,102 +83,41 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 制約の解決
|
||||
/// </summary>
|
||||
/// <param name="clothBase"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
unsafe internal JobHandle SolverConstraint(JobHandle jobHandle)
|
||||
{
|
||||
var tm = MagicaManager.Team;
|
||||
var sm = MagicaManager.Simulation;
|
||||
var vm = MagicaManager.VMesh;
|
||||
|
||||
var job = new TethreConstraintJob()
|
||||
{
|
||||
stepParticleIndexArray = sm.processingStepParticle.Buffer,
|
||||
|
||||
teamDataArray = tm.teamDataArray.GetNativeArray(),
|
||||
parameterArray = tm.parameterArray.GetNativeArray(),
|
||||
centerDataArray = tm.centerDataArray.GetNativeArray(),
|
||||
|
||||
attributes = vm.attributes.GetNativeArray(),
|
||||
vertexDepths = vm.vertexDepths.GetNativeArray(),
|
||||
vertexRootIndices = vm.vertexRootIndices.GetNativeArray(),
|
||||
|
||||
teamIdArray = sm.teamIdArray.GetNativeArray(),
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
frictionArray = sm.frictionArray.GetNativeArray(),
|
||||
|
||||
stepBasicPositionBuffer = sm.stepBasicPositionBuffer,
|
||||
};
|
||||
jobHandle = job.Schedule(sm.processingStepParticle.GetJobSchedulePtr(), 32, jobHandle);
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct TethreConstraintJob : IJobParallelForDefer
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> stepParticleIndexArray;
|
||||
|
||||
// Solver
|
||||
//=========================================================================================
|
||||
internal static void SolverConstraint(
|
||||
DataChunk chunk,
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ClothParameters> parameterArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<InertiaConstraint.CenterData> centerDataArray;
|
||||
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
ref InertiaConstraint.CenterData cdata,
|
||||
// vmesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> vertexDepths;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> vertexRootIndices;
|
||||
|
||||
ref NativeArray<VertexAttribute> attributes,
|
||||
ref NativeArray<float> vertexDepths,
|
||||
ref NativeArray<int> vertexRootIndices,
|
||||
// particle
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<short> teamIdArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> frictionArray;
|
||||
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
ref NativeArray<float3> velocityPosArray,
|
||||
ref NativeArray<float> frictionArray,
|
||||
// buffer
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> stepBasicPositionBuffer;
|
||||
|
||||
// パーティクルごと
|
||||
public void Execute(int index)
|
||||
ref NativeArray<float3> stepBasicPositionBuffer
|
||||
)
|
||||
{
|
||||
// pindexのチームは有効であることが保証されている
|
||||
int pindex = stepParticleIndexArray[index];
|
||||
|
||||
int teamId = teamIdArray[pindex];
|
||||
var tdata = teamDataArray[teamId];
|
||||
var param = parameterArray[teamId].tetherConstraint;
|
||||
//if (param.stiffness < 1e-06f)
|
||||
// return;
|
||||
|
||||
int p_start = tdata.particleChunk.startIndex;
|
||||
int l_index = pindex - p_start;
|
||||
int v_start = tdata.proxyCommonChunk.startIndex;
|
||||
int vindex = v_start + l_index;
|
||||
|
||||
//int pindex = p_start;
|
||||
int pindex = p_start + chunk.startIndex;
|
||||
//int vindex = tdata.proxyCommonChunk.startIndex;
|
||||
int vindex = tdata.proxyCommonChunk.startIndex + chunk.startIndex;
|
||||
//for (int k = 0; k < tdata.particleChunk.dataLength; k++, pindex++, vindex++)
|
||||
for (int k = 0; k < chunk.dataLength; k++, pindex++, vindex++)
|
||||
{
|
||||
var attr = attributes[vindex];
|
||||
if (attr.IsMove() == false)
|
||||
return;
|
||||
continue;
|
||||
|
||||
int rootIndex = vertexRootIndices[vindex];
|
||||
if (rootIndex < 0)
|
||||
return;
|
||||
continue;
|
||||
|
||||
//Debug.Log($"Tether [{pindex}] root:{rootIndex + p_start}");
|
||||
|
||||
@ -198,7 +135,7 @@ namespace MagicaCloth2
|
||||
|
||||
// 距離がほぼ0ならば処理をスキップする(エラーの回避)
|
||||
if (distance < Define.System.Epsilon)
|
||||
return;
|
||||
continue;
|
||||
|
||||
// 復元距離
|
||||
// フラグにより初期姿勢かアニメーション後姿勢かを切り替える
|
||||
@ -210,7 +147,7 @@ namespace MagicaCloth2
|
||||
|
||||
// 初期位置がまったく同じ状況を考慮
|
||||
if (calcDistance == 0.0f)
|
||||
return;
|
||||
continue;
|
||||
|
||||
// 現在の伸縮割合
|
||||
//Develop.Assert(calcDistance > 0.0f);
|
||||
@ -220,8 +157,8 @@ namespace MagicaCloth2
|
||||
float dist = 0;
|
||||
float stiffness;
|
||||
float attn;
|
||||
float compressionLimit = 1.0f - param.compressionLimit;
|
||||
float stretchLimit = 1.0f + param.stretchLimit;
|
||||
float compressionLimit = 1.0f - param.tetherConstraint.compressionLimit;
|
||||
float stretchLimit = 1.0f + param.tetherConstraint.stretchLimit;
|
||||
//float widthRatio = math.max(param.stiffnessWidth, 0.001f); // 0.2?
|
||||
//float widthRatio = 0.1f; // 0.2?
|
||||
if (ratio < compressionLimit)
|
||||
@ -243,7 +180,7 @@ namespace MagicaCloth2
|
||||
attn = Define.System.TetherStretchVelocityAttenuation;
|
||||
}
|
||||
else
|
||||
return;
|
||||
continue;
|
||||
|
||||
// 移動量
|
||||
float3 add = (v / distance) * (dist * stiffness);
|
||||
|
||||
@ -4,9 +4,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
@ -17,6 +16,11 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public class TriangleBendingConstraint : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// ボリュームとして処理する判定フラグ
|
||||
/// </summary>
|
||||
const sbyte VOLUME_SIGN = 100;
|
||||
|
||||
public enum Method
|
||||
{
|
||||
None = 0,
|
||||
@ -29,7 +33,7 @@ namespace MagicaCloth2
|
||||
|
||||
/// <summary>
|
||||
/// 方向性ありの2面角曲げ制約
|
||||
/// 初期姿勢を保た持つように復元する
|
||||
/// 初期姿勢を保つように復元する
|
||||
/// </summary>
|
||||
DirectionDihedralAngle = 2,
|
||||
}
|
||||
@ -73,16 +77,17 @@ namespace MagicaCloth2
|
||||
|
||||
public void Convert(SerializeData sdata)
|
||||
{
|
||||
//method = sdata.method;
|
||||
// モードはDirectionDihedralAngleに固定する
|
||||
method = sdata.stiffness > Define.System.Epsilon ? Method.DirectionDihedralAngle : Method.None;
|
||||
//method = sdata.stiffness > Define.System.Epsilon ? Method.DihedralAngle : Method.None;
|
||||
|
||||
stiffness = sdata.stiffness;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
internal class ConstraintData : IValid
|
||||
[System.Serializable]
|
||||
public class ConstraintData : IValid
|
||||
{
|
||||
public ResultCode result;
|
||||
public ulong[] trianglePairArray;
|
||||
@ -116,29 +121,16 @@ namespace MagicaCloth2
|
||||
public ExNativeArray<float> restAngleOrVolumeArray;
|
||||
|
||||
/// <summary>
|
||||
/// トライアングルペアごとの復元方向もしくはボリューム判定(100=このペアはボリュームである)
|
||||
/// トライアングルペアごとの復元方向もしくはボリューム判定(VOLUME_SIGN(100)=このペアはボリュームである)
|
||||
/// </summary>
|
||||
public ExNativeArray<sbyte> signOrVolumeArray;
|
||||
|
||||
/// <summary>
|
||||
/// トライアングルペアごとの結果書き込みローカルインデックス
|
||||
/// 4つのbyteを1つのuintに結合したもの
|
||||
/// </summary>
|
||||
public ExNativeArray<uint> writeDataArray;
|
||||
//public int DataCount => trianglePairArray?.Count ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// 頂点ごとの書き込みバッファの数と開始インデックス
|
||||
/// (上位10bit = カウンタ, 下位22bit = 開始インデックス)
|
||||
/// ボリューム計算の浮動小数点誤差を回避するための倍数
|
||||
/// </summary>
|
||||
public ExNativeArray<uint> writeIndexArray;
|
||||
|
||||
/// <summary>
|
||||
/// 頂点ごとの書き込みバッファ(集計用)
|
||||
/// writeIndexArrayに従う
|
||||
/// </summary>
|
||||
public ExNativeArray<float3> writeBuffer;
|
||||
|
||||
public int DataCount => trianglePairArray?.Count ?? 0;
|
||||
const float VolumeScale = 1000.0f;
|
||||
|
||||
//=========================================================================================
|
||||
public TriangleBendingConstraint()
|
||||
@ -146,9 +138,6 @@ namespace MagicaCloth2
|
||||
trianglePairArray = new ExNativeArray<ulong>(0, true);
|
||||
restAngleOrVolumeArray = new ExNativeArray<float>(0, true);
|
||||
signOrVolumeArray = new ExNativeArray<sbyte>(0, true);
|
||||
writeDataArray = new ExNativeArray<uint>(0, true);
|
||||
writeIndexArray = new ExNativeArray<uint>(0, true);
|
||||
writeBuffer = new ExNativeArray<float3>(0, true);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@ -156,9 +145,6 @@ namespace MagicaCloth2
|
||||
trianglePairArray?.Dispose();
|
||||
restAngleOrVolumeArray?.Dispose();
|
||||
signOrVolumeArray?.Dispose();
|
||||
writeDataArray?.Dispose();
|
||||
writeIndexArray?.Dispose();
|
||||
writeBuffer?.Dispose();
|
||||
|
||||
trianglePairArray = null;
|
||||
restAngleOrVolumeArray = null;
|
||||
@ -172,9 +158,6 @@ namespace MagicaCloth2
|
||||
sb.AppendLine($" -trianglePairArray:{trianglePairArray.ToSummary()}");
|
||||
sb.AppendLine($" -restAngleOrVolumeArray:{restAngleOrVolumeArray.ToSummary()}");
|
||||
sb.AppendLine($" -signOrVolumeArray:{signOrVolumeArray.ToSummary()}");
|
||||
sb.AppendLine($" -writeDataArray:{writeDataArray.ToSummary()}");
|
||||
sb.AppendLine($" -writeIndexArray:{writeIndexArray.ToSummary()}");
|
||||
sb.AppendLine($" -writeBuffer:{writeBuffer.ToSummary()}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
@ -186,7 +169,7 @@ namespace MagicaCloth2
|
||||
/// <param name="proxyMesh"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
internal static ConstraintData CreateData(VirtualMesh proxyMesh, in ClothParameters parameters)
|
||||
public static ConstraintData CreateData(VirtualMesh proxyMesh, in ClothParameters parameters)
|
||||
{
|
||||
var constraintData = new ConstraintData();
|
||||
|
||||
@ -223,7 +206,7 @@ namespace MagicaCloth2
|
||||
if (proxyMesh.edgeToTriangles.ContainsKey(edge) == false)
|
||||
continue;
|
||||
|
||||
var triangles = proxyMesh.edgeToTriangles.ToFixedList128Bytes(edge);
|
||||
var triangles = proxyMesh.edgeToTriangles.MC2ToFixedList128Bytes(edge);
|
||||
int tcnt = triangles.Length;
|
||||
|
||||
// トライアングルの組み合わせ
|
||||
@ -276,6 +259,7 @@ namespace MagicaCloth2
|
||||
trianglePairList.Add(pair);
|
||||
restAngleOrVolumeList.Add(restData);
|
||||
signOrVolumeList.Add(signFlag);
|
||||
//Debug.Log($"rest angle:{math.degrees(restData)}, signFlag:{signFlag}");
|
||||
|
||||
uint writeData = DataUtility.Pack32(
|
||||
multiBuilder.CountValuesForKey(vtx.x),
|
||||
@ -320,7 +304,7 @@ namespace MagicaCloth2
|
||||
|
||||
volumeCount++;
|
||||
|
||||
//Develop.DebugLog($"Volume Pair. edge:{edge}, tri:({tri0},{tri1}) restAngle:{degAngle}");
|
||||
//Develop.DebugLog($"Volume Pair. edge:{edge}, tri:({tri0},{tri1}) restAngle:{degAngle}, restData:{restData}, signFlag:{signFlag}");
|
||||
}
|
||||
}
|
||||
//if (math.all(tri0 - 243) == false || math.all(tri1 - 243) == false)
|
||||
@ -357,13 +341,15 @@ namespace MagicaCloth2
|
||||
static void InitVolume(VirtualMesh proxyMesh, int v0, int v1, int v2, int v3, out float volumeRest, out sbyte signFlag)
|
||||
{
|
||||
// 0/1が対角点,2/3が共通辺
|
||||
float3 pos0 = proxyMesh.localPositions[v0];
|
||||
float3 pos1 = proxyMesh.localPositions[v1];
|
||||
float3 pos2 = proxyMesh.localPositions[v2];
|
||||
float3 pos3 = proxyMesh.localPositions[v3];
|
||||
// ここは実行時とボリューム値を合わせるためワールド座標で計算する必要がある。
|
||||
float3 pos0 = MathUtility.TransformPoint(proxyMesh.localPositions[v0], proxyMesh.initLocalToWorld);
|
||||
float3 pos1 = MathUtility.TransformPoint(proxyMesh.localPositions[v1], proxyMesh.initLocalToWorld);
|
||||
float3 pos2 = MathUtility.TransformPoint(proxyMesh.localPositions[v2], proxyMesh.initLocalToWorld);
|
||||
float3 pos3 = MathUtility.TransformPoint(proxyMesh.localPositions[v3], proxyMesh.initLocalToWorld);
|
||||
|
||||
volumeRest = (1.0f / 6.0f) * math.dot(math.cross(pos1 - pos0, pos2 - pos0), pos3 - pos0);
|
||||
signFlag = 100; // Volume
|
||||
volumeRest *= VolumeScale; // 浮動小数点演算誤差回避
|
||||
signFlag = VOLUME_SIGN; // Volume
|
||||
}
|
||||
|
||||
static void InitDihedralAngle(VirtualMesh proxyMesh, int v0, int v1, int v2, int v3, out float restAngle, out sbyte signFlag)
|
||||
@ -409,11 +395,6 @@ namespace MagicaCloth2
|
||||
tdata.bendingPairChunk = trianglePairArray.AddRange(cdata.trianglePairArray);
|
||||
restAngleOrVolumeArray.AddRange(cdata.restAngleOrVolumeArray);
|
||||
signOrVolumeArray.AddRange(cdata.signOrVolumeArray);
|
||||
writeDataArray.AddRange(cdata.writeDataArray);
|
||||
|
||||
// write buffer
|
||||
tdata.bendingWriteIndexChunk = writeIndexArray.AddRange(cdata.writeIndexArray);
|
||||
tdata.bendingBufferChunk = writeBuffer.AddRange(cdata.writeBufferCount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,159 +411,78 @@ namespace MagicaCloth2
|
||||
trianglePairArray.Remove(tdata.bendingPairChunk);
|
||||
restAngleOrVolumeArray.Remove(tdata.bendingPairChunk);
|
||||
signOrVolumeArray.Remove(tdata.bendingPairChunk);
|
||||
writeDataArray.Remove(tdata.bendingPairChunk);
|
||||
|
||||
// write buffer
|
||||
writeIndexArray.Remove(tdata.bendingWriteIndexChunk);
|
||||
writeBuffer.Remove(tdata.bendingBufferChunk);
|
||||
|
||||
tdata.bendingPairChunk.Clear();
|
||||
tdata.bendingWriteIndexChunk.Clear();
|
||||
tdata.bendingBufferChunk.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 制約の解決
|
||||
/// </summary>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
unsafe internal JobHandle SolverConstraint(JobHandle jobHandle)
|
||||
{
|
||||
var tm = MagicaManager.Team;
|
||||
var sm = MagicaManager.Simulation;
|
||||
var vm = MagicaManager.VMesh;
|
||||
|
||||
if (DataCount > 0)
|
||||
{
|
||||
var triangleBendingJob = new TriangleBendingJob()
|
||||
{
|
||||
simulationPower = MagicaManager.Time.SimulationPower,
|
||||
|
||||
stepTriangleBendIndexArray = sm.processingStepTriangleBending.Buffer,
|
||||
|
||||
teamDataArray = tm.teamDataArray.GetNativeArray(),
|
||||
parameterArray = tm.parameterArray.GetNativeArray(),
|
||||
|
||||
attributes = vm.attributes.GetNativeArray(),
|
||||
depthArray = vm.vertexDepths.GetNativeArray(),
|
||||
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
frictionArray = sm.frictionArray.GetNativeArray(),
|
||||
|
||||
trianglePairArray = trianglePairArray.GetNativeArray(),
|
||||
restAngleOrVolumeArray = restAngleOrVolumeArray.GetNativeArray(),
|
||||
signOrVolumeArray = signOrVolumeArray.GetNativeArray(),
|
||||
|
||||
writeDataArray = writeDataArray.GetNativeArray(),
|
||||
writeIndexArray = writeIndexArray.GetNativeArray(),
|
||||
writeBuffer = writeBuffer.GetNativeArray(),
|
||||
};
|
||||
jobHandle = triangleBendingJob.Schedule(sm.processingStepTriangleBending.GetJobSchedulePtr(), 16, jobHandle);
|
||||
|
||||
// 集計(速度影響はなし)
|
||||
var aggregateJob = new SolveAggregateBufferJob()
|
||||
{
|
||||
stepParticleIndexArray = sm.processingStepParticle.Buffer,
|
||||
|
||||
teamDataArray = tm.teamDataArray.GetNativeArray(),
|
||||
|
||||
attributes = vm.attributes.GetNativeArray(),
|
||||
|
||||
teamIdArray = sm.teamIdArray.GetNativeArray(),
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
|
||||
writeIndexArray = writeIndexArray.GetNativeArray(),
|
||||
writeBuffer = writeBuffer.GetNativeArray(),
|
||||
};
|
||||
jobHandle = aggregateJob.Schedule(sm.processingStepParticle.GetJobSchedulePtr(), 16, jobHandle);
|
||||
}
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct TriangleBendingJob : IJobParallelForDefer
|
||||
{
|
||||
public float4 simulationPower;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> stepTriangleBendIndexArray;
|
||||
|
||||
// Solver
|
||||
//=========================================================================================
|
||||
internal unsafe static void SolverConstraint(
|
||||
DataChunk chunk,
|
||||
in float4 simulationPower,
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ClothParameters> parameterArray;
|
||||
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
// vmesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> depthArray;
|
||||
|
||||
|
||||
ref NativeArray<VertexAttribute> attributes,
|
||||
ref NativeArray<float> depthArray,
|
||||
// particle
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> frictionArray;
|
||||
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
ref NativeArray<float> frictionArray,
|
||||
// constraints
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ulong> trianglePairArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float> restAngleOrVolumeArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<sbyte> signOrVolumeArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<uint> writeDataArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<uint> writeIndexArray;
|
||||
|
||||
// output
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> writeBuffer;
|
||||
|
||||
// ベンドトライアングルペアごと
|
||||
public void Execute(int index)
|
||||
ref NativeArray<ulong> trianglePairArray,
|
||||
ref NativeArray<float> restAngleOrVolumeArray,
|
||||
ref NativeArray<sbyte> signOrVolumeArray,
|
||||
// buffer2
|
||||
ref NativeArray<float3> tempVectorBufferA,
|
||||
ref NativeArray<int> tempCountBuffer
|
||||
)
|
||||
{
|
||||
// インデックスのチームは有効であることが保証されている
|
||||
//int pairIndex = stepTriangleBendIndexArray[index];
|
||||
//int teamId = trianglePairTeamIdArray[pairIndex];
|
||||
uint pack = (uint)stepTriangleBendIndexArray[index];
|
||||
int pairIndex = DataUtility.Unpack12_20Low(pack);
|
||||
int teamId = DataUtility.Unpack12_20Hi(pack);
|
||||
var tdata = teamDataArray[teamId];
|
||||
var parameter = parameterArray[teamId].triangleBendingConstraint;
|
||||
if (parameter.method == Method.None)
|
||||
if (param.triangleBendingConstraint.method == Method.None)
|
||||
return;
|
||||
|
||||
if (tdata.bendingPairChunk.IsValid == false)
|
||||
return;
|
||||
|
||||
// 剛性
|
||||
float stiffness = parameter.stiffness;
|
||||
float stiffness = param.triangleBendingConstraint.stiffness;
|
||||
if (stiffness < 1e-06f)
|
||||
return;
|
||||
stiffness = math.saturate(stiffness * simulationPower.y);
|
||||
|
||||
|
||||
int p_start = tdata.particleChunk.startIndex;
|
||||
int v_start = tdata.proxyCommonChunk.startIndex;
|
||||
int pindex;
|
||||
int vindex;
|
||||
|
||||
int* sumPt = (int*)tempVectorBufferA.GetUnsafePtr();
|
||||
int* cntPt = (int*)tempCountBuffer.GetUnsafePtr();
|
||||
|
||||
// ■計算
|
||||
// ベンドペアごと
|
||||
//int pairIndex = tdata.bendingPairChunk.startIndex;
|
||||
int pairIndex = tdata.bendingPairChunk.startIndex + chunk.startIndex;
|
||||
//for (int k = 0; k < tdata.bendingPairChunk.dataLength; k++, pairIndex++)
|
||||
for (int k = 0; k < chunk.dataLength; k++, pairIndex++)
|
||||
{
|
||||
// トライアングルペア
|
||||
var pairData = trianglePairArray[pairIndex];
|
||||
int4 vertices = DataUtility.Unpack64(pairData);
|
||||
//Debug.Log(vertices);
|
||||
|
||||
int4 pindex4 = vertices + p_start;
|
||||
int4 vindex4 = vertices + v_start;
|
||||
|
||||
// 状態
|
||||
float3x4 nextPosBuffer = 0;
|
||||
float3x4 addPosBuffer = 0;
|
||||
float4 invMassBuffer = 1;
|
||||
//int4 fixedBuffer = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int pindex = p_start + vertices[i];
|
||||
int vindex = v_start + vertices[i];
|
||||
pindex = pindex4[i];
|
||||
vindex = vindex4[i];
|
||||
nextPosBuffer[i] = nextPosArray[pindex];
|
||||
float friction = frictionArray[pindex];
|
||||
float depth = depthArray[vindex];
|
||||
@ -598,45 +498,116 @@ namespace MagicaCloth2
|
||||
|
||||
// メソッドごとの解決
|
||||
bool result = false;
|
||||
if (signOrVolume == 100)
|
||||
if (signOrVolume == VOLUME_SIGN)
|
||||
{
|
||||
// Volume
|
||||
result = Volume(nextPosBuffer, invMassBuffer, restAngle, stiffness, ref addPosBuffer);
|
||||
float volumeRest = restAngle * tdata.scaleRatio; // スケール倍率
|
||||
|
||||
// マイナススケール
|
||||
volumeRest *= tdata.negativeScaleSign;
|
||||
|
||||
result = CalcVolume(nextPosBuffer, invMassBuffer, volumeRest, stiffness, ref addPosBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Triangle Bending
|
||||
float sign = signOrVolume < 0 ? -1 : 1;
|
||||
if (parameter.method == Method.DihedralAngle)
|
||||
if (param.triangleBendingConstraint.method == Method.DihedralAngle)
|
||||
{
|
||||
// 二面角
|
||||
result = DihedralAngle(0, nextPosBuffer, invMassBuffer, restAngle, stiffness, ref addPosBuffer);
|
||||
// 方向性なし二面角
|
||||
result = CalcDihedralAngle(0, nextPosBuffer, invMassBuffer, restAngle, stiffness, ref addPosBuffer);
|
||||
}
|
||||
else if (parameter.method == Method.DirectionDihedralAngle)
|
||||
else if (param.triangleBendingConstraint.method == Method.DirectionDihedralAngle)
|
||||
{
|
||||
// 方向性二面角
|
||||
// 方向性あり二面角
|
||||
float sign = signOrVolume < 0 ? -1 : 1;
|
||||
restAngle *= sign;
|
||||
result = DihedralAngle(sign, nextPosBuffer, invMassBuffer, restAngle, stiffness, ref addPosBuffer);
|
||||
|
||||
// マイナススケール
|
||||
restAngle *= tdata.negativeScaleSign;
|
||||
|
||||
result = CalcDihedralAngle(sign, nextPosBuffer, invMassBuffer, restAngle, stiffness, ref addPosBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// 集計バッファへ格納
|
||||
if (result)
|
||||
{
|
||||
int4 writeData = DataUtility.Unpack32(writeDataArray[dataIndex]);
|
||||
int indexStart = tdata.bendingWriteIndexChunk.startIndex;
|
||||
int bufferStart = tdata.bendingBufferChunk.startIndex;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int l_vindex = vertices[i];
|
||||
int start = DataUtility.Unpack12_20Low(writeIndexArray[indexStart + l_vindex]);
|
||||
int bufferIndex = bufferStart + start + writeData[i];
|
||||
writeBuffer[bufferIndex] = addPosBuffer[i];
|
||||
pindex = pindex4[i];
|
||||
InterlockUtility.AddFloat3(pindex, addPosBuffer[i], cntPt, sumPt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Volume(in float3x4 nextPosBuffer, in float4 invMassBuffer, float volumeRest, float stiffness, ref float3x4 addPosBuffer)
|
||||
internal unsafe static void SumConstraint(
|
||||
DataChunk chunk,
|
||||
// team
|
||||
ref TeamManager.TeamData tdata,
|
||||
ref ClothParameters param,
|
||||
// vmesh
|
||||
ref NativeArray<VertexAttribute> attributes,
|
||||
// particle
|
||||
ref NativeArray<float3> nextPosArray,
|
||||
// buffer2
|
||||
ref NativeArray<float3> tempVectorBufferA,
|
||||
ref NativeArray<int> tempCountBuffer
|
||||
)
|
||||
{
|
||||
if (param.triangleBendingConstraint.method == Method.None)
|
||||
return;
|
||||
|
||||
if (tdata.bendingPairChunk.IsValid == false)
|
||||
return;
|
||||
|
||||
// 剛性
|
||||
float stiffness = param.triangleBendingConstraint.stiffness;
|
||||
if (stiffness < 1e-06f)
|
||||
return;
|
||||
|
||||
int p_start = tdata.particleChunk.startIndex;
|
||||
int v_start = tdata.proxyCommonChunk.startIndex;
|
||||
|
||||
int* sumPt = (int*)tempVectorBufferA.GetUnsafePtr();
|
||||
int* cntPt = (int*)tempCountBuffer.GetUnsafePtr();
|
||||
|
||||
// ■集計
|
||||
// パーティクルごと
|
||||
int pindex = p_start + chunk.startIndex;
|
||||
int vindex = v_start + chunk.startIndex;
|
||||
//for (int k = 0; k < tdata.particleChunk.dataLength; k++, pindex++, vindex++)
|
||||
for (int k = 0; k < chunk.dataLength; k++, pindex++, vindex++)
|
||||
{
|
||||
// 移動のみ
|
||||
if (attributes[vindex].IsDontMove() == false)
|
||||
{
|
||||
int cnt = cntPt[pindex];
|
||||
if (cnt > 0)
|
||||
{
|
||||
int pindex2 = pindex * 3;
|
||||
float3 add = new float3(sumPt[pindex2], sumPt[pindex2 + 1], sumPt[pindex2 + 2]);
|
||||
add /= cnt;
|
||||
// データは固定小数点なので戻す
|
||||
add *= InterlockUtility.ToFloat;
|
||||
|
||||
nextPosArray[pindex] = nextPosArray[pindex] + add;
|
||||
}
|
||||
}
|
||||
|
||||
// バッファクリア
|
||||
tempCountBuffer[pindex] = 0;
|
||||
tempVectorBufferA[pindex] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool CalcVolume(
|
||||
in float3x4 nextPosBuffer,
|
||||
in float4 invMassBuffer,
|
||||
float volumeRest,
|
||||
float stiffness,
|
||||
ref float3x4 addPosBuffer
|
||||
)
|
||||
{
|
||||
float3 nextPos0 = nextPosBuffer[0];
|
||||
float3 nextPos1 = nextPosBuffer[1];
|
||||
@ -649,6 +620,7 @@ namespace MagicaCloth2
|
||||
float invMass3 = invMassBuffer[3];
|
||||
|
||||
float volume = (1.0f / 6.0f) * math.dot(math.cross(nextPos1 - nextPos0, nextPos2 - nextPos0), nextPos3 - nextPos0);
|
||||
volume *= VolumeScale; // 浮動小数点演算誤差回避
|
||||
|
||||
float3 grad0 = math.cross(nextPos1 - nextPos2, nextPos3 - nextPos2);
|
||||
float3 grad1 = math.cross(nextPos2 - nextPos0, nextPos3 - nextPos0);
|
||||
@ -660,21 +632,29 @@ namespace MagicaCloth2
|
||||
invMass1 * math.lengthsq(grad1) +
|
||||
invMass2 * math.lengthsq(grad2) +
|
||||
invMass3 * math.lengthsq(grad3);
|
||||
lambda *= VolumeScale; // 浮動小数点演算誤差回避
|
||||
|
||||
if (math.abs(lambda) < 1e-06f)
|
||||
return false;
|
||||
|
||||
lambda = stiffness * (volume - volumeRest) / lambda;
|
||||
lambda = stiffness * (volumeRest - volume) / lambda;
|
||||
|
||||
addPosBuffer[0] = -lambda * invMass0 * grad0;
|
||||
addPosBuffer[1] = -lambda * invMass1 * grad1;
|
||||
addPosBuffer[2] = -lambda * invMass2 * grad2;
|
||||
addPosBuffer[3] = -lambda * invMass3 * grad3;
|
||||
addPosBuffer[0] = lambda * invMass0 * grad0;
|
||||
addPosBuffer[1] = lambda * invMass1 * grad1;
|
||||
addPosBuffer[2] = lambda * invMass2 * grad2;
|
||||
addPosBuffer[3] = lambda * invMass3 * grad3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DihedralAngle(float sign, in float3x4 nextPosBuffer, in float4 invMassBuffer, float restAngle, float stiffness, ref float3x4 addPosBuffer)
|
||||
static bool CalcDihedralAngle(
|
||||
float sign,
|
||||
in float3x4 nextPosBuffer,
|
||||
in float4 invMassBuffer,
|
||||
float restAngle,
|
||||
float stiffness,
|
||||
ref float3x4 addPosBuffer
|
||||
)
|
||||
{
|
||||
float3 nextPos0 = nextPosBuffer[0];
|
||||
float3 nextPos1 = nextPosBuffer[1];
|
||||
@ -695,6 +675,7 @@ namespace MagicaCloth2
|
||||
|
||||
float3 n1 = math.cross(nextPos2 - nextPos0, nextPos3 - nextPos0);
|
||||
float3 n2 = math.cross(nextPos3 - nextPos1, nextPos2 - nextPos1);
|
||||
|
||||
float n1_lengsq = math.lengthsq(n1);
|
||||
float n2_lengsq = math.lengthsq(n2);
|
||||
|
||||
@ -717,14 +698,6 @@ namespace MagicaCloth2
|
||||
dot = MathUtility.Clamp1(dot);
|
||||
float phi = math.acos(dot);
|
||||
|
||||
// 方向性
|
||||
float dir = math.dot(math.cross(n1, n2), e);
|
||||
if (sign != 0)
|
||||
{
|
||||
phi *= math.sign(dir);
|
||||
dir = 1; // lambdaを反転させるため
|
||||
}
|
||||
|
||||
float lambda =
|
||||
invMass0 * math.lengthsq(d0) +
|
||||
invMass1 * math.lengthsq(d1) +
|
||||
@ -734,10 +707,20 @@ namespace MagicaCloth2
|
||||
if (lambda == 0.0f)
|
||||
return false;
|
||||
|
||||
lambda = (phi - restAngle) / lambda * stiffness;
|
||||
// 方向性
|
||||
float dirSign = math.sign(math.dot(math.cross(n1, n2), e));
|
||||
if (sign != 0)
|
||||
{
|
||||
// 方向性あり(DirectionDihedralAngle)
|
||||
phi *= dirSign;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 方向性なし(DihedralAngle)
|
||||
lambda *= dirSign;
|
||||
}
|
||||
|
||||
if (dir > 0.0f)
|
||||
lambda = -lambda;
|
||||
lambda = (restAngle - phi) / lambda * stiffness;
|
||||
|
||||
float3 corr0 = -invMass0 * lambda * d0;
|
||||
float3 corr1 = -invMass1 * lambda * d1;
|
||||
@ -752,66 +735,4 @@ namespace MagicaCloth2
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct SolveAggregateBufferJob : IJobParallelForDefer
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> stepParticleIndexArray;
|
||||
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
|
||||
// vmesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
|
||||
// particle
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<short> teamIdArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
|
||||
// constraint
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<uint> writeIndexArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> writeBuffer;
|
||||
|
||||
// ステップパーティクルごと
|
||||
public void Execute(int index)
|
||||
{
|
||||
// pindexのチームは有効であることが保証されている
|
||||
int pindex = stepParticleIndexArray[index];
|
||||
int teamId = teamIdArray[pindex];
|
||||
var tdata = teamDataArray[teamId];
|
||||
if (tdata.bendingPairChunk.IsValid == false)
|
||||
return;
|
||||
|
||||
int l_index = pindex - tdata.particleChunk.startIndex;
|
||||
|
||||
// 固定なら無効
|
||||
int vindex = tdata.proxyCommonChunk.startIndex + l_index;
|
||||
if (attributes[vindex].IsDontMove())
|
||||
return;
|
||||
|
||||
// 書き込みバッファの値を平均化してnextPosに加算する
|
||||
uint pack = writeIndexArray[tdata.bendingWriteIndexChunk.startIndex + l_index];
|
||||
int cnt = DataUtility.Unpack12_20Hi(pack);
|
||||
int start = DataUtility.Unpack12_20Low(pack);
|
||||
int bufferIndex = tdata.bendingBufferChunk.startIndex + start;
|
||||
float3 add = 0;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
add += writeBuffer[bufferIndex + i];
|
||||
}
|
||||
if (cnt > 0)
|
||||
{
|
||||
add /= cnt;
|
||||
nextPosArray[pindex] = nextPosArray[pindex] + add;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
// Magica Cloth 2.
|
||||
// Copyright (c) 2025 MagicaSoft.
|
||||
// https://magicasoft.jp
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
@ -83,8 +86,57 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public List<Renderer> cameraCullingRenderers = new List<Renderer>();
|
||||
|
||||
/// <summary>
|
||||
/// 距離カリングの状態と距離
|
||||
/// Distance Culling State and Distance.
|
||||
/// [OK] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
public CheckSliderSerializeData distanceCullingLength;
|
||||
|
||||
/// <summary>
|
||||
/// 距離カリングのフェード割合(0.0 ~ 1.0)
|
||||
/// Distance culling fade rate (0.0 to 1.0).
|
||||
/// [OK] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float distanceCullingFadeRatio;
|
||||
|
||||
/// <summary>
|
||||
/// 距離カリングの測定対象(None=メインカメラ)
|
||||
/// Distance culling measurement target (None = main camera).
|
||||
/// [OK] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
public GameObject distanceCullingReferenceObject;
|
||||
|
||||
//=========================================================================================
|
||||
public struct CullingParams
|
||||
{
|
||||
public bool useDistanceCulling;
|
||||
public float distanceCullingLength;
|
||||
public float distanceCullingFadeRatio;
|
||||
|
||||
public void Convert(CullingSettings cullingSettings)
|
||||
{
|
||||
useDistanceCulling = cullingSettings.distanceCullingLength.use;
|
||||
distanceCullingLength = cullingSettings.distanceCullingLength.value;
|
||||
distanceCullingFadeRatio = cullingSettings.distanceCullingFadeRatio;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
public CullingSettings()
|
||||
{
|
||||
distanceCullingLength = new CheckSliderSerializeData(false, 30.0f);
|
||||
distanceCullingFadeRatio = 0.2f;
|
||||
}
|
||||
|
||||
public void DataValidate()
|
||||
{
|
||||
distanceCullingLength.DataValidate(0.0f, Define.System.DistanceCullingMaxLength);
|
||||
distanceCullingFadeRatio = Mathf.Clamp01(distanceCullingFadeRatio);
|
||||
}
|
||||
|
||||
public CullingSettings Clone()
|
||||
@ -94,6 +146,9 @@ namespace MagicaCloth2
|
||||
cameraCullingMode = cameraCullingMode,
|
||||
cameraCullingMethod = cameraCullingMethod,
|
||||
cameraCullingRenderers = new List<Renderer>(cameraCullingRenderers),
|
||||
distanceCullingLength = distanceCullingLength.Clone(),
|
||||
distanceCullingFadeRatio = distanceCullingFadeRatio,
|
||||
distanceCullingReferenceObject = distanceCullingReferenceObject,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -19,10 +19,8 @@ namespace MagicaCloth2
|
||||
public bool enable = false;
|
||||
|
||||
/// <summary>
|
||||
/// bones for skinning.
|
||||
/// Calculated from the parent-child structure line of bones registered here.
|
||||
/// スキニング用ボーン
|
||||
/// ここに登録されたボーンの親子構造ラインから算出される
|
||||
/// Bones for custom skinning.
|
||||
/// カスタムスキニング用ボーン
|
||||
/// [NG] Runtime changes.
|
||||
/// [NG] Export/Import with Presets
|
||||
/// </summary>
|
||||
|
||||
@ -42,7 +42,14 @@ namespace MagicaCloth2
|
||||
/// General processing.
|
||||
/// </summary>
|
||||
private ClothProcess process = new ClothProcess();
|
||||
public ClothProcess Process { get { process.cloth = this; return process; } }
|
||||
public ClothProcess Process
|
||||
{
|
||||
get
|
||||
{
|
||||
process.cloth = this;
|
||||
return process;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cloth component transform.
|
||||
@ -53,7 +60,14 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// Synchronization target.
|
||||
/// </summary>
|
||||
public MagicaCloth SyncCloth => SerializeData.IsBoneSpring() ? null : SerializeData.selfCollisionConstraint.GetSyncPartner();
|
||||
public MagicaCloth SyncPartnerCloth
|
||||
{
|
||||
get
|
||||
{
|
||||
var syncCloth = SerializeData.IsBoneSpring() ? null : SerializeData.selfCollisionConstraint.GetSyncPartner();
|
||||
return syncCloth == this ? null : syncCloth;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the cloth component is in a valid state.
|
||||
@ -66,18 +80,27 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
private void Reset()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// Automatically generate pre-build ID
|
||||
serializeData2.preBuildData.buildId = PreBuildSerializeData.GenerateBuildID();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
Process.DataUpdate();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (MagicaManager.initializationLocation == MagicaManager.InitializationLocation.Awake)
|
||||
{
|
||||
Process.Init();
|
||||
|
||||
// If Awake() is called, OnDestroy() will also be called, so remove it from monitoring.
|
||||
MagicaManager.Team.RemoveMonitoringProcess(Process);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
@ -91,6 +114,12 @@ namespace MagicaCloth2
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (MagicaManager.initializationLocation == MagicaManager.InitializationLocation.Start)
|
||||
{
|
||||
Process.Init();
|
||||
MagicaManager.Team.RemoveMonitoringProcess(Process);
|
||||
}
|
||||
|
||||
Process.AutoBuild();
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
executionOrder: 5
|
||||
icon: {fileID: 2800000, guid: cf7e3400035e987478c3a19e57b4cf75, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
||||
@ -29,8 +29,14 @@ namespace MagicaCloth2
|
||||
/// Event after completion of cloth data construction.
|
||||
/// (true = Success, false = Failure)
|
||||
/// </summary>
|
||||
public Action<bool> OnBuildComplete;
|
||||
public Action<MagicaCloth, bool> OnBuildComplete;
|
||||
|
||||
/// <summary>
|
||||
/// レンダラーメッシュ変更後イベント
|
||||
/// Renderer mesh change event.
|
||||
/// (true = Change to custom mesh, false = Change to original mesh)
|
||||
/// </summary>
|
||||
public Action<MagicaCloth, Renderer, bool> OnRendererMeshChange;
|
||||
|
||||
/// <summary>
|
||||
/// 初期化を実行します
|
||||
@ -66,22 +72,33 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
/// <returns>true=start build. false=build failed.</returns>
|
||||
public bool BuildAndRun()
|
||||
{
|
||||
bool ret = false;
|
||||
bool buildComplate = true;
|
||||
|
||||
try
|
||||
{
|
||||
if (Application.isPlaying == false)
|
||||
return false;
|
||||
throw new MagicaClothProcessingException();
|
||||
|
||||
DisableAutoBuild();
|
||||
|
||||
if (Process.IsState(ClothProcess.State_Build))
|
||||
{
|
||||
Develop.LogError($"Already built.:{this.name}");
|
||||
return false;
|
||||
throw new MagicaClothProcessingException();
|
||||
}
|
||||
|
||||
// initialize generated data.
|
||||
if (Process.GenerateInitialization() == false)
|
||||
return false;
|
||||
throw new MagicaClothProcessingException();
|
||||
|
||||
// check Pre-Build
|
||||
bool usePreBuildData = serializeData2.preBuildData.UsePreBuild();
|
||||
|
||||
if (usePreBuildData == false)
|
||||
{
|
||||
// Runtime Build.
|
||||
// setting by type.
|
||||
switch (serializeData.clothType)
|
||||
{
|
||||
@ -93,15 +110,37 @@ namespace MagicaCloth2
|
||||
if (nowSelection == null || nowSelection.IsValid() == false || nowSelection.IsUserEdit() == false)
|
||||
{
|
||||
if (Process.GenerateBoneClothSelection() == false)
|
||||
return false;
|
||||
throw new MagicaClothProcessingException();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// build and run.
|
||||
Process.StartBuild();
|
||||
ret = Process.StartRuntimeBuild();
|
||||
if (ret)
|
||||
buildComplate = false; // OnBuildCompleteはランタイム構築後に呼ばれる
|
||||
}
|
||||
else
|
||||
{
|
||||
// pre-build
|
||||
ret = Process.PreBuildDataConstruction();
|
||||
}
|
||||
}
|
||||
catch (MagicaClothProcessingException)
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// ビルド完了イベント
|
||||
if (buildComplate)
|
||||
OnBuildComplete?.Invoke(this, ret);
|
||||
}
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -123,7 +162,7 @@ namespace MagicaCloth2
|
||||
var replaceDict = new Dictionary<int, Transform>();
|
||||
foreach (var t in useTransformSet)
|
||||
{
|
||||
if (targetTransformDict.ContainsKey(t.name))
|
||||
if (t && targetTransformDict.ContainsKey(t.name))
|
||||
{
|
||||
replaceDict.Add(t.GetInstanceID(), targetTransformDict[t.name]);
|
||||
}
|
||||
@ -133,6 +172,18 @@ namespace MagicaCloth2
|
||||
Process.ReplaceTransform(replaceDict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// コンポーネントが保持するすべてのトランスフォームを取得します。
|
||||
/// Gets all the transforms held by the component.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public HashSet<Transform> GetUsedTransform()
|
||||
{
|
||||
var useTransformSet = new HashSet<Transform>();
|
||||
Process.GetUsedTransform(useTransformSet);
|
||||
return useTransformSet;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// パラメータの変更を通知
|
||||
@ -197,8 +248,8 @@ namespace MagicaCloth2
|
||||
// Reset
|
||||
tdata.flag.SetBits(TeamManager.Flag_Reset, true);
|
||||
tdata.flag.SetBits(TeamManager.Flag_TimeReset, true);
|
||||
tdata.flag.SetBits(TeamManager.Flag_CullingKeep, false);
|
||||
Process.SetState(ClothProcess.State_CullingKeep, false);
|
||||
tdata.flag.SetBits(TeamManager.Flag_CameraCullingKeep, false);
|
||||
Process.SetState(ClothProcess.State_CameraCullingKeep, false);
|
||||
Process.UpdateRendererUse();
|
||||
}
|
||||
}
|
||||
@ -251,5 +302,50 @@ namespace MagicaCloth2
|
||||
Process.SetSkipWriting(sw);
|
||||
}
|
||||
}
|
||||
|
||||
private RenderData GetRenderData(Renderer ren)
|
||||
{
|
||||
if (IsValid() == false || ren == null)
|
||||
return null;
|
||||
int handle = ren.GetInstanceID();
|
||||
return MagicaManager.Render.GetRendererData(handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MeshClothのオリジナルメッシュを取得します
|
||||
/// Get the original mesh of MeshCloth.
|
||||
/// </summary>
|
||||
/// <param name="ren"></param>
|
||||
/// <returns>null if not found</returns>
|
||||
public Mesh GetOriginalMesh(Renderer ren)
|
||||
{
|
||||
return GetRenderData(ren)?.originalMesh ?? null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MeshClothのカスタムメッシュを取得します
|
||||
/// Get the custom mesh for MeshCloth.
|
||||
/// </summary>
|
||||
/// <param name="ren"></param>
|
||||
/// <returns>null if not found</returns>
|
||||
public Mesh GetCustomMesh(Renderer ren)
|
||||
{
|
||||
return GetRenderData(ren)?.customMesh ?? null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MeshClothのSkinnedMeshRendererに設定されているカスタムボーンリストを取得します
|
||||
/// カスタムボーンリストはオリジナルのBonesからスキニングに不要なTransformをnullに設定し、
|
||||
/// また最後にレンダラーのTransformが追加されるなど加工されているので注意してください。
|
||||
/// Gets the custom bone list set for the SkinnedMeshRenderer of MeshCloth.
|
||||
/// Please note that the custom bone list has been processed by setting Transforms
|
||||
/// that are not necessary for skinning to null from the original Bones, and adding the renderer Transform at the end.
|
||||
/// </summary>
|
||||
/// <param name="ren"></param>
|
||||
/// <returns>null if not found</returns>
|
||||
public List<Transform> GetCustomBones(Renderer ren)
|
||||
{
|
||||
return GetRenderData(ren)?.transformList ?? null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,13 +212,7 @@ namespace MagicaCloth2
|
||||
|
||||
public void Fill(VertexAttribute attr)
|
||||
{
|
||||
#if UNITY_2020
|
||||
int cnt = Count;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
attributes[i] = attr;
|
||||
#else
|
||||
Array.Fill(attributes, attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
|
||||
@ -200,8 +200,9 @@ namespace MagicaCloth2
|
||||
public void SetWindDirection(Vector3 dir, bool localSpace = false)
|
||||
{
|
||||
Vector3 lv = localSpace ? dir : transform.InverseTransformDirection(dir);
|
||||
directionAngleX = Mathf.Atan2(lv.z, lv.x) * Mathf.Rad2Deg;
|
||||
directionAngleY = Mathf.Atan2(lv.z, lv.y) * Mathf.Rad2Deg;
|
||||
var angles = Quaternion.FromToRotation(Vector3.forward, lv).eulerAngles;
|
||||
directionAngleX = angles.x > 180 ? angles.x - 360 : angles.x;
|
||||
directionAngleY = angles.y > 180 ? angles.y - 360 : angles.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +34,8 @@ namespace MagicaCloth2
|
||||
RenderMesh_UnknownWarning = 10100,
|
||||
RenderMesh_VertexWeightIs5BonesOrMore,
|
||||
|
||||
Init_NonUniformScale = 10200,
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Error(20000 - )
|
||||
///////////////////////////////////////////////////////////////////
|
||||
@ -42,11 +44,15 @@ namespace MagicaCloth2
|
||||
// Validating serialized data
|
||||
SerializeData_InvalidData = 20050,
|
||||
SerializeData_Over31Renderers,
|
||||
SerializeData_DuplicateRootBone,
|
||||
SerializeData_DuplicateRenderer,
|
||||
|
||||
// init
|
||||
Init_InvalidData = 20100,
|
||||
Init_InvalidPaintMap,
|
||||
Init_PaintMapNotReadable,
|
||||
Init_ScaleIsZero,
|
||||
Init_NegativeScale,
|
||||
|
||||
// RenderSetup
|
||||
RenderSetup_Exception = 20200,
|
||||
@ -76,6 +82,11 @@ namespace MagicaCloth2
|
||||
CreateCloth_InvalidPaintMap,
|
||||
CreateCloth_PaintMapNotReadable,
|
||||
CreateCloth_PaintMapCountMismatch,
|
||||
CreateCloth_CanNotStart,
|
||||
CreateCloth_VertexAttributeListCountMismatch,
|
||||
CreateCloth_VertexAttributeListIsNull,
|
||||
CreateCloth_VertexAttributeListDataMismatch,
|
||||
CreateCloth_InvalidVertexAttributeData,
|
||||
|
||||
// Reduction
|
||||
Reduction_Exception = 20500,
|
||||
@ -131,6 +142,41 @@ namespace MagicaCloth2
|
||||
MagicaMesh_Invalid,
|
||||
MagicaMesh_InvalidRenderer,
|
||||
MagicaMesh_InvalidMeshFilter,
|
||||
|
||||
// PreBuildData
|
||||
PreBuildData_UnknownError = 22600,
|
||||
PreBuildData_MagicaClothException,
|
||||
PreBuildData_VirtualMeshDeserializationException,
|
||||
PreBuildData_VerificationResult,
|
||||
PreBuildData_VersionMismatch,
|
||||
PreBuildData_InvalidClothData,
|
||||
PreBuildData_Empty,
|
||||
PreBuildData_InvalidScale,
|
||||
|
||||
// PreBuild
|
||||
PreBuild_UnknownError = 22700,
|
||||
PreBuild_Exception,
|
||||
PreBuild_InvalidPreBuildData,
|
||||
PreBuild_InvalidRenderSetupData,
|
||||
PreBuild_SetupDeserializationError,
|
||||
|
||||
// PreBuild Deserialization
|
||||
Deserialization_UnknownError = 22800,
|
||||
Deserialization_Exception,
|
||||
|
||||
// Init SerializeData
|
||||
InitSerializeData_UnknownError = 22900,
|
||||
InitSerializeData_InvalidHash,
|
||||
InitSerializeData_InvalidVersion,
|
||||
InitSerializeData_InvalidSetupData,
|
||||
InitSerializeData_ClothTypeMismatch,
|
||||
InitSerializeData_SetupCountMismatch,
|
||||
InitSerializeData_CustomSkinningBoneCountMismatch,
|
||||
InitSerializeData_MeshClothSetupValidationError,
|
||||
InitSerializeData_BoneClothSetupValidationError,
|
||||
InitSerializeData_BoneSpringSetupValidationError,
|
||||
InitSerializeData_DeserializationError,
|
||||
InitSerializeData_InvalidCloneMesh,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,11 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public const string DefineSymbol = "MAGICACLOTH2";
|
||||
|
||||
/// <summary>
|
||||
/// 現在有効なPreBuildの最新バージョン
|
||||
/// </summary>
|
||||
public const int LatestPreBuildVersion = 2;
|
||||
|
||||
/// <summary>
|
||||
/// 計算を省略する最小の浮動小数点数
|
||||
/// </summary>
|
||||
@ -72,6 +77,16 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public const float SameSurfaceAngle = 80.0f;
|
||||
|
||||
/// <summary>
|
||||
/// 未来予測時のルートからの距離制限倍率
|
||||
/// </summary>
|
||||
public const float MaxDistanceRatioFutuerPrediction = 1.3f;
|
||||
|
||||
/// <summary>
|
||||
/// 分割ジョブを適用するプロキシメッシュメッシュの頂点数
|
||||
/// </summary>
|
||||
public const int SplitProxyMeshVertexCount = 300;
|
||||
|
||||
/// <summary>
|
||||
/// [Reduction]
|
||||
/// 有効フラグ。常にtrueとする。
|
||||
@ -319,7 +334,19 @@ namespace MagicaCloth2
|
||||
/// [Self Collision]
|
||||
/// 反復回数
|
||||
/// </summary>
|
||||
public const int SelfCollisionSolverIteration = 4;
|
||||
public const int SelfCollisionSolverIteration = 4; // 4
|
||||
|
||||
/// <summary>
|
||||
/// [Self Collision]
|
||||
/// 無効グリッド座標
|
||||
/// </summary>
|
||||
public const int SelfCollisionIgnoreGrid = 1000000;
|
||||
|
||||
/// <summary>
|
||||
/// [Self Collision]
|
||||
/// 交差判定の分割数
|
||||
/// </summary>
|
||||
public const int SelfCollisionIntersectDiv = 2; // 8
|
||||
|
||||
/// <summary>
|
||||
/// [Self Collision]
|
||||
@ -351,12 +378,6 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public static readonly float SelfCollisionPointTriangleAngleCos = math.cos(math.radians(60.0f));
|
||||
|
||||
/// <summary>
|
||||
/// [Self Collision]
|
||||
/// 交差判定の分割数
|
||||
/// </summary>
|
||||
public const int SelfCollisionIntersectDiv = 8;
|
||||
|
||||
/// <summary>
|
||||
/// [Self Collision]
|
||||
/// Thicknessの最小値(m)
|
||||
@ -398,6 +419,12 @@ namespace MagicaCloth2
|
||||
/// BoneSpring利用時のfriction値
|
||||
/// </summary>
|
||||
public const float BoneSpringCollisionFriction = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// [Culling]
|
||||
/// 距離カリングの最大距離
|
||||
/// </summary>
|
||||
public const float DistanceCullingMaxLength = 100.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ namespace MagicaCloth2
|
||||
public class ClothManager : IManager, IValid
|
||||
{
|
||||
// すべて
|
||||
internal HashSet<ClothProcess> clothSet = new HashSet<ClothProcess>();
|
||||
internal HashSet<ClothProcess> clothSet = new HashSet<ClothProcess>(256);
|
||||
|
||||
// BoneCloth,BoneSpring
|
||||
internal HashSet<ClothProcess> boneClothSet = new HashSet<ClothProcess>();
|
||||
@ -50,6 +50,7 @@ namespace MagicaCloth2
|
||||
|
||||
// 更新処理
|
||||
MagicaManager.afterEarlyUpdateDelegate -= OnEarlyClothUpdate;
|
||||
MagicaManager.firstPreUpdateDelegate -= OnFirstPreUpdate;
|
||||
MagicaManager.afterLateUpdateDelegate -= OnAfterLateUpdate;
|
||||
MagicaManager.beforeLateUpdateDelegate -= OnBeforeLateUpdate;
|
||||
}
|
||||
@ -69,6 +70,7 @@ namespace MagicaCloth2
|
||||
|
||||
// 更新処理
|
||||
MagicaManager.afterEarlyUpdateDelegate += OnEarlyClothUpdate;
|
||||
MagicaManager.firstPreUpdateDelegate += OnFirstPreUpdate;
|
||||
MagicaManager.afterLateUpdateDelegate += OnAfterLateUpdate;
|
||||
MagicaManager.beforeLateUpdateDelegate += OnBeforeLateUpdate;
|
||||
|
||||
@ -118,6 +120,9 @@ namespace MagicaCloth2
|
||||
break;
|
||||
}
|
||||
|
||||
// チームマネージャの作業バッファへ登録
|
||||
MagicaManager.Team.comp2TeamIdMap.Add(cprocess.cloth.GetInstanceID(), teamId);
|
||||
|
||||
return teamId;
|
||||
}
|
||||
|
||||
@ -140,11 +145,15 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
void OnEarlyClothUpdate()
|
||||
{
|
||||
//Debug.Log($"OnEarlyClothUpdate. F:{Time.frameCount}");
|
||||
if (MagicaManager.Team.TrueTeamCount > 0) // カリング判定があるのでDisableチームもまわす必要がある
|
||||
{
|
||||
// カメラカリング更新
|
||||
if (MagicaManager.Team.ActiveTeamCount > 0)
|
||||
{
|
||||
//Debug.Log($"TransformRestoreUpdate. F:{Time.frameCount}");
|
||||
// チームカリング更新
|
||||
MagicaManager.Team.TeamCullingUpdate();
|
||||
// この更新は次のTransform復元の前に行う必要がある
|
||||
MagicaManager.Team.CameraCullingPostProcess();
|
||||
}
|
||||
|
||||
// BoneClothのTransform復元更新
|
||||
ClearMasterJob();
|
||||
@ -153,6 +162,25 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PreUpdate開始時に実行される更新処理
|
||||
/// </summary>
|
||||
void OnFirstPreUpdate()
|
||||
{
|
||||
//Debug.Log($"OnFirstPreUpdate. F:{Time.frameCount}");
|
||||
if (MagicaManager.Team.TrueTeamCount > 0) // カリング判定があるのでDisableチームもまわす必要がある
|
||||
{
|
||||
//Debug.Log($"existFixedTeam:{MagicaManager.Bone.existFixedTeam.Value}");
|
||||
// FixedUpdateが0回かつFixedTeamが存在する場合のみ
|
||||
if (MagicaManager.Time.FixedUpdateCount == 0 && MagicaManager.Bone.existFixedTeam.Value)
|
||||
{
|
||||
ClearMasterJob();
|
||||
masterJob = MagicaManager.Bone.RestoreBaseTransform(masterJob);
|
||||
CompleteMasterJob();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnBeforeLateUpdate()
|
||||
{
|
||||
if (MagicaManager.Time.updateLocation == TimeManager.UpdateLocation.BeforeLateUpdate)
|
||||
@ -166,7 +194,9 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
static readonly ProfilerMarker startClothUpdateMainProfiler = new ProfilerMarker("StartClothUpdate.Main");
|
||||
static readonly ProfilerMarker startClothUpdateTimeProfiler = new ProfilerMarker("StartClothUpdate.Time");
|
||||
static readonly ProfilerMarker startClothUpdateTeamProfiler = new ProfilerMarker("StartClothUpdate.Team");
|
||||
static readonly ProfilerMarker startClothUpdatePrePareProfiler = new ProfilerMarker("StartClothUpdate.Prepare");
|
||||
static readonly ProfilerMarker startClothUpdateScheduleProfiler = new ProfilerMarker("StartClothUpdate.Schedule");
|
||||
|
||||
/// <summary>
|
||||
@ -177,13 +207,16 @@ namespace MagicaCloth2
|
||||
if (MagicaManager.IsPlaying() == false)
|
||||
return;
|
||||
|
||||
// ■コンポーネント0なら終了
|
||||
var tm = MagicaManager.Team;
|
||||
if (tm.TrueTeamCount == 0)
|
||||
return;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// シミュレーション開始イベント
|
||||
MagicaManager.OnPreSimulation?.Invoke();
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
var tm = MagicaManager.Team;
|
||||
var vm = MagicaManager.VMesh;
|
||||
var sm = MagicaManager.Simulation;
|
||||
var bm = MagicaManager.Bone;
|
||||
var wm = MagicaManager.Wind;
|
||||
@ -192,22 +225,21 @@ namespace MagicaCloth2
|
||||
//Develop.DebugLog($"StartClothUpdate. F:{Time.frameCount}, dtime:{Time.deltaTime}, stime:{Time.smoothDeltaTime}");
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
startClothUpdateMainProfiler.Begin();
|
||||
// ■時間マネージャ更新
|
||||
startClothUpdateTimeProfiler.Begin();
|
||||
MagicaManager.Time.FrameUpdate();
|
||||
startClothUpdateTimeProfiler.End();
|
||||
|
||||
// ■常に実行するチーム更新
|
||||
startClothUpdateTeamProfiler.Begin();
|
||||
tm.AlwaysTeamUpdate();
|
||||
startClothUpdateTeamProfiler.End();
|
||||
|
||||
// ■ここで実行チーム数が0ならば終了
|
||||
if (tm.ActiveTeamCount == 0)
|
||||
{
|
||||
startClothUpdateMainProfiler.End();
|
||||
return;
|
||||
}
|
||||
|
||||
int maxUpdateCount = tm.maxUpdateCount.Value;
|
||||
//Debug.Log($"maxUpdateCount:{maxUpdateCount}");
|
||||
startClothUpdatePrePareProfiler.Begin();
|
||||
|
||||
// ■常に実行する風ゾーン更新
|
||||
wm.AlwaysWindUpdate();
|
||||
@ -215,106 +247,32 @@ namespace MagicaCloth2
|
||||
// ■作業バッファ更新
|
||||
sm.WorkBufferUpdate();
|
||||
|
||||
startClothUpdateMainProfiler.End();
|
||||
startClothUpdatePrePareProfiler.End();
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
#if true
|
||||
startClothUpdateScheduleProfiler.Begin();
|
||||
|
||||
// マスタージョブ初期化
|
||||
ClearMasterJob();
|
||||
|
||||
// ■トランスフォーム情報の読み込み
|
||||
masterJob = bm.ReadTransform(masterJob);
|
||||
masterJob = bm.ReadTransformSchedule(masterJob);
|
||||
|
||||
// ■プロキシメッシュをスキニングし基本姿勢を求める
|
||||
masterJob = vm.PreProxyMeshUpdate(masterJob);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// チームのセンター姿勢の決定と慣性用の移動量計算
|
||||
masterJob = tm.CalcCenterAndInertiaAndWind(masterJob);
|
||||
|
||||
// パーティクルリセットの適用
|
||||
masterJob = sm.PreSimulationUpdate(masterJob);
|
||||
|
||||
// ■コライダーのローカル姿勢を求める
|
||||
masterJob = MagicaManager.Collider.PreSimulationUpdate(masterJob);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ■クロスシミュレーション実行
|
||||
// ステップ実行
|
||||
for (int i = 0; i < maxUpdateCount; i++)
|
||||
{
|
||||
masterJob = sm.SimulationStepUpdate(maxUpdateCount, i, masterJob);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// 表示位置の決定
|
||||
masterJob = sm.CalcDisplayPosition(masterJob);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ■クロスシミュレーション後の頂点姿勢計算
|
||||
// プロキシメッシュの頂点から法線接線を求め姿勢を確定させる
|
||||
// ラインがある場合はベースラインごとに姿勢を整える
|
||||
// BoneClothの場合は頂点姿勢を連動するトランスフォームデータにコピーする
|
||||
masterJob = vm.PostProxyMeshUpdate(masterJob);
|
||||
|
||||
// マッピングメッシュ
|
||||
int mappingCount = tm.MappingCount;
|
||||
if (mappingCount > 0)
|
||||
{
|
||||
// マッピングメッシュ頂点姿勢をプロキシメッシュからスキニングし求める
|
||||
// マッピングメッシュのローカル空間に座標変換する
|
||||
masterJob = vm.PostMappingMeshUpdate(masterJob);
|
||||
|
||||
// レンダーデータへ反映する
|
||||
foreach (var cprocess in meshClothSet)
|
||||
{
|
||||
if (cprocess == null || cprocess.IsValid() == false || cprocess.IsEnable == false)
|
||||
continue;
|
||||
|
||||
// カリングによる非表示中ならば書き込まない
|
||||
if (cprocess.IsCullingInvisible())
|
||||
continue;
|
||||
|
||||
int cnt = cprocess.renderMeshInfoList.Count;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
var info = cprocess.renderMeshInfoList[i];
|
||||
var renderData = MagicaManager.Render.GetRendererData(info.renderHandle);
|
||||
|
||||
// Position/Normal書き込み
|
||||
masterJob = renderData.UpdatePositionNormal(info.mappingChunk, masterJob);
|
||||
|
||||
// BoneWeight書き込み
|
||||
if (renderData.ChangeCustomMesh)
|
||||
{
|
||||
masterJob = renderData.UpdateBoneWeight(info.mappingChunk, masterJob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ■BoneClothのTransformへの書き込み
|
||||
masterJob = bm.WriteTransform(masterJob);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ■コライダー更新後処理
|
||||
masterJob = MagicaManager.Collider.PostSimulationUpdate(masterJob);
|
||||
|
||||
// ■チーム更新後処理
|
||||
masterJob = tm.PostTeamUpdate(masterJob);
|
||||
// ■シミュレーションジョブ
|
||||
masterJob = sm.ClothSimulationSchedule(masterJob);
|
||||
|
||||
startClothUpdateScheduleProfiler.End();
|
||||
//-----------------------------------------------------------------
|
||||
//JobHandle.ScheduleBatchedJobs();
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ジョブを即実行
|
||||
//JobHandle.ScheduleBatchedJobs();
|
||||
// ■ジョブ完了待ちの間に行う処理
|
||||
// カメラカリングの準備
|
||||
tm.CameraCullingPreProcess();
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ■現在は即時実行のためここでジョブの完了待ちを行う
|
||||
CompleteMasterJob();
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// シミュレーション終了イベント
|
||||
|
||||
@ -40,6 +40,7 @@ namespace MagicaCloth2
|
||||
public static SimulationManager Simulation => managers?[6] as SimulationManager;
|
||||
public static ColliderManager Collider => managers?[7] as ColliderManager;
|
||||
public static WindManager Wind => managers?[8] as WindManager;
|
||||
public static PreBuildManager PreBuild => managers?[9] as PreBuildManager;
|
||||
|
||||
//=========================================================================================
|
||||
// player loop delegate
|
||||
@ -55,6 +56,11 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public static UpdateMethod afterFixedUpdateDelegate;
|
||||
|
||||
/// <summary>
|
||||
/// PreUpdate()の開始直後
|
||||
/// </summary>
|
||||
public static UpdateMethod firstPreUpdateDelegate;
|
||||
|
||||
/// <summary>
|
||||
/// Update()の後
|
||||
/// </summary>
|
||||
@ -91,8 +97,6 @@ namespace MagicaCloth2
|
||||
//=========================================================================================
|
||||
static volatile bool isPlaying = false;
|
||||
|
||||
//static bool isValid = false;
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// Reload Domain 対策
|
||||
@ -122,6 +126,7 @@ namespace MagicaCloth2
|
||||
managers.Add(new SimulationManager()); // [6]
|
||||
managers.Add(new ColliderManager()); // [7]
|
||||
managers.Add(new WindManager()); // [8]
|
||||
managers.Add(new PreBuildManager()); // [9]
|
||||
foreach (var manager in managers)
|
||||
manager.Initialize();
|
||||
|
||||
@ -321,7 +326,7 @@ namespace MagicaCloth2
|
||||
type = typeof(MagicaManager),
|
||||
updateDelegate = () => afterEarlyUpdateDelegate?.Invoke()
|
||||
};
|
||||
AddPlayerLoop(afterEarlyUpdate, ref playerLoop, "EarlyUpdate", string.Empty, last: true);
|
||||
AddPlayerLoop(afterEarlyUpdate, ref playerLoop, "EarlyUpdate", string.Empty, firstLast: 1);
|
||||
|
||||
// after fixed update
|
||||
// FixedUpdate()の後
|
||||
@ -335,6 +340,17 @@ namespace MagicaCloth2
|
||||
};
|
||||
AddPlayerLoop(afterFixedUpdate, ref playerLoop, "FixedUpdate", "ScriptRunBehaviourFixedUpdate");
|
||||
|
||||
// first pre update
|
||||
PlayerLoopSystem firstPreUpdate = new PlayerLoopSystem()
|
||||
{
|
||||
type = typeof(MagicaManager),
|
||||
updateDelegate = () =>
|
||||
{
|
||||
firstPreUpdateDelegate?.Invoke();
|
||||
}
|
||||
};
|
||||
AddPlayerLoop(firstPreUpdate, ref playerLoop, "PreUpdate", string.Empty, firstLast: -1);
|
||||
|
||||
// after update
|
||||
// Update()の後
|
||||
PlayerLoopSystem afterUpdate = new PlayerLoopSystem()
|
||||
@ -403,13 +419,18 @@ namespace MagicaCloth2
|
||||
/// <param name="playerLoop"></param>
|
||||
/// <param name="categoryName"></param>
|
||||
/// <param name="systemName"></param>
|
||||
static void AddPlayerLoop(PlayerLoopSystem method, ref PlayerLoopSystem playerLoop, string categoryName, string systemName, bool last = false, bool before = false)
|
||||
static void AddPlayerLoop(PlayerLoopSystem method, ref PlayerLoopSystem playerLoop, string categoryName, string systemName, int firstLast = 0, bool before = false)
|
||||
{
|
||||
int sysIndex = Array.FindIndex(playerLoop.subSystemList, (s) => s.type.Name == categoryName);
|
||||
PlayerLoopSystem category = playerLoop.subSystemList[sysIndex];
|
||||
var systemList = new List<PlayerLoopSystem>(category.subSystemList);
|
||||
|
||||
if (last)
|
||||
if (firstLast < 0)
|
||||
{
|
||||
// 最初に追加
|
||||
systemList.Insert(0, method);
|
||||
}
|
||||
else if (firstLast > 0)
|
||||
{
|
||||
// 最後に追加
|
||||
systemList.Add(method);
|
||||
|
||||
@ -33,7 +33,6 @@ namespace MagicaCloth2
|
||||
{
|
||||
if (IsPlaying())
|
||||
{
|
||||
//Team.globalTimeScale = Mathf.Clamp01(timeScale);
|
||||
Time.GlobalTimeScale = Mathf.Clamp01(timeScale);
|
||||
}
|
||||
}
|
||||
@ -47,7 +46,6 @@ namespace MagicaCloth2
|
||||
{
|
||||
if (IsPlaying())
|
||||
{
|
||||
//return Team.globalTimeScale;
|
||||
return Time.GlobalTimeScale;
|
||||
}
|
||||
else
|
||||
@ -153,5 +151,74 @@ namespace MagicaCloth2
|
||||
return TimeManager.UpdateLocation.AfterLateUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 未使用のデータをすべて解放します
|
||||
/// Free all unused data.
|
||||
/// - Unused PreBuild data
|
||||
/// </summary>
|
||||
public static void UnloadUnusedData()
|
||||
{
|
||||
if (IsPlaying())
|
||||
{
|
||||
PreBuild.UnloadUnusedData();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviourでのMagicaClothの初期化場所
|
||||
/// MagicaCloth initialization location in MonoBehaviour.
|
||||
/// </summary>
|
||||
public enum InitializationLocation
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize with MonoBehaviour.Start().
|
||||
/// (Default)
|
||||
/// </summary>
|
||||
Start = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Initialize with MonoBehaviour.Awake().
|
||||
/// </summary>
|
||||
Awake = 1,
|
||||
}
|
||||
internal static InitializationLocation initializationLocation = InitializationLocation.Start;
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviourでのMagicaClothの初期化場所を設定する
|
||||
/// Setting MagicaCloth initialization location in MonoBehaviour.
|
||||
/// </summary>
|
||||
/// <param name="initLocation"></param>
|
||||
public static void SetInitializationLocation(InitializationLocation initLocation)
|
||||
{
|
||||
initializationLocation = initLocation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分割ジョブを適用するプロキシメッシュの頂点数を設定する
|
||||
/// Sets the number of vertices for the proxy mesh to which the split job will be applied.
|
||||
/// </summary>
|
||||
/// <param name="vertexCount"></param>
|
||||
public static void SetSplitProxyMeshVertexCount(int vertexCount)
|
||||
{
|
||||
if (IsPlaying())
|
||||
Simulation.splitProxyMeshVertexCount = vertexCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分割ジョブを適用するプロキシメッシュの頂点数を取得する
|
||||
/// Gets the vertex count of the proxy mesh to which the split job is applied.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int GetSplitProxyMeshVertexCount()
|
||||
{
|
||||
if (IsPlaying())
|
||||
return Simulation.splitProxyMeshVertexCount;
|
||||
else
|
||||
{
|
||||
Develop.LogError("MagicaManager is not starting!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,8 +15,8 @@ namespace MagicaCloth2
|
||||
public enum RefreshMode
|
||||
{
|
||||
/// <summary>
|
||||
/// コンポーネント生成時に1度だけ送信する
|
||||
/// Send only once when the component is created.
|
||||
/// コンポーネントのAwake()で1度だけ送信する
|
||||
/// Send once at the component's Awake()
|
||||
/// </summary>
|
||||
OnAwake = 0,
|
||||
|
||||
@ -25,6 +25,18 @@ namespace MagicaCloth2
|
||||
/// Send content every frame.
|
||||
/// </summary>
|
||||
EveryFrame = 1,
|
||||
|
||||
/// <summary>
|
||||
/// コンポーネントのStart()で一度だけ送信する
|
||||
/// Send once at the component's Start().
|
||||
/// </summary>
|
||||
OnStart = 2,
|
||||
|
||||
/// <summary>
|
||||
/// コンポーネントは何もしません。送信には手動でRefresh()を呼ぶ必要があります
|
||||
/// The component does nothing. You must manually call Refresh() to submit.
|
||||
/// </summary>
|
||||
Manual = 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -64,6 +76,12 @@ namespace MagicaCloth2
|
||||
[Range(Define.System.MaxSimulationCountPerFrame_Low, Define.System.MaxSimulationCountPerFrame_Hi)]
|
||||
public int maxSimulationCountPerFrame = Define.System.DefaultMaxSimulationCountPerFrame;
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviourでのMagicaClothの初期化場所。
|
||||
/// MagicaCloth initialization location in MonoBehaviour.
|
||||
/// </summary>
|
||||
public MagicaManager.InitializationLocation initializationLocation = MagicaManager.InitializationLocation.Start;
|
||||
|
||||
/// <summary>
|
||||
/// シミュレーションの更新場所
|
||||
/// BeforeLateUpdate : LateUpdate()の前に実行します。これはUnity 2D Animationで利用する場合に必要です。
|
||||
@ -75,6 +93,27 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public TimeManager.UpdateLocation updateLocation = TimeManager.UpdateLocation.AfterLateUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// PlayerLoopの監視
|
||||
/// MagicaClothのシステムはUnityのPlayerLoopに登録することで動作します
|
||||
/// この登録が他の外部アセットにより上書きされてしまうと、MagicaClothのシステムが停止してしまいます
|
||||
/// このフラグを有効にすると、PlayerLoopを監視して、上書きされていた場合は再度システムを登録するようになります
|
||||
///
|
||||
/// PlayerLoop monitoring.
|
||||
/// The MagicaCloth system works by registering it in Unity's PlayerLoop.
|
||||
/// If this registration is overwritten by other external assets, the MagicaCloth system will stop working.
|
||||
/// When this flag is enabled, the PlayerLoop will be monitored, and the system will be registered again if it has been overwritten.
|
||||
/// </summary>
|
||||
public bool monitorPlayerLoop = false;
|
||||
|
||||
/// <summary>
|
||||
/// ジョブ分割を適用するプロキシメッシュの頂点数
|
||||
///
|
||||
/// The number of proxy mesh vertices to apply job splitting to.
|
||||
/// </summary>
|
||||
[Min(0)]
|
||||
public int splitProxyMeshVertexCount = Define.System.SplitProxyMeshVertexCount;
|
||||
|
||||
//=========================================================================================
|
||||
public void Awake()
|
||||
{
|
||||
@ -82,6 +121,12 @@ namespace MagicaCloth2
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (refreshMode == RefreshMode.OnStart)
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (refreshMode == RefreshMode.EveryFrame)
|
||||
@ -108,7 +153,12 @@ namespace MagicaCloth2
|
||||
|
||||
MagicaManager.SetSimulationFrequency(simulationFrequency);
|
||||
MagicaManager.SetMaxSimulationCountPerFrame(maxSimulationCountPerFrame);
|
||||
MagicaManager.SetInitializationLocation(initializationLocation);
|
||||
MagicaManager.SetUpdateLocation(updateLocation);
|
||||
MagicaManager.SetSplitProxyMeshVertexCount(splitProxyMeshVertexCount);
|
||||
|
||||
if (monitorPlayerLoop)
|
||||
MagicaManager.InitCustomGameLoop();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -4,7 +4,7 @@ MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
executionOrder: -50
|
||||
icon: {fileID: 2800000, guid: 4b0d1adb21ff82e4e8e9ea02f486a85f, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
||||
@ -5,10 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
@ -37,6 +34,7 @@ namespace MagicaCloth2
|
||||
//=========================================================================================
|
||||
// セットアップデータ
|
||||
internal RenderSetupData setupData;
|
||||
internal RenderSetupData.UniqueSerializationData preBuildUniqueSerializeData;
|
||||
|
||||
internal string Name => setupData?.name ?? "(empty)";
|
||||
|
||||
@ -44,40 +42,27 @@ namespace MagicaCloth2
|
||||
internal bool HasBoneWeight => setupData?.hasBoneWeight ?? false;
|
||||
|
||||
//=========================================================================================
|
||||
// カスタムメッシュ情報
|
||||
Mesh customMesh;
|
||||
NativeArray<Vector3> localPositions;
|
||||
NativeArray<Vector3> localNormals;
|
||||
NativeArray<BoneWeight> boneWeights;
|
||||
BoneWeight centerBoneWeight;
|
||||
// オリジナル情報
|
||||
internal Mesh originalMesh { get; private set; }
|
||||
private Renderer renderer;
|
||||
private SkinnedMeshRenderer skinnedMeshRendere;
|
||||
private MeshFilter meshFilter;
|
||||
internal List<Transform> transformList { get; private set; }
|
||||
internal Mesh customMesh { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// カスタムメッシュの使用フラグ
|
||||
/// </summary>
|
||||
public bool UseCustomMesh { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// カスタムメッシュの変更フラグ
|
||||
/// </summary>
|
||||
public bool ChangeCustomMesh { get; private set; }
|
||||
|
||||
public bool ChangePositionNormal { get; private set; }
|
||||
public bool ChangeBoneWeight { get; private set; }
|
||||
// RenderDataWorkバッファへのインデックス(RenderManagerが管理)
|
||||
internal int renderDataWorkIndex { get; private set; } = -1;
|
||||
|
||||
//=========================================================================================
|
||||
public void Dispose()
|
||||
{
|
||||
// オリジナルメッシュに戻す
|
||||
SwapOriginalMesh();
|
||||
SwapOriginalMesh(null);
|
||||
|
||||
setupData?.Dispose();
|
||||
preBuildUniqueSerializeData = null;
|
||||
|
||||
if (localPositions.IsCreated)
|
||||
localPositions.Dispose();
|
||||
if (localNormals.IsCreated)
|
||||
localNormals.Dispose();
|
||||
if (boneWeights.IsCreated)
|
||||
boneWeights.Dispose();
|
||||
MagicaManager.Render.RemoveRenderDataWork(renderDataWorkIndex);
|
||||
|
||||
if (customMesh)
|
||||
GameObject.Destroy(customMesh);
|
||||
@ -98,17 +83,42 @@ namespace MagicaCloth2
|
||||
/// この処理はスレッド化できないので少し負荷がかかるが即時実行する
|
||||
/// </summary>
|
||||
/// <param name="ren"></param>
|
||||
internal void Initialize(Renderer ren)
|
||||
internal void Initialize(
|
||||
Renderer ren,
|
||||
RenderSetupData referenceSetupData,
|
||||
RenderSetupData.UniqueSerializationData referencePreBuildUniqueSetupData,
|
||||
RenderSetupSerializeData referenceInitSetupData
|
||||
)
|
||||
{
|
||||
Debug.Assert(ren);
|
||||
|
||||
// セットアップデータ作成
|
||||
setupData = new RenderSetupData(ren);
|
||||
// PreBuildでは外部から受け渡される
|
||||
if (referenceSetupData != null && referencePreBuildUniqueSetupData != null)
|
||||
{
|
||||
setupData = referenceSetupData;
|
||||
preBuildUniqueSerializeData = referencePreBuildUniqueSetupData;
|
||||
|
||||
// センタートランスフォーム用ボーンウエイト
|
||||
centerBoneWeight = new BoneWeight();
|
||||
centerBoneWeight.boneIndex0 = setupData.renderTransformIndex;
|
||||
centerBoneWeight.weight0 = 1.0f;
|
||||
originalMesh = preBuildUniqueSerializeData.originalMesh;
|
||||
renderer = preBuildUniqueSerializeData.renderer;
|
||||
skinnedMeshRendere = preBuildUniqueSerializeData.skinRenderer;
|
||||
meshFilter = preBuildUniqueSerializeData.meshFilter;
|
||||
transformList = preBuildUniqueSerializeData.transformList;
|
||||
}
|
||||
else
|
||||
{
|
||||
setupData = new RenderSetupData(referenceInitSetupData, ren);
|
||||
preBuildUniqueSerializeData = null;
|
||||
|
||||
originalMesh = setupData.originalMesh;
|
||||
renderer = setupData.renderer;
|
||||
skinnedMeshRendere = setupData.skinRenderer;
|
||||
meshFilter = setupData.meshFilter;
|
||||
transformList = setupData.transformList;
|
||||
}
|
||||
|
||||
// レンダーデータワークを確保
|
||||
renderDataWorkIndex = MagicaManager.Render.AddRenderDataWork(this);
|
||||
}
|
||||
|
||||
internal ResultCode Result => setupData?.result ?? ResultCode.None;
|
||||
@ -127,41 +137,39 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
void SwapCustomMesh()
|
||||
void SwapCustomMesh(ClothProcess process)
|
||||
{
|
||||
Debug.Assert(setupData != null);
|
||||
|
||||
if (setupData.IsFaild())
|
||||
return;
|
||||
if (setupData.originalMesh == null)
|
||||
if (originalMesh == null)
|
||||
return;
|
||||
if (MagicaManager.Render.IsSetRenderDataWorkFlag(renderDataWorkIndex, RenderManager.RenderDataFlag_UseCustomMesh))
|
||||
return;
|
||||
|
||||
// カスタムメッシュの作成
|
||||
if (customMesh == null)
|
||||
{
|
||||
Debug.Assert(setupData.originalMesh);
|
||||
|
||||
//Debug.Assert(setupData.originalMesh);
|
||||
// クローン作成
|
||||
customMesh = GameObject.Instantiate(setupData.originalMesh);
|
||||
customMesh = GameObject.Instantiate(originalMesh);
|
||||
customMesh.MarkDynamic();
|
||||
|
||||
// 作業配列
|
||||
int vertexCount = setupData.vertexCount;
|
||||
localPositions = new NativeArray<Vector3>(vertexCount, Allocator.Persistent);
|
||||
localNormals = new NativeArray<Vector3>(vertexCount, Allocator.Persistent);
|
||||
if (HasBoneWeight)
|
||||
boneWeights = new NativeArray<BoneWeight>(vertexCount, Allocator.Persistent);
|
||||
|
||||
// bind pose
|
||||
if (HasBoneWeight)
|
||||
{
|
||||
int transformCount = setupData.TransformCount;
|
||||
int transformCount = preBuildUniqueSerializeData != null ? preBuildUniqueSerializeData.transformList.Count : setupData.TransformCount;
|
||||
var bindPoseList = new List<Matrix4x4>(transformCount);
|
||||
bindPoseList.AddRange(setupData.bindPoseList);
|
||||
// rootBone/skinning bones
|
||||
while (bindPoseList.Count < transformCount)
|
||||
bindPoseList.Add(Matrix4x4.identity);
|
||||
customMesh.bindposes = bindPoseList.ToArray();
|
||||
|
||||
// スキニング用ボーンを書き換える
|
||||
// このリストにはオリジナルのスキニングボーン+レンダラーのトランスフォームが含まれている
|
||||
skinnedMeshRendere.bones = transformList.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,45 +178,76 @@ namespace MagicaCloth2
|
||||
|
||||
// カスタムメッシュに表示切り替え
|
||||
SetMesh(customMesh);
|
||||
MagicaManager.Render.SetBitsRenderDataWorkFlag(renderDataWorkIndex, RenderManager.RenderDataFlag_UseCustomMesh, true);
|
||||
|
||||
// スキニング用ボーンを書き換える
|
||||
if (HasBoneWeight)
|
||||
{
|
||||
// このリストにはオリジナルのスキニングボーン+レンダラーのトランスフォームが含まれている
|
||||
setupData.skinRenderer.bones = setupData.transformList.ToArray();
|
||||
}
|
||||
|
||||
UseCustomMesh = true;
|
||||
// Event
|
||||
if (process != null)
|
||||
process.cloth?.OnRendererMeshChange?.Invoke(process.cloth, renderer, true);
|
||||
}
|
||||
|
||||
void ResetCustomMeshWorkData()
|
||||
{
|
||||
var rm = MagicaManager.Render;
|
||||
ref var wdata = ref rm.GetRenderDataWorkRef(renderDataWorkIndex);
|
||||
int vcnt = setupData.vertexCount;
|
||||
|
||||
// オリジナルデータをコピーする
|
||||
if (setupData.HasMeshDataArray)
|
||||
{
|
||||
var meshData = setupData.meshDataArray[0];
|
||||
using var localPositions = new NativeArray<Vector3>(vcnt, Allocator.TempJob);
|
||||
using var localNormals = new NativeArray<Vector3>(vcnt, Allocator.TempJob);
|
||||
meshData.GetVertices(localPositions);
|
||||
meshData.GetNormals(localNormals);
|
||||
if (HasBoneWeight)
|
||||
rm.renderMeshPositions.CopyFrom(localPositions, wdata.renderMeshPositionAndNormalChunk.startIndex, vcnt);
|
||||
rm.renderMeshNormals.CopyFrom(localNormals, wdata.renderMeshPositionAndNormalChunk.startIndex, vcnt);
|
||||
if (wdata.HasMeshTangent)
|
||||
{
|
||||
using var localTangents = new NativeArray<Vector4>(vcnt, Allocator.TempJob);
|
||||
meshData.GetTangents(localTangents);
|
||||
rm.renderMeshTangents.CopyFrom(localTangents, wdata.renderMeshTangentChunk.startIndex, vcnt);
|
||||
wdata.flag.SetBits(RenderManager.RenderDataFlag_HasTangent, true); // 最終的な接線あり
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rm.renderMeshPositions.CopyFrom(setupData.localPositions, wdata.renderMeshPositionAndNormalChunk.startIndex, vcnt);
|
||||
rm.renderMeshNormals.CopyFrom(setupData.localNormals, wdata.renderMeshPositionAndNormalChunk.startIndex, vcnt);
|
||||
if (wdata.HasMeshTangent && setupData.HasTangent)
|
||||
{
|
||||
rm.renderMeshTangents.CopyFrom(setupData.localTangents, wdata.renderMeshTangentChunk.startIndex, vcnt);
|
||||
wdata.flag.SetBits(RenderManager.RenderDataFlag_HasTangent, true); // 最終的な接線あり
|
||||
}
|
||||
}
|
||||
if (HasBoneWeight && wdata.HasBoneWeight)
|
||||
{
|
||||
using var boneWeights = new NativeArray<BoneWeight>(vcnt, Allocator.TempJob);
|
||||
setupData.GetBoneWeightsRun(boneWeights);
|
||||
rm.renderMeshBoneWeights.CopyFrom(boneWeights, wdata.renderMeshBoneWeightChunk.startIndex, vcnt);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// オリジナルメッシュに戻す
|
||||
/// </summary>
|
||||
void SwapOriginalMesh()
|
||||
void SwapOriginalMesh(ClothProcess process)
|
||||
{
|
||||
if (UseCustomMesh && setupData != null)
|
||||
{
|
||||
SetMesh(setupData.originalMesh);
|
||||
var rm = MagicaManager.Render;
|
||||
|
||||
if (setupData.skinRenderer != null)
|
||||
if (rm.IsSetRenderDataWorkFlag(renderDataWorkIndex, RenderManager.RenderDataFlag_UseCustomMesh) && setupData != null)
|
||||
{
|
||||
setupData.skinRenderer.bones = setupData.transformList.ToArray();
|
||||
SetMesh(originalMesh);
|
||||
|
||||
if (skinnedMeshRendere != null)
|
||||
{
|
||||
skinnedMeshRendere.bones = transformList.ToArray();
|
||||
}
|
||||
}
|
||||
rm.SetBitsRenderDataWorkFlag(renderDataWorkIndex, RenderManager.RenderDataFlag_UseCustomMesh, false);
|
||||
|
||||
UseCustomMesh = false;
|
||||
// Event
|
||||
if (process != null)
|
||||
process.cloth?.OnRendererMeshChange?.Invoke(process.cloth, renderer, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -222,13 +261,13 @@ namespace MagicaCloth2
|
||||
|
||||
if (setupData != null)
|
||||
{
|
||||
if (setupData.meshFilter != null)
|
||||
if (meshFilter != null)
|
||||
{
|
||||
setupData.meshFilter.mesh = mesh;
|
||||
meshFilter.mesh = mesh;
|
||||
}
|
||||
else if (setupData.skinRenderer != null)
|
||||
else if (skinnedMeshRendere != null)
|
||||
{
|
||||
setupData.skinRenderer.sharedMesh = mesh;
|
||||
skinnedMeshRendere.sharedMesh = mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -251,7 +290,7 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
public void EndUse(ClothProcess cprocess)
|
||||
{
|
||||
Debug.Assert(useProcessSet.Count > 0);
|
||||
//Debug.Assert(useProcessSet.Count > 0);
|
||||
UpdateUse(cprocess, -1);
|
||||
}
|
||||
|
||||
@ -263,36 +302,62 @@ namespace MagicaCloth2
|
||||
}
|
||||
else if (add < 0)
|
||||
{
|
||||
Debug.Assert(useProcessSet.Count > 0);
|
||||
//Debug.Assert(useProcessSet.Count > 0);
|
||||
if (useProcessSet.Contains(cprocess))
|
||||
useProcessSet.Remove(cprocess);
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
// Invisible状態
|
||||
bool invisible = useProcessSet.Any(x => x.IsCullingInvisible() && x.IsCullingKeep() == false);
|
||||
bool invisible = useProcessSet.Any(x => (x.IsCameraCullingInvisible() && x.IsCameraCullingKeep() == false) || x.IsDistanceCullingInvisible());
|
||||
|
||||
// 状態変更
|
||||
bool modifyBoneWeight = false;
|
||||
if (invisible || useProcessSet.Count == 0)
|
||||
{
|
||||
// 利用停止
|
||||
// オリジナルメッシュに切り替え
|
||||
SwapOriginalMesh();
|
||||
ChangeCustomMesh = true;
|
||||
SwapOriginalMesh(cprocess);
|
||||
}
|
||||
else if (useProcessSet.Count == 1)
|
||||
else if (add == 0 && useProcessSet.Count > 0)
|
||||
{
|
||||
// カリング復帰
|
||||
// カスタムメッシュに切り替え、および作業バッファ作成
|
||||
// すでにカスタムメッシュが存在する場合は作業バッファのみ再初期化する
|
||||
SwapCustomMesh(cprocess);
|
||||
modifyBoneWeight = true;
|
||||
}
|
||||
else if (add > 0 && useProcessSet.Count == 1)
|
||||
{
|
||||
// 利用開始
|
||||
// カスタムメッシュに切り替え、および作業バッファ作成
|
||||
// すでにカスタムメッシュが存在する場合は作業バッファのみ最初期化する
|
||||
SwapCustomMesh();
|
||||
ChangeCustomMesh = true;
|
||||
// すでにカスタムメッシュが存在する場合は作業バッファのみ再初期化する
|
||||
SwapCustomMesh(cprocess);
|
||||
modifyBoneWeight = true;
|
||||
}
|
||||
else if (add != 0)
|
||||
{
|
||||
// 複数から利用されている状態で1つが停止した。
|
||||
// バッファを最初期化する
|
||||
ResetCustomMeshWorkData();
|
||||
ChangeCustomMesh = true;
|
||||
modifyBoneWeight = true;
|
||||
}
|
||||
|
||||
// BoneWeight変更を連動するマッピングに指示する
|
||||
if (modifyBoneWeight)
|
||||
{
|
||||
ref var wdata = ref MagicaManager.Render.GetRenderDataWorkRef(renderDataWorkIndex);
|
||||
int mcnt = wdata.mappingDataIndexList.Length;
|
||||
for (int i = 0; i < mcnt; i++)
|
||||
{
|
||||
int mindex = wdata.mappingDataIndexList[i];
|
||||
ref var mdata = ref MagicaManager.Team.GetMappingDataRef(mindex);
|
||||
mdata.flag.SetBits(TeamManager.MappingDataFlag_ModifyBoneWeight, true);
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.Log($"add:{add}, invisible:{invisible}, useCount:{useProcessSet.Count}, ModifyBoneWeight = {flag.IsSet(Flag_ModifyBoneWeight)}");
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
@ -312,177 +377,39 @@ namespace MagicaCloth2
|
||||
//=========================================================================================
|
||||
internal void WriteMesh()
|
||||
{
|
||||
if (UseCustomMesh == false || useProcessSet.Count == 0)
|
||||
var rm = MagicaManager.Render;
|
||||
ref var wdata = ref rm.GetRenderDataWorkRef(renderDataWorkIndex);
|
||||
|
||||
if (wdata.UseCustomMesh == false || useProcessSet.Count == 0)
|
||||
return;
|
||||
|
||||
// 書き込み停止中ならスキップ
|
||||
if (isSkipWriting)
|
||||
return;
|
||||
|
||||
//Debug.Log($"WriteMesh [{Name}] ChangePositionNormal:{flag.IsSet(Flag_ChangePositionNormal)}, ChangeBoneWeight:{flag.IsSet(Flag_ChangeBoneWeight)}");
|
||||
|
||||
// メッシュに反映
|
||||
if (ChangePositionNormal)
|
||||
if (wdata.flag.IsSet(RenderManager.RenderDataFlag_WritePositionNormal))
|
||||
{
|
||||
customMesh.SetVertices(localPositions);
|
||||
customMesh.SetNormals(localNormals);
|
||||
customMesh.SetVertices(rm.renderMeshPositions.GetNativeArray(), wdata.renderMeshPositionAndNormalChunk.startIndex, wdata.renderMeshPositionAndNormalChunk.dataLength);
|
||||
customMesh.SetNormals(rm.renderMeshNormals.GetNativeArray(), wdata.renderMeshPositionAndNormalChunk.startIndex, wdata.renderMeshPositionAndNormalChunk.dataLength);
|
||||
wdata.flag.SetBits(RenderManager.RenderDataFlag_WritePositionNormal, false);
|
||||
//Debug.Log($"[{customMesh.name}] Write Position+Normal");
|
||||
}
|
||||
if (ChangeBoneWeight && HasBoneWeight)
|
||||
if (wdata.flag.IsSet(RenderManager.RenderDataFlag_WriteTangent))
|
||||
{
|
||||
customMesh.boneWeights = boneWeights.ToArray();
|
||||
customMesh.SetTangents(rm.renderMeshTangents.GetNativeArray(), wdata.renderMeshTangentChunk.startIndex, wdata.renderMeshTangentChunk.dataLength);
|
||||
wdata.flag.SetBits(RenderManager.RenderDataFlag_WriteTangent, false);
|
||||
//Debug.Log($"[{customMesh.name}] Write Tangent");
|
||||
}
|
||||
|
||||
// 完了
|
||||
ChangeCustomMesh = false;
|
||||
ChangePositionNormal = false;
|
||||
ChangeBoneWeight = false;
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// メッシュの位置法線を更新
|
||||
/// </summary>
|
||||
/// <param name="mappingChunk"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
internal JobHandle UpdatePositionNormal(DataChunk mappingChunk, JobHandle jobHandle = default)
|
||||
if (wdata.flag.IsSet(RenderManager.RenderDataFlag_WriteBoneWeight))
|
||||
{
|
||||
if (UseCustomMesh == false)
|
||||
return jobHandle;
|
||||
|
||||
var vm = MagicaManager.VMesh;
|
||||
|
||||
// 座標・法線の差分書き換え
|
||||
var job = new UpdatePositionNormalJob2()
|
||||
{
|
||||
startIndex = mappingChunk.startIndex,
|
||||
|
||||
meshLocalPositions = localPositions.Reinterpret<float3>(),
|
||||
meshLocalNormals = localNormals.Reinterpret<float3>(),
|
||||
|
||||
mappingReferenceIndices = vm.mappingReferenceIndices.GetNativeArray(),
|
||||
mappingAttributes = vm.mappingAttributes.GetNativeArray(),
|
||||
mappingPositions = vm.mappingPositions.GetNativeArray(),
|
||||
mappingNormals = vm.mappingNormals.GetNativeArray(),
|
||||
};
|
||||
jobHandle = job.Schedule(mappingChunk.dataLength, 32, jobHandle);
|
||||
|
||||
ChangePositionNormal = true;
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct UpdatePositionNormalJob2 : IJobParallelFor
|
||||
{
|
||||
public int startIndex;
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> meshLocalPositions;
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> meshLocalNormals;
|
||||
|
||||
// mapping mesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> mappingReferenceIndices;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> mappingAttributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> mappingPositions;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> mappingNormals;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
int vindex = index + startIndex;
|
||||
|
||||
// 無効頂点なら書き込まない
|
||||
var attr = mappingAttributes[vindex];
|
||||
if (attr.IsInvalid())
|
||||
return;
|
||||
|
||||
// 固定も書き込まない(todo:一旦こうする)
|
||||
if (attr.IsFixed())
|
||||
return;
|
||||
|
||||
// 書き込む頂点インデックス
|
||||
int windex = mappingReferenceIndices[vindex];
|
||||
|
||||
// 座標書き込み
|
||||
meshLocalPositions[windex] = mappingPositions[vindex];
|
||||
|
||||
// 法線書き込み
|
||||
meshLocalNormals[windex] = mappingNormals[vindex];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メッシュのボーンウエイト書き込み
|
||||
/// </summary>
|
||||
/// <param name="vmesh"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
internal JobHandle UpdateBoneWeight(DataChunk mappingChunk, JobHandle jobHandle = default)
|
||||
{
|
||||
if (UseCustomMesh == false)
|
||||
return jobHandle;
|
||||
|
||||
// ボーンウエイトの差分書き換え
|
||||
if (HasBoneWeight)
|
||||
{
|
||||
var vm = MagicaManager.VMesh;
|
||||
|
||||
var job = new UpdateBoneWeightJob2()
|
||||
{
|
||||
startIndex = mappingChunk.startIndex,
|
||||
centerBoneWeight = centerBoneWeight,
|
||||
meshBoneWeights = boneWeights,
|
||||
|
||||
mappingReferenceIndices = vm.mappingReferenceIndices.GetNativeArray(),
|
||||
mappingAttributes = vm.mappingAttributes.GetNativeArray(),
|
||||
};
|
||||
jobHandle = job.Schedule(mappingChunk.dataLength, 32, jobHandle);
|
||||
|
||||
ChangeBoneWeight = true;
|
||||
}
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct UpdateBoneWeightJob2 : IJobParallelFor
|
||||
{
|
||||
public int startIndex;
|
||||
public BoneWeight centerBoneWeight;
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<BoneWeight> meshBoneWeights;
|
||||
|
||||
// mapping mesh
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> mappingReferenceIndices;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> mappingAttributes;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
int vindex = index + startIndex;
|
||||
|
||||
// 無効頂点なら書き込まない
|
||||
var attr = mappingAttributes[vindex];
|
||||
if (attr.IsInvalid())
|
||||
return;
|
||||
|
||||
// 固定も書き込まない(todo:一旦こうする)
|
||||
if (attr.IsFixed())
|
||||
return;
|
||||
|
||||
// 書き込む頂点インデックス
|
||||
int windex = mappingReferenceIndices[vindex];
|
||||
|
||||
// 使用頂点のウエイトはcenterTransform100%で書き込む
|
||||
meshBoneWeights[windex] = centerBoneWeight;
|
||||
// BoneWeightはNativeArrayの区間指定ができない
|
||||
var boneWeightsSlice = new NativeSlice<BoneWeight>(rm.renderMeshBoneWeights.GetNativeArray(), wdata.renderMeshBoneWeightChunk.startIndex, wdata.renderMeshBoneWeightChunk.dataLength);
|
||||
customMesh.boneWeights = boneWeightsSlice.ToArray();
|
||||
wdata.flag.SetBits(RenderManager.RenderDataFlag_WriteBoneWeight, false);
|
||||
//Debug.Log($"[{customMesh.name}] Write BoneWeight");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
// https://magicasoft.jp
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
@ -17,6 +20,78 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
Dictionary<int, RenderData> renderDataDict = new Dictionary<int, RenderData>();
|
||||
|
||||
//=========================================================================================
|
||||
// ■RenderData
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// RenderDataの状態フラグ(32bit)
|
||||
/// </summary>
|
||||
public const int RenderDataFlag_UseCustomMesh = 0; // カスタムメッシュの利用
|
||||
public const int RenderDataFlag_WritePositionNormal = 1; // 座標および法線の書き込み
|
||||
public const int RenderDataFlag_WriteBoneWeight = 2; // ボーンウエイトの書き込み
|
||||
//public const int RenderDataFlag_ModifyBoneWeight = 3; // ボーンウエイトの変更
|
||||
public const int RenderDataFlag_HasMeshTangent = 4; // オリジナルメッシュが接線を持っているかどうか
|
||||
public const int RenderDataFlag_HasTangent = 5; // 最終的に接線情報を持っているかどうか
|
||||
public const int RenderDataFlag_WriteTangent = 6; // 接線の書き込み
|
||||
public const int RenderDataFlag_HasSkinnedMesh = 7;
|
||||
public const int RenderDataFlag_HasBoneWeight = 8;
|
||||
|
||||
public struct RenderDataWork : IValid
|
||||
{
|
||||
/// <summary>
|
||||
/// RenderData状態フラグ
|
||||
/// </summary>
|
||||
public BitField32 flag;
|
||||
|
||||
/// <summary>
|
||||
/// バッファへの格納先情報
|
||||
/// </summary>
|
||||
public DataChunk renderMeshPositionAndNormalChunk;
|
||||
public DataChunk renderMeshTangentChunk;
|
||||
public DataChunk renderMeshBoneWeightChunk;
|
||||
|
||||
/// <summary>
|
||||
/// 制御頂点に設定するボーンウエイト
|
||||
/// </summary>
|
||||
public BoneWeight centerBoneWeight;
|
||||
|
||||
/// <summary>
|
||||
/// 紐づけられているマッピングメッシュデータへのインデックスリスト
|
||||
/// </summary>
|
||||
public FixedList32Bytes<short> mappingDataIndexList;
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return renderMeshPositionAndNormalChunk.IsValid;
|
||||
}
|
||||
|
||||
public bool UseCustomMesh => flag.IsSet(RenderDataFlag_UseCustomMesh);
|
||||
public bool HasMeshTangent => flag.IsSet(RenderDataFlag_HasMeshTangent);
|
||||
public bool HasTangent => flag.IsSet(RenderDataFlag_HasTangent);
|
||||
public bool HasBoneWeight => flag.IsSet(RenderDataFlag_HasBoneWeight);
|
||||
|
||||
public void AddMappingIndex(int mindex)
|
||||
{
|
||||
mappingDataIndexList.Add((short)mindex);
|
||||
}
|
||||
|
||||
public void RemoveMappingIndex(int mindex)
|
||||
{
|
||||
mappingDataIndexList.MC2RemoveItemAtSwapBack((short)mindex);
|
||||
}
|
||||
}
|
||||
public ExNativeArray<RenderDataWork> renderDataWorkArray;
|
||||
|
||||
public int RenderDataWorkCount => renderDataWorkArray?.Count ?? 0;
|
||||
|
||||
//=========================================================================================
|
||||
// ■RenderMesh
|
||||
//=========================================================================================
|
||||
public ExNativeArray<float3> renderMeshPositions;
|
||||
public ExNativeArray<float3> renderMeshNormals;
|
||||
public ExNativeArray<float4> renderMeshTangents;
|
||||
public ExNativeArray<BoneWeight> renderMeshBoneWeights;
|
||||
|
||||
bool isValid = false;
|
||||
|
||||
//=========================================================================================
|
||||
@ -24,6 +99,15 @@ namespace MagicaCloth2
|
||||
{
|
||||
Dispose();
|
||||
|
||||
// 作業バッファ
|
||||
const int capacity = 0;
|
||||
const bool create = true;
|
||||
renderDataWorkArray = new ExNativeArray<RenderDataWork>(capacity, create);
|
||||
renderMeshPositions = new ExNativeArray<float3>(capacity, create);
|
||||
renderMeshNormals = new ExNativeArray<float3>(capacity, create);
|
||||
renderMeshTangents = new ExNativeArray<float4>(capacity, create);
|
||||
renderMeshBoneWeights = new ExNativeArray<BoneWeight>(capacity, create);
|
||||
|
||||
// 更新処理
|
||||
MagicaManager.afterDelayedDelegate += PreRenderingUpdate;
|
||||
|
||||
@ -48,6 +132,18 @@ namespace MagicaCloth2
|
||||
}
|
||||
renderDataDict.Clear();
|
||||
|
||||
// 作業バッファ
|
||||
renderDataWorkArray?.Dispose();
|
||||
renderMeshPositions?.Dispose();
|
||||
renderMeshNormals?.Dispose();
|
||||
renderMeshTangents?.Dispose();
|
||||
renderMeshBoneWeights?.Dispose();
|
||||
renderDataWorkArray = null;
|
||||
renderMeshPositions = null;
|
||||
renderMeshNormals = null;
|
||||
renderMeshBoneWeights = null;
|
||||
renderMeshTangents = null;
|
||||
|
||||
// 更新処理
|
||||
MagicaManager.afterDelayedDelegate -= PreRenderingUpdate;
|
||||
}
|
||||
@ -63,7 +159,12 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
/// <param name="ren"></param>
|
||||
/// <returns></returns>
|
||||
public int AddRenderer(Renderer ren)
|
||||
public int AddRenderer(
|
||||
Renderer ren,
|
||||
RenderSetupData referenceSetupData,
|
||||
RenderSetupData.UniqueSerializationData referenceUniqueSetupData,
|
||||
RenderSetupSerializeData referenceInitSetupData
|
||||
)
|
||||
{
|
||||
if (isValid == false)
|
||||
return 0;
|
||||
@ -78,7 +179,7 @@ namespace MagicaCloth2
|
||||
{
|
||||
// 新規
|
||||
var rdata = new RenderData();
|
||||
rdata.Initialize(ren);
|
||||
rdata.Initialize(ren, referenceSetupData, referenceUniqueSetupData, referenceInitSetupData);
|
||||
renderDataDict.Add(handle, rdata);
|
||||
}
|
||||
|
||||
@ -96,8 +197,6 @@ namespace MagicaCloth2
|
||||
|
||||
bool delete = false;
|
||||
|
||||
//if(renderDataDict.ContainsKey(handle) == )
|
||||
|
||||
//Debug.Log($"RemoveRenderer:{handle}");
|
||||
//Debug.Assert(ren);
|
||||
Debug.Assert(renderDataDict.ContainsKey(handle));
|
||||
@ -137,6 +236,92 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
public int AddRenderDataWork(RenderData rdata)
|
||||
{
|
||||
if (isValid == false)
|
||||
return -1;
|
||||
|
||||
var wdata = new RenderDataWork();
|
||||
|
||||
// オリジナルメッシュの接線情報を確認
|
||||
wdata.flag.SetBits(RenderDataFlag_HasMeshTangent, rdata.originalMesh.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.Tangent));
|
||||
//Debug.Log($"OriginalMesh[{originalMesh.name}] hasTangent:{originalMesh.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.Tangent)}");
|
||||
|
||||
// Flag
|
||||
wdata.flag.SetBits(RenderDataFlag_HasSkinnedMesh, rdata.HasSkinnedMesh);
|
||||
wdata.flag.SetBits(RenderDataFlag_HasBoneWeight, rdata.HasBoneWeight);
|
||||
|
||||
// センタートランスフォーム用ボーンウエイト
|
||||
var centerBoneWeight = new BoneWeight();
|
||||
centerBoneWeight.boneIndex0 = rdata.setupData.renderTransformIndex;
|
||||
centerBoneWeight.weight0 = 1.0f;
|
||||
wdata.centerBoneWeight = centerBoneWeight;
|
||||
|
||||
// レンダーメッシュ用バッファ確保
|
||||
int vcnt = rdata.originalMesh.vertexCount;
|
||||
wdata.renderMeshPositionAndNormalChunk = renderMeshPositions.AddRange(vcnt);
|
||||
renderMeshNormals.AddRange(vcnt);
|
||||
if (wdata.HasMeshTangent)
|
||||
wdata.renderMeshTangentChunk = renderMeshTangents.AddRange(vcnt);
|
||||
if (wdata.HasBoneWeight)
|
||||
{
|
||||
wdata.renderMeshBoneWeightChunk = renderMeshBoneWeights.AddRange(vcnt);
|
||||
}
|
||||
|
||||
// 格納
|
||||
var c = renderDataWorkArray.Add(wdata);
|
||||
return c.startIndex;
|
||||
}
|
||||
|
||||
public void RemoveRenderDataWork(int index)
|
||||
{
|
||||
if (isValid == false)
|
||||
return;
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
// バッファ削除
|
||||
ref var wdata = ref GetRenderDataWorkRef(index);
|
||||
if (wdata.renderMeshPositionAndNormalChunk.IsValid)
|
||||
{
|
||||
renderMeshPositions.Remove(wdata.renderMeshPositionAndNormalChunk);
|
||||
renderMeshNormals.Remove(wdata.renderMeshPositionAndNormalChunk);
|
||||
}
|
||||
if (wdata.renderMeshTangentChunk.IsValid)
|
||||
{
|
||||
renderMeshTangents.Remove(wdata.renderMeshTangentChunk);
|
||||
}
|
||||
if (wdata.renderMeshBoneWeightChunk.IsValid)
|
||||
{
|
||||
renderMeshBoneWeights.Remove(wdata.renderMeshBoneWeightChunk);
|
||||
}
|
||||
wdata.renderMeshPositionAndNormalChunk.Clear();
|
||||
wdata.renderMeshTangentChunk.Clear();
|
||||
wdata.renderMeshBoneWeightChunk.Clear();
|
||||
wdata.flag.Clear();
|
||||
|
||||
// 削除
|
||||
renderDataWorkArray.RemoveAndFill(new DataChunk(index));
|
||||
}
|
||||
|
||||
public ref RenderDataWork GetRenderDataWorkRef(int index)
|
||||
{
|
||||
return ref renderDataWorkArray.GetRef(index);
|
||||
}
|
||||
|
||||
public bool IsSetRenderDataWorkFlag(int index, int flag)
|
||||
{
|
||||
ref var wdata = ref GetRenderDataWorkRef(index);
|
||||
return wdata.flag.IsSet(flag);
|
||||
}
|
||||
|
||||
public void SetBitsRenderDataWorkFlag(int index, int flag, bool sw)
|
||||
{
|
||||
ref var wdata = ref GetRenderDataWorkRef(index);
|
||||
wdata.flag.SetBits(flag, sw);
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 有効化
|
||||
@ -157,14 +342,21 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
static readonly ProfilerMarker writeMeshTimeProfiler = new ProfilerMarker("WriteMesh");
|
||||
|
||||
/// <summary>
|
||||
/// レンダリング前更新
|
||||
/// </summary>
|
||||
void PreRenderingUpdate()
|
||||
{
|
||||
if (renderDataDict.Count == 0)
|
||||
return;
|
||||
|
||||
// メッシュへの反映
|
||||
writeMeshTimeProfiler.Begin();
|
||||
foreach (var rdata in renderDataDict.Values)
|
||||
rdata?.WriteMesh();
|
||||
writeMeshTimeProfiler.End();
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
@ -179,7 +371,25 @@ namespace MagicaCloth2
|
||||
else
|
||||
{
|
||||
sb.AppendLine($"Render Manager. Count({renderDataDict.Count})");
|
||||
sb.AppendLine($" [RenderMeshBuffer]");
|
||||
sb.AppendLine($" -renderMeshPositions:{renderMeshPositions.ToSummary()}");
|
||||
sb.AppendLine($" -renderMeshNormals:{renderMeshNormals.ToSummary()}");
|
||||
sb.AppendLine($" -renderMeshTangents:{renderMeshTangents.ToSummary()}");
|
||||
|
||||
sb.AppendLine($" [RenderDataWork]");
|
||||
sb.AppendLine($" -Count:{renderDataWorkArray.Count}");
|
||||
if (renderDataWorkArray.Count > 0)
|
||||
{
|
||||
for (int j = 0; j < renderDataWorkArray.Count; j++)
|
||||
{
|
||||
var wdata = renderDataWorkArray[j];
|
||||
if (wdata.IsValid() == false)
|
||||
continue;
|
||||
sb.AppendLine($" [{j}] MappingListCount:{wdata.mappingDataIndexList.Length}");
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine($" [RenderData]");
|
||||
foreach (var kv in renderDataDict)
|
||||
{
|
||||
sb.Append(kv.Value.ToString());
|
||||
|
||||
@ -7,6 +7,7 @@ using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
@ -19,10 +20,11 @@ namespace MagicaCloth2
|
||||
/// またこの情報はキャラクターが動き出す前に取得しておく必要がある
|
||||
/// そのためAwake()などで実行する
|
||||
/// </summary>
|
||||
public class RenderSetupData : IDisposable, ITransform
|
||||
public partial class RenderSetupData : IDisposable, ITransform
|
||||
{
|
||||
public ResultCode result;
|
||||
public string name = string.Empty;
|
||||
public bool isManaged; // pre-build DeserializeManager管理
|
||||
|
||||
// タイプ
|
||||
public enum SetupType
|
||||
@ -45,11 +47,17 @@ namespace MagicaCloth2
|
||||
public Mesh.MeshDataArray meshDataArray; // Jobで利用するためのMeshData
|
||||
public int skinRootBoneIndex;
|
||||
public int skinBoneCount;
|
||||
|
||||
// MeshDataでは取得できないメッシュ情報
|
||||
public List<Matrix4x4> bindPoseList;
|
||||
public NativeArray<byte> bonesPerVertexArray;
|
||||
public NativeArray<BoneWeight1> boneWeightArray;
|
||||
|
||||
// PreBuild時のみ保持する情報.逆にmeshDataArrayは持たない
|
||||
public NativeArray<Vector3> localPositions;
|
||||
public NativeArray<Vector3> localNormals;
|
||||
public NativeArray<Vector4> localTangents;
|
||||
|
||||
// Bone ---------------------------------------------------------------
|
||||
public List<int> rootTransformIdList;
|
||||
public enum BoneConnectionMode
|
||||
@ -82,7 +90,7 @@ namespace MagicaCloth2
|
||||
public List<FixedList512Bytes<int>> transformChildIdList; // 子IDリスト
|
||||
public NativeArray<float3> transformPositions;
|
||||
public NativeArray<quaternion> transformRotations;
|
||||
public NativeArray<float3> transformLocalPositins;
|
||||
public NativeArray<float3> transformLocalPositions;
|
||||
public NativeArray<quaternion> transformLocalRotations;
|
||||
public NativeArray<float3> transformScales;
|
||||
public NativeArray<quaternion> transformInverseRotations;
|
||||
@ -95,16 +103,21 @@ namespace MagicaCloth2
|
||||
public bool IsSuccess() => result.IsSuccess();
|
||||
public bool IsFaild() => result.IsFaild();
|
||||
public int TransformCount => transformList?.Count ?? 0;
|
||||
public bool HasMeshDataArray => meshDataArray.Length > 0;
|
||||
public bool HasLocalPositions => localPositions.IsCreated;
|
||||
public bool HasTangent => localTangents.IsCreated && localTangents.Length > 0;
|
||||
|
||||
//static readonly ProfilerMarker initProfiler = new ProfilerMarker("Render Setup");
|
||||
static readonly ProfilerMarker readTransformProfiler = new ProfilerMarker("readTransform");
|
||||
|
||||
//=========================================================================================
|
||||
public RenderSetupData() { }
|
||||
|
||||
/// <summary>
|
||||
/// レンダラーから基本情報を作成する(メインスレッドのみ)
|
||||
/// タイプはMeshになる
|
||||
/// </summary>
|
||||
/// <param name="ren"></param>
|
||||
public RenderSetupData(Renderer ren)
|
||||
public RenderSetupData(RenderSetupSerializeData referenceInitSetupData, Renderer ren)
|
||||
{
|
||||
//using (initProfiler.Auto())
|
||||
{
|
||||
@ -119,6 +132,9 @@ namespace MagicaCloth2
|
||||
return;
|
||||
}
|
||||
|
||||
// 初期化データの有無
|
||||
bool useInitData = referenceInitSetupData != null;
|
||||
|
||||
name = ren.name;
|
||||
|
||||
var sren = ren as SkinnedMeshRenderer;
|
||||
@ -133,7 +149,36 @@ namespace MagicaCloth2
|
||||
// 描画の基準トランスフォーム
|
||||
var renderTransform = ren.transform;
|
||||
|
||||
if (sren)
|
||||
if (useInitData)
|
||||
{
|
||||
// 初期化データがある場合はコピーして終わり
|
||||
skinBoneCount = referenceInitSetupData.skinBoneCount;
|
||||
skinRootBoneIndex = referenceInitSetupData.skinRootBoneIndex;
|
||||
renderTransformIndex = referenceInitSetupData.renderTransformIndex;
|
||||
hasBoneWeight = referenceInitSetupData.hasBoneWeight;
|
||||
|
||||
// transformList復元
|
||||
transformList = new List<Transform>(new Transform[referenceInitSetupData.transformCount]);
|
||||
int ucnt = referenceInitSetupData.useTransformCount;
|
||||
for (int i = 0; i < ucnt; i++)
|
||||
{
|
||||
int tindex = referenceInitSetupData.useTransformIndexArray[i];
|
||||
transformList[tindex] = referenceInitSetupData.transformArray[i];
|
||||
}
|
||||
|
||||
// SkinnedMeshRendererかつオリジナルメッシュが存在する場合はSkinnedMeshRenererを復元する
|
||||
// 実行時キャラクターコピーへの対応
|
||||
if (sren && referenceInitSetupData.originalMesh && sren.sharedMesh != referenceInitSetupData.originalMesh && skinBoneCount > 0)
|
||||
{
|
||||
sren.sharedMesh = referenceInitSetupData.originalMesh;
|
||||
var newBones = new Transform[skinBoneCount];
|
||||
transformList.CopyTo(0, newBones, 0, skinBoneCount);
|
||||
sren.bones = newBones;
|
||||
sren.rootBone = transformList[skinRootBoneIndex];
|
||||
//Debug.Log($"★SkinnedMeshRenderer再構成");
|
||||
}
|
||||
}
|
||||
else if (sren)
|
||||
{
|
||||
// bones
|
||||
// このスキニングボーンの取得が特に重くメモリアロケーションも頻発する問題児
|
||||
@ -188,7 +233,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
// トランスフォーム情報の読み取り
|
||||
ReadTransformInformation(includeChilds: false);
|
||||
ReadTransformInformation(includeChilds: false, referenceInitSetupData, ren.transform);
|
||||
|
||||
// bindpose / weights
|
||||
if (sren)
|
||||
@ -207,12 +252,14 @@ namespace MagicaCloth2
|
||||
|
||||
// どうもコピーを作らないとダメらしい..
|
||||
// ※具体的にはメッシュのクローンを作成したときに壊れる
|
||||
var weightArray = mesh.GetAllBoneWeights();
|
||||
var perVertexArray = mesh.GetBonesPerVertex();
|
||||
using var weightArray = mesh.GetAllBoneWeights();
|
||||
using var perVertexArray = mesh.GetBonesPerVertex();
|
||||
boneWeightArray = new NativeArray<BoneWeight1>(weightArray, Allocator.Persistent);
|
||||
bonesPerVertexArray = new NativeArray<byte>(perVertexArray, Allocator.Persistent);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// 5ボーン以上を利用する頂点ウエイトは警告とする。一応無効となるだけで動くのでエラーにはしない。
|
||||
// なおこの検証はビルド環境では行わない
|
||||
int vcnt = mesh.vertexCount;
|
||||
using var bonesPerVertexResult = new NativeReference<Define.Result>(Allocator.TempJob);
|
||||
var job = new VertexWeight5BoneCheckJob()
|
||||
@ -223,6 +270,7 @@ namespace MagicaCloth2
|
||||
};
|
||||
job.Run();
|
||||
result.SetWarning(bonesPerVertexResult.Value);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -276,6 +324,10 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 5ウエイト以上の検出
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
struct VertexWeight5BoneCheckJob : IJob
|
||||
{
|
||||
@ -301,6 +353,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// ルートボーンリストから基本情報を作成する(メインスレッドのみ)
|
||||
@ -309,6 +362,7 @@ namespace MagicaCloth2
|
||||
/// <param name="renderTransform"></param>
|
||||
/// <param name="rootTransforms"></param>
|
||||
public RenderSetupData(
|
||||
RenderSetupSerializeData referenceInitSetupData,
|
||||
SetupType setType,
|
||||
Transform renderTransform,
|
||||
List<Transform> rootTransforms,
|
||||
@ -322,6 +376,8 @@ namespace MagicaCloth2
|
||||
//using (initProfiler.Auto())
|
||||
try
|
||||
{
|
||||
bool useInitData = referenceInitSetupData != null;
|
||||
|
||||
// Boneタイプに設定
|
||||
setupType = setType;
|
||||
|
||||
@ -344,6 +400,15 @@ namespace MagicaCloth2
|
||||
this.name = name;
|
||||
|
||||
// 必要なトランスフォーム情報
|
||||
if (useInitData)
|
||||
{
|
||||
// 初期化データがある場合はコピーして終わり
|
||||
transformList = new List<Transform>(referenceInitSetupData.transformArray);
|
||||
skinBoneCount = referenceInitSetupData.skinBoneCount;
|
||||
renderTransformIndex = referenceInitSetupData.renderTransformIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
var indexDict = new Dictionary<Transform, int>(256);
|
||||
transformList = new List<Transform>(256);
|
||||
|
||||
@ -370,6 +435,14 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
// スキニングボーン数
|
||||
skinBoneCount = transformList.Count;
|
||||
|
||||
// レンダートランスフォームを最後に追加
|
||||
renderTransformIndex = transformList.Count;
|
||||
transformList.Add(renderTransform);
|
||||
}
|
||||
|
||||
// root transform id
|
||||
rootTransformIdList = new List<int>(rootTransforms.Count);
|
||||
foreach (var t in rootTransforms)
|
||||
@ -392,15 +465,8 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
// スキニングボーン数
|
||||
skinBoneCount = transformList.Count;
|
||||
|
||||
// レンダートランスフォームを最後に追加
|
||||
renderTransformIndex = transformList.Count;
|
||||
transformList.Add(renderTransform);
|
||||
|
||||
// トランスフォーム情報の読み取り
|
||||
ReadTransformInformation(includeChilds: true);
|
||||
ReadTransformInformation(includeChilds: true, referenceInitSetupData, renderTransform);
|
||||
|
||||
// 完了
|
||||
result.SetSuccess();
|
||||
@ -422,24 +488,90 @@ namespace MagicaCloth2
|
||||
/// トランスフォーム情報の読み取り(メインスレッドのみ)
|
||||
/// この情報だけはキャラクターが動く前に取得する必要がある
|
||||
/// </summary>
|
||||
void ReadTransformInformation(bool includeChilds)
|
||||
void ReadTransformInformation(bool includeChilds, RenderSetupSerializeData referenceInitSetupData, Transform rendererTransform)
|
||||
{
|
||||
readTransformProfiler.Begin();
|
||||
|
||||
int tcnt = transformList.Count;
|
||||
using var transformArray = new TransformAccessArray(transformList.ToArray());
|
||||
bool useInitData = referenceInitSetupData != null;
|
||||
|
||||
// バッファ作成
|
||||
transformPositions = new NativeArray<float3>(tcnt, Allocator.Persistent);
|
||||
transformRotations = new NativeArray<quaternion>(tcnt, Allocator.Persistent);
|
||||
transformLocalPositins = new NativeArray<float3>(tcnt, Allocator.Persistent);
|
||||
transformLocalPositions = new NativeArray<float3>(tcnt, Allocator.Persistent);
|
||||
transformLocalRotations = new NativeArray<quaternion>(tcnt, Allocator.Persistent);
|
||||
transformScales = new NativeArray<float3>(tcnt, Allocator.Persistent);
|
||||
transformInverseRotations = new NativeArray<quaternion>(tcnt, Allocator.Persistent);
|
||||
|
||||
// 読み取り
|
||||
if (useInitData)
|
||||
{
|
||||
Debug.Assert(tcnt == referenceInitSetupData.transformCount);
|
||||
|
||||
// 初期化データがある場合はコピーして終わり
|
||||
int ucnt = referenceInitSetupData.useTransformCount;
|
||||
|
||||
if (ucnt == tcnt)
|
||||
{
|
||||
// 全体コピー
|
||||
NativeArray<float3>.Copy(referenceInitSetupData.transformPositions, 0, transformPositions, 0, ucnt);
|
||||
NativeArray<quaternion>.Copy(referenceInitSetupData.transformRotations, 0, transformRotations, 0, ucnt);
|
||||
NativeArray<float3>.Copy(referenceInitSetupData.transformLocalPositions, 0, transformLocalPositions, 0, ucnt);
|
||||
NativeArray<quaternion>.Copy(referenceInitSetupData.transformLocalRotations, 0, transformLocalRotations, 0, ucnt);
|
||||
NativeArray<float3>.Copy(referenceInitSetupData.transformScales, 0, transformScales, 0, ucnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 差分
|
||||
for (int i = 0; i < ucnt; i++)
|
||||
{
|
||||
int tindex = referenceInitSetupData.useTransformIndexArray[i];
|
||||
transformPositions[tindex] = referenceInitSetupData.transformPositions[i];
|
||||
transformRotations[tindex] = referenceInitSetupData.transformRotations[i];
|
||||
transformLocalPositions[tindex] = referenceInitSetupData.transformLocalPositions[i];
|
||||
transformLocalRotations[tindex] = referenceInitSetupData.transformLocalRotations[i];
|
||||
transformScales[tindex] = referenceInitSetupData.transformScales[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 逆回転のみ計算で求める
|
||||
var job = new CalcInverseRotationJob()
|
||||
{
|
||||
rotations = transformRotations,
|
||||
inverseRotations = transformInverseRotations,
|
||||
};
|
||||
job.Run(tcnt);
|
||||
|
||||
// 初期センタートランスフォームを別途コピーしておく
|
||||
initRenderLocalToWorld = referenceInitSetupData.initRenderLocalToWorld;
|
||||
initRenderWorldtoLocal = referenceInitSetupData.initRenderWorldtoLocal;
|
||||
initRenderRotation = referenceInitSetupData.initRenderRotation;
|
||||
initRenderScale = referenceInitSetupData.initRenderScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
//using var transformArray = new TransformAccessArray(transformList.ToArray());
|
||||
// Unity6.1対応
|
||||
using var transformArray = new TransformAccessArray(transformList.Count);
|
||||
int cnt = transformList.Count;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
var t = transformList[i];
|
||||
if (t == null)
|
||||
t = rendererTransform;
|
||||
//transformArray[i] = t;
|
||||
transformArray.Add(t);
|
||||
}
|
||||
|
||||
|
||||
var job = new ReadTransformJob()
|
||||
{
|
||||
positions = transformPositions,
|
||||
rotations = transformRotations,
|
||||
scales = transformScales,
|
||||
localPositions = transformLocalPositins,
|
||||
localPositions = transformLocalPositions,
|
||||
localRotations = transformLocalRotations,
|
||||
inverseRotations = transformInverseRotations,
|
||||
inverseRotations = transformInverseRotations
|
||||
};
|
||||
// シミュレーション以外でワーカーを消費したくないのでRun()版にしておく
|
||||
job.RunReadOnly(transformArray);
|
||||
@ -449,15 +581,24 @@ namespace MagicaCloth2
|
||||
initRenderWorldtoLocal = math.inverse(initRenderLocalToWorld);
|
||||
initRenderRotation = transformRotations[renderTransformIndex];
|
||||
initRenderScale = transformScales[renderTransformIndex];
|
||||
}
|
||||
|
||||
// id
|
||||
// id / parent id
|
||||
transformIdList = new List<int>(tcnt);
|
||||
transformParentIdList = new List<int>(tcnt);
|
||||
for (int i = 0; i < tcnt; i++)
|
||||
{
|
||||
int id = 0, pid = 0;
|
||||
|
||||
var t = transformList[i];
|
||||
transformIdList.Add(t?.GetInstanceID() ?? 0);
|
||||
transformParentIdList.Add(t?.parent?.GetInstanceID() ?? 0);
|
||||
if (t)
|
||||
{
|
||||
id = t.GetInstanceID();
|
||||
if (includeChilds && t.parent)
|
||||
pid = t.parent.GetInstanceID();
|
||||
}
|
||||
transformIdList.Add(id);
|
||||
transformParentIdList.Add(pid);
|
||||
}
|
||||
|
||||
// child id
|
||||
@ -468,7 +609,7 @@ namespace MagicaCloth2
|
||||
{
|
||||
var t = transformList[i];
|
||||
var clist = new FixedList512Bytes<int>();
|
||||
if (t?.childCount > 0)
|
||||
if (t && t.childCount > 0)
|
||||
{
|
||||
for (int j = 0; j < t.childCount; j++)
|
||||
{
|
||||
@ -479,6 +620,32 @@ namespace MagicaCloth2
|
||||
transformChildIdList.Add(clist);
|
||||
}
|
||||
}
|
||||
|
||||
readTransformProfiler.End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 逆回転を計算で求める
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
struct CalcInverseRotationJob : IJobParallelFor
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<quaternion> rotations;
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<quaternion> inverseRotations;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
var rot = rotations[index];
|
||||
if (math.any(rot.value))
|
||||
{
|
||||
// どれか1つでも != 0 なら実行する
|
||||
var irot = math.inverse(rot);
|
||||
inverseRotations[index] = irot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -487,16 +654,22 @@ namespace MagicaCloth2
|
||||
[BurstCompile]
|
||||
struct ReadTransformJob : IJobParallelForTransform
|
||||
{
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> positions;
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<quaternion> rotations;
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> scales;
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> localPositions;
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<quaternion> localRotations;
|
||||
[NativeDisableParallelForRestriction]
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<quaternion> inverseRotations;
|
||||
|
||||
@ -527,23 +700,22 @@ namespace MagicaCloth2
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (bonesPerVertexArray.IsCreated)
|
||||
bonesPerVertexArray.Dispose();
|
||||
if (boneWeightArray.IsCreated)
|
||||
boneWeightArray.Dispose();
|
||||
// Pre-Build DeserializeManager管理中は破棄させない
|
||||
if (isManaged)
|
||||
return;
|
||||
|
||||
if (transformPositions.IsCreated)
|
||||
transformPositions.Dispose();
|
||||
if (transformRotations.IsCreated)
|
||||
transformRotations.Dispose();
|
||||
if (transformLocalPositins.IsCreated)
|
||||
transformLocalPositins.Dispose();
|
||||
if (transformLocalRotations.IsCreated)
|
||||
transformLocalRotations.Dispose();
|
||||
if (transformScales.IsCreated)
|
||||
transformScales.Dispose();
|
||||
if (transformInverseRotations.IsCreated)
|
||||
transformInverseRotations.Dispose();
|
||||
bonesPerVertexArray.MC2DisposeSafe();
|
||||
boneWeightArray.MC2DisposeSafe();
|
||||
localPositions.MC2DisposeSafe();
|
||||
localNormals.MC2DisposeSafe();
|
||||
localTangents.MC2DisposeSafe();
|
||||
|
||||
transformPositions.MC2DisposeSafe();
|
||||
transformRotations.MC2DisposeSafe();
|
||||
transformLocalPositions.MC2DisposeSafe();
|
||||
transformLocalRotations.MC2DisposeSafe();
|
||||
transformScales.MC2DisposeSafe();
|
||||
transformInverseRotations.MC2DisposeSafe();
|
||||
|
||||
// MeshDataArrayはメインスレッドのみDispose()可能
|
||||
if (setupType == SetupType.MeshCloth)
|
||||
@ -554,10 +726,14 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
public void GetUsedTransform(HashSet<Transform> transformSet)
|
||||
{
|
||||
if (transformList != null)
|
||||
{
|
||||
foreach (var t in transformList)
|
||||
if (t)
|
||||
transformSet.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
|
||||
{
|
||||
@ -622,9 +798,10 @@ namespace MagicaCloth2
|
||||
|
||||
public float4x4 GetRendeerLocalToWorldMatrix()
|
||||
{
|
||||
var pos = transformPositions[renderTransformIndex];
|
||||
var rot = transformRotations[renderTransformIndex];
|
||||
var scl = transformScales[renderTransformIndex];
|
||||
int index = renderTransformIndex;
|
||||
var pos = transformPositions[index];
|
||||
var rot = transformRotations[index];
|
||||
var scl = transformScales[index];
|
||||
return float4x4.TRS(pos, rot, scl);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -96,7 +96,7 @@ namespace MagicaCloth2
|
||||
//=========================================================================================
|
||||
void AfterFixedUpdate()
|
||||
{
|
||||
//Debug.Log($"AF. F:{Time.frameCount}");
|
||||
//Debug.Log($"AfterFixedUpdate. F:{Time.frameCount}");
|
||||
FixedUpdateCount++;
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ namespace MagicaCloth2
|
||||
sb.AppendLine($"MaxSimulationCountPerFrame:{maxSimulationCountPerFrame}");
|
||||
sb.AppendLine($"GlobalTimeScale:{GlobalTimeScale}");
|
||||
sb.AppendLine($"SimulationDeltaTime:{SimulationDeltaTime}");
|
||||
sb.AppendLine($"MaxDeltaTime:{MaxDeltaTime}");
|
||||
//sb.AppendLine($"MaxDeltaTime:{MaxDeltaTime}");
|
||||
sb.AppendLine($"SimulationPower:{SimulationPower}");
|
||||
}
|
||||
sb.AppendLine();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -86,6 +86,12 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyFrom(in TeamWindData wdata)
|
||||
{
|
||||
windZoneList = wdata.windZoneList;
|
||||
movingWind = wdata.movingWind;
|
||||
}
|
||||
|
||||
//public void DebugLog(int teamId)
|
||||
//{
|
||||
// Debug.Log($"TeamWindData:{teamId}, zoneCnt:{ZoneCount}");
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
// https://magicasoft.jp
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
@ -16,7 +17,7 @@ namespace MagicaCloth2
|
||||
/// TransformAccessArrayを中心とした一連のTransform管理クラス
|
||||
/// スレッドで利用できるように様々な工夫を行っている
|
||||
/// </summary>
|
||||
public class TransformData : IDisposable
|
||||
public partial class TransformData : IDisposable
|
||||
{
|
||||
internal List<Transform> transformList;
|
||||
|
||||
@ -101,10 +102,7 @@ namespace MagicaCloth2
|
||||
Queue<int> emptyStack;
|
||||
|
||||
//=========================================================================================
|
||||
public TransformData()
|
||||
{
|
||||
Init(100);
|
||||
}
|
||||
public TransformData() { }
|
||||
|
||||
public TransformData(int capacity)
|
||||
{
|
||||
@ -133,7 +131,7 @@ namespace MagicaCloth2
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
transformList.Clear();
|
||||
transformList?.Clear();
|
||||
idArray?.Dispose();
|
||||
parentIdArray?.Dispose();
|
||||
flagArray?.Dispose();
|
||||
@ -145,15 +143,11 @@ namespace MagicaCloth2
|
||||
localPositionArray?.Dispose();
|
||||
localRotationArray?.Dispose();
|
||||
inverseRotationArray?.Dispose();
|
||||
emptyStack.Clear();
|
||||
emptyStack?.Clear();
|
||||
|
||||
// transformAccessArrayはメインスレッドのみ
|
||||
if (transformAccessArray.isCreated)
|
||||
{
|
||||
//if (MagicaManager.Discard != null)
|
||||
// MagicaManager.Discard.AddMain(transformAccessArray);
|
||||
//else
|
||||
// transformAccessArray.Dispose();
|
||||
transformAccessArray.Dispose();
|
||||
}
|
||||
}
|
||||
@ -161,6 +155,7 @@ namespace MagicaCloth2
|
||||
public int Count => transformList.Count;
|
||||
public int RootCount => rootIdList?.Count ?? 0;
|
||||
public bool IsDirty => isDirty;
|
||||
public bool IsEmpty => transformList == null;
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
@ -951,5 +946,19 @@ namespace MagicaCloth2
|
||||
{
|
||||
return math.inverse(GetLocalToWorldMatrix(index));
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
public override string ToString()
|
||||
{
|
||||
int transformListCount = transformList?.Count ?? 0;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("==== TransformData ====");
|
||||
sb.AppendLine($"isDirty:{isDirty}");
|
||||
sb.AppendLine($"transformList:{transformListCount}");
|
||||
sb.AppendLine($"flagArray:{flagArray.Length}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,16 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
internal ExNativeArray<quaternion> initLocalRotationArray;
|
||||
|
||||
/// <summary>
|
||||
/// シミュレーションの基準となるlocalPosition
|
||||
/// </summary>
|
||||
internal ExNativeArray<float3> baseLocalPositionArray;
|
||||
|
||||
/// <summary>
|
||||
/// シミュレーションの基準となるlocalRotation
|
||||
/// </summary>
|
||||
internal ExNativeArray<quaternion> baseLocalRotationArray;
|
||||
|
||||
/// <summary>
|
||||
/// ワールド座標
|
||||
/// </summary>
|
||||
@ -44,7 +54,7 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// ワールド逆回転
|
||||
/// </summary>
|
||||
internal ExNativeArray<quaternion> inverseRotationArray;
|
||||
//internal ExNativeArray<quaternion> inverseRotationArray;
|
||||
|
||||
/// <summary>
|
||||
/// ワールドスケール
|
||||
@ -62,6 +72,16 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
internal ExNativeArray<quaternion> localRotationArray;
|
||||
|
||||
/// <summary>
|
||||
/// ローカルスケール
|
||||
/// </summary>
|
||||
internal ExNativeArray<float3> localScaleArray;
|
||||
|
||||
/// <summary>
|
||||
/// ワールド変換マトリックス
|
||||
/// </summary>
|
||||
internal ExNativeArray<float4x4> localToWorldMatrixArray;
|
||||
|
||||
/// <summary>
|
||||
/// 接続チームID(0=なし)
|
||||
/// </summary>
|
||||
@ -78,15 +98,16 @@ namespace MagicaCloth2
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 書き込み用トランスフォームのデータ参照インデックス
|
||||
/// つまり上記配列へのインデックス
|
||||
/// コンポーネント用ワールド座標
|
||||
/// </summary>
|
||||
//internal ExNativeArray<short> writeIndexArray;
|
||||
internal ExNativeArray<float3> componentPositionArray;
|
||||
|
||||
/// <summary>
|
||||
/// 書き込み用トランスフォームアクセス配列
|
||||
/// コンポーネント用トランスフォーム
|
||||
/// </summary>
|
||||
//internal TransformAccessArray writeTransformAccessArray;
|
||||
internal TransformAccessArray componentTransformAccessArray;
|
||||
|
||||
internal NativeReference<bool> existFixedTeam;
|
||||
|
||||
bool isValid;
|
||||
|
||||
@ -98,24 +119,32 @@ namespace MagicaCloth2
|
||||
flagArray?.Dispose();
|
||||
initLocalPositionArray?.Dispose();
|
||||
initLocalRotationArray?.Dispose();
|
||||
baseLocalPositionArray?.Dispose();
|
||||
baseLocalRotationArray?.Dispose();
|
||||
positionArray?.Dispose();
|
||||
rotationArray?.Dispose();
|
||||
inverseRotationArray?.Dispose();
|
||||
//inverseRotationArray?.Dispose();
|
||||
scaleArray?.Dispose();
|
||||
localPositionArray?.Dispose();
|
||||
localRotationArray?.Dispose();
|
||||
localScaleArray?.Dispose();
|
||||
localToWorldMatrixArray?.Dispose();
|
||||
teamIdArray?.Dispose();
|
||||
//writeIndexArray?.Dispose();
|
||||
|
||||
flagArray = null;
|
||||
initLocalPositionArray = null;
|
||||
initLocalRotationArray = null;
|
||||
baseLocalPositionArray = null;
|
||||
baseLocalRotationArray = null;
|
||||
positionArray = null;
|
||||
rotationArray = null;
|
||||
inverseRotationArray = null;
|
||||
//inverseRotationArray = null;
|
||||
scaleArray = null;
|
||||
localPositionArray = null;
|
||||
localRotationArray = null;
|
||||
localScaleArray = null;
|
||||
localToWorldMatrixArray = null;
|
||||
teamIdArray = null;
|
||||
//writeIndexArray = null;
|
||||
|
||||
@ -123,6 +152,13 @@ namespace MagicaCloth2
|
||||
transformAccessArray.Dispose();
|
||||
//if (writeTransformAccessArray.isCreated)
|
||||
// writeTransformAccessArray.Dispose();
|
||||
|
||||
componentPositionArray?.Dispose();
|
||||
if (componentTransformAccessArray.isCreated)
|
||||
componentTransformAccessArray.Dispose();
|
||||
|
||||
if (existFixedTeam.IsCreated)
|
||||
existFixedTeam.Dispose();
|
||||
}
|
||||
|
||||
public void EnterdEditMode()
|
||||
@ -138,16 +174,25 @@ namespace MagicaCloth2
|
||||
flagArray = new ExNativeArray<ExBitFlag8>(capacity);
|
||||
initLocalPositionArray = new ExNativeArray<float3>(capacity);
|
||||
initLocalRotationArray = new ExNativeArray<quaternion>(capacity);
|
||||
baseLocalPositionArray = new ExNativeArray<float3>(capacity);
|
||||
baseLocalRotationArray = new ExNativeArray<quaternion>(capacity);
|
||||
positionArray = new ExNativeArray<float3>(capacity);
|
||||
rotationArray = new ExNativeArray<quaternion>(capacity);
|
||||
inverseRotationArray = new ExNativeArray<quaternion>(capacity);
|
||||
//inverseRotationArray = new ExNativeArray<quaternion>(capacity);
|
||||
scaleArray = new ExNativeArray<float3>(capacity);
|
||||
localPositionArray = new ExNativeArray<float3>(capacity);
|
||||
localRotationArray = new ExNativeArray<quaternion>(capacity);
|
||||
localScaleArray = new ExNativeArray<float3>(capacity);
|
||||
localToWorldMatrixArray = new ExNativeArray<float4x4>(capacity);
|
||||
teamIdArray = new ExNativeArray<short>(capacity);
|
||||
|
||||
transformAccessArray = new TransformAccessArray(capacity);
|
||||
|
||||
componentPositionArray = new ExNativeArray<float3>(capacity);
|
||||
componentTransformAccessArray = new TransformAccessArray(capacity);
|
||||
|
||||
existFixedTeam = new NativeReference<bool>(Allocator.Persistent);
|
||||
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
@ -158,30 +203,34 @@ namespace MagicaCloth2
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// TransformDataを追加する
|
||||
/// VirtualMeshのTransformDataを追加する
|
||||
/// </summary>
|
||||
/// <param name="tdata"></param>
|
||||
/// <returns></returns>
|
||||
internal DataChunk AddTransform(TransformData tdata, int teamId)
|
||||
internal DataChunk AddTransform(VirtualMeshContainer cmesh, int teamId)
|
||||
{
|
||||
if (isValid == false)
|
||||
return default;
|
||||
|
||||
Debug.Assert(tdata != null);
|
||||
int cnt = tdata.Count;
|
||||
Debug.Assert(cmesh != null);
|
||||
int cnt = cmesh.GetTransformCount();
|
||||
|
||||
// データコピー追加
|
||||
var c = flagArray.AddRange(tdata.flagArray);
|
||||
initLocalPositionArray.AddRange(tdata.initLocalPositionArray);
|
||||
initLocalRotationArray.AddRange(tdata.initLocalRotationArray);
|
||||
var c = flagArray.AddRange(cmesh.shareVirtualMesh.transformData.flagArray);
|
||||
initLocalPositionArray.AddRange(cmesh.shareVirtualMesh.transformData.initLocalPositionArray);
|
||||
initLocalRotationArray.AddRange(cmesh.shareVirtualMesh.transformData.initLocalRotationArray);
|
||||
baseLocalPositionArray.AddRange(cmesh.shareVirtualMesh.transformData.initLocalPositionArray);
|
||||
baseLocalRotationArray.AddRange(cmesh.shareVirtualMesh.transformData.initLocalRotationArray);
|
||||
|
||||
// 領域のみ追加
|
||||
positionArray.AddRange(cnt);
|
||||
rotationArray.AddRange(cnt);
|
||||
inverseRotationArray.AddRange(cnt);
|
||||
//inverseRotationArray.AddRange(cnt);
|
||||
scaleArray.AddRange(cnt);
|
||||
localPositionArray.AddRange(cnt);
|
||||
localRotationArray.AddRange(cnt);
|
||||
localScaleArray.AddRange(cnt);
|
||||
localToWorldMatrixArray.AddRange(cnt);
|
||||
|
||||
// チームID
|
||||
teamIdArray.AddRange(cnt, (short)teamId);
|
||||
@ -190,16 +239,19 @@ namespace MagicaCloth2
|
||||
int nowcnt = transformAccessArray.length;
|
||||
|
||||
// データチャンクの開始まで埋める
|
||||
var meshT = cmesh.GetCenterTransform();
|
||||
int start = c.startIndex;
|
||||
while (nowcnt < start)
|
||||
{
|
||||
transformAccessArray.Add(null);
|
||||
transformAccessArray.Add(meshT);
|
||||
nowcnt++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
var t = tdata.transformList[i];
|
||||
Transform t = cmesh.GetTransformFromIndex(i);
|
||||
if (t == null)
|
||||
t = meshT;
|
||||
int index = c.startIndex + i;
|
||||
if (index < nowcnt)
|
||||
transformAccessArray[index] = t;
|
||||
@ -215,7 +267,7 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
internal DataChunk AddTransform(int count, int teamId)
|
||||
internal DataChunk AddTransform(int count, int teamId, Transform t)
|
||||
{
|
||||
if (isValid == false)
|
||||
return default;
|
||||
@ -224,30 +276,34 @@ namespace MagicaCloth2
|
||||
var c = flagArray.AddRange(count);
|
||||
initLocalPositionArray.AddRange(count);
|
||||
initLocalRotationArray.AddRange(count);
|
||||
baseLocalPositionArray.AddRange(count);
|
||||
baseLocalRotationArray.AddRange(count);
|
||||
positionArray.AddRange(count);
|
||||
rotationArray.AddRange(count);
|
||||
inverseRotationArray.AddRange(count);
|
||||
//inverseRotationArray.AddRange(count);
|
||||
scaleArray.AddRange(count);
|
||||
localPositionArray.AddRange(count);
|
||||
localRotationArray.AddRange(count);
|
||||
localScaleArray.AddRange(count);
|
||||
localToWorldMatrixArray.AddRange(count);
|
||||
|
||||
// チームID
|
||||
teamIdArray.AddRange(count, (short)teamId);
|
||||
|
||||
// トランスフォームはすべてnullで登録する
|
||||
// トランスフォームはすべてnullで登録する(Unity6.1でnull登録はNGになった!)
|
||||
int nowcnt = transformAccessArray.length;
|
||||
|
||||
// データチャンクの開始まで埋める
|
||||
int start = c.startIndex;
|
||||
while (nowcnt < start)
|
||||
{
|
||||
transformAccessArray.Add(null);
|
||||
transformAccessArray.Add(t);
|
||||
nowcnt++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Transform t = null;
|
||||
//Transform t = null;
|
||||
int index = c.startIndex + i;
|
||||
if (index < nowcnt)
|
||||
transformAccessArray[index] = t;
|
||||
@ -273,12 +329,16 @@ namespace MagicaCloth2
|
||||
var c = flagArray.Add(flag);
|
||||
initLocalPositionArray.Add(t.localPosition);
|
||||
initLocalRotationArray.Add(t.localRotation);
|
||||
baseLocalPositionArray.Add(t.localPosition);
|
||||
baseLocalRotationArray.Add(t.localRotation);
|
||||
positionArray.Add(t.position);
|
||||
rotationArray.Add(t.rotation);
|
||||
inverseRotationArray.Add(math.inverse(t.rotation));
|
||||
//inverseRotationArray.Add(math.inverse(t.rotation));
|
||||
scaleArray.Add(t.lossyScale);
|
||||
localPositionArray.Add(t.localPosition);
|
||||
localRotationArray.Add(t.localRotation);
|
||||
localScaleArray.Add(t.localScale);
|
||||
localToWorldMatrixArray.Add(float4x4.identity); // ここは単位行列
|
||||
|
||||
// チームID
|
||||
teamIdArray.Add((short)teamId);
|
||||
@ -311,12 +371,16 @@ namespace MagicaCloth2
|
||||
flagArray[index] = flag;
|
||||
initLocalPositionArray[index] = t.localPosition;
|
||||
initLocalRotationArray[index] = t.localRotation;
|
||||
baseLocalPositionArray[index] = t.localPosition;
|
||||
baseLocalRotationArray[index] = t.localRotation;
|
||||
positionArray[index] = t.position;
|
||||
rotationArray[index] = t.rotation;
|
||||
inverseRotationArray[index] = math.inverse(t.rotation);
|
||||
//inverseRotationArray[index] = math.inverse(t.rotation);
|
||||
scaleArray[index] = t.lossyScale;
|
||||
localPositionArray[index] = t.localPosition;
|
||||
localRotationArray[index] = t.localRotation;
|
||||
localScaleArray[index] = t.localScale;
|
||||
//localToWorldMatrix[index] = t.localToWorldMatrix; // ここは不要
|
||||
teamIdArray[index] = (short)teamId;
|
||||
transformAccessArray[index] = t;
|
||||
}
|
||||
@ -342,12 +406,16 @@ namespace MagicaCloth2
|
||||
flagArray[toIndex] = flagArray[fromIndex];
|
||||
initLocalPositionArray[toIndex] = initLocalPositionArray[fromIndex];
|
||||
initLocalRotationArray[toIndex] = initLocalRotationArray[fromIndex];
|
||||
baseLocalPositionArray[toIndex] = baseLocalPositionArray[fromIndex];
|
||||
baseLocalRotationArray[toIndex] = baseLocalRotationArray[fromIndex];
|
||||
positionArray[toIndex] = positionArray[fromIndex];
|
||||
rotationArray[toIndex] = rotationArray[fromIndex];
|
||||
inverseRotationArray[toIndex] = inverseRotationArray[fromIndex];
|
||||
//inverseRotationArray[toIndex] = inverseRotationArray[fromIndex];
|
||||
scaleArray[toIndex] = scaleArray[fromIndex];
|
||||
localPositionArray[toIndex] = localPositionArray[fromIndex];
|
||||
localRotationArray[toIndex] = localRotationArray[fromIndex];
|
||||
localScaleArray[toIndex] = localScaleArray[fromIndex];
|
||||
//localToWorldMatrix[toIndex] = localToWorldMatrix[fromIndex]; // ここは不要
|
||||
transformAccessArray[toIndex] = transformAccessArray[fromIndex];
|
||||
teamIdArray[toIndex] = teamIdArray[fromIndex];
|
||||
}
|
||||
@ -366,12 +434,16 @@ namespace MagicaCloth2
|
||||
flagArray.RemoveAndFill(c);
|
||||
initLocalPositionArray.Remove(c);
|
||||
initLocalRotationArray.Remove(c);
|
||||
baseLocalPositionArray.Remove(c);
|
||||
baseLocalRotationArray.Remove(c);
|
||||
positionArray.Remove(c);
|
||||
rotationArray.Remove(c);
|
||||
inverseRotationArray.Remove(c);
|
||||
//inverseRotationArray.Remove(c);
|
||||
scaleArray.Remove(c);
|
||||
localPositionArray.Remove(c);
|
||||
localRotationArray.Remove(c);
|
||||
localScaleArray.Remove(c);
|
||||
localToWorldMatrixArray.Remove(c);
|
||||
teamIdArray.RemoveAndFill(c, 0);
|
||||
|
||||
// トランスフォーム削除
|
||||
@ -454,12 +526,16 @@ namespace MagicaCloth2
|
||||
var nc = flagArray.Expand(c, newLength);
|
||||
initLocalPositionArray.Expand(c, newLength);
|
||||
initLocalRotationArray.Expand(c, newLength);
|
||||
baseLocalPositionArray.Expand(c, newLength);
|
||||
baseLocalRotationArray.Expand(c, newLength);
|
||||
positionArray.Expand(c, newLength);
|
||||
rotationArray.Expand(c, newLength);
|
||||
inverseRotationArray.Expand(c, newLength);
|
||||
//inverseRotationArray.Expand(c, newLength);
|
||||
scaleArray.Expand(c, newLength);
|
||||
localPositionArray.Expand(c, newLength);
|
||||
localRotationArray.Expand(c, newLength);
|
||||
localScaleArray.Expand(c, newLength);
|
||||
localToWorldMatrixArray.Expand(c, newLength);
|
||||
|
||||
// チームID
|
||||
teamIdArray.Expand(c, newLength);
|
||||
@ -467,8 +543,11 @@ namespace MagicaCloth2
|
||||
// トランスフォームアクセス配列の拡張
|
||||
if (c.startIndex != nc.startIndex)
|
||||
{
|
||||
// 旧領域の先頭Transform
|
||||
Transform frontT = transformAccessArray[c.startIndex];
|
||||
|
||||
while (transformAccessArray.length < (nc.startIndex + nc.dataLength))
|
||||
transformAccessArray.Add(null);
|
||||
transformAccessArray.Add(frontT);
|
||||
|
||||
for (int i = 0; i < c.dataLength; i++)
|
||||
{
|
||||
@ -490,11 +569,14 @@ namespace MagicaCloth2
|
||||
/// <returns></returns>
|
||||
public JobHandle RestoreTransform(JobHandle jobHandle)
|
||||
{
|
||||
existFixedTeam.Value = false;
|
||||
if (Count > 0)
|
||||
{
|
||||
//Debug.Log("RestoreTransform");
|
||||
var job = new RestoreTransformJob()
|
||||
{
|
||||
existFixedTeam = existFixedTeam,
|
||||
|
||||
flagList = flagArray.GetNativeArray(),
|
||||
localPositionArray = initLocalPositionArray.GetNativeArray(),
|
||||
localRotationArray = initLocalRotationArray.GetNativeArray(),
|
||||
@ -511,6 +593,9 @@ namespace MagicaCloth2
|
||||
[BurstCompile]
|
||||
struct RestoreTransformJob : IJobParallelForTransform
|
||||
{
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeReference<bool> existFixedTeam;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ExBitFlag8> flagList;
|
||||
|
||||
@ -531,19 +616,102 @@ namespace MagicaCloth2
|
||||
if (transform.isValid == false)
|
||||
return;
|
||||
var flag = flagList[index];
|
||||
if (flag.IsSet(Flag_Enable) == false)
|
||||
return;
|
||||
if (flag.IsSet(Flag_Restore) == false)
|
||||
return;
|
||||
|
||||
// Keepカリング時はスキップする
|
||||
int teamId = teamIdArray[index];
|
||||
var tdata = teamDataArray[teamId];
|
||||
if (tdata.IsCullingInvisible && tdata.IsCullingKeep)
|
||||
|
||||
// 一度のみ復元フラグが立っている場合は実行する
|
||||
if (flag.IsSet(Flag_Enable) == false && tdata.flag.IsSet(TeamManager.Flag_RestoreTransformOnlyOnec) == false)
|
||||
return;
|
||||
|
||||
// Keepカリング時はスキップする
|
||||
if ((tdata.IsCameraCullingInvisible && tdata.IsCameraCullingKeep) || tdata.IsDistanceCullingInvisible)
|
||||
return;
|
||||
|
||||
transform.localPosition = localPositionArray[index];
|
||||
transform.localRotation = localRotationArray[index];
|
||||
|
||||
// 物理更新チームの存在
|
||||
if (tdata.IsFixedUpdate)
|
||||
existFixedTeam.Value = true;
|
||||
|
||||
//Debug.Log($"RestoreTransform [{index}] lpos:{localPositionArray[index]}, lrot:{localRotationArray[index]}");
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// UnityPhysicsチームかつFixedUpdateが実行されなかったフレームは退避させておいたベース姿勢で再度復元させる
|
||||
/// </summary>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
public JobHandle RestoreBaseTransform(JobHandle jobHandle)
|
||||
{
|
||||
if (Count > 0)
|
||||
{
|
||||
//Debug.Log("RestoreTransform");
|
||||
var job = new RestoreBaseTransformJob()
|
||||
{
|
||||
flagList = flagArray.GetNativeArray(),
|
||||
baseLocalPositionArray = baseLocalPositionArray.GetNativeArray(),
|
||||
baseLocalRotationArray = baseLocalRotationArray.GetNativeArray(),
|
||||
teamIdArray = teamIdArray.GetNativeArray(),
|
||||
|
||||
teamDataArray = MagicaManager.Team.teamDataArray.GetNativeArray(),
|
||||
};
|
||||
jobHandle = job.Schedule(transformAccessArray, jobHandle);
|
||||
}
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct RestoreBaseTransformJob : IJobParallelForTransform
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ExBitFlag8> flagList;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> baseLocalPositionArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<quaternion> baseLocalRotationArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<short> teamIdArray;
|
||||
|
||||
// team
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TeamManager.TeamData> teamDataArray;
|
||||
|
||||
|
||||
public void Execute(int index, TransformAccess transform)
|
||||
{
|
||||
if (transform.isValid == false)
|
||||
return;
|
||||
var flag = flagList[index];
|
||||
if (flag.IsSet(Flag_Restore) == false)
|
||||
return;
|
||||
|
||||
int teamId = teamIdArray[index];
|
||||
var tdata = teamDataArray[teamId];
|
||||
|
||||
// Fixed更新チームのみ
|
||||
if (tdata.IsFixedUpdate == false)
|
||||
return;
|
||||
|
||||
// 一度のみ復元フラグが立っている場合は実行する
|
||||
if (flag.IsSet(Flag_Enable) == false && tdata.flag.IsSet(TeamManager.Flag_RestoreTransformOnlyOnec) == false)
|
||||
return;
|
||||
|
||||
// Keepカリング時はスキップする
|
||||
if ((tdata.IsCameraCullingInvisible && tdata.IsCameraCullingKeep) || tdata.IsDistanceCullingInvisible)
|
||||
return;
|
||||
|
||||
transform.localPosition = baseLocalPositionArray[index];
|
||||
transform.localRotation = baseLocalRotationArray[index];
|
||||
|
||||
//Debug.Log($"RestoreTransform [{index}] lpos:{baseLocalPositionArray[index]}, lrot:{baseLocalRotationArray[index].value}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -553,21 +721,25 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
public JobHandle ReadTransform(JobHandle jobHandle)
|
||||
public JobHandle ReadTransformSchedule(JobHandle jobHandle)
|
||||
{
|
||||
if (Count > 0)
|
||||
{
|
||||
// todo:未来予測などがあると色々複雑化するところ
|
||||
|
||||
var job = new ReadTransformJob()
|
||||
{
|
||||
fixedUpdateCount = MagicaManager.Time.FixedUpdateCount,
|
||||
|
||||
flagList = flagArray.GetNativeArray(),
|
||||
positionArray = positionArray.GetNativeArray(),
|
||||
rotationArray = rotationArray.GetNativeArray(),
|
||||
scaleList = scaleArray.GetNativeArray(),
|
||||
localPositionArray = localPositionArray.GetNativeArray(),
|
||||
localRotationArray = localRotationArray.GetNativeArray(),
|
||||
inverseRotationArray = inverseRotationArray.GetNativeArray(),
|
||||
localScaleArray = localScaleArray.GetNativeArray(),
|
||||
//inverseRotationArray = inverseRotationArray.GetNativeArray(),
|
||||
localToWorldMatrixArray = localToWorldMatrixArray.GetNativeArray(),
|
||||
baseLocalPositionArray = baseLocalPositionArray.GetNativeArray(),
|
||||
baseLocalRotationArray = baseLocalRotationArray.GetNativeArray(),
|
||||
|
||||
teamIdArray = teamIdArray.GetNativeArray(),
|
||||
|
||||
@ -582,6 +754,8 @@ namespace MagicaCloth2
|
||||
[BurstCompile]
|
||||
struct ReadTransformJob : IJobParallelForTransform
|
||||
{
|
||||
public int fixedUpdateCount;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ExBitFlag8> flagList;
|
||||
|
||||
@ -596,7 +770,15 @@ namespace MagicaCloth2
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<quaternion> localRotationArray;
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<quaternion> inverseRotationArray;
|
||||
public NativeArray<float3> localScaleArray;
|
||||
//[Unity.Collections.WriteOnly]
|
||||
//public NativeArray<quaternion> inverseRotationArray;
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float4x4> localToWorldMatrixArray;
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> baseLocalPositionArray;
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<quaternion> baseLocalRotationArray;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<short> teamIdArray;
|
||||
@ -615,7 +797,7 @@ namespace MagicaCloth2
|
||||
if (flag.IsSet(Flag_Read) == false)
|
||||
return;
|
||||
|
||||
// カリング時は書き込まない
|
||||
// カリング時は読み込まない
|
||||
int teamId = teamIdArray[index];
|
||||
var tdata = teamDataArray[teamId];
|
||||
if (tdata.IsCullingInvisible)
|
||||
@ -629,6 +811,7 @@ namespace MagicaCloth2
|
||||
rotationArray[index] = rot;
|
||||
localPositionArray[index] = transform.localPosition;
|
||||
localRotationArray[index] = transform.localRotation;
|
||||
localScaleArray[index] = transform.localScale;
|
||||
|
||||
// マトリックスから正確なスケール値を算出する(これはTransform.lossyScaleと等価)
|
||||
var irot = math.inverse(rot);
|
||||
@ -636,8 +819,24 @@ namespace MagicaCloth2
|
||||
var scl = new float3(m2.c0.x, m2.c1.y, m2.c2.z);
|
||||
scaleList[index] = scl;
|
||||
|
||||
//Debug.Log($"ReadTransform [{index}] pos:{pos}, rot:{rot}, scl:{scl}");
|
||||
//Debug.Log($"LtoW:\n{LtoW}");
|
||||
|
||||
// ワールド->ローカル変換用の逆クォータニオン
|
||||
inverseRotationArray[index] = math.inverse(rot);
|
||||
//inverseRotationArray[index] = math.inverse(rot);
|
||||
|
||||
// ワールド変換マトリックス
|
||||
localToWorldMatrixArray[index] = LtoW;
|
||||
|
||||
// 今回の姿勢を基本姿勢として退避させる
|
||||
// Fixed更新チームかつFixedUpdateが実行されている場合、そもそもFixed更新出ない場合は毎回
|
||||
if ((tdata.IsFixedUpdate && fixedUpdateCount > 0) || tdata.IsFixedUpdate == false)
|
||||
{
|
||||
baseLocalPositionArray[index] = transform.localPosition;
|
||||
baseLocalRotationArray[index] = transform.localRotation;
|
||||
}
|
||||
|
||||
//Debug.Log($"ReadTransform [{index}] pos:{pos}, rot:{rot}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,7 +847,7 @@ namespace MagicaCloth2
|
||||
/// <param name="count"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
public JobHandle WriteTransform(JobHandle jobHandle)
|
||||
public JobHandle WriteTransformSchedule(JobHandle jobHandle)
|
||||
{
|
||||
var job = new WriteTransformJob()
|
||||
{
|
||||
@ -700,6 +899,7 @@ namespace MagicaCloth2
|
||||
// カリング時は書き込まない
|
||||
int teamId = teamIdArray[index];
|
||||
var tdata = teamDataArray[teamId];
|
||||
//if (tdata.IsCameraCullingInvisible)
|
||||
if (tdata.IsCullingInvisible)
|
||||
return;
|
||||
|
||||
@ -711,20 +911,101 @@ namespace MagicaCloth2
|
||||
{
|
||||
// ワールド回転
|
||||
transform.rotation = worldRotations[index];
|
||||
//Debug.Log($"WriteTransform [{index}] (World!) rot:{worldRotations[index]}");
|
||||
|
||||
// BoneSpringのみワールド座標を書き込む
|
||||
if (tdata.IsSpring)
|
||||
{
|
||||
transform.position = worldPositions[index];
|
||||
}
|
||||
}
|
||||
else if (flag.IsSet(Flag_LocalPosRotWrite))
|
||||
{
|
||||
// ローカル座標・回転を書き込む
|
||||
transform.localPosition = localPositions[index];
|
||||
transform.localRotation = localRotations[index];
|
||||
|
||||
//Debug.Log($"WriteTransform [{index}] (local!) lpos:{localPositions[index]}, lrot:{localRotations[index]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// コンポーネント用トランスフォームの登録
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
internal int AddComponentTransform(Transform t)
|
||||
{
|
||||
if (isValid == false)
|
||||
return -1;
|
||||
Debug.Assert(t);
|
||||
|
||||
int index = componentPositionArray.Add(float3.zero).startIndex;
|
||||
|
||||
// トランスフォーム
|
||||
int nowcnt = componentTransformAccessArray.length;
|
||||
if (index < nowcnt)
|
||||
componentTransformAccessArray[index] = t;
|
||||
else
|
||||
componentTransformAccessArray.Add(t);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// コンポーネント用トランスフォームの削除
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
internal void RemoveComponentTransform(int index)
|
||||
{
|
||||
if (isValid == false)
|
||||
return;
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
componentPositionArray.Remove(index);
|
||||
|
||||
// トランスフォーム削除
|
||||
componentTransformAccessArray[index] = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// トランスフォームを読み込むジョブを発行する
|
||||
/// </summary>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
internal JobHandle ReadComponentTransform(JobHandle jobHandle)
|
||||
{
|
||||
if (componentPositionArray.Count > 0)
|
||||
{
|
||||
var job = new ReadComponentTransformJob()
|
||||
{
|
||||
positionArray = componentPositionArray.GetNativeArray(),
|
||||
};
|
||||
jobHandle = job.ScheduleReadOnly(componentTransformAccessArray, 16, jobHandle);
|
||||
}
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct ReadComponentTransformJob : IJobParallelForTransform
|
||||
{
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> positionArray;
|
||||
|
||||
public void Execute(int index, TransformAccess transform)
|
||||
{
|
||||
if (transform.isValid == false)
|
||||
return;
|
||||
|
||||
positionArray[index] = transform.position;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================================================
|
||||
public void InformationLog(StringBuilder allsb)
|
||||
{
|
||||
@ -741,12 +1022,16 @@ namespace MagicaCloth2
|
||||
sb.AppendLine($" -flagArray:{flagArray.ToSummary()}");
|
||||
sb.AppendLine($" -initLocalPositionArray:{initLocalPositionArray.ToSummary()}");
|
||||
sb.AppendLine($" -initLocalRotationArray:{initLocalRotationArray.ToSummary()}");
|
||||
sb.AppendLine($" -baseLocalPositionArray:{baseLocalPositionArray.ToSummary()}");
|
||||
sb.AppendLine($" -baseLocalRotationArray:{baseLocalRotationArray.ToSummary()}");
|
||||
sb.AppendLine($" -positionArray:{positionArray.ToSummary()}");
|
||||
sb.AppendLine($" -rotationArray:{rotationArray.ToSummary()}");
|
||||
sb.AppendLine($" -inverseRotationArray:{inverseRotationArray.ToSummary()}");
|
||||
//sb.AppendLine($" -inverseRotationArray:{inverseRotationArray.ToSummary()}");
|
||||
sb.AppendLine($" -scaleArray:{scaleArray.ToSummary()}");
|
||||
sb.AppendLine($" -localPositionArray:{localPositionArray.ToSummary()}");
|
||||
sb.AppendLine($" -localRotationArray:{localRotationArray.ToSummary()}");
|
||||
sb.AppendLine($" -localScaleArray:{localScaleArray.ToSummary()}");
|
||||
sb.AppendLine($" -localToWorldMatirxArray:{localToWorldMatrixArray.ToSummary()}");
|
||||
sb.AppendLine($" -teamIdArray:{teamIdArray.ToSummary()}");
|
||||
|
||||
if (transformAccessArray.isCreated)
|
||||
|
||||
@ -22,12 +22,15 @@ namespace MagicaCloth2
|
||||
public Matrix4x4 worldToLocalMatrix;
|
||||
public int pid;
|
||||
|
||||
public TransformRecord(Transform t)
|
||||
public TransformRecord(Transform t, bool read)
|
||||
{
|
||||
if (t)
|
||||
{
|
||||
transform = t;
|
||||
id = t.GetInstanceID();
|
||||
|
||||
if (read)
|
||||
{
|
||||
localPosition = t.localPosition;
|
||||
localRotation = t.localRotation;
|
||||
position = t.position;
|
||||
@ -35,6 +38,7 @@ namespace MagicaCloth2
|
||||
scale = t.lossyScale;
|
||||
localToWorldMatrix = t.localToWorldMatrix;
|
||||
worldToLocalMatrix = t.worldToLocalMatrix;
|
||||
}
|
||||
|
||||
if (t.parent)
|
||||
pid = t.parent.GetInstanceID();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,8 @@ namespace MagicaCloth2
|
||||
|
||||
//=========================================================================================
|
||||
GridMap<int> gridMap;
|
||||
NativeParallelHashSet<int2> joinPairSet;
|
||||
//NativeParallelHashSet<int2> joinPairSet;
|
||||
NativeParallelMultiHashMap<ushort, ushort> joinPairMap;
|
||||
NativeReference<int> resultRef;
|
||||
|
||||
//=========================================================================================
|
||||
@ -48,8 +49,10 @@ namespace MagicaCloth2
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (joinPairSet.IsCreated)
|
||||
joinPairSet.Dispose();
|
||||
//if (joinPairSet.IsCreated)
|
||||
// joinPairSet.Dispose();
|
||||
if (joinPairMap.IsCreated)
|
||||
joinPairMap.Dispose();
|
||||
if (resultRef.IsCreated)
|
||||
resultRef.Dispose();
|
||||
gridMap?.Dispose();
|
||||
@ -77,7 +80,8 @@ namespace MagicaCloth2
|
||||
|
||||
// 頂点ごとの接続マップ
|
||||
// インデックスが若い方が記録する
|
||||
joinPairSet = new NativeParallelHashSet<int2>(vmesh.VertexCount / 4, Allocator.Persistent);
|
||||
//joinPairSet = new NativeParallelHashSet<int2>(vmesh.VertexCount / 4, Allocator.Persistent);
|
||||
joinPairMap = new NativeParallelMultiHashMap<ushort, ushort>(vmesh.VertexCount, Allocator.Persistent);
|
||||
resultRef = new NativeReference<int>(Allocator.Persistent);
|
||||
|
||||
// ポイントをグリッドに登録
|
||||
@ -100,14 +104,18 @@ namespace MagicaCloth2
|
||||
localPositions = vmesh.localPositions.GetNativeArray(),
|
||||
joinIndices = workData.vertexJoinIndices,
|
||||
gridMap = gridMap.GetMultiHashMap(),
|
||||
joinPairSet = joinPairSet,
|
||||
//joinPairSet = joinPairSet,
|
||||
joinPairMap = joinPairMap,
|
||||
};
|
||||
searchJoinJob.Run();
|
||||
|
||||
// 結合する
|
||||
#if false
|
||||
var joinJob = new JoinJob()
|
||||
{
|
||||
joinPairSet = joinPairSet,
|
||||
vertexCount = vmesh.VertexCount,
|
||||
//joinPairSet = joinPairSet,
|
||||
joinPairMap = joinPairMap,
|
||||
joinIndices = workData.vertexJoinIndices,
|
||||
vertexToVertexMap = workData.vertexToVertexMap,
|
||||
boneWeights = vmesh.boneWeights.GetNativeArray(),
|
||||
@ -115,6 +123,25 @@ namespace MagicaCloth2
|
||||
result = resultRef,
|
||||
};
|
||||
joinJob.Run();
|
||||
#endif
|
||||
#if true
|
||||
// 高速化および詳細メッシュがある場合に1つの頂点に大量に結合しオーバーフローが発生する問題を回避したもの
|
||||
// 以前はA->B->C結合時にA->C間が接続距離以上でもA->Cが結合されてしまったが、この改良版ではそれがおこならない
|
||||
// そのため以前とは結果がことなることに注意!
|
||||
using var tempList = new NativeList<ushort>(2048, Allocator.Persistent);
|
||||
var joinJob2 = new JoinJob2()
|
||||
{
|
||||
vertexCount = vmesh.VertexCount,
|
||||
joinPairMap = joinPairMap,
|
||||
joinIndices = workData.vertexJoinIndices,
|
||||
vertexToVertexMap = workData.vertexToVertexMap,
|
||||
boneWeights = vmesh.boneWeights.GetNativeArray(),
|
||||
attributes = vmesh.attributes.GetNativeArray(),
|
||||
result = resultRef,
|
||||
tempList = tempList,
|
||||
};
|
||||
joinJob2.Run();
|
||||
#endif
|
||||
|
||||
// 頂点の接続状態を最新に更新する。すべて最新の生存ポイントを指すように変更する
|
||||
UpdateJoinAndLink();
|
||||
@ -191,7 +218,8 @@ namespace MagicaCloth2
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeParallelMultiHashMap<int3, int> gridMap;
|
||||
|
||||
public NativeParallelHashSet<int2> joinPairSet;
|
||||
//public NativeParallelHashSet<int2> joinPairSet;
|
||||
public NativeParallelMultiHashMap<ushort, ushort> joinPairMap;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
@ -222,14 +250,91 @@ namespace MagicaCloth2
|
||||
continue;
|
||||
|
||||
// 結合登録
|
||||
int2 ehash = DataUtility.PackInt2(vindex, tvindex);
|
||||
joinPairSet.Add(ehash);
|
||||
//int2 ehash = DataUtility.PackInt2(vindex, tvindex);
|
||||
//joinPairSet.Add(ehash);
|
||||
joinPairMap.Add((ushort)vindex, (ushort)tvindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct JoinJob2 : IJob
|
||||
{
|
||||
public int vertexCount;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeParallelMultiHashMap<ushort, ushort> joinPairMap;
|
||||
|
||||
public NativeArray<int> joinIndices;
|
||||
public NativeParallelMultiHashMap<ushort, ushort> vertexToVertexMap;
|
||||
public NativeArray<VirtualMeshBoneWeight> boneWeights;
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
public NativeReference<int> result;
|
||||
|
||||
public NativeList<ushort> tempList;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
for (ushort vindexLive = 0; vindexLive < vertexCount; vindexLive++)
|
||||
{
|
||||
// すでに結合済みならスキップ
|
||||
if (joinIndices[vindexLive] >= 0)
|
||||
continue;
|
||||
|
||||
// 対象ループ
|
||||
foreach (ushort vindexDead in joinPairMap.GetValuesForKey(vindexLive))
|
||||
{
|
||||
// 対象がすでに結合ずみならスキップ
|
||||
if (joinIndices[vindexDead] >= 0)
|
||||
continue;
|
||||
|
||||
// 結合(vertexDead -> vertexLive)
|
||||
joinIndices[vindexDead] = vindexLive;
|
||||
cnt++;
|
||||
|
||||
vertexToVertexMap.MC2RemoveValue(vindexLive, vindexDead);
|
||||
|
||||
tempList.Clear();
|
||||
foreach (ushort i in vertexToVertexMap.GetValuesForKey(vindexDead))
|
||||
{
|
||||
tempList.Add(i);
|
||||
}
|
||||
foreach (ushort i in tempList)
|
||||
{
|
||||
if (joinIndices[i] >= 0)
|
||||
continue;
|
||||
if (i == vindexLive || i == vindexDead)
|
||||
continue;
|
||||
|
||||
vertexToVertexMap.MC2RemoveValue(i, vindexDead);
|
||||
|
||||
vertexToVertexMap.MC2UniqueAdd(vindexLive, i);
|
||||
vertexToVertexMap.MC2UniqueAdd(i, vindexLive);
|
||||
|
||||
// p2にBoneWeightを結合
|
||||
var bw = boneWeights[vindexLive];
|
||||
bw.AddWeight(boneWeights[vindexDead]);
|
||||
boneWeights[vindexLive] = bw;
|
||||
|
||||
// 属性
|
||||
var attr1 = attributes[vindexDead];
|
||||
var attr2 = attributes[vindexLive];
|
||||
attributes[vindexLive] = VertexAttribute.JoinAttribute(attr1, attr2);
|
||||
attributes[vindexDead] = VertexAttribute.Invalid; // 削除頂点は無効にする
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 削除頂点数記録
|
||||
result.Value = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
#if false // old
|
||||
[BurstCompile]
|
||||
struct JoinJob : IJob
|
||||
{
|
||||
@ -245,32 +350,31 @@ namespace MagicaCloth2
|
||||
public void Execute()
|
||||
{
|
||||
var workSet = new FixedList512Bytes<ushort>();
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
foreach (var ehash in joinPairSet)
|
||||
{
|
||||
int vindex2 = ehash[0]; // 生存側
|
||||
int vindex1 = ehash[1]; // 削除側
|
||||
int vindexLive = ehash[0]; // 生存側
|
||||
int vindexDead = ehash[1]; // 削除側
|
||||
|
||||
// 両方とも生存インデックスに変換する
|
||||
while (joinIndices[vindex1] >= 0)
|
||||
while (joinIndices[vindexDead] >= 0)
|
||||
{
|
||||
vindex1 = joinIndices[vindex1];
|
||||
vindexDead = joinIndices[vindexDead];
|
||||
}
|
||||
while (joinIndices[vindex2] >= 0)
|
||||
while (joinIndices[vindexLive] >= 0)
|
||||
{
|
||||
vindex2 = joinIndices[vindex2];
|
||||
vindexLive = joinIndices[vindexLive];
|
||||
}
|
||||
if (vindex1 == vindex2)
|
||||
if (vindexDead == vindexLive)
|
||||
continue;
|
||||
|
||||
// 結合(vertex1 -> vertex2)
|
||||
joinIndices[vindex1] = vindex2;
|
||||
joinIndices[vindexDead] = vindexLive;
|
||||
cnt++;
|
||||
|
||||
// 接続数を結合する(重複は弾かれる)
|
||||
workSet.Clear();
|
||||
foreach (ushort i in vertexToVertexMap.GetValuesForKey((ushort)vindex1))
|
||||
foreach (ushort i in vertexToVertexMap.GetValuesForKey((ushort)vindexDead))
|
||||
{
|
||||
int index = i;
|
||||
// 生存インデックス
|
||||
@ -278,10 +382,10 @@ namespace MagicaCloth2
|
||||
{
|
||||
index = joinIndices[index];
|
||||
}
|
||||
if (index != vindex1 && index != vindex2)
|
||||
workSet.Set((ushort)index);
|
||||
if (index != vindexDead && index != vindexLive)
|
||||
workSet.MC2Set((ushort)index);
|
||||
}
|
||||
foreach (ushort i in vertexToVertexMap.GetValuesForKey((ushort)vindex2))
|
||||
foreach (ushort i in vertexToVertexMap.GetValuesForKey((ushort)vindexLive))
|
||||
{
|
||||
int index = i;
|
||||
// 生存インデックス
|
||||
@ -289,32 +393,33 @@ namespace MagicaCloth2
|
||||
{
|
||||
index = joinIndices[index];
|
||||
}
|
||||
if (index != vindex1 && index != vindex2)
|
||||
workSet.Set((ushort)index);
|
||||
if (index != vindexDead && index != vindexLive)
|
||||
workSet.MC2Set((ushort)index);
|
||||
}
|
||||
vertexToVertexMap.Remove((ushort)vindex2);
|
||||
vertexToVertexMap.Remove((ushort)vindexLive);
|
||||
for (int i = 0; i < workSet.Length; i++)
|
||||
{
|
||||
vertexToVertexMap.Add((ushort)vindex2, workSet[i]);
|
||||
vertexToVertexMap.Add((ushort)vindexLive, workSet[i]);
|
||||
}
|
||||
//Debug.Assert(workSet.Length > 0);
|
||||
|
||||
// p2にBoneWeightを結合
|
||||
var bw = boneWeights[vindex2];
|
||||
bw.AddWeight(boneWeights[vindex1]);
|
||||
boneWeights[vindex2] = bw;
|
||||
var bw = boneWeights[vindexLive];
|
||||
bw.AddWeight(boneWeights[vindexDead]);
|
||||
boneWeights[vindexLive] = bw;
|
||||
|
||||
// 属性
|
||||
var attr1 = attributes[vindex1];
|
||||
var attr2 = attributes[vindex2];
|
||||
attributes[vindex2] = VertexAttribute.JoinAttribute(attr1, attr2);
|
||||
attributes[vindex1] = VertexAttribute.Invalid; // 削除頂点は無効にする
|
||||
var attr1 = attributes[vindexDead];
|
||||
var attr2 = attributes[vindexLive];
|
||||
attributes[vindexLive] = VertexAttribute.JoinAttribute(attr1, attr2);
|
||||
attributes[vindexDead] = VertexAttribute.Invalid; // 削除頂点は無効にする
|
||||
}
|
||||
|
||||
// 削除頂点数記録
|
||||
result.Value = cnt;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
@ -395,7 +500,7 @@ namespace MagicaCloth2
|
||||
if (tvindex == vindex)
|
||||
continue;
|
||||
|
||||
newLinkSet.Set((ushort)tvindex);
|
||||
newLinkSet.MC2Set((ushort)tvindex);
|
||||
}
|
||||
// 生存のみの新しいセットに入れ替え
|
||||
vertexToVertexMap.Remove((ushort)vindex);
|
||||
|
||||
@ -450,12 +450,12 @@ namespace MagicaCloth2
|
||||
foreach (ushort nindex in vertexToVertexMap.GetValuesForKey((ushort)vindex1))
|
||||
{
|
||||
if (nindex != vindex1 && nindex != vindex2)
|
||||
newLink.Set(nindex);
|
||||
newLink.MC2Set(nindex);
|
||||
}
|
||||
foreach (ushort nindex in vertexToVertexMap.GetValuesForKey((ushort)vindex2))
|
||||
{
|
||||
if (nindex != vindex1 && nindex != vindex2)
|
||||
newLink.Set(nindex);
|
||||
newLink.MC2Set(nindex);
|
||||
}
|
||||
vertexToVertexMap.Remove((ushort)vindex2);
|
||||
for (int i = 0; i < newLink.Length; i++)
|
||||
@ -558,7 +558,7 @@ namespace MagicaCloth2
|
||||
if (tvindex == vindex)
|
||||
continue;
|
||||
|
||||
newLinkSet.Set((ushort)tvindex);
|
||||
newLinkSet.MC2Set((ushort)tvindex);
|
||||
}
|
||||
// 生存のみの新しいセットに入れ替え
|
||||
vertexToVertexMap.Remove((ushort)vindex);
|
||||
@ -640,12 +640,12 @@ namespace MagicaCloth2
|
||||
foreach (ushort index in vertexToVertexMap.GetValuesForKey((ushort)vindex))
|
||||
{
|
||||
if (index != vindex && index != tvindex)
|
||||
joinVlink.Set(index);
|
||||
joinVlink.MC2Set(index);
|
||||
}
|
||||
foreach (ushort index in vertexToVertexMap.GetValuesForKey((ushort)tvindex))
|
||||
{
|
||||
if (index != vindex && index != tvindex)
|
||||
joinVlink.Set(index);
|
||||
joinVlink.MC2Set(index);
|
||||
}
|
||||
|
||||
// 点になるのはNG
|
||||
@ -662,20 +662,20 @@ namespace MagicaCloth2
|
||||
// 結合後のトライアングルの外周をひと筆書きし、すべての外周頂点が使われているならOK!
|
||||
// 外周頂点が一筆書きできない場合は2つ以上のグループに分かれいる(X型になる)
|
||||
var stack = new FixedList512Bytes<ushort>();
|
||||
stack.Push(joinVlink[0]);
|
||||
stack.MC2Push(joinVlink[0]);
|
||||
while (stack.Length > 0)
|
||||
{
|
||||
ushort index = stack.Pop();
|
||||
ushort index = stack.MC2Pop();
|
||||
if (joinVlink.Contains(index) == false)
|
||||
continue;
|
||||
joinVlink.RemoveItemAtSwapBack(index);
|
||||
joinVlink.MC2RemoveItemAtSwapBack(index);
|
||||
|
||||
foreach (ushort nindex in vertexToVertexMap.GetValuesForKey((ushort)index))
|
||||
{
|
||||
if (joinVlink.Contains(nindex))
|
||||
{
|
||||
// next
|
||||
stack.Push(nindex);
|
||||
stack.MC2Push(nindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -716,13 +716,13 @@ namespace MagicaCloth2
|
||||
{
|
||||
int index = vlist[i];
|
||||
if (index != vindex && index != tvindex)
|
||||
joinVlink.SetLimit((ushort)index);
|
||||
joinVlink.MC2SetLimit((ushort)index);
|
||||
}
|
||||
for (int i = 0; i < tvlist.Length; i++)
|
||||
{
|
||||
int index = tvlist[i];
|
||||
if (index != vindex && index != tvindex)
|
||||
joinVlink.SetLimit((ushort)index);
|
||||
joinVlink.MC2SetLimit((ushort)index);
|
||||
}
|
||||
|
||||
// 点になるのはNG
|
||||
@ -739,13 +739,13 @@ namespace MagicaCloth2
|
||||
// 結合後のトライアングルの外周をひと筆書きし、すべての外周頂点が使われているならOK!
|
||||
// 外周頂点が一筆書きできない場合は2つ以上のグループに分かれいる(X型になる)
|
||||
var stack = new FixedList512Bytes<ushort>();
|
||||
stack.Push(joinVlink[0]);
|
||||
stack.MC2Push(joinVlink[0]);
|
||||
while (stack.Length > 0)
|
||||
{
|
||||
ushort index = stack.Pop();
|
||||
ushort index = stack.MC2Pop();
|
||||
if (joinVlink.Contains(index) == false)
|
||||
continue;
|
||||
joinVlink.RemoveItemAtSwapBack(index);
|
||||
joinVlink.MC2RemoveItemAtSwapBack(index);
|
||||
|
||||
var link = vertexToVertexArray[index];
|
||||
for (int i = 0; i < link.Length; i++)
|
||||
@ -754,7 +754,7 @@ namespace MagicaCloth2
|
||||
if (joinVlink.Contains(nindex))
|
||||
{
|
||||
// next
|
||||
stack.Push(nindex);
|
||||
stack.MC2Push(nindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,9 +35,7 @@ namespace MagicaCloth2
|
||||
public DebugAxis animatedAxis = DebugAxis.None;
|
||||
public bool animatedShape = false;
|
||||
public bool inertiaCenter = true;
|
||||
//public bool basicPosition = false;
|
||||
//public DebugAxis basicAxis = DebugAxis.None;
|
||||
//public bool basicShape = false;
|
||||
public bool customSkinningBone = true;
|
||||
|
||||
//=====================================================================
|
||||
// ■デバッグ用
|
||||
@ -60,6 +58,7 @@ namespace MagicaCloth2
|
||||
//public bool horizontalDistanceConstraint = false;
|
||||
public bool collisionNormal = false;
|
||||
public bool cellCube = false;
|
||||
public bool baseLinePos = false;
|
||||
public int vertexMinIndex = 0;
|
||||
public int vertexMaxIndex = 100000;
|
||||
public int triangleMinIndex = 0;
|
||||
@ -103,16 +102,11 @@ namespace MagicaCloth2
|
||||
#endif
|
||||
}
|
||||
|
||||
public float GetLineSize()
|
||||
{
|
||||
//return 0.03f; // 固定
|
||||
return 0.05f; // 固定
|
||||
}
|
||||
public float GetLineSize() => 0.05f; // 固定
|
||||
|
||||
public float GetInertiaCenterRadius()
|
||||
{
|
||||
return 0.01f; // 固定
|
||||
}
|
||||
public float GetInertiaCenterRadius() => 0.01f; // 固定
|
||||
|
||||
public float GetCustomSkinningRadius() => 0.02f; // 固定
|
||||
|
||||
public bool IsReferOldPos()
|
||||
{
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// Magica Cloth 2.
|
||||
// Copyright (c) 2023 MagicaSoft.
|
||||
// https://magicasoft.jp
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
@ -428,7 +429,7 @@ namespace MagicaCloth2
|
||||
{
|
||||
float time = i / 15.0f;
|
||||
float val = curve.Evaluate(time);
|
||||
m.SetValue(i, val);
|
||||
m.MC2SetValue(i, val);
|
||||
}
|
||||
|
||||
return m;
|
||||
@ -447,32 +448,81 @@ namespace MagicaCloth2
|
||||
int index = (int)(math.saturate(time) * 15);
|
||||
time -= index * interval;
|
||||
float t = time / interval;
|
||||
return math.lerp(curve.GetValue(index), curve.GetValue(index + 1), t);
|
||||
return math.lerp(curve.MC2GetValue(index), curve.MC2GetValue(index + 1), t);
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 8bitフラグからコライダータイプを取得する
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ColliderManager.ColliderType GetColliderType(in ExBitFlag8 flag)
|
||||
{
|
||||
return (ColliderManager.ColliderType)(flag.Value & 0x0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 8bitフラグにコライダータイプを設定する
|
||||
/// 16bitフラグにコライダータイプを設定する
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
/// <param name="ctype"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ExBitFlag8 SetColliderType(ExBitFlag8 flag, ColliderManager.ColliderType ctype)
|
||||
public static ExBitFlag16 SetColliderType(ExBitFlag16 flag, ColliderManager.ColliderType ctype)
|
||||
{
|
||||
flag.Value = (byte)(flag.Value & 0xf0 | (byte)ctype);
|
||||
flag.Value = (ushort)((flag.Value & 0xfff0) | (ushort)ctype);
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 16bitフラグからコライダータイプを取得する
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ColliderManager.ColliderType GetColliderType(in ExBitFlag16 flag)
|
||||
{
|
||||
return (ColliderManager.ColliderType)(flag.Value & 0x000f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 16bitフラグにシンメトリータイプを設定する
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
/// <param name="stype"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ExBitFlag16 SetSymmetryType(ExBitFlag16 flag, ColliderManager.SymmetryType stype)
|
||||
{
|
||||
flag.Value = (ushort)((flag.Value & 0xff0f) | (((ushort)stype) << 4));
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 16bitフラグからシンメトリータイプを取得する
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ColliderManager.SymmetryType GetSymmetryType(in ExBitFlag16 flag)
|
||||
{
|
||||
return (ColliderManager.SymmetryType)((flag.Value & 0x00f0) >> 4);
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 配列をDeepコピーする
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="src"></param>
|
||||
/// <param name="dst"></param>
|
||||
public static void ArrayCopy<T>(T[] src, ref T[] dst)
|
||||
{
|
||||
if (src == null)
|
||||
{
|
||||
dst = null;
|
||||
return;
|
||||
}
|
||||
if (src.Length == 0)
|
||||
{
|
||||
dst = new T[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst = new T[src.Length];
|
||||
Array.Copy(src, dst, src.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ namespace MagicaCloth2
|
||||
/// GridSize>0である必要あり!
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class GridMap<T> : IDisposable where T : unmanaged, IEquatable<T>
|
||||
public class GridMap<T> : IDisposable where T : unmanaged // , IEquatable<T>
|
||||
{
|
||||
private NativeParallelMultiHashMap<int3, T> gridMap;
|
||||
|
||||
|
||||
@ -3,10 +3,6 @@
|
||||
// https://magicasoft.jp
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace MagicaCloth2
|
||||
@ -19,13 +15,12 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// 固定小数点への変換倍率
|
||||
/// </summary>
|
||||
const int ToFixed = 100000;
|
||||
internal const int ToFixed = 1000000;
|
||||
|
||||
/// <summary>
|
||||
/// 少数への復元倍率
|
||||
/// </summary>
|
||||
const float ToFloat = 0.00001f;
|
||||
|
||||
internal const float ToFloat = 0.000001f;
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
@ -65,17 +60,6 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 集計バッファのカウンタのみインクリメントする
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="cntPt"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
unsafe internal static void Increment(int index, int* cntPt)
|
||||
{
|
||||
Interlocked.Increment(ref cntPt[index]);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
unsafe internal static void Max(int index, float value, int* pt)
|
||||
{
|
||||
@ -91,16 +75,16 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static float3 ReadAverageFloat3(int index, in NativeArray<int> countArray, in NativeArray<int> sumArray)
|
||||
unsafe internal static float3 ReadAverageFloat3(int index, int* cntPt, int* sumPt)
|
||||
{
|
||||
int count = countArray[index];
|
||||
int count = cntPt[index];
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
int dataIndex = index * 3;
|
||||
|
||||
// 集計
|
||||
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
|
||||
float3 add = new float3(sumPt[dataIndex], sumPt[dataIndex + 1], sumPt[dataIndex + 2]);
|
||||
add /= count;
|
||||
|
||||
// データは固定小数点なので戻す
|
||||
@ -110,10 +94,10 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static float3 ReadFloat3(int index, in NativeArray<int> bufferArray)
|
||||
unsafe internal static float3 ReadFloat3(int index, int* vecPt)
|
||||
{
|
||||
int dataIndex = index * 3;
|
||||
float3 v = new float3(bufferArray[dataIndex], bufferArray[dataIndex + 1], bufferArray[dataIndex + 2]);
|
||||
float3 v = new float3(vecPt[dataIndex], vecPt[dataIndex + 1], vecPt[dataIndex + 2]);
|
||||
|
||||
// データは固定小数点なので戻す
|
||||
v *= ToFloat;
|
||||
@ -122,351 +106,9 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static float ReadFloat(int index, in NativeArray<int> bufferArray)
|
||||
unsafe internal static float ReadFloat(int index, int* floatPt)
|
||||
{
|
||||
return bufferArray[index] * ToFloat;
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// 指定アドレスにfloat値を加算する
|
||||
/// </summary>
|
||||
/// <param name="pt"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="value"></param>
|
||||
unsafe public static void AddFloat(int* pt, int index, float value)
|
||||
{
|
||||
float current = UnsafeUtility.ReadArrayElement<float>(pt, index);
|
||||
int currenti = math.asint(current);
|
||||
while (true)
|
||||
{
|
||||
float next = current + value;
|
||||
int nexti = math.asint(next);
|
||||
int prev = Interlocked.CompareExchange(ref pt[index], nexti, currenti);
|
||||
if (prev == currenti)
|
||||
return;
|
||||
else
|
||||
{
|
||||
currenti = prev;
|
||||
current = math.asfloat(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 加算集計バッファを平均化してnextPosに加算する
|
||||
/// </summary>
|
||||
/// <param name="particleList"></param>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
internal static JobHandle SolveAggregateBufferAndClear(in NativeList<int> particleList, float velocityAttenuation, JobHandle jobHandle)
|
||||
{
|
||||
var sm = MagicaManager.Simulation;
|
||||
|
||||
if (velocityAttenuation > 1e-06f)
|
||||
{
|
||||
// 速度影響あり
|
||||
var job = new AggregateWithVelocityJob()
|
||||
{
|
||||
jobParticleIndexList = particleList,
|
||||
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
|
||||
velocityAttenuation = velocityAttenuation,
|
||||
countArray = sm.countArray,
|
||||
sumArray = sm.sumArray,
|
||||
};
|
||||
jobHandle = job.Schedule(particleList, 16, jobHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 速度影響なし
|
||||
var job = new AggregateJob()
|
||||
{
|
||||
//velocityLimit = velocityLimit,
|
||||
jobParticleIndexList = particleList,
|
||||
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
|
||||
countArray = sm.countArray,
|
||||
sumArray = sm.sumArray,
|
||||
};
|
||||
jobHandle = job.Schedule(particleList, 16, jobHandle);
|
||||
}
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct AggregateJob : IJobParallelForDefer
|
||||
{
|
||||
// 速度制限
|
||||
//public float velocityLimit;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeList<int> jobParticleIndexList;
|
||||
|
||||
// particle
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
|
||||
// aggregate
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> countArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> sumArray;
|
||||
|
||||
// 集計パーティクルごと
|
||||
public void Execute(int index)
|
||||
{
|
||||
int pindex = jobParticleIndexList[index];
|
||||
|
||||
int count = countArray[pindex];
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
int dataIndex = pindex * 3;
|
||||
|
||||
// 集計
|
||||
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
|
||||
add /= count;
|
||||
|
||||
// データは固定小数点なので戻す
|
||||
add *= ToFloat;
|
||||
|
||||
// 速度制限
|
||||
//add = MathUtility.ClampVector(add, velocityLimit);
|
||||
|
||||
// 書き出し
|
||||
nextPosArray[pindex] = nextPosArray[pindex] + add;
|
||||
|
||||
// 集計バッファクリア
|
||||
countArray[pindex] = 0;
|
||||
sumArray[dataIndex] = 0;
|
||||
sumArray[dataIndex + 1] = 0;
|
||||
sumArray[dataIndex + 2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 速度影響あり
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
struct AggregateWithVelocityJob : IJobParallelForDefer
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeList<int> jobParticleIndexList;
|
||||
|
||||
// particle
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
|
||||
// aggregate
|
||||
public float velocityAttenuation;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> countArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> sumArray;
|
||||
|
||||
// 集計パーティクルごと
|
||||
public void Execute(int index)
|
||||
{
|
||||
int pindex = jobParticleIndexList[index];
|
||||
|
||||
int count = countArray[pindex];
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
int dataIndex = pindex * 3;
|
||||
|
||||
// 集計
|
||||
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
|
||||
add /= count;
|
||||
|
||||
// データは固定小数点なので戻す
|
||||
add *= ToFloat;
|
||||
|
||||
// 書き出し
|
||||
nextPosArray[pindex] = nextPosArray[pindex] + add;
|
||||
|
||||
// 速度影響
|
||||
velocityPosArray[pindex] = velocityPosArray[pindex] + add * velocityAttenuation;
|
||||
|
||||
// 集計バッファクリア
|
||||
countArray[pindex] = 0;
|
||||
sumArray[dataIndex] = 0;
|
||||
sumArray[dataIndex + 1] = 0;
|
||||
sumArray[dataIndex + 2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal static JobHandle SolveAggregateBufferAndClear(in ExProcessingList<int> processingList, float velocityAttenuation, JobHandle jobHandle)
|
||||
{
|
||||
return SolveAggregateBufferAndClear(processingList.Buffer, processingList.Counter, velocityAttenuation, jobHandle);
|
||||
}
|
||||
|
||||
unsafe internal static JobHandle SolveAggregateBufferAndClear(in NativeArray<int> particleArray, in NativeReference<int> counter, float velocityAttenuation, JobHandle jobHandle)
|
||||
{
|
||||
var sm = MagicaManager.Simulation;
|
||||
|
||||
if (velocityAttenuation > 1e-06f)
|
||||
{
|
||||
// 速度影響あり
|
||||
var job = new AggregateWithVelocityJob2()
|
||||
{
|
||||
particleIndexArray = particleArray,
|
||||
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
|
||||
|
||||
velocityAttenuation = velocityAttenuation,
|
||||
countArray = sm.countArray,
|
||||
sumArray = sm.sumArray,
|
||||
};
|
||||
jobHandle = job.Schedule((int*)counter.GetUnsafePtrWithoutChecks(), 16, jobHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 速度影響なし
|
||||
var job = new AggregateJob2()
|
||||
{
|
||||
//velocityLimit = velocityLimit,
|
||||
particleIndexArray = particleArray,
|
||||
|
||||
nextPosArray = sm.nextPosArray.GetNativeArray(),
|
||||
|
||||
countArray = sm.countArray,
|
||||
sumArray = sm.sumArray,
|
||||
};
|
||||
jobHandle = job.Schedule((int*)counter.GetUnsafePtrWithoutChecks(), 16, jobHandle);
|
||||
}
|
||||
|
||||
return jobHandle;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct AggregateJob2 : IJobParallelForDefer
|
||||
{
|
||||
// 速度制限
|
||||
//public float velocityLimit;
|
||||
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> particleIndexArray;
|
||||
|
||||
// particle
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
|
||||
// aggregate
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> countArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> sumArray;
|
||||
|
||||
// 集計パーティクルごと
|
||||
public void Execute(int index)
|
||||
{
|
||||
int pindex = particleIndexArray[index];
|
||||
|
||||
int count = countArray[pindex];
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
int dataIndex = pindex * 3;
|
||||
|
||||
// 集計
|
||||
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
|
||||
add /= count;
|
||||
|
||||
// データは固定小数点なので戻す
|
||||
add *= ToFloat;
|
||||
|
||||
// 速度制限
|
||||
//add = MathUtility.ClampVector(add, velocityLimit);
|
||||
|
||||
// 書き出し
|
||||
nextPosArray[pindex] = nextPosArray[pindex] + add;
|
||||
|
||||
// 集計バッファクリア
|
||||
countArray[pindex] = 0;
|
||||
sumArray[dataIndex] = 0;
|
||||
sumArray[dataIndex + 1] = 0;
|
||||
sumArray[dataIndex + 2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 速度影響あり
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
struct AggregateWithVelocityJob2 : IJobParallelForDefer
|
||||
{
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> particleIndexArray;
|
||||
|
||||
// particle
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> nextPosArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float3> velocityPosArray;
|
||||
|
||||
// aggregate
|
||||
public float velocityAttenuation;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> countArray;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<int> sumArray;
|
||||
|
||||
// 集計パーティクルごと
|
||||
public void Execute(int index)
|
||||
{
|
||||
int pindex = particleIndexArray[index];
|
||||
|
||||
int count = countArray[pindex];
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
int dataIndex = pindex * 3;
|
||||
|
||||
// 集計
|
||||
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
|
||||
add /= count;
|
||||
|
||||
// データは固定小数点なので戻す
|
||||
add *= ToFloat;
|
||||
|
||||
// 書き出し
|
||||
nextPosArray[pindex] = nextPosArray[pindex] + add;
|
||||
|
||||
// 速度影響
|
||||
velocityPosArray[pindex] = velocityPosArray[pindex] + add * velocityAttenuation;
|
||||
|
||||
// 集計バッファクリア
|
||||
countArray[pindex] = 0;
|
||||
sumArray[dataIndex] = 0;
|
||||
sumArray[dataIndex + 1] = 0;
|
||||
sumArray[dataIndex + 2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 集計バッファのカウンタのみゼロクリアする
|
||||
/// </summary>
|
||||
/// <param name="jobHandle"></param>
|
||||
/// <returns></returns>
|
||||
internal static JobHandle ClearCountArray(JobHandle jobHandle)
|
||||
{
|
||||
var sm = MagicaManager.Simulation;
|
||||
|
||||
return JobUtility.Fill(sm.countArray, sm.countArray.Length, 0, jobHandle);
|
||||
return floatPt[index] * ToFloat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ namespace MagicaCloth2
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float GetValue(in this float4x4 m, int index)
|
||||
public static float MC2GetValue(in this float4x4 m, int index)
|
||||
{
|
||||
index = math.clamp(index, 0, 15);
|
||||
return m[index / 4][index % 4];
|
||||
@ -28,7 +28,7 @@ namespace MagicaCloth2
|
||||
/// <param name="index"></param>
|
||||
/// <param name="value"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SetValue(ref this float4x4 m, int index, float value)
|
||||
public static void MC2SetValue(ref this float4x4 m, int index, float value)
|
||||
{
|
||||
index = math.clamp(index, 0, 15);
|
||||
m[index / 4][index % 4] = value;
|
||||
@ -41,7 +41,7 @@ namespace MagicaCloth2
|
||||
/// <param name="time">0.0 ~ 1.0</param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float EvaluateCurveClamp01(in this float4x4 m, float time)
|
||||
public static float MC2EvaluateCurveClamp01(in this float4x4 m, float time)
|
||||
{
|
||||
return math.saturate(DataUtility.EvaluateCurve(m, time));
|
||||
}
|
||||
@ -53,7 +53,7 @@ namespace MagicaCloth2
|
||||
/// <param name="time">0.0 ~ 1.0</param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float EvaluateCurve(in this float4x4 m, float time)
|
||||
public static float MC2EvaluateCurve(in this float4x4 m, float time)
|
||||
{
|
||||
return DataUtility.EvaluateCurve(m, time);
|
||||
}
|
||||
|
||||
@ -223,6 +223,45 @@ namespace MagicaCloth2
|
||||
return quaternion.AxisAngle(math.normalize(axis), angle * t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// fromからtoへ回転させるクォータニオンを返します(単位化なし)
|
||||
/// </summary>
|
||||
/// <param name="from"></param>
|
||||
/// <param name="to"></param>
|
||||
/// <param name="t">補間率(0.0-1.0)</param>
|
||||
/// <returns></returns>
|
||||
public static quaternion FromToRotationWithoutNormalize(in float3 v1, in float3 v2, float t = 1.0f)
|
||||
{
|
||||
//float3 v1 = math.normalize(from);
|
||||
//float3 v2 = math.normalize(to);
|
||||
|
||||
float c = Clamp1(math.dot(v1, v2));
|
||||
float angle = math.acos(c);
|
||||
float3 axis = math.cross(v1, v2);
|
||||
|
||||
if (math.abs(1.0f + c) < 1e-06f)
|
||||
{
|
||||
angle = (float)math.PI;
|
||||
|
||||
if (v1.x > v1.y && v1.x > v1.z)
|
||||
{
|
||||
axis = math.cross(v1, new float3(0, 1, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
axis = math.cross(v1, new float3(1, 0, 0));
|
||||
}
|
||||
}
|
||||
else if (math.abs(1.0f - c) < 1e-06f)
|
||||
{
|
||||
//angle = 0.0f;
|
||||
//axis = new float3(1, 0, 0);
|
||||
return quaternion.identity;
|
||||
}
|
||||
|
||||
return quaternion.AxisAngle(math.normalize(axis), angle * t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// fromからtoへ回転させるクォータニオンを返します
|
||||
/// </summary>
|
||||
@ -287,13 +326,15 @@ namespace MagicaCloth2
|
||||
public static quaternion ToRotation(in float3 nor, in float3 tan)
|
||||
{
|
||||
#if MC2_DEBUG
|
||||
// 安全性確認
|
||||
float ln = math.length(nor);
|
||||
float lt = math.length(tan);
|
||||
Develop.Assert(ln > 0.0f);
|
||||
Develop.Assert(lt > 0.0f);
|
||||
Develop.Assert(ln > 0.99f && ln < 1.01f);
|
||||
Develop.Assert(lt > 0.99f && lt < 1.01f);
|
||||
float dot = math.dot(nor / ln, tan / lt);
|
||||
Develop.Assert(dot != 1.0f && dot != -1.0f);
|
||||
#endif
|
||||
// 2 つの入力ベクトルは単位長であり、同一直線上にないことが前提となります。
|
||||
return quaternion.LookRotation(tan, nor);
|
||||
}
|
||||
|
||||
@ -402,6 +443,45 @@ namespace MagicaCloth2
|
||||
axis = q.value.xyz / s;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// クォータニオンからオイラー角度を計算して返す
|
||||
/// </summary>
|
||||
/// <param name="q"></param>
|
||||
/// <returns>(Deg)角度</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float3 ToEuler(in quaternion q)
|
||||
{
|
||||
float3 angles = 0;
|
||||
|
||||
// クォータニオンの成分
|
||||
float qx = q.value.x;
|
||||
float qy = q.value.y;
|
||||
float qz = q.value.z;
|
||||
float qw = q.value.w;
|
||||
|
||||
// ピッチ (x軸回転)
|
||||
float sinX = 2f * (qw * qx - qz * qy);
|
||||
if (math.abs(sinX) >= 0.99999f) // ジンバルロックの検出
|
||||
{
|
||||
angles.x = math.sign(sinX) * 90f; // ±90度(deg)
|
||||
angles.y = math.atan2(2f * (qw * qy + qx * qz), 1f - 2f * (qx * qx + qy * qy));
|
||||
angles.y = math.degrees(angles.y);
|
||||
angles.z = 0f; // ジンバルロックでロールは不定
|
||||
}
|
||||
else
|
||||
{
|
||||
angles.x = math.asin(sinX);
|
||||
// ヨー (y軸回転)
|
||||
angles.y = math.atan2(2f * (qw * qy + qx * qz), 1f - 2f * (qx * qx + qy * qy));
|
||||
// ロール (z軸回転)
|
||||
//angles.z = math.atan2(2f * (qw * qz + qx * qy), 1f - 2f * (qy * qy + qz * qz));
|
||||
angles.z = math.atan2(2f * (qw * qz + qx * qy), 1f - 2f * (qx * qx + qz * qz)); // どうやらこれっぽい
|
||||
angles = math.degrees(angles);
|
||||
}
|
||||
|
||||
return angles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 与えられた線分abおよび点cに対して、ab上の最近接点t(0.0-1.0)を計算して返す
|
||||
/// </summary>
|
||||
@ -570,6 +650,82 @@ namespace MagicaCloth2
|
||||
return math.dot(c1 - c2, c1 - c2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2つの線分(p1-q1)(p2-q2)の最近接点(s, t)を計算する
|
||||
/// この関数ではs/tのみで接点と距離は計算しない
|
||||
/// </summary>
|
||||
/// <param name="p1">線分1の始点</param>
|
||||
/// <param name="q1">線分1の終点</param>
|
||||
/// <param name="p2">線分2の始点</param>
|
||||
/// <param name="q2">線分2の終点</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ClosestPtSegmentSegment2(in float3 p1, in float3 q1, in float3 p2, in float3 q2, out float s, out float t)
|
||||
{
|
||||
//s = 0.0f;
|
||||
//t = 0.0f;
|
||||
float3 d1 = q1 - p1; // 線分s1の方向ベクトル
|
||||
float3 d2 = q2 - p2; // 線分s2の方向ベクトル
|
||||
float3 r = p1 - p2;
|
||||
float a = math.dot(d1, d1); // 線分s1の距離の平方、常に正
|
||||
float e = math.dot(d2, d2); // 線分s2の距離の平方、常に正
|
||||
float f = math.dot(d2, r);
|
||||
// 片方あるいは両方の線分が点に縮退しているかどうかチェック
|
||||
if (a <= 1e-8f && e <= 1e-8f)
|
||||
{
|
||||
// 両方の線分が点に縮退
|
||||
s = t = 0.0f;
|
||||
}
|
||||
else if (a <= 1e-8f)
|
||||
{
|
||||
// 最初の線分が点に縮退
|
||||
s = 0.0f;
|
||||
t = math.saturate(f / e);
|
||||
}
|
||||
else
|
||||
{
|
||||
float c = math.dot(d1, r);
|
||||
if (e <= 1e-8f)
|
||||
{
|
||||
// 2番目の線分が点に縮退
|
||||
t = 0.0f;
|
||||
s = math.saturate(-c / a);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ここから一般的な縮退の場合を開始
|
||||
float b = math.dot(d1, d2);
|
||||
float denom = a * e - b * b; // 常に正
|
||||
// 線分が平行でない場合、L1上のL2に対する最近接点を計算、そして
|
||||
// 線分s1に対してクランプ。そうでない場合は任意s(ここでは0)を選択
|
||||
if (denom != 0.0f)
|
||||
{
|
||||
s = math.saturate((b * f - c * e) / denom);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = 0.0f;
|
||||
}
|
||||
// L2上のs1(s)に対する最近接点を以下を用いて計算
|
||||
// t = dot((p1 + d1 * s) - p2, d2) / dot(d2, d2) = (b * s + f) / e
|
||||
t = (b * s + f) / e;
|
||||
// tが[0,1]の中にあれば終了。
|
||||
// そうでなければtをクランプ、sをtの新しい値に対して以下を用いて再計算
|
||||
// s = dot((p2 + d2 * t) - p1, d1) / dot(d1, d1) = (t * b - c) / a
|
||||
// そしてsを[0,1]にクランプ
|
||||
if (t < 0.0f)
|
||||
{
|
||||
t = 0.0f;
|
||||
s = math.saturate(-c / a);
|
||||
}
|
||||
else if (t > 1.0f)
|
||||
{
|
||||
t = 1.0f;
|
||||
s = math.saturate((b - c) / a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 三角形(abc)から点(p)への最近接点とその重心座標uvwを返す
|
||||
/// </summary>
|
||||
@ -780,6 +936,7 @@ namespace MagicaCloth2
|
||||
return tan;
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// トライアングルの回転姿勢を返す
|
||||
/// 法線と(重心-p0)の軸からなるクォータニオン
|
||||
@ -815,6 +972,7 @@ namespace MagicaCloth2
|
||||
var tan = math.normalize(p3 - p2);
|
||||
return quaternion.LookRotation(tan, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// トライアングルペアのなす角を返す(ラジアン)
|
||||
@ -1064,30 +1222,45 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float3 TransformPoint(in float3 pos, in float4x4 localToWorldMatrix)
|
||||
public static float3 TransformPoint(in float3 pos, in float3 wpos, in quaternion wrot, in float3 wscl)
|
||||
{
|
||||
return math.transform(localToWorldMatrix, pos);
|
||||
return math.transform(Matrix4x4.TRS(wpos, wrot, wscl), pos);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float3 TransformVector(in float3 vec, in float4x4 localToWorldMatrix)
|
||||
public static float3 TransformPoint(in float3 pos, in float4x4 m)
|
||||
{
|
||||
return math.mul(localToWorldMatrix, new float4(vec, 0)).xyz;
|
||||
return math.transform(m, pos);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float3 TransformDirection(in float3 dir, in float4x4 localToWorldMatrix)
|
||||
public static float3 TransformVector(in float3 vec, in float4x4 m)
|
||||
{
|
||||
return math.mul(m, new float4(vec, 0)).xyz;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float3 TransformDirection(in float3 dir, in float4x4 m)
|
||||
{
|
||||
float len = math.length(dir);
|
||||
if (len > 0.0f)
|
||||
return math.normalize(TransformVector(dir, localToWorldMatrix)) * len;
|
||||
return math.normalize(TransformVector(dir, m)) * len;
|
||||
else
|
||||
return dir;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static quaternion TransformRotation(in quaternion rot, in float4x4 m, in float3 normalTangentFlip)
|
||||
{
|
||||
ToNormalTangent(rot, out float3 nor, out float3 tan);
|
||||
nor = math.mul(m, new float4(nor, 0)).xyz * normalTangentFlip.y;
|
||||
tan = math.mul(m, new float4(tan, 0)).xyz * normalTangentFlip.z;
|
||||
return quaternion.LookRotation(tan, nor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 距離を空間変換する
|
||||
/// 不均等スケールを考慮して各軸の平均値を返す
|
||||
/// 非一様スケールを考慮して各軸の平均値を返す
|
||||
/// </summary>
|
||||
/// <param name="dist"></param>
|
||||
/// <param name="localToWorldMatrix"></param>
|
||||
@ -1139,6 +1312,12 @@ namespace MagicaCloth2
|
||||
return math.transform(worldToLocalMatrix, pos);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float3 InverseTransformPoint(in float3 pos, in float3 wpos, in quaternion wrot, in float3 wscl)
|
||||
{
|
||||
return math.transform(math.inverse(Matrix4x4.TRS(wpos, wrot, wscl)), pos);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float3 InverseTransformVector(in float3 vec, in float4x4 worldToLocalMatrix)
|
||||
{
|
||||
@ -1364,6 +1543,7 @@ namespace MagicaCloth2
|
||||
|
||||
if (math.dot(planeDir, v) < 0.0f)
|
||||
{
|
||||
// 押し出し発生
|
||||
// 押出し座標
|
||||
outPos = pos - gv;
|
||||
|
||||
@ -1373,9 +1553,10 @@ namespace MagicaCloth2
|
||||
}
|
||||
else
|
||||
{
|
||||
// 押し出し不要。何もしない
|
||||
outPos = pos;
|
||||
|
||||
// 面までの距離を返す
|
||||
// 面までの距離を返す(+)
|
||||
return len;
|
||||
}
|
||||
}
|
||||
@ -1554,5 +1735,57 @@ namespace MagicaCloth2
|
||||
Develop.Assert(mass > 0.0f);
|
||||
return 1.0f / mass;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数をn分割して、指定インデックスの範囲を返します。
|
||||
/// 数は整数のみ。
|
||||
/// 例:100(dataLength)を5(divCount)分割した結果
|
||||
/// divIndex(0):0~20
|
||||
/// divIndex(1):20~40
|
||||
/// divIndex(2):40~60
|
||||
/// divIndex(3):60~80
|
||||
/// divIndex(4):80~100
|
||||
///
|
||||
/// ただし、数が分割数を下回る場合は範囲外のインデックスは-1となる
|
||||
/// 例:3(dataLength)を5(divCount)分割した結果
|
||||
/// divIndex(0):0~1
|
||||
/// divIndex(1):1~2
|
||||
/// divIndex(2):2~3
|
||||
/// divIndex(3):-1~-1
|
||||
/// divIndex(4):-1~-1
|
||||
/// </summary>
|
||||
/// <param name="dataLength"></param>
|
||||
/// <param name="divCount"></param>
|
||||
/// <param name="divIndex"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int2 CalcSplitRange(int dataLength, int divCount, int divIndex)
|
||||
{
|
||||
if (dataLength <= 0)
|
||||
return -1;
|
||||
|
||||
if (dataLength < divCount)
|
||||
{
|
||||
if (divIndex < dataLength)
|
||||
return new int2(divIndex, divIndex + 1);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
float segment = (float)dataLength / divCount;
|
||||
int start = (int)(segment * divIndex);
|
||||
int end = (divIndex == divCount - 1) ? dataLength : (int)(segment * (divIndex + 1));
|
||||
return new int2(start, end);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static DataChunk GetWorkerChunk(int dataLenght, int workerCount, int workerIndex)
|
||||
{
|
||||
int2 range = CalcSplitRange(dataLenght, workerCount, workerIndex);
|
||||
if (range.x < 0)
|
||||
return DataChunk.Empty;
|
||||
else
|
||||
return new DataChunk(range.x, range.y - range.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ using System.Text;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
{
|
||||
@ -389,6 +390,12 @@ namespace MagicaCloth2
|
||||
NativeArray<T>.Copy(nativeArray, array);
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int startIndex)
|
||||
{
|
||||
Debug.Assert(array != null);
|
||||
NativeArray<T>.Copy(nativeArray, startIndex, array, 0, array.Length);
|
||||
}
|
||||
|
||||
public void CopyTo<U>(U[] array) where U : struct
|
||||
{
|
||||
NativeArray<U>.Copy(nativeArray.Reinterpret<U>(), array);
|
||||
@ -399,11 +406,22 @@ namespace MagicaCloth2
|
||||
NativeArray<T>.Copy(array, nativeArray);
|
||||
}
|
||||
|
||||
public void CopyFrom(T[] array, int startIndex)
|
||||
{
|
||||
Debug.Assert(array != null);
|
||||
NativeArray<T>.Copy(array, 0, nativeArray, startIndex, array.Length);
|
||||
}
|
||||
|
||||
public void CopyFrom<U>(NativeArray<U> array) where U : struct
|
||||
{
|
||||
NativeArray<T>.Copy(array.Reinterpret<T>(), nativeArray);
|
||||
}
|
||||
|
||||
public void CopyFrom<U>(NativeArray<U> array, int dstIndex, int length) where U : struct
|
||||
{
|
||||
NativeArray<T>.Copy(array.Reinterpret<T>(), 0, nativeArray, dstIndex, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 型もサイズも異なる配列にデータをコピーする。
|
||||
/// int3 -> int[]など
|
||||
@ -474,6 +492,11 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(int index)
|
||||
{
|
||||
Remove(new DataChunk(index));
|
||||
}
|
||||
|
||||
public void RemoveAndFill(DataChunk chunk, T clearData = default(T))
|
||||
{
|
||||
Remove(chunk);
|
||||
|
||||
@ -67,6 +67,11 @@ namespace MagicaCloth2
|
||||
count = length;
|
||||
}
|
||||
|
||||
public ExSimpleNativeArray(SerializationData sdata)
|
||||
{
|
||||
Deserialize(sdata);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (nativeArray.IsCreated)
|
||||
@ -108,11 +113,13 @@ namespace MagicaCloth2
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 領域のみ拡張する
|
||||
/// すでにその長さの領域が確保されている場合は何もしない
|
||||
/// </summary>
|
||||
/// <param name="capacity"></param>
|
||||
public void AddCapacity(int capacity)
|
||||
/// <param name="newLength"></param>
|
||||
public void SetLength(int newLength)
|
||||
{
|
||||
Expand(capacity, true);
|
||||
if (newLength > length)
|
||||
Expand(newLength - length, force: true, copy: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -216,6 +223,16 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
public void AddRange(NativeArray<T> narray, int start, int length)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
Expand(length);
|
||||
NativeArray<T>.Copy(narray, start, nativeArray, count, length);
|
||||
count += length;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddRange(NativeList<T> nlist)
|
||||
{
|
||||
Debug.Assert(nlist.IsCreated);
|
||||
@ -481,7 +498,8 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
/// <param name="dataLength"></param>
|
||||
/// <param name="force">強制的に領域を追加</param>
|
||||
void Expand(int dataLength, bool force = false)
|
||||
/// <param name="copy">古いデータをコピーするかどうか</param>
|
||||
void Expand(int dataLength, bool force = false, bool copy = true)
|
||||
{
|
||||
int newlength = force ? length + dataLength : count + dataLength;
|
||||
|
||||
@ -499,8 +517,11 @@ namespace MagicaCloth2
|
||||
var newNativeArray = new NativeArray<T>(newlength, Allocator.Persistent);
|
||||
|
||||
// copy
|
||||
if (copy)
|
||||
{
|
||||
// コピーは使用分だけ
|
||||
NativeArray<T>.Copy(nativeArray, newNativeArray, count);
|
||||
}
|
||||
|
||||
nativeArray.Dispose();
|
||||
nativeArray = newNativeArray;
|
||||
@ -512,8 +533,8 @@ namespace MagicaCloth2
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine($"ExNativeArray Length:{Length} Count:{Count} IsValid:{IsValid}");
|
||||
sb.AppendLine("---- Datas[100] ----");
|
||||
sb.AppendLine($"ExSimpleNativeArray Length:{Length} Count:{Count} IsValid:{IsValid}");
|
||||
sb.AppendLine("---- Datas[~100] ----");
|
||||
if (IsValid)
|
||||
{
|
||||
for (int i = 0; i < Length && i < 100; i++)
|
||||
@ -524,5 +545,59 @@ namespace MagicaCloth2
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// シリアライズデータ
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class SerializationData
|
||||
{
|
||||
public int count;
|
||||
public int length;
|
||||
public byte[] arrayBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// シリアライズする
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SerializationData Serialize()
|
||||
{
|
||||
var data = new SerializationData();
|
||||
data.count = count;
|
||||
data.length = length;
|
||||
if (nativeArray.IsCreated && nativeArray.Length > 0)
|
||||
{
|
||||
data.arrayBytes = nativeArray.MC2ToRawBytes();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// デシリアライズする
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public bool Deserialize(SerializationData data)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose();
|
||||
count = data.count;
|
||||
length = data.length;
|
||||
if (data.length > 0 && data.arrayBytes != null)
|
||||
{
|
||||
nativeArray = NativeArrayExtensions.MC2FromRawBytes<T>(data.arrayBytes, Allocator.Persistent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ namespace MagicaCloth2
|
||||
// Common
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsCapacity<T>(ref this FixedList128Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static bool MC2IsCapacity<T>(ref this FixedList128Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
return fixedList.Length >= fixedList.Capacity;
|
||||
}
|
||||
@ -30,7 +30,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Set<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Set<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Contains(item) == false)
|
||||
{
|
||||
@ -46,7 +46,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SetLimit<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2SetLimit<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Length >= fixedList.Capacity)
|
||||
{
|
||||
@ -67,7 +67,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RemoveItemAtSwapBack<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2RemoveItemAtSwapBack<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
for (int i = 0; i < fixedList.Length; i++)
|
||||
{
|
||||
@ -83,13 +83,13 @@ namespace MagicaCloth2
|
||||
// Stack
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Push<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Push<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Pop<T>(ref this FixedList128Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Pop<T>(ref this FixedList128Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
int index = fixedList.Length - 1;
|
||||
T item = fixedList[index];
|
||||
@ -101,13 +101,13 @@ namespace MagicaCloth2
|
||||
// Queue
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Enqueue<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Enqueue<T>(ref this FixedList128Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Dequque<T>(ref this FixedList128Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Dequque<T>(ref this FixedList128Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
T item = fixedList[0];
|
||||
fixedList.RemoveAt(0);
|
||||
|
||||
@ -8,14 +8,13 @@ using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
{
|
||||
//[BurstCompatible]
|
||||
public static class FixedList32BytesExtensions
|
||||
{
|
||||
//=====================================================================
|
||||
// Common
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsCapacity<T>(ref this FixedList32Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static bool MC2IsCapacity<T>(ref this FixedList32Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
return fixedList.Length >= fixedList.Capacity;
|
||||
}
|
||||
@ -31,7 +30,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Set<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Set<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Contains(item) == false)
|
||||
{
|
||||
@ -47,7 +46,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SetLimit<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2SetLimit<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Length >= fixedList.Capacity)
|
||||
{
|
||||
@ -68,7 +67,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RemoveItemAtSwapBack<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2RemoveItemAtSwapBack<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
for (int i = 0; i < fixedList.Length; i++)
|
||||
{
|
||||
@ -84,13 +83,13 @@ namespace MagicaCloth2
|
||||
// Stack
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Push<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Push<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Pop<T>(ref this FixedList32Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Pop<T>(ref this FixedList32Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
int index = fixedList.Length - 1;
|
||||
T item = fixedList[index];
|
||||
@ -102,13 +101,13 @@ namespace MagicaCloth2
|
||||
// Queue
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Enqueue<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Enqueue<T>(ref this FixedList32Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Dequque<T>(ref this FixedList32Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Dequque<T>(ref this FixedList32Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
T item = fixedList[0];
|
||||
fixedList.RemoveAt(0);
|
||||
|
||||
@ -15,7 +15,7 @@ namespace MagicaCloth2
|
||||
// Common
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsCapacity<T>(ref this FixedList4096Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static bool MC2IsCapacity<T>(ref this FixedList4096Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
return fixedList.Length >= fixedList.Capacity;
|
||||
}
|
||||
@ -30,7 +30,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Set<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Set<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Contains(item) == false)
|
||||
{
|
||||
@ -46,7 +46,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SetLimit<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2SetLimit<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Length >= fixedList.Capacity)
|
||||
{
|
||||
@ -67,7 +67,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RemoveItemAtSwapBack<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2RemoveItemAtSwapBack<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
for (int i = 0; i < fixedList.Length; i++)
|
||||
{
|
||||
@ -83,13 +83,13 @@ namespace MagicaCloth2
|
||||
// Stack
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Push<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Push<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Pop<T>(ref this FixedList4096Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Pop<T>(ref this FixedList4096Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
int index = fixedList.Length - 1;
|
||||
T item = fixedList[index];
|
||||
@ -101,13 +101,13 @@ namespace MagicaCloth2
|
||||
// Queue
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Enqueue<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Enqueue<T>(ref this FixedList4096Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Dequque<T>(ref this FixedList4096Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Dequque<T>(ref this FixedList4096Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
T item = fixedList[0];
|
||||
fixedList.RemoveAt(0);
|
||||
|
||||
@ -15,7 +15,7 @@ namespace MagicaCloth2
|
||||
// Common
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsCapacity<T>(ref this FixedList512Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static bool MC2IsCapacity<T>(ref this FixedList512Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
return fixedList.Length >= fixedList.Capacity;
|
||||
}
|
||||
@ -30,7 +30,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Set<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Set<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Contains(item) == false)
|
||||
{
|
||||
@ -46,7 +46,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SetLimit<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2SetLimit<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Length >= fixedList.Capacity)
|
||||
{
|
||||
@ -67,7 +67,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RemoveItemAtSwapBack<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2RemoveItemAtSwapBack<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
for (int i = 0; i < fixedList.Length; i++)
|
||||
{
|
||||
@ -83,13 +83,13 @@ namespace MagicaCloth2
|
||||
// Stack
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Push<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Push<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Pop<T>(ref this FixedList512Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Pop<T>(ref this FixedList512Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
int index = fixedList.Length - 1;
|
||||
T item = fixedList[index];
|
||||
@ -101,13 +101,13 @@ namespace MagicaCloth2
|
||||
// Queue
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Enqueue<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Enqueue<T>(ref this FixedList512Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Dequque<T>(ref this FixedList512Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Dequque<T>(ref this FixedList512Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
T item = fixedList[0];
|
||||
fixedList.RemoveAt(0);
|
||||
|
||||
@ -15,7 +15,7 @@ namespace MagicaCloth2
|
||||
// Common
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsCapacity<T>(ref this FixedList64Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static bool MC2IsCapacity<T>(ref this FixedList64Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
return fixedList.Length >= fixedList.Capacity;
|
||||
}
|
||||
@ -30,7 +30,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Set<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Set<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Contains(item) == false)
|
||||
{
|
||||
@ -46,7 +46,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SetLimit<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2SetLimit<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
if (fixedList.Length >= fixedList.Capacity)
|
||||
{
|
||||
@ -67,7 +67,7 @@ namespace MagicaCloth2
|
||||
/// <param name="fixedList"></param>
|
||||
/// <param name="item"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RemoveItemAtSwapBack<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2RemoveItemAtSwapBack<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
for (int i = 0; i < fixedList.Length; i++)
|
||||
{
|
||||
@ -83,13 +83,13 @@ namespace MagicaCloth2
|
||||
// Stack
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Push<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Push<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Pop<T>(ref this FixedList64Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Pop<T>(ref this FixedList64Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
int index = fixedList.Length - 1;
|
||||
T item = fixedList[index];
|
||||
@ -101,13 +101,13 @@ namespace MagicaCloth2
|
||||
// Queue
|
||||
//=====================================================================
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Enqueue<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
public static void MC2Enqueue<T>(ref this FixedList64Bytes<T> fixedList, T item) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
fixedList.Add(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T Dequque<T>(ref this FixedList64Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
public static T MC2Dequque<T>(ref this FixedList64Bytes<T> fixedList) where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
T item = fixedList[0];
|
||||
fixedList.RemoveAt(0);
|
||||
|
||||
@ -8,14 +8,14 @@ namespace MagicaCloth2
|
||||
/// <summary>
|
||||
/// NativeArrayの拡張メソッド
|
||||
/// </summary>
|
||||
static class NativeArrayExtensions
|
||||
public static class NativeArrayExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// NativeArrayが確保されている場合のみDispose()する
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="array"></param>
|
||||
public static void DisposeSafe<T>(ref this NativeArray<T> array) where T : unmanaged
|
||||
public static void MC2DisposeSafe<T>(ref this NativeArray<T> array) where T : unmanaged
|
||||
{
|
||||
if (array.IsCreated)
|
||||
array.Dispose();
|
||||
@ -31,13 +31,55 @@ namespace MagicaCloth2
|
||||
/// <param name="size"></param>
|
||||
/// <param name="allocator"></param>
|
||||
/// <param name="options"></param>
|
||||
public static void Resize<T>(ref this NativeArray<T> array, int size, Allocator allocator = Allocator.Persistent, NativeArrayOptions options = NativeArrayOptions.ClearMemory) where T : unmanaged
|
||||
public static void MC2Resize<T>(ref this NativeArray<T> array, int size, Allocator allocator = Allocator.Persistent, NativeArrayOptions options = NativeArrayOptions.ClearMemory) where T : unmanaged
|
||||
{
|
||||
if (array.IsCreated == false || array.Length < size)
|
||||
{
|
||||
array.DisposeSafe();
|
||||
array.MC2DisposeSafe();
|
||||
array = new NativeArray<T>(size, allocator, options);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NativeArrayをbyte[]に変換する
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="array"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] MC2ToRawBytes<T>(ref this NativeArray<T> array) where T : unmanaged
|
||||
{
|
||||
if (array.IsCreated == false || array.Length == 0)
|
||||
return null;
|
||||
var slice = new NativeSlice<T>(array).SliceConvert<byte>();
|
||||
var bytes = new byte[slice.Length];
|
||||
slice.CopyTo(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// byte[]からNativeArrayを作成する
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="allocator"></param>
|
||||
/// <returns></returns>
|
||||
public static NativeArray<T> MC2FromRawBytes<T>(byte[] bytes, Allocator allocator = Allocator.Persistent) where T : unmanaged
|
||||
{
|
||||
if (bytes == null)
|
||||
return new NativeArray<T>();
|
||||
|
||||
int structSize = Unity.Collections.LowLevel.Unsafe.UnsafeUtility.SizeOf<T>();
|
||||
|
||||
int length = bytes.Length / structSize;
|
||||
var array = new NativeArray<T>(length, allocator);
|
||||
if (length > 0)
|
||||
{
|
||||
using var byteArray = new NativeArray<byte>(bytes, Allocator.Temp);
|
||||
//using var byteArray = new NativeArray<byte>(bytes, Allocator.Persistent);
|
||||
var slice = new NativeSlice<byte>(byteArray).SliceConvert<T>();
|
||||
slice.CopyTo(array);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,17 +2,21 @@
|
||||
// Copyright (c) 2023 MagicaSoft.
|
||||
// https://magicasoft.jp
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
{
|
||||
/// <summary>
|
||||
/// NativeMultiHashMapの拡張メソッド
|
||||
/// </summary>
|
||||
static class NativeMultiHashMapExtensions
|
||||
public static class NativeMultiHashMapExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// NativeMultiHashMapのキーに指定データが存在するか判定する
|
||||
/// NativeParallelMultiHashMapのキーに指定データが存在するか判定する
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
@ -21,9 +25,9 @@ namespace MagicaCloth2
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
#if MC2_COLLECTIONS_200
|
||||
public static bool Contains<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
public static bool MC2Contains<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
#else
|
||||
public static bool Contains<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : struct, IEquatable<TKey> where TValue : struct, IEquatable<TValue>
|
||||
public static bool MC2Contains<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : struct, IEquatable<TKey> where TValue : struct, IEquatable<TValue>
|
||||
#endif
|
||||
{
|
||||
foreach (TValue val in map.GetValuesForKey(key))
|
||||
@ -35,7 +39,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NativeMultiHashMapのキーに対して重複なしのデータを追加する
|
||||
/// NativeParallelMultiHashMapキーに対して重複なしのデータを追加する
|
||||
/// すでにキーに同じデータが存在する場合は追加しない。
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
@ -44,26 +48,59 @@ namespace MagicaCloth2
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
#if MC2_COLLECTIONS_200
|
||||
public static void UniqueAdd<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
public static void MC2UniqueAdd<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
#else
|
||||
public static void UniqueAdd<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : struct, IEquatable<TKey> where TValue : struct, IEquatable<TValue>
|
||||
public static void MC2UniqueAdd<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : struct, IEquatable<TKey> where TValue : struct, IEquatable<TValue>
|
||||
#endif
|
||||
{
|
||||
if (map.Contains(key, value) == false)
|
||||
if (map.MC2Contains(key, value) == false)
|
||||
{
|
||||
map.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NativeMultiHashMapのキーに存在するデータを削除する
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="map"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
#if MC2_COLLECTIONS_200
|
||||
public static bool MC2RemoveValue<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
#else
|
||||
public static bool MC2RemoveValue<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key, TValue value) where TKey : struct, IEquatable<TKey> where TValue : struct, IEquatable<TValue>
|
||||
#endif
|
||||
{
|
||||
NativeParallelMultiHashMapIterator<TKey> it;
|
||||
TValue item;
|
||||
if (map.TryGetFirstValue(key, out item, out it))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (item.Equals(value))
|
||||
{
|
||||
map.Remove(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while (map.TryGetNextValue(out item, ref it));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 現在のキーのデータをFixedList512Bytesに変換して返す
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
#if MC2_COLLECTIONS_200
|
||||
public static FixedList512Bytes<TValue> ToFixedList512Bytes<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
public static FixedList512Bytes<TValue> MC2ToFixedList512Bytes<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
#else
|
||||
public static FixedList512Bytes<TValue> ToFixedList512Bytes<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key) where TKey : struct, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
public static FixedList512Bytes<TValue> MC2ToFixedList512Bytes<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key) where TKey : struct, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
#endif
|
||||
{
|
||||
var fixlist = new FixedList512Bytes<TValue>();
|
||||
@ -84,9 +121,9 @@ namespace MagicaCloth2
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
#if MC2_COLLECTIONS_200
|
||||
public static FixedList128Bytes<TValue> ToFixedList128Bytes<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
public static FixedList128Bytes<TValue> MC2ToFixedList128Bytes<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
#else
|
||||
public static FixedList128Bytes<TValue> ToFixedList128Bytes<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key) where TKey : struct, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
public static FixedList128Bytes<TValue> MC2ToFixedList128Bytes<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map, TKey key) where TKey : struct, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
#endif
|
||||
{
|
||||
var fixlist = new FixedList128Bytes<TValue>();
|
||||
@ -100,5 +137,91 @@ namespace MagicaCloth2
|
||||
|
||||
return fixlist;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NativeParallelMultiHashMapをKeyとValueの配列に変換します
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="map"></param>
|
||||
/// <returns></returns>
|
||||
#if MC2_COLLECTIONS_200
|
||||
public static (TKey[], TValue[]) MC2Serialize<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged
|
||||
#else
|
||||
public static (TKey[], TValue[]) MC2Serialize<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map) where TKey : struct, IEquatable<TKey> where TValue : struct
|
||||
#endif
|
||||
{
|
||||
if (map.IsCreated == false || map.Count() == 0 || map.IsEmpty)
|
||||
return (null, null);
|
||||
|
||||
using var keyNativeArray = map.GetKeyArray(Allocator.Persistent);
|
||||
using var valueNativeArray = map.GetValueArray(Allocator.Persistent);
|
||||
|
||||
return (keyNativeArray.ToArray(), valueNativeArray.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// KeyとValueの配列からNativeParallelMultiHashMapを復元します
|
||||
/// 高速化のためBurstを利用
|
||||
/// ジェネリック型ジョブは明示的に型を指定する必要があるため型ごとに関数が発生します
|
||||
/// </summary>
|
||||
/// <param name="keyArray"></param>
|
||||
/// <param name="valueArray"></param>
|
||||
/// <returns></returns>
|
||||
public static NativeParallelMultiHashMap<int2, ushort> MC2Deserialize(int2[] keyArray, ushort[] valueArray)
|
||||
{
|
||||
int keyCount = keyArray?.Length ?? 0;
|
||||
int valueCount = valueArray?.Length ?? 0;
|
||||
Debug.Assert(keyCount == valueCount);
|
||||
var map = new NativeParallelMultiHashMap<int2, ushort>(keyCount, Allocator.Persistent);
|
||||
if (keyCount > 0 && valueCount > 0)
|
||||
{
|
||||
using var keyNativeArray = new NativeArray<int2>(keyArray, Allocator.Persistent);
|
||||
using var valueNativeArray = new NativeArray<ushort>(valueArray, Allocator.Persistent);
|
||||
var job = new SetParallelMultiHashMapJob<int2, ushort>() { map = map, keyArray = keyNativeArray, valueArray = valueNativeArray };
|
||||
job.Run();
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
#if MC2_COLLECTIONS_200
|
||||
struct SetParallelMultiHashMapJob<TKey, TValue> : IJob where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged
|
||||
#else
|
||||
struct SetParallelMultiHashMapJob<TKey, TValue> : IJob where TKey : struct, IEquatable<TKey> where TValue : struct
|
||||
#endif
|
||||
{
|
||||
public NativeParallelMultiHashMap<TKey, TValue> map;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TKey> keyArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<TValue> valueArray;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
int cnt = keyArray.Length;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
map.Add(keyArray[i], valueArray[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NativeParallelMultiHashMapが確保されている場合のみDispose()する
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="map"></param>
|
||||
#if MC2_COLLECTIONS_200
|
||||
public static void MC2DisposeSafe<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
|
||||
#else
|
||||
public static void MC2DisposeSafe<TKey, TValue>(ref this NativeParallelMultiHashMap<TKey, TValue> map) where TKey : struct, IEquatable<TKey> where TValue : struct, IEquatable<TValue>
|
||||
#endif
|
||||
{
|
||||
if (map.IsCreated)
|
||||
map.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ namespace MagicaCloth2
|
||||
/// <param name="dataCount"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
unsafe public static int InterlockedStartIndex(ref this NativeReference<int> counter, int dataCount)
|
||||
unsafe public static int MC2InterlockedStartIndex(ref this NativeReference<int> counter, int dataCount)
|
||||
{
|
||||
int* cntPt = (int*)counter.GetUnsafePtr();
|
||||
int start = Interlocked.Add(ref *cntPt, dataCount) - dataCount;
|
||||
|
||||
@ -2,25 +2,31 @@
|
||||
// Copyright (c) 2023 MagicaSoft.
|
||||
// https://magicasoft.jp
|
||||
using System.Diagnostics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagicaCloth2
|
||||
{
|
||||
/// <summary>
|
||||
/// 様々な処理の結果
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public struct ResultCode
|
||||
{
|
||||
[SerializeField]
|
||||
volatile Define.Result result;
|
||||
|
||||
/// <summary>
|
||||
/// 警告:警告は1つのみ保持
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
volatile Define.Result warning;
|
||||
|
||||
public Define.Result Result => result;
|
||||
|
||||
public static ResultCode None => new ResultCode(Define.Result.None);
|
||||
public static ResultCode Empty => new ResultCode(Define.Result.Empty);
|
||||
public static ResultCode Success => new ResultCode(Define.Result.Success);
|
||||
public static ResultCode Error => new ResultCode(Define.Result.Error);
|
||||
|
||||
public ResultCode(Define.Result initResult)
|
||||
{
|
||||
@ -119,9 +125,13 @@ namespace MagicaCloth2
|
||||
case Define.Result.RenderSetup_Unreadable:
|
||||
return "It is necessary to turn on [Read/Write] in the model import settings.";
|
||||
case Define.Result.RenderSetup_Over65535vertices:
|
||||
return "Original mesh must have no more than 65,535 vertices";
|
||||
return "Original mesh must have no more than 65,535 vertices.";
|
||||
case Define.Result.SerializeData_Over31Renderers:
|
||||
return $"There are {Define.System.MaxRendererCount} renderers that can be set.";
|
||||
case Define.Result.Init_ScaleIsZero:
|
||||
return "Component scale values is 0.";
|
||||
case Define.Result.Init_NegativeScale:
|
||||
return "Component has negative scale.";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -133,6 +143,8 @@ namespace MagicaCloth2
|
||||
{
|
||||
case Define.Result.RenderMesh_VertexWeightIs5BonesOrMore:
|
||||
return "The source renderer mesh contains vertex weights that utilize more than 5 bones.\nA weight of 5 or more is invalid.";
|
||||
case Define.Result.Init_NonUniformScale:
|
||||
return "Component scale values should be uniform.\nIf the scale is not uniform, there is a risk that it will not work properly.";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ namespace MagicaCloth2
|
||||
string name = string.Empty;
|
||||
DateTime stime;
|
||||
DateTime etime;
|
||||
//bool isFinish;
|
||||
bool isFinish;
|
||||
|
||||
public TimeSpan() { }
|
||||
|
||||
@ -21,21 +21,23 @@ namespace MagicaCloth2
|
||||
{
|
||||
this.name = name;
|
||||
stime = DateTime.Now;
|
||||
isFinish = false;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
stime = DateTime.Now;
|
||||
isFinish = false;
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
//etime = DateTime.Now;
|
||||
if (isFinish == false)
|
||||
{
|
||||
etime = DateTime.Now;
|
||||
//if (isFinish == false)
|
||||
//{
|
||||
// etime = DateTime.Now;
|
||||
// isFinish = true;
|
||||
//}
|
||||
isFinish = true;
|
||||
}
|
||||
}
|
||||
|
||||
public double TotalSeconds()
|
||||
@ -60,5 +62,10 @@ namespace MagicaCloth2
|
||||
{
|
||||
Develop.DebugLog(this);
|
||||
}
|
||||
|
||||
public void Log()
|
||||
{
|
||||
Develop.Log(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ namespace MagicaCloth2
|
||||
/// <param name="rsetup"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
public void ImportFrom(RenderSetupData rsetup)
|
||||
public void ImportFrom(RenderSetupData rsetup, int uvChannel)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -44,7 +44,7 @@ namespace MagicaCloth2
|
||||
rsetup.transformIdList,
|
||||
rsetup.transformParentIdList,
|
||||
rsetup.rootTransformIdList,
|
||||
rsetup.transformLocalPositins,
|
||||
rsetup.transformLocalPositions,
|
||||
rsetup.transformLocalRotations,
|
||||
rsetup.transformPositions,
|
||||
rsetup.transformRotations,
|
||||
@ -68,7 +68,7 @@ namespace MagicaCloth2
|
||||
// メッシュタイプ
|
||||
meshType = MeshType.NormalMesh;
|
||||
isBoneCloth = false;
|
||||
ImportMeshType(rsetup, indices);
|
||||
ImportMeshType(rsetup, indices, uvChannel);
|
||||
|
||||
// スキニングメッシュでは1回スキニングを行いクロスローカル空間に姿勢を変換する
|
||||
if (rsetup.hasBoneWeight)
|
||||
@ -129,7 +129,7 @@ namespace MagicaCloth2
|
||||
/// </summary>
|
||||
/// <param name="rsetup"></param>
|
||||
/// <param name="transformIndices"></param>
|
||||
void ImportMeshType(RenderSetupData rsetup, int[] transformIndices)
|
||||
void ImportMeshType(RenderSetupData rsetup, int[] transformIndices, int uvChannel)
|
||||
{
|
||||
// root bone
|
||||
skinRootIndex = transformIndices[rsetup.skinRootBoneIndex];
|
||||
@ -155,6 +155,7 @@ namespace MagicaCloth2
|
||||
meshData.GetNormals(localNormals.GetNativeArray<Vector3>());
|
||||
if (meshData.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.Tangent))
|
||||
{
|
||||
// 接線情報がメッシュに存在する
|
||||
using var tangents = new NativeArray<Vector4>(vcnt, Allocator.TempJob);
|
||||
meshData.GetTangents(tangents);
|
||||
// tangent変換(Vector4->float3)
|
||||
@ -162,6 +163,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
else
|
||||
{
|
||||
// 接線情報がメッシュに存在しない
|
||||
Develop.DebugLogWarning($"[{name}] Tangents not found!");
|
||||
// tangentを生成する
|
||||
// このtangentは描画用では無く姿勢制御用なのである意味適当でも大丈夫
|
||||
@ -174,11 +176,19 @@ namespace MagicaCloth2
|
||||
}
|
||||
if (meshData.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.TexCoord0))
|
||||
{
|
||||
meshData.GetUVs(0, uv.GetNativeArray<Vector2>());
|
||||
uvChannel = Mathf.Clamp(uvChannel, 0, 7);
|
||||
UnityEngine.Rendering.VertexAttribute useTexCoord = UnityEngine.Rendering.VertexAttribute.TexCoord0 + uvChannel;
|
||||
if (meshData.HasVertexAttribute(useTexCoord) == false)
|
||||
{
|
||||
Develop.LogWarning($"[{name}] UV{uvChannel} not found! => Use UV0.");
|
||||
uvChannel = 0;
|
||||
}
|
||||
//Debug.Log($"Fetch UV:{uvChannel}");
|
||||
meshData.GetUVs(uvChannel, uv.GetNativeArray<Vector2>());
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[{name}] UV not found!");
|
||||
Develop.LogWarning($"[{name}] UV0 not found!");
|
||||
}
|
||||
|
||||
// 属性
|
||||
@ -439,7 +449,7 @@ namespace MagicaCloth2
|
||||
skinBoneTransformIndices.AddRange(transformIndices, rsetup.skinBoneCount);
|
||||
skinBoneBindPoses.AddRange(vcnt);
|
||||
|
||||
// Transformの情報をローカル空間に変換し頂点情報に割り当てる
|
||||
// Transformの情報をクロスローカル空間に変換し頂点情報に割り当てる
|
||||
// およびバインドポーズの算出
|
||||
var WtoL = rsetup.initRenderWorldtoLocal;
|
||||
var LtoW = rsetup.initRenderLocalToWorld;
|
||||
@ -899,13 +909,17 @@ namespace MagicaCloth2
|
||||
quaternion rot = transformRotations[vindex];
|
||||
float3 scl = transformScales[vindex];
|
||||
|
||||
// トランスフォーム姿勢をローカル空間に変換する
|
||||
// トランスフォーム姿勢をクロスローカル空間に変換する
|
||||
// オリジナル
|
||||
#if true
|
||||
float3 lpos = MathUtility.InverseTransformPoint(pos, WtoL);
|
||||
float3 lnor, ltan;
|
||||
lnor = math.mul(rot, math.up());
|
||||
ltan = math.mul(rot, math.forward());
|
||||
lnor = MathUtility.InverseTransformDirection(lnor, WtoL);
|
||||
ltan = MathUtility.InverseTransformDirection(ltan, WtoL);
|
||||
#endif
|
||||
//Debug.Log($"Import [{vindex}] lpos:{lpos}, lnor:{lnor}, ltan:{ltan}");
|
||||
|
||||
localPositions[vindex] = lpos;
|
||||
localNormals[vindex] = lnor;
|
||||
@ -928,7 +942,7 @@ namespace MagicaCloth2
|
||||
/// レンダーデータからインポートする
|
||||
/// </summary>
|
||||
/// <param name="renderData"></param>
|
||||
public void ImportFrom(RenderData renderData)
|
||||
public void ImportFrom(RenderData renderData, int uvChannel)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -938,7 +952,7 @@ namespace MagicaCloth2
|
||||
throw new MagicaClothProcessingException();
|
||||
}
|
||||
|
||||
ImportFrom(renderData.setupData);
|
||||
ImportFrom(renderData.setupData, uvChannel);
|
||||
}
|
||||
catch (MagicaClothProcessingException)
|
||||
{
|
||||
@ -1764,16 +1778,6 @@ namespace MagicaCloth2
|
||||
return transformData.GetTransformFromIndex(centerTransformIndex);
|
||||
}
|
||||
|
||||
public float4x4 GetCenterLocalToWorldMatrix()
|
||||
{
|
||||
return transformData.GetLocalToWorldMatrix(centerTransformIndex);
|
||||
}
|
||||
|
||||
public float4x4 GetCenterWorldToLocalMatrix()
|
||||
{
|
||||
return transformData.GetWorldToLocalMatrix(centerTransformIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// カスタムスキニング用ボーンを登録する
|
||||
/// </summary>
|
||||
@ -1828,6 +1832,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
#if false
|
||||
/// <summary>
|
||||
/// UnityMeshに出力する(メインスレッドのみ)
|
||||
/// ※ほぼデバッグ用
|
||||
@ -1893,93 +1898,6 @@ namespace MagicaCloth2
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メッシュの基準トランスフォームを返す
|
||||
/// 通常はレンダラーのtransform
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Transform ExportCenterTransform()
|
||||
{
|
||||
return transformData.GetTransformFromIndex(centerTransformIndex);
|
||||
}
|
||||
|
||||
public Transform ExportSkinRootBone()
|
||||
{
|
||||
return transformData.GetTransformFromIndex(skinRootIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メッシュのスキニング用ボーンリストを返す
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<Transform> ExportSkinningBones()
|
||||
{
|
||||
var sbones = new List<Transform>(SkinBoneCount);
|
||||
for (int i = 0; i < SkinBoneCount; i++)
|
||||
{
|
||||
sbones.Add(transformData.GetTransformFromIndex(skinBoneTransformIndices[i]));
|
||||
}
|
||||
return sbones;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メッシュのバウンディングボックスを返す
|
||||
/// スキニングの場合はスキニングルートボーンからのバウンディングボックスとなる
|
||||
/// それ以外はセンターボーンからのバウンディングボックスとなる
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/*public Bounds ExportBounds()
|
||||
{
|
||||
float3 offset = 0;
|
||||
if (skinRootIndex >= 0 && centerTransformIndex != skinRootIndex)
|
||||
{
|
||||
// スキニングのルートボーンが別の場合
|
||||
// ちょっと面倒
|
||||
float3 wmin = transformData.TransformPoint(centerTransformIndex, boundingBox.Value.Min);
|
||||
float3 wmax = transformData.TransformPoint(centerTransformIndex, boundingBox.Value.Max);
|
||||
float3 lmin = transformData.InverseTransformPoint(skinRootIndex, wmin);
|
||||
float3 lmax = transformData.InverseTransformPoint(skinRootIndex, wmax);
|
||||
float3 cen = (lmax + lmin) * 0.5f;
|
||||
float3 size = math.abs(lmax - lmin);
|
||||
return new Bounds(cen, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Bounds(boundingBox.Value.Center, boundingBox.Value.Extents);
|
||||
}
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// 現在のメッシュをレンダラーに反映させる(主にデバッグ用)
|
||||
/// </summary>
|
||||
/// <param name="ren"></param>
|
||||
public Mesh ToRenderer(Renderer ren)
|
||||
{
|
||||
Mesh mesh = null;
|
||||
if (IsSuccess == false)
|
||||
return mesh;
|
||||
|
||||
if (ren is MeshRenderer)
|
||||
{
|
||||
mesh = ExportToMesh();
|
||||
var filter = ren.GetComponent<MeshFilter>();
|
||||
filter.mesh = mesh;
|
||||
}
|
||||
else if (ren is SkinnedMeshRenderer)
|
||||
{
|
||||
var sren = ren as SkinnedMeshRenderer;
|
||||
mesh = ExportToMesh(true);
|
||||
var rootBone = ExportSkinRootBone();
|
||||
var skinBones = ExportSkinningBones().ToArray();
|
||||
|
||||
sren.rootBone = rootBone;
|
||||
sren.bones = skinBones;
|
||||
sren.sharedMesh = mesh;
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,6 +237,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct Mapping_CalcDirectWeightJob : IJob
|
||||
{
|
||||
// data
|
||||
@ -282,10 +283,10 @@ namespace MagicaCloth2
|
||||
// ウエイトバッファ
|
||||
var weights = new ExCostSortedList4(-1);
|
||||
|
||||
stack.Push(pindex);
|
||||
stack.MC2Push(pindex);
|
||||
while (stack.IsEmpty == false)
|
||||
{
|
||||
pindex = stack.Pop();
|
||||
pindex = stack.MC2Pop();
|
||||
|
||||
if (useSet.Contains(pindex))
|
||||
continue;
|
||||
@ -305,7 +306,7 @@ namespace MagicaCloth2
|
||||
|
||||
// 次の接続
|
||||
DataUtility.Unpack12_20(proxyVertexToVertexIndexArray[pindex], out var dcnt, out var dstart);
|
||||
for (int i = 0; i < dcnt && stack.IsCapacity() == false; i++)
|
||||
for (int i = 0; i < dcnt && stack.MC2IsCapacity() == false; i++)
|
||||
{
|
||||
ushort tindex = proxyVertexToVertexDataArray[dstart + i];
|
||||
|
||||
@ -317,7 +318,7 @@ namespace MagicaCloth2
|
||||
if (dist > weightLength)
|
||||
continue;
|
||||
|
||||
stack.Push(tindex);
|
||||
stack.MC2Push(tindex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -94,13 +94,13 @@ namespace MagicaCloth2
|
||||
if (edgeToTriangleList.ContainsKey(edge))
|
||||
{
|
||||
var tlist = edgeToTriangleList[edge];
|
||||
tlist.Set(i);
|
||||
tlist.MC2Set(i);
|
||||
edgeToTriangleList[edge] = tlist;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tlist = new FixedList128Bytes<int>();
|
||||
tlist.Set(i);
|
||||
tlist.MC2Set(i);
|
||||
edgeToTriangleList.Add(edge, tlist);
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,9 +346,6 @@ namespace MagicaCloth2
|
||||
{
|
||||
center = center,
|
||||
localPositions = localPositions.GetNativeArray(),
|
||||
vertexParentIndices = vertexParentIndices,
|
||||
vertexChildIndexArray = vertexChildIndexArray,
|
||||
vertexChildDataArray = vertexChildDataArray,
|
||||
|
||||
localNormals = localNormals.GetNativeArray(),
|
||||
localTangents = localTangents.GetNativeArray(),
|
||||
@ -356,96 +353,7 @@ namespace MagicaCloth2
|
||||
};
|
||||
job1.Run(vcnt);
|
||||
}
|
||||
#if false // ★どうもうまくいかないので一旦停止!
|
||||
// 頂点ウエイトから
|
||||
else if (mode == NormalAlignmentSettings.AlignmentMode.BoneWeight)
|
||||
{
|
||||
var job2 = new ProxyNormalWeightAdjustmentJob()
|
||||
{
|
||||
WtoL = initWorldToLocal,
|
||||
localPositions = localPositions.GetNativeArray(),
|
||||
boneWeights = boneWeights.GetNativeArray(),
|
||||
|
||||
transformPositionArray = transformData.positionArray.GetNativeArray(),
|
||||
|
||||
localNormals = localNormals.GetNativeArray(),
|
||||
localTangents = localTangents.GetNativeArray(),
|
||||
normalAdjustmentRotations = normalAdjustmentRotations,
|
||||
};
|
||||
job2.Run(vcnt);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if false
|
||||
[BurstCompile]
|
||||
struct ProxyNormalWeightAdjustmentJob : IJobParallelFor
|
||||
{
|
||||
public float4x4 WtoL;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> localPositions;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VirtualMeshBoneWeight> boneWeights;
|
||||
|
||||
// transform
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> transformPositionArray;
|
||||
|
||||
// out
|
||||
//[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> localNormals;
|
||||
//[Unity.Collections.WriteOnly]
|
||||
public NativeArray<float3> localTangents;
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<quaternion> normalAdjustmentRotations;
|
||||
|
||||
public void Execute(int vindex)
|
||||
{
|
||||
var lpos = localPositions[vindex];
|
||||
var bw = boneWeights[vindex];
|
||||
|
||||
// 現在の回転
|
||||
var lrot = MathUtility.ToRotation(localNormals[vindex], localTangents[vindex]);
|
||||
|
||||
// 影響するボーンへの方向をまとめる
|
||||
float3 bv = 0;
|
||||
int bcnt = bw.Count;
|
||||
if (bcnt == 0)
|
||||
return;
|
||||
for (int i = 0; i < bcnt; i++)
|
||||
{
|
||||
var bonePos = math.transform(WtoL, transformPositionArray[bw.boneIndices[i]]);
|
||||
//var v = transformPositionArray[bw.boneIndices[i]] - lpos;
|
||||
var v = lpos - bonePos;
|
||||
v = math.normalizesafe(v, float3.zero);
|
||||
v *= bw.weights[i];
|
||||
bv += v;
|
||||
}
|
||||
if (math.lengthsq(bv) < Define.System.Epsilon)
|
||||
return;
|
||||
|
||||
// 法線確定
|
||||
float3 n = math.normalize(bv);
|
||||
|
||||
// 法線をもとに接線を計算する
|
||||
var lnor = localNormals[vindex];
|
||||
var ltan = localTangents[vindex];
|
||||
var dotNormal = math.dot(n, lnor);
|
||||
var dotTangent = math.dot(n, ltan);
|
||||
float3 tv = dotNormal < dotTangent ? lnor : ltan;
|
||||
float3 tan = math.cross(tv, n);
|
||||
|
||||
//localNormals[vindex] = tan;
|
||||
//localTangents[vindex] = n;
|
||||
localNormals[vindex] = n;
|
||||
localTangents[vindex] = tan;
|
||||
var nrot = MathUtility.ToRotation(n, tan);
|
||||
|
||||
// 補正用回転を算出し格納する
|
||||
normalAdjustmentRotations[vindex] = math.mul(math.inverse(lrot), nrot);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[BurstCompile]
|
||||
struct ProxyNormalRadiationAdjustmentJob : IJobParallelFor
|
||||
@ -453,12 +361,6 @@ namespace MagicaCloth2
|
||||
public float3 center;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> localPositions;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<int> vertexParentIndices;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<uint> vertexChildIndexArray;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<ushort> vertexChildDataArray;
|
||||
|
||||
// out
|
||||
public NativeArray<float3> localNormals;
|
||||
@ -472,57 +374,32 @@ namespace MagicaCloth2
|
||||
var v = lpos - center;
|
||||
if (math.length(v) < Define.System.Epsilon)
|
||||
return;
|
||||
v = math.normalize(v);
|
||||
|
||||
// 指定されたセンターからの放射方向に法線を変更する
|
||||
var n = math.normalize(v);
|
||||
|
||||
// 現在の回転
|
||||
var lrot = MathUtility.ToRotation(localNormals[vindex], localTangents[vindex]);
|
||||
var ln = localNormals[vindex];
|
||||
var lt = localTangents[vindex];
|
||||
var lrot = MathUtility.ToRotation(ln, lt);
|
||||
|
||||
// 子がいる場合は子へのベクトルから算出
|
||||
var nrot = lrot;
|
||||
int pindex = vertexParentIndices[vindex];
|
||||
var pack = vertexChildIndexArray[vindex];
|
||||
DataUtility.Unpack12_20(pack, out var dcnt, out var dstart);
|
||||
if (dcnt > 0)
|
||||
// 接線を補正する
|
||||
float dot = math.dot(n, lt);
|
||||
if (dot < 0.99f)
|
||||
{
|
||||
float3 cv = 0;
|
||||
for (int i = 0; i < dcnt; i++)
|
||||
{
|
||||
int cindex = vertexChildDataArray[dstart + i];
|
||||
cv += localPositions[cindex] - lpos;
|
||||
float3 bn = math.normalize(math.cross(n, lt));
|
||||
lt = math.normalize(math.cross(bn, n));
|
||||
}
|
||||
if (math.lengthsq(cv) > Define.System.Epsilon)
|
||||
else
|
||||
{
|
||||
cv = math.normalize(cv);
|
||||
float3 n = math.cross(cv, v);
|
||||
n = math.cross(n, cv);
|
||||
// 元の接線と新しい法線が同じベクトルの場合は、従法線から新しい接線を算出する
|
||||
var lbn = math.normalize(math.cross(ln, lt));
|
||||
lt = math.normalize(math.cross(lbn, n));
|
||||
}
|
||||
|
||||
if (math.lengthsq(n) > Define.System.Epsilon)
|
||||
{
|
||||
n = math.normalize(n);
|
||||
localNormals[vindex] = n;
|
||||
localTangents[vindex] = cv;
|
||||
nrot = MathUtility.ToRotation(n, cv);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 子がいなく親がいる場合は親からのベクトルから算出
|
||||
else if (pindex >= 0)
|
||||
{
|
||||
var ppos = localPositions[pindex];
|
||||
var w = lpos - ppos;
|
||||
w = math.normalize(w);
|
||||
|
||||
float3 n = math.cross(w, v);
|
||||
n = math.cross(n, w);
|
||||
|
||||
if (math.lengthsq(n) > Define.System.Epsilon)
|
||||
{
|
||||
n = math.normalize(n);
|
||||
localNormals[vindex] = n;
|
||||
localTangents[vindex] = w;
|
||||
nrot = MathUtility.ToRotation(n, w);
|
||||
}
|
||||
}
|
||||
localTangents[vindex] = lt;
|
||||
var nrot = MathUtility.ToRotation(n, lt);
|
||||
|
||||
// 補正用回転を算出し格納する
|
||||
normalAdjustmentRotations[vindex] = math.mul(math.inverse(lrot), nrot);
|
||||
@ -837,11 +714,11 @@ namespace MagicaCloth2
|
||||
var vset_z = (ptr + tri.z);
|
||||
|
||||
if (vset_x->Length < 7)
|
||||
vset_x->Set(tindex);
|
||||
vset_x->MC2Set(tindex);
|
||||
if (vset_y->Length < 7)
|
||||
vset_y->Set(tindex);
|
||||
vset_y->MC2Set(tindex);
|
||||
if (vset_z->Length < 7)
|
||||
vset_z->Set(tindex);
|
||||
vset_z->MC2Set(tindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1103,7 +980,10 @@ namespace MagicaCloth2
|
||||
// 頂点のローカル回転
|
||||
var vrot = MathUtility.ToRotation(localNormals[vindex], localTangents[vindex]);
|
||||
|
||||
vertexToTransformRotations[vindex] = math.mul(math.inverse(vrot), trot);
|
||||
// 頂点ローカル回転をトランスフォームローカル回転に復元する回転を求める
|
||||
var toRot = math.mul(math.inverse(vrot), trot);
|
||||
|
||||
vertexToTransformRotations[vindex] = toRot;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1131,7 +1011,7 @@ namespace MagicaCloth2
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int2 edge = edges[j];
|
||||
edgeToTriangles.UniqueAdd(edge, (ushort)i);
|
||||
edgeToTriangles.MC2UniqueAdd(edge, (ushort)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1157,13 +1037,13 @@ namespace MagicaCloth2
|
||||
|
||||
public void Execute(int vindex)
|
||||
{
|
||||
float3 pos = localPositions[vindex];
|
||||
var nor = localNormals[vindex];
|
||||
var tan = localTangents[vindex];
|
||||
float3 lpos = localPositions[vindex];
|
||||
var lnor = localNormals[vindex];
|
||||
var ltan = localTangents[vindex];
|
||||
|
||||
// マッピング用の頂点バインドポーズを求める
|
||||
quaternion rot = MathUtility.ToRotation(nor, tan);
|
||||
vertexBindPosePositions[vindex] = -pos;
|
||||
quaternion rot = MathUtility.ToRotation(lnor, ltan);
|
||||
vertexBindPosePositions[vindex] = -lpos;
|
||||
vertexBindPoseRotations[vindex] = math.inverse(rot);
|
||||
}
|
||||
}
|
||||
@ -1192,12 +1072,12 @@ namespace MagicaCloth2
|
||||
ushort y = (ushort)tri.y;
|
||||
ushort z = (ushort)tri.z;
|
||||
|
||||
vertexToVertexMap.UniqueAdd(tri.x, y);
|
||||
vertexToVertexMap.UniqueAdd(tri.x, z);
|
||||
vertexToVertexMap.UniqueAdd(tri.y, x);
|
||||
vertexToVertexMap.UniqueAdd(tri.y, z);
|
||||
vertexToVertexMap.UniqueAdd(tri.z, x);
|
||||
vertexToVertexMap.UniqueAdd(tri.z, y);
|
||||
vertexToVertexMap.MC2UniqueAdd(tri.x, y);
|
||||
vertexToVertexMap.MC2UniqueAdd(tri.x, z);
|
||||
vertexToVertexMap.MC2UniqueAdd(tri.y, x);
|
||||
vertexToVertexMap.MC2UniqueAdd(tri.y, z);
|
||||
vertexToVertexMap.MC2UniqueAdd(tri.z, x);
|
||||
vertexToVertexMap.MC2UniqueAdd(tri.z, y);
|
||||
|
||||
edgeSet.Add(DataUtility.PackInt2(tri.xy));
|
||||
edgeSet.Add(DataUtility.PackInt2(tri.yz));
|
||||
@ -1226,8 +1106,8 @@ namespace MagicaCloth2
|
||||
{
|
||||
int2 line = lines[i];
|
||||
|
||||
vertexToVertexMap.UniqueAdd(line.x, (ushort)line.y);
|
||||
vertexToVertexMap.UniqueAdd(line.y, (ushort)line.x);
|
||||
vertexToVertexMap.MC2UniqueAdd(line.x, (ushort)line.y);
|
||||
vertexToVertexMap.MC2UniqueAdd(line.y, (ushort)line.x);
|
||||
|
||||
edgeSet.Add(DataUtility.PackInt2(line));
|
||||
}
|
||||
@ -1268,10 +1148,10 @@ namespace MagicaCloth2
|
||||
struct SkinningBoneInfo
|
||||
{
|
||||
//public int transformIndex;
|
||||
public int startTransformIndex;
|
||||
public float3 startPos;
|
||||
public int endTransformIndex;
|
||||
public float3 endPos;
|
||||
public int parentTransformIndex;
|
||||
public float3 parentPos;
|
||||
public int childTransformIndex;
|
||||
public float3 childPos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1282,39 +1162,6 @@ namespace MagicaCloth2
|
||||
if (CustomSkinningBoneCount == 0)
|
||||
return;
|
||||
|
||||
#if false
|
||||
// ボーン情報の構築
|
||||
using var boneInfoList = new NativeList<SkinningBoneInfo>(CustomSkinningBoneCount, Allocator.Persistent);
|
||||
for (int i = 0; i < CustomSkinningBoneCount; i++)
|
||||
{
|
||||
int tindex = customSkinningBoneIndices[i];
|
||||
if (tindex == -1)
|
||||
continue;
|
||||
|
||||
// 登録
|
||||
var info = new SkinningBoneInfo();
|
||||
info.transformIndex = tindex;
|
||||
info.startPos = bones[i].localPosition;
|
||||
boneInfoList.Add(info);
|
||||
Debug.Log($"[{boneInfoList.Length - 1}] {i}, tindex:{tindex}");
|
||||
}
|
||||
if (boneInfoList.Length == 0)
|
||||
return;
|
||||
|
||||
// 頂点ごとにカスタムスキニングウエイトを算出
|
||||
var job = new Proxy_CalcCustomSkinningWeightsJob2()
|
||||
{
|
||||
distanceReduction = setting.distanceReduction,
|
||||
distancePow = setting.distancePow,
|
||||
|
||||
//attributes = attributes.GetNativeArray(),
|
||||
localPositions = localPositions.GetNativeArray(),
|
||||
boneInfoList = boneInfoList,
|
||||
boneWeights = boneWeights.GetNativeArray(),
|
||||
};
|
||||
job.Run(VertexCount);
|
||||
#endif
|
||||
#if true
|
||||
// ボーン情報の構築
|
||||
using var boneInfoList = new NativeList<SkinningBoneInfo>(CustomSkinningBoneCount * 2, Allocator.Persistent);
|
||||
for (int i = 0; i < CustomSkinningBoneCount; i++)
|
||||
@ -1322,6 +1169,9 @@ namespace MagicaCloth2
|
||||
int tindex = customSkinningBoneIndices[i];
|
||||
if (tindex == -1)
|
||||
continue;
|
||||
|
||||
#if MC2_CUSTOM_SKINNING_V1
|
||||
// 旧
|
||||
int pid = bones[i].pid;
|
||||
if (pid == 0)
|
||||
continue;
|
||||
@ -1330,16 +1180,22 @@ namespace MagicaCloth2
|
||||
continue;
|
||||
|
||||
// ボーンライン情報の作成
|
||||
// localPositonはクロス空間での座標に変換済み
|
||||
var info = new SkinningBoneInfo();
|
||||
//info.transformIndex = customSkinningBoneIndices[pindex];
|
||||
info.startTransformIndex = customSkinningBoneIndices[pindex];
|
||||
info.startPos = bones[pindex].localPosition;
|
||||
info.endTransformIndex = tindex;
|
||||
info.endPos = bones[i].localPosition;
|
||||
info.parentTransformIndex = customSkinningBoneIndices[pindex];
|
||||
info.parentPos = bones[pindex].localPosition;
|
||||
info.childTransformIndex = tindex;
|
||||
info.childPos = bones[i].localPosition;
|
||||
|
||||
// 距離がほぼ0なら無効
|
||||
if (math.distance(info.startPos, info.endPos) < Define.System.Epsilon)
|
||||
if (math.distance(info.parentPos, info.childPos) < Define.System.Epsilon)
|
||||
continue;
|
||||
#else
|
||||
// V2
|
||||
var info = new SkinningBoneInfo();
|
||||
info.childTransformIndex = tindex;
|
||||
info.childPos = bones[i].localPosition;
|
||||
#endif
|
||||
|
||||
// 登録
|
||||
boneInfoList.Add(info);
|
||||
@ -1349,12 +1205,11 @@ namespace MagicaCloth2
|
||||
return;
|
||||
|
||||
// 頂点ごとにカスタムスキニングウエイトを算出
|
||||
#if MC2_CUSTOM_SKINNING_V1
|
||||
// 旧
|
||||
var job = new Proxy_CalcCustomSkinningWeightsJob()
|
||||
{
|
||||
isBoneCloth = isBoneCloth,
|
||||
//angularAttenuation = setting.angularAttenuation,
|
||||
//distanceReduction = setting.distanceReduction,
|
||||
//distancePow = setting.distancePow,
|
||||
angularAttenuation = Define.System.CustomSkinningAngularAttenuation,
|
||||
distanceReduction = Define.System.CustomSkinningDistanceReduction,
|
||||
distancePow = Define.System.CustomSkinningDistancePow,
|
||||
@ -1364,19 +1219,36 @@ namespace MagicaCloth2
|
||||
boneInfoList = boneInfoList,
|
||||
boneWeights = boneWeights.GetNativeArray(),
|
||||
};
|
||||
job.Run(VertexCount);
|
||||
#else
|
||||
// V2
|
||||
var job = new Proxy_CalcCustomSkinningWeightsJobV2()
|
||||
{
|
||||
isBoneCloth = isBoneCloth,
|
||||
angularAttenuation = Define.System.CustomSkinningAngularAttenuation,
|
||||
distanceReduction = Define.System.CustomSkinningDistanceReduction,
|
||||
distancePow = Define.System.CustomSkinningDistancePow,
|
||||
|
||||
attributes = attributes.GetNativeArray(),
|
||||
localPositions = localPositions.GetNativeArray(),
|
||||
boneInfoList = boneInfoList,
|
||||
boneWeights = boneWeights.GetNativeArray(),
|
||||
};
|
||||
#endif
|
||||
job.Run(VertexCount);
|
||||
}
|
||||
|
||||
#if false
|
||||
#if !MC2_CUSTOM_SKINNING_V1
|
||||
// V2
|
||||
[BurstCompile]
|
||||
struct Proxy_CalcCustomSkinningWeightsJob2 : IJobParallelFor
|
||||
struct Proxy_CalcCustomSkinningWeightsJobV2 : IJobParallelFor
|
||||
{
|
||||
public bool isBoneCloth;
|
||||
public float angularAttenuation;
|
||||
public float distanceReduction;
|
||||
public float distancePow;
|
||||
|
||||
//[Unity.Collections.ReadOnly]
|
||||
//public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<VertexAttribute> attributes;
|
||||
[Unity.Collections.ReadOnly]
|
||||
public NativeArray<float3> localPositions;
|
||||
[Unity.Collections.ReadOnly]
|
||||
@ -1384,12 +1256,12 @@ namespace MagicaCloth2
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<VirtualMeshBoneWeight> boneWeights;
|
||||
|
||||
// プロキシメッシュ頂点ごと
|
||||
public void Execute(int vindex)
|
||||
{
|
||||
// 固定は無効(※この時点ではまだ属性がない!)
|
||||
//var attr = attributes[vindex];
|
||||
//if (attr.IsMove() == false)
|
||||
// return;
|
||||
// 移動属性のみ
|
||||
if (attributes[vindex].IsDontMove())
|
||||
return;
|
||||
|
||||
var lpos = localPositions[vindex];
|
||||
|
||||
@ -1398,12 +1270,14 @@ namespace MagicaCloth2
|
||||
for (int i = 0; i < bcnt; i++)
|
||||
{
|
||||
var binfo = boneInfoList[i];
|
||||
var bpos = binfo.childPos;
|
||||
int boneIndex = binfo.childTransformIndex;
|
||||
|
||||
// 距離
|
||||
float dist = math.distance(lpos, binfo.startPos);
|
||||
var v = lpos - bpos;
|
||||
float dist = math.length(v);
|
||||
|
||||
// 登録。すでに登録済みならばdistがより小さい場合のみ再登録
|
||||
int boneIndex = binfo.transformIndex;
|
||||
int nowIndex = costList.indexOf(boneIndex);
|
||||
if (nowIndex >= 0)
|
||||
{
|
||||
@ -1417,34 +1291,44 @@ namespace MagicaCloth2
|
||||
costList.Add(dist, boneIndex);
|
||||
}
|
||||
|
||||
// ウエイト算出
|
||||
// (0)最小距離のn%を減算する
|
||||
// (1)最小距離のn%を減算する
|
||||
int cnt = costList.Count;
|
||||
//const float lengthWeight = 0.8f;
|
||||
float mindist = costList.MinCost * distanceReduction;
|
||||
costList.costs -= mindist;
|
||||
float mindist = costList.MinCost * distanceReduction; // 0.6
|
||||
for (int i = 0; i < cnt; i++)
|
||||
costList.costs[i] = costList.costs[i] - mindist;
|
||||
|
||||
// (1)distanceをn乗する
|
||||
//const float pow = 2.0f;
|
||||
costList.costs = math.pow(costList.costs, distancePow);
|
||||
// (2)distanceをn乗する
|
||||
for (int i = 0; i < cnt; i++)
|
||||
costList.costs[i] = math.pow(costList.costs[i], distancePow); // 2.0
|
||||
|
||||
// (2)最小値の逆数にする
|
||||
float min = math.max(costList.MinCost, 1e-06f);
|
||||
// ウエイト算出
|
||||
if (costList.MinCost < Define.System.Epsilon)
|
||||
{
|
||||
costList.costs = new float4(1, 0, 0, 0);
|
||||
costList.data = new int4(costList.data[0], 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// コストの逆数の合計
|
||||
cnt = costList.Count;
|
||||
float sum = 0;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
costList.costs[i] = min / costList.costs[i];
|
||||
sum += costList.costs[i];
|
||||
sum += 1.0f / costList.costs[i];
|
||||
}
|
||||
|
||||
// (3)割合を出す
|
||||
costList.costs /= sum;
|
||||
// 1.0fに正規化
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
costList.costs[i] = (1.0f / costList.costs[i]) / sum;
|
||||
}
|
||||
|
||||
// (4)極小のウエイトは削除する
|
||||
// 極小のウエイトは削除する
|
||||
const float InvalidWeight = 0.001f; // 0.1%
|
||||
sum = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (costList.costs[i] < 0.01f || i >= cnt)
|
||||
if (costList.costs[i] < InvalidWeight || i >= cnt)
|
||||
{
|
||||
// 打ち切り
|
||||
costList.costs[i] = 0.0f;
|
||||
@ -1456,20 +1340,18 @@ namespace MagicaCloth2
|
||||
}
|
||||
}
|
||||
Debug.Assert(sum > 0);
|
||||
|
||||
// (5)再度1.0に平均化
|
||||
costList.costs /= sum;
|
||||
|
||||
costList.costs /= sum; // 再度1.0正規化
|
||||
}
|
||||
//Debug.Log($"[{vindex}] :{costList}");
|
||||
|
||||
// ウエイト作成
|
||||
// ウエイト構造体に変換して格納
|
||||
var bw = new VirtualMeshBoneWeight(costList.data, costList.costs);
|
||||
boneWeights[vindex] = bw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if true
|
||||
#if MC2_CUSTOM_SKINNING_V1
|
||||
[BurstCompile]
|
||||
struct Proxy_CalcCustomSkinningWeightsJob : IJobParallelFor
|
||||
{
|
||||
@ -1487,7 +1369,7 @@ namespace MagicaCloth2
|
||||
[Unity.Collections.WriteOnly]
|
||||
public NativeArray<VirtualMeshBoneWeight> boneWeights;
|
||||
|
||||
|
||||
// プロキシメッシュ頂点ごと
|
||||
public void Execute(int vindex)
|
||||
{
|
||||
// BoneClothカスタムスキニングでは固定は動かさない
|
||||
@ -1501,21 +1383,21 @@ namespace MagicaCloth2
|
||||
for (int i = 0; i < bcnt; i++)
|
||||
{
|
||||
var binfo = boneInfoList[i];
|
||||
float3 d = MathUtility.ClosestPtPointSegment(lpos, binfo.startPos, binfo.endPos);
|
||||
float3 d = MathUtility.ClosestPtPointSegment(lpos, binfo.parentPos, binfo.childPos);
|
||||
//float dist = math.distance(lpos, d);
|
||||
|
||||
// ボーンラインとの角度により判定距離を調整する
|
||||
// ラインと水平になるほど影響がよわくなる
|
||||
var v = lpos - d;
|
||||
var bv = binfo.endPos - binfo.startPos;
|
||||
var bv = binfo.childPos - binfo.parentPos;
|
||||
float dot = math.dot(math.normalize(v), math.normalize(bv));
|
||||
float ratio = 1.0f + math.abs(dot) * angularAttenuation;
|
||||
float ratio = 1.0f + math.abs(dot) * angularAttenuation; // 1.0
|
||||
|
||||
// 登録。すでに登録済みならばdistがより小さい場合のみ再登録
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
int boneIndex = j == 0 ? binfo.startTransformIndex : binfo.endTransformIndex;
|
||||
float dist = j == 0 ? math.distance(lpos, binfo.startPos) : math.distance(lpos, binfo.endPos);
|
||||
int boneIndex = j == 0 ? binfo.parentTransformIndex : binfo.childTransformIndex;
|
||||
float dist = j == 0 ? math.distance(lpos, binfo.parentPos) : math.distance(lpos, binfo.childPos);
|
||||
dist *= ratio;
|
||||
|
||||
int nowIndex = costList.indexOf(boneIndex);
|
||||
@ -1535,11 +1417,11 @@ namespace MagicaCloth2
|
||||
// ウエイト算出
|
||||
// (0)最小距離のn%を減算する
|
||||
int cnt = costList.Count;
|
||||
float mindist = costList.MinCost * distanceReduction;
|
||||
float mindist = costList.MinCost * distanceReduction; // 0.6
|
||||
costList.costs -= mindist;
|
||||
|
||||
// (1)distanceをn乗する
|
||||
costList.costs = math.pow(costList.costs, distancePow);
|
||||
costList.costs = math.pow(costList.costs, distancePow); // 2.0
|
||||
|
||||
// (2)最小値の逆数にする
|
||||
float min = math.max(costList.MinCost, 1e-06f);
|
||||
@ -1950,7 +1832,7 @@ namespace MagicaCloth2
|
||||
int pindex = vertexParentIndices[vindex];
|
||||
if (pindex >= 0)
|
||||
{
|
||||
vertexChildMap.UniqueAdd(pindex, (ushort)vindex);
|
||||
vertexChildMap.MC2UniqueAdd(pindex, (ushort)vindex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2261,16 +2143,21 @@ namespace MagicaCloth2
|
||||
float3 tan = localTangents[vindex];
|
||||
quaternion rot = MathUtility.ToRotation(nor, tan);
|
||||
|
||||
|
||||
float3 lpos = math.mul(iprot, pos - ppos);
|
||||
quaternion lrot = math.mul(iprot, rot);
|
||||
vertexLocalPositions[vindex] = lpos;
|
||||
vertexLocalRotations[vindex] = lrot;
|
||||
|
||||
//Debug.Log($"vertexLocalPositions [{vindex}] : {lpos}");
|
||||
//Debug.Log($"vertexLocalRotations [{vindex}] : {lrot}");
|
||||
}
|
||||
else
|
||||
{
|
||||
vertexLocalPositions[vindex] = 0;
|
||||
vertexLocalRotations[vindex] = quaternion.identity;
|
||||
|
||||
//Debug.Log($"vertexLocalPositions [{vindex}] : 0");
|
||||
//Debug.Log($"vertexLocalRotations [{vindex}] : (0, 0, 0, 1)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2379,7 +2266,7 @@ namespace MagicaCloth2
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
#if false // pitch/yaw個別制限はv1.0では実装しないので一旦ん停止
|
||||
#if false // pitch/yaw個別制限はv1.0では実装しないので一旦停止
|
||||
/// <summary>
|
||||
/// 角度制限計算用ローカル回転の算出
|
||||
/// </summary>
|
||||
|
||||
@ -48,7 +48,7 @@ namespace MagicaCloth2
|
||||
float sameDistance = maxSideLength * math.saturate(Define.System.ReductionSameDistance);
|
||||
float simpleDistance = maxSideLength * math.saturate(settings.simpleDistance);
|
||||
float shapeDistance = maxSideLength * math.saturate(settings.shapeDistance);
|
||||
//Develop.DebugLog($"ReductionDista. maxSideLength:{maxSideLength}, same:{sameDistance}, simple:{simpleDistance}, shape:{shapeDistance}");
|
||||
Develop.DebugLog($"ReductionDista. maxSideLength:{maxSideLength}, same:{sameDistance}, simple:{simpleDistance}, shape:{shapeDistance}");
|
||||
|
||||
// 同一距離リダクション
|
||||
ct.ThrowIfCancellationRequested();
|
||||
@ -659,7 +659,7 @@ namespace MagicaCloth2
|
||||
{
|
||||
int newIndex2 = vertexRemapIndices[oldVertexIndex];
|
||||
//Debug.Assert(newIndex != newIndex2);
|
||||
newVertexToVertexMap.UniqueAdd((ushort)newIndex, (ushort)newIndex2);
|
||||
newVertexToVertexMap.MC2UniqueAdd((ushort)newIndex, (ushort)newIndex2);
|
||||
}
|
||||
|
||||
//Debug.Log($"[{newIndex}] cnt:{newVertexToVertexMap.CountValuesForKey((ushort)newIndex)}");
|
||||
@ -764,7 +764,7 @@ namespace MagicaCloth2
|
||||
if (vindex == edge.x || vindex == edge.y)
|
||||
continue;
|
||||
|
||||
if (newVertexToVertexMap.Contains((ushort)edge.y, vindex))
|
||||
if (newVertexToVertexMap.MC2Contains((ushort)edge.y, vindex))
|
||||
{
|
||||
// トライアングル生成
|
||||
int3 tri = DataUtility.PackInt3(edge.x, edge.y, vindex);
|
||||
|
||||
@ -14,7 +14,7 @@ namespace MagicaCloth2
|
||||
{
|
||||
//=========================================================================================
|
||||
/// <summary>
|
||||
/// 頂点間の平均/最大距離を調べてる(スレッド可)
|
||||
/// 頂点間の平均/最大距離を調べる(スレッド可)
|
||||
/// 結果はaverageVertexDistance/maxVertexDistanceに格納される
|
||||
/// </summary>
|
||||
internal void CalcAverageAndMaxVertexDistanceRun()
|
||||
|
||||
@ -22,6 +22,8 @@ namespace MagicaCloth2
|
||||
|
||||
public ResultCode result = new ResultCode();
|
||||
|
||||
public bool isManaged; // PreBuild DeserializeManager管理
|
||||
|
||||
/// <summary>
|
||||
/// メッシュタイプ
|
||||
/// </summary>
|
||||
@ -360,26 +362,34 @@ namespace MagicaCloth2
|
||||
public int mappingId;
|
||||
|
||||
//=========================================================================================
|
||||
public VirtualMesh()
|
||||
public VirtualMesh() { }
|
||||
|
||||
public VirtualMesh(bool initialize)
|
||||
{
|
||||
transformData = new TransformData();
|
||||
if (initialize)
|
||||
{
|
||||
transformData = new TransformData(100);
|
||||
|
||||
// 最小限のデータ
|
||||
averageVertexDistance = new NativeReference<float>(0.0f, Allocator.Persistent);
|
||||
maxVertexDistance = new NativeReference<float>(0.0f, Allocator.Persistent);
|
||||
|
||||
|
||||
// 作業中にしておく
|
||||
result.SetProcess();
|
||||
}
|
||||
}
|
||||
|
||||
public VirtualMesh(string name) : this()
|
||||
public VirtualMesh(string name) : this(true)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// PreBuild DeserializeManager管理中は破棄させない
|
||||
if (isManaged)
|
||||
return;
|
||||
|
||||
result.Clear();
|
||||
referenceIndices.Dispose();
|
||||
attributes.Dispose();
|
||||
@ -471,7 +481,8 @@ namespace MagicaCloth2
|
||||
return false;
|
||||
|
||||
// レンダラーが存在する場合はその存在を確認する
|
||||
if (centerTransformIndex >= 0 && transformData.GetTransformFromIndex(centerTransformIndex) == null)
|
||||
// ただしPreBuildではtransformListは空なのでスキップする
|
||||
if (centerTransformIndex >= 0 && transformData.IsEmpty == false && transformData.GetTransformFromIndex(centerTransformIndex) == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -483,23 +494,38 @@ namespace MagicaCloth2
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine($"===== {name} =====");
|
||||
sb.Append($"Result:{result}");
|
||||
sb.Append($", Type:{meshType}");
|
||||
sb.Append($", Vertex:{VertexCount}");
|
||||
sb.Append($", Line:{LineCount}");
|
||||
sb.Append($", Triangle:{TriangleCount}");
|
||||
sb.Append($", Edge:{EdgeCount}");
|
||||
sb.Append($", SkinBone:{SkinBoneCount}");
|
||||
sb.Append($", Transform:{transformData?.Count}");
|
||||
sb.Append($", BaseLine:{BaseLineCount}");
|
||||
sb.AppendLine($"Result:{result.GetResultString()}");
|
||||
sb.AppendLine($"Type:{meshType}");
|
||||
sb.AppendLine($"Vertex:{VertexCount}");
|
||||
sb.AppendLine($"Line:{LineCount}");
|
||||
sb.AppendLine($"Triangle:{TriangleCount}");
|
||||
sb.AppendLine($"Edge:{EdgeCount}");
|
||||
sb.AppendLine($"SkinBone:{SkinBoneCount}");
|
||||
sb.AppendLine($"Transform:{TransformCount}");
|
||||
if (averageVertexDistance.IsCreated)
|
||||
sb.AppendLine($"avgDist:{averageVertexDistance.Value}");
|
||||
if (maxVertexDistance.IsCreated)
|
||||
sb.AppendLine($"maxDist:{maxVertexDistance.Value}");
|
||||
if (boundingBox.IsCreated)
|
||||
sb.AppendLine($"AABB:{boundingBox.Value}");
|
||||
sb.AppendLine();
|
||||
|
||||
if (averageVertexDistance.IsCreated)
|
||||
sb.Append($"avgDist:{averageVertexDistance.Value}");
|
||||
if (maxVertexDistance.IsCreated)
|
||||
sb.Append($", maxDist:{maxVertexDistance.Value}");
|
||||
if (boundingBox.IsCreated)
|
||||
sb.Append($", AABB:{boundingBox.Value}");
|
||||
sb.AppendLine($"<<< Proxy >>>");
|
||||
sb.AppendLine($"BaseLine:{BaseLineCount}");
|
||||
sb.AppendLine($"EdgeCount:{EdgeCount}");
|
||||
int edgeToTrianglesCnt = edgeToTriangles.IsCreated ? edgeToTriangles.Count() : 0;
|
||||
sb.AppendLine($"edgeToTriangles:{edgeToTrianglesCnt}");
|
||||
sb.AppendLine($"CustomSkinningBoneCount:{CustomSkinningBoneCount}");
|
||||
sb.AppendLine($"CenterFixedPointCount:{CenterFixedPointCount}");
|
||||
sb.AppendLine($"NormalAdjustmentRotationCount:{NormalAdjustmentRotationCount}");
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendLine($"<<< Mapping >>>");
|
||||
sb.AppendLine($"centerWorldPosition:{centerWorldPosition}");
|
||||
sb.AppendLine();
|
||||
|
||||
//sb.AppendLine($"<<< TransformData >>>");
|
||||
sb.AppendLine(transformData?.ToString() ?? "(none)");
|
||||
sb.AppendLine();
|
||||
|
||||
return sb.ToString();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user