ADD: 야모스크립트 업데이트

This commit is contained in:
Yamo4490 2025-05-15 00:19:38 +09:00
parent 493a9c6273
commit 9e18ee5baf
73 changed files with 7456 additions and 212 deletions

View File

@ -0,0 +1,25 @@
{
"name": "MagicaCloth2Example",
"rootNamespace": "",
"references": [
"MagicaClothV2",
"Unity.InputSystem"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [
"MAGICACLOTH2"
],
"versionDefines": [
{
"name": "com.unity.inputsystem",
"expression": "1.0.0",
"define": "MC2_INPUTSYSTEM"
}
],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5bc0ea054e216f5498d1a84885db7ab1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,196 @@
// Magica Cloth 2.
// Copyright (c) 2025 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
#if MC2_INPUTSYSTEM
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.EnhancedTouch;
#endif
namespace MagicaCloth2
{
/// <summary>
/// InputManager/InputSystem入力切り替えラッパー
/// </summary>
public class SimpleInput
{
#if MC2_INPUTSYSTEM
// (New) Imput System
public static void Init()
{
EnhancedTouchSupport.Enable();
}
public static int touchCount
{
get
{
return UnityEngine.InputSystem.EnhancedTouch.Touch.activeTouches.Count;
}
}
public static UnityEngine.Touch GetTouch(int index)
{
var touchData = new UnityEngine.Touch();
int count = UnityEngine.InputSystem.EnhancedTouch.Touch.activeTouches.Count;
if (index < count)
{
var touch = UnityEngine.InputSystem.EnhancedTouch.Touch.activeTouches[index];
// convert
touchData.fingerId = touch.finger.index;
touchData.position = touch.screenPosition;
touchData.deltaPosition = touch.delta;
switch (touch.phase)
{
case UnityEngine.InputSystem.TouchPhase.Canceled:
touchData.phase = UnityEngine.TouchPhase.Canceled;
break;
case UnityEngine.InputSystem.TouchPhase.Ended:
touchData.phase = UnityEngine.TouchPhase.Ended;
break;
case UnityEngine.InputSystem.TouchPhase.Moved:
touchData.phase = UnityEngine.TouchPhase.Moved;
break;
case UnityEngine.InputSystem.TouchPhase.Began:
touchData.phase = UnityEngine.TouchPhase.Began;
break;
}
}
return touchData;
}
public static bool GetKey(KeyCode key)
{
switch (key)
{
case KeyCode.Escape:
return Keyboard.current.escapeKey.isPressed;
default:
return false;
}
}
public static bool GetKeyDown(KeyCode key)
{
switch (key)
{
case KeyCode.Backspace:
return Keyboard.current.backspaceKey.wasPressedThisFrame;
default:
return false;
}
}
public static bool GetMouseButtonDown(int button)
{
switch (button)
{
case 0:
return Mouse.current.leftButton.wasPressedThisFrame;
case 1:
return Mouse.current.rightButton.wasPressedThisFrame;
case 2:
return Mouse.current.middleButton.wasPressedThisFrame;
default:
return false;
}
}
public static bool GetMouseButtonUp(int button)
{
switch (button)
{
case 0:
return Mouse.current.leftButton.wasReleasedThisFrame;
case 1:
return Mouse.current.rightButton.wasReleasedThisFrame;
case 2:
return Mouse.current.middleButton.wasReleasedThisFrame;
default:
return false;
}
}
public static Vector3 mousePosition
{
get
{
return Mouse.current.position.ReadValue();
}
}
public static float GetMouseScrollWheel()
{
// 古いInputSystemに不具合あり
// ホイールデルタがデフォルトでx120されて返ってくる
// これはWindowsのみの挙動でMac/Linuxでは発生しない
// そしてUnity 2023.2以降は修正された
float value = Mouse.current.scroll.ReadValue().y * 0.12f; // base
#if UNITY_2023_2_OR_NEWER
return value;
#else
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
return value / 120.0f; // ホイールデルタの不具合を吸収
#else
return value;
#endif
#endif
}
#else
// (Old) Imput Manager
public static void Init()
{
}
public static int touchCount
{
get
{
return Input.touchCount;
}
}
public static Touch GetTouch(int index)
{
return Input.GetTouch(index);
}
public static bool GetKey(KeyCode key)
{
return Input.GetKey(key);
}
public static bool GetKeyDown(KeyCode key)
{
return Input.GetKeyDown(key);
}
public static bool GetMouseButtonDown(int button)
{
return Input.GetMouseButtonDown(button);
}
public static bool GetMouseButtonUp(int button)
{
return Input.GetMouseButtonUp(button);
}
public static Vector3 mousePosition
{
get
{
return Input.mousePosition;
}
}
public static float GetMouseScrollWheel()
{
return Input.GetAxis("Mouse ScrollWheel");
}
#endif
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 9334313e83f924348a48a1da0b4c1cb9
guid: ab72fcfec8965ae4181307a06400b57b
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c5abe9243ed7c7545bfe1ccdbaa8c8b7
guid: 20f694a56cb3ba842b35402189c3b2f6
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 0c4999626de3e0d4692c31a1511fec66
guid: 098d9df8397d80f45baed0214420d1cf
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8a0637df5c1ee8a4d8d6c5d2f3807cde
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 30700d501f109174891f340ae1fc1833
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ca2d4f8e19e54d642bbc386701570fd4
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8ef5d38bbe84ef44cb76386cf579b78d
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ee41de38686ef9b439643dd695fd9f9d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9d96bb6c1a7bbf14b95fba198bd36558
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 01f984873de94d845a6f0dad6e1764ce
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 54b38eb7d538c7f44b7fd7a9df0478d3
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 44a8005bc0be2894fb5f7cec86f3eeae
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/External/MagicaCloth2/Res/Preset/MC2_Preset_SoftSkirt.json (Stored with Git LFS) vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 95115815f2f656045acda9f116a05915
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,211 @@
// Magica Cloth 2.
// Copyright (c) 2025 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// 初期化データ
/// </summary>
[System.Serializable]
public class ClothInitSerializeData : ITransform
{
public const int InitDataVersion = 2;
public int initVersion;
public int localHash;
public int globalHash;
public ClothProcess.ClothType clothType;
public TransformRecordSerializeData clothTransformRecord;
public TransformRecordSerializeData normalAdjustmentTransformRecord;
public List<TransformRecordSerializeData> customSkinningBoneRecords;
public List<RenderSetupSerializeData> clothSetupDataList;
public bool HasData()
{
if (initVersion == 0)
return false;
if (localHash == 0 || globalHash == 0)
return false;
return true;
}
public void Clear()
{
initVersion = 0;
localHash = 0;
globalHash = 0;
clothType = ClothProcess.ClothType.MeshCloth;
clothTransformRecord = new TransformRecordSerializeData();
normalAdjustmentTransformRecord = new TransformRecordSerializeData();
customSkinningBoneRecords = new List<TransformRecordSerializeData>();
clothSetupDataList = new List<RenderSetupSerializeData>();
}
public ResultCode DataValidate(ClothProcess cprocess)
{
if (localHash == 0 || globalHash == 0)
return new ResultCode(Define.Result.InitSerializeData_InvalidHash);
if (initVersion == 0)
return new ResultCode(Define.Result.InitSerializeData_InvalidVersion);
if (clothSetupDataList == null || clothSetupDataList.Count == 0)
return new ResultCode(Define.Result.InitSerializeData_InvalidSetupData);
var cloth = cprocess.cloth;
var sdata = cloth.SerializeData;
if (clothType != sdata.clothType)
return new ResultCode(Define.Result.InitSerializeData_ClothTypeMismatch);
if (clothType == ClothProcess.ClothType.MeshCloth)
{
int rendererCount = sdata.sourceRenderers.Count;
if (clothSetupDataList.Count != rendererCount)
return new ResultCode(Define.Result.InitSerializeData_SetupCountMismatch);
// 各レンダラー情報の検証
for (int i = 0; i < rendererCount; i++)
{
if (clothSetupDataList[i].DataValidateMeshCloth(sdata.sourceRenderers[i]) == false)
return new ResultCode(Define.Result.InitSerializeData_MeshClothSetupValidationError);
}
}
else if (clothType == ClothProcess.ClothType.BoneCloth)
{
if (clothSetupDataList.Count != 1)
return new ResultCode(Define.Result.InitSerializeData_SetupCountMismatch);
if (clothSetupDataList[0].DataValidateBoneCloth(sdata, RenderSetupData.SetupType.BoneCloth) == false)
return new ResultCode(Define.Result.InitSerializeData_BoneClothSetupValidationError);
}
else if (clothType == ClothProcess.ClothType.BoneSpring)
{
if (clothSetupDataList.Count != 1)
return new ResultCode(Define.Result.InitSerializeData_SetupCountMismatch);
if (clothSetupDataList[0].DataValidateBoneCloth(sdata, RenderSetupData.SetupType.BoneSpring) == false)
return new ResultCode(Define.Result.InitSerializeData_BoneSpringSetupValidationError);
}
// カスタムスキニングボーン
if (sdata.customSkinningSetting.skinningBones.Count != customSkinningBoneRecords.Count)
return new ResultCode(Define.Result.InitSerializeData_CustomSkinningBoneCountMismatch);
// V1かつMeshClothかつSkinnedMeshRendererの場合のみ、(Clone)メッシュ利用時は無効とする
// これは(Clone)メッシュを再度加工することによりボーンウエイトなどのデータがおかしくなりエラーが発生するため
if (initVersion <= 1 && clothType == ClothProcess.ClothType.MeshCloth)
{
for (int i = 0; i < sdata.sourceRenderers.Count; i++)
{
SkinnedMeshRenderer sren = sdata.sourceRenderers[i] as SkinnedMeshRenderer;
if (sren && sren.sharedMesh && sren.sharedMesh.name.Contains("(Clone)"))
{
return new ResultCode(Define.Result.InitSerializeData_InvalidCloneMesh);
}
}
}
return ResultCode.Success;
}
public bool Serialize(
ClothSerializeData sdata,
TransformRecord clothTransformRecord,
TransformRecord normalAdjustmentTransformRecord,
List<RenderSetupData> setupList
)
{
initVersion = InitDataVersion; // version
clothType = sdata.clothType;
this.clothTransformRecord = new TransformRecordSerializeData();
this.clothTransformRecord.Serialize(clothTransformRecord);
this.normalAdjustmentTransformRecord = new TransformRecordSerializeData();
this.normalAdjustmentTransformRecord.Serialize(normalAdjustmentTransformRecord);
// カスタムスキニングボーン
customSkinningBoneRecords = new List<TransformRecordSerializeData>();
int bcnt = sdata.customSkinningSetting.skinningBones.Count;
for (int i = 0; i < bcnt; i++)
{
var tr = new TransformRecord(sdata.customSkinningSetting.skinningBones[i], read: true);
var trs = new TransformRecordSerializeData();
trs.Serialize(tr);
customSkinningBoneRecords.Add(trs);
}
// setup data
clothSetupDataList = new List<RenderSetupSerializeData>();
if (setupList != null && setupList.Count > 0)
{
foreach (var setup in setupList)
{
var meshSetupData = new RenderSetupSerializeData();
meshSetupData.Serialize(setup);
clothSetupDataList.Add(meshSetupData);
}
}
localHash = GetLocalHash();
globalHash = GetGlobalHash();
return true;
}
public void GetUsedTransform(HashSet<Transform> transformSet)
{
clothTransformRecord?.GetUsedTransform(transformSet);
normalAdjustmentTransformRecord?.GetUsedTransform(transformSet);
customSkinningBoneRecords?.ForEach(x => x.GetUsedTransform(transformSet));
clothSetupDataList?.ForEach(x => x.GetUsedTransform(transformSet));
}
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
{
clothTransformRecord?.ReplaceTransform(replaceDict);
normalAdjustmentTransformRecord?.ReplaceTransform(replaceDict);
customSkinningBoneRecords?.ForEach(x => x.ReplaceTransform(replaceDict));
clothSetupDataList?.ForEach(x => x.ReplaceTransform(replaceDict));
}
int GetLocalHash()
{
// ローカルハッシュ
// ・編集用メッシュが再構築されるたびにこのハッシュで保存チェックされる
// ・各種カウント+配列数
// ・Transformの姿勢は無視する。ただし階層構造の変更は見る
int hash = 0;
hash += initVersion * 9876;
hash += (int)clothType * 5656;
hash += clothTransformRecord?.GetLocalHash() ?? 0;
hash += normalAdjustmentTransformRecord?.GetLocalHash() ?? 0;
customSkinningBoneRecords?.ForEach(x => hash += x?.GetLocalHash() ?? 0);
clothSetupDataList?.ForEach(x => hash += x?.GetLocalHash() ?? 0);
return hash;
}
int GetGlobalHash()
{
// グローバルハッシュ
// ・頂点ペイント終了時にこのハッシュで保存チェックされる
// ・保存チェックにはローカルハッシュも含まれる
// ・Transformのローカル姿勢を見る(localPosition/localRotation/localScale)
// ・ただしSetupDataのinitRenderScaleのみワールドスケールをチェックする
int hash = 0;
hash += clothTransformRecord?.GetGlobalHash() ?? 0;
hash += normalAdjustmentTransformRecord?.GetGlobalHash() ?? 0;
customSkinningBoneRecords?.ForEach(x => hash += x?.GetGlobalHash() ?? 0);
clothSetupDataList?.ForEach(x => hash += x?.GetGlobalHash() ?? 0);
return hash;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 893eb3d42574b394d82065f5781ac45f
guid: 87cb8cdfb6686334d904a1e0c0536944
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -0,0 +1,25 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
namespace MagicaCloth2
{
/// <summary>
/// メッシュへの書き込み対象
/// Write target to mesh.
/// </summary>
public enum ClothMeshWriteMode
{
/// <summary>
/// 位置と法線
/// Position, Normal
/// </summary>
PositionAndNormal = 0,
/// <summary>
/// 位置と法線と接線
/// Position, Normal, Tangent
/// </summary>
PositionAndNormalTangent = 1,
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c89429b06b0fde045af1104d0fe4d6b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,52 @@
// Magica Cloth 2.
// Copyright (c) 2025 MagicaSoft.
// https://magicasoft.jp
namespace MagicaCloth2
{
/// <summary>
/// シンメトリーモード
/// Symmetry mode.
/// </summary>
public enum ColliderSymmetryMode
{
None = 0,
/// <summary>
/// 人体の骨格を参照しすべて自動設定する
/// キャラクターにAnimatorコンポーネントが必要です
/// Automatically set everything based on the human skeleton.
/// Character must have an Animator component.
/// </summary>
AutomaticHumanBody = 1,
/// <summary>
/// SymmetryTargetの姿勢から自動設定します
/// Automatically set based on the SymmetryTarget's posture.
/// </summary>
AutomaticTarget = 2,
/// <summary>
/// X軸を左右対称
/// Symmetry on the X axis.
/// </summary>
X_Symmetry = 100,
/// <summary>
/// Y軸を左右対称
/// Symmetry on the Y axis.
/// </summary>
Y_Symmetry = 101,
/// <summary>
/// Z軸を左右対称
/// Symmetry on the Z axis.
/// </summary>
Z_Symmetry = 102,
/// <summary>
/// XYZ軸を左右対称
/// Symmetry on the XYZ axis.
/// </summary>
XYZ_Symmetry = 200,
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02f9b444838ae8a41916aab95109474e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,130 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// プロパティをアニメーションから制御するためのラッパー.
/// Wrapper for controlling properties from animation.
/// </summary>
public partial class MagicaCloth
{
[HideInInspector]
public float animationPoseRatioProperty;
float _animationPoseRatioProperty;
[HideInInspector]
public float gravityProperty;
float _gravityProperty;
[HideInInspector]
public float dampingProperty;
float _dampingProperty;
[HideInInspector]
public float worldInertiaProperty;
float _worldInertiaProperty;
[HideInInspector]
public float localInertiaProperty;
float _localInertiaProperty;
[HideInInspector]
public float windInfluenceProperty;
float _windInfluenceProperty;
[HideInInspector]
public float blendWeightProperty;
float _blendWeightProperty;
//=========================================================================================
internal void InitAnimationProperty()
{
animationPoseRatioProperty = serializeData.animationPoseRatio;
_animationPoseRatioProperty = animationPoseRatioProperty;
gravityProperty = serializeData.gravity;
_gravityProperty = gravityProperty;
dampingProperty = serializeData.damping.value;
_dampingProperty = dampingProperty;
worldInertiaProperty = serializeData.inertiaConstraint.worldInertia;
_worldInertiaProperty = worldInertiaProperty;
localInertiaProperty = serializeData.inertiaConstraint.localInertia;
_localInertiaProperty = localInertiaProperty;
windInfluenceProperty = serializeData.wind.influence;
_windInfluenceProperty = windInfluenceProperty;
blendWeightProperty = serializeData.blendWeight;
_blendWeightProperty = blendWeightProperty;
}
/// <summary>
/// アニメーションによりMagicaClothのプロパティが変更されたときに呼び出される.
/// Called when a property of MagicaCloth changes due to animation.
/// </summary>
void OnDidApplyAnimationProperties()
{
if (Application.isPlaying)
{
//Debug.Log($"Animated property changes. F:{Time.frameCount}");
if (animationPoseRatioProperty != _animationPoseRatioProperty)
{
_animationPoseRatioProperty = animationPoseRatioProperty;
serializeData.animationPoseRatio = animationPoseRatioProperty;
SetParameterChange();
}
if (gravityProperty != _gravityProperty)
{
_gravityProperty = gravityProperty;
serializeData.gravity = gravityProperty;
SetParameterChange();
}
if (dampingProperty != _dampingProperty)
{
_dampingProperty = dampingProperty;
serializeData.damping.value = dampingProperty;
SetParameterChange();
}
if (worldInertiaProperty != _worldInertiaProperty)
{
_worldInertiaProperty = worldInertiaProperty;
serializeData.inertiaConstraint.worldInertia = worldInertiaProperty;
SetParameterChange();
}
if (localInertiaProperty != _localInertiaProperty)
{
_localInertiaProperty = localInertiaProperty;
serializeData.inertiaConstraint.localInertia = localInertiaProperty;
SetParameterChange();
}
if (windInfluenceProperty != _windInfluenceProperty)
{
_windInfluenceProperty = windInfluenceProperty;
serializeData.wind.influence = windInfluenceProperty;
SetParameterChange();
}
if (blendWeightProperty != _blendWeightProperty)
{
_blendWeightProperty = blendWeightProperty;
serializeData.blendWeight = blendWeightProperty;
SetParameterChange();
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fea7c53425d793a44b3d484072c68bde
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,301 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using System.Collections.Generic;
using System.Text;
using Unity.Profiling;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// PreBuildの管理マネージャ
/// </summary>
public class PreBuildManager : IManager, IValid
{
/// <summary>
/// 共有ビルドデータの復元データ
/// </summary>
internal class ShareDeserializationData : IDisposable
{
internal string buildId;
internal ResultCode result;
internal int referenceCount;
internal List<RenderSetupData> renderSetupDataList = new List<RenderSetupData>();
internal VirtualMesh proxyMesh = null;
internal List<VirtualMesh> renderMeshList = new List<VirtualMesh>();
internal DistanceConstraint.ConstraintData distanceConstraintData;
internal TriangleBendingConstraint.ConstraintData bendingConstraintData;
internal InertiaConstraint.ConstraintData inertiaConstraintData;
public void Dispose()
{
foreach (var data in renderSetupDataList)
{
if (data != null)
{
data.isManaged = false;
data.Dispose();
}
}
renderSetupDataList.Clear();
if (proxyMesh != null)
{
proxyMesh.isManaged = false;
proxyMesh.Dispose();
proxyMesh = null;
}
foreach (var rmesh in renderMeshList)
{
if (rmesh != null)
{
rmesh.isManaged = false;
rmesh.Dispose();
}
}
renderMeshList.Clear();
distanceConstraintData = null;
bendingConstraintData = null;
inertiaConstraintData = null;
buildId = string.Empty;
result.Clear();
referenceCount = 0;
}
public void Deserialize(SharePreBuildData sharePreBuilddata)
{
result.SetProcess();
try
{
// データ検証
var validataResult = sharePreBuilddata.DataValidate();
if (validataResult.IsFaild())
{
result.Merge(validataResult);
throw new MagicaClothProcessingException();
}
// Deserialize
foreach (var sdata in sharePreBuilddata.renderSetupDataList)
{
renderSetupDataList.Add(RenderSetupData.ShareDeserialize(sdata));
}
proxyMesh = VirtualMesh.ShareDeserialize(sharePreBuilddata.proxyMesh);
foreach (var sdata in sharePreBuilddata.renderMeshList)
{
renderMeshList.Add(VirtualMesh.ShareDeserialize(sdata));
}
distanceConstraintData = sharePreBuilddata.distanceConstraintData;
bendingConstraintData = sharePreBuilddata.bendingConstraintData;
inertiaConstraintData = sharePreBuilddata.inertiaConstraintData;
result.SetSuccess();
}
catch (MagicaClothProcessingException)
{
}
catch (Exception exception)
{
Debug.LogException(exception);
result.SetError(Define.Result.Deserialization_Exception);
}
}
public int RenderMeshCount => renderMeshList?.Count ?? 0;
public VirtualMeshContainer GetProxyMeshContainer()
{
return new VirtualMeshContainer()
{
shareVirtualMesh = proxyMesh,
uniqueData = null,
};
}
public VirtualMeshContainer GetRenderMeshContainer(int index)
{
if (index >= RenderMeshCount)
return null;
return new VirtualMeshContainer()
{
shareVirtualMesh = renderMeshList[index],
uniqueData = null,
};
}
}
Dictionary<SharePreBuildData, ShareDeserializationData> deserializationDict = new Dictionary<SharePreBuildData, ShareDeserializationData>();
bool isValid = false;
//=========================================================================================
public void Dispose()
{
foreach (var kv in deserializationDict)
{
kv.Value.Dispose();
}
deserializationDict.Clear();
isValid = false;
}
public void EnterdEditMode()
{
Dispose();
}
public void Initialize()
{
isValid = true;
}
public bool IsValid()
{
return isValid;
}
public void InformationLog(StringBuilder allsb)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"========== PreBuild Manager ==========");
if (IsValid() == false)
{
sb.AppendLine($"PreBuild Manager. Invalid.");
}
else
{
int cnt = deserializationDict.Count;
sb.AppendLine($"Count:{cnt}");
foreach (var kv in deserializationDict)
{
sb.AppendLine($"[{kv.Key.buildId}] refcnt:{kv.Value.referenceCount}, result:{kv.Value.result.GetResultString()}, proxyMesh:{kv.Value.proxyMesh != null}");
}
}
sb.AppendLine();
Debug.Log(sb.ToString());
allsb.Append(sb);
}
//=========================================================================================
static readonly ProfilerMarker deserializationProfiler = new ProfilerMarker("PreBuild.Deserialization");
/// <summary>
/// PreBuildDataをデシリアライズし登録する
/// すでに登録されていた場合は参照カウンタを加算する
/// </summary>
/// <param name="sdata"></param>
/// <param name="referenceIncrement"></param>
/// <returns></returns>
internal ShareDeserializationData RegisterPreBuildData(SharePreBuildData sdata, bool referenceIncrement)
{
if (isValid == false)
return null;
if (sdata == null)
return null;
if (deserializationDict.ContainsKey(sdata) == false)
{
deserializationProfiler.Begin();
//var span = new TimeSpan($"Deserialization [{sdata.buildId}]");
// new
var data = new ShareDeserializationData();
data.buildId = sdata.buildId;
data.Deserialize(sdata);
deserializationDict.Add(sdata, data);
deserializationProfiler.End();
//span.Log();
Develop.DebugLog($"RegisterPreBuildData.Deserialize [{sdata.buildId}] F:{Time.frameCount}");
}
var ddata = deserializationDict[sdata];
// reference counter
if (referenceIncrement)
ddata.referenceCount++;
Develop.DebugLog($"RegisterPreBuildData [{sdata.buildId}] C:{ddata.referenceCount} F:{Time.frameCount}");
return ddata;
}
internal ShareDeserializationData GetPreBuildData(SharePreBuildData sdata)
{
if (sdata == null)
return null;
if (deserializationDict.ContainsKey(sdata))
return deserializationDict[sdata];
return null;
}
/// <summary>
/// PreBuildDataのデシリアライズデータを解除する
/// 参照カウンタが0でも破棄はしない
/// </summary>
/// <param name="sdata"></param>
internal void UnregisterPreBuildData(SharePreBuildData sdata)
{
if (isValid == false)
return;
if (sdata == null)
return;
if (deserializationDict.ContainsKey(sdata))
{
var ddata = deserializationDict[sdata];
// reference counter
ddata.referenceCount--;
Develop.DebugLog($"UnregisterPreBuildData [{sdata.buildId}] C:{ddata.referenceCount} F:{Time.frameCount}");
}
else
{
Develop.DebugLogWarning($"UnregisterPreBuildData not found! [{sdata.buildId}]");
}
}
/// <summary>
/// 未使用のデシリアライズデータをすべて破棄する
/// </summary>
internal void UnloadUnusedData()
{
var removeKeys = new List<SharePreBuildData>();
foreach (var kv in deserializationDict)
{
if (kv.Value.referenceCount <= 0)
removeKeys.Add(kv.Key);
}
foreach (var key in removeKeys)
{
var ddata = deserializationDict[key];
ddata.Dispose();
deserializationDict.Remove(key);
Develop.DebugLog($"Unload pre-build deserialization data [{key.buildId}] F:{Time.frameCount}");
}
removeKeys.Clear();
Develop.DebugLog($"Unload pre-build deserialization data count:{deserializationDict.Count} F:{Time.frameCount}");
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 800b8846d5572fe438974d4af951c076
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,202 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
namespace MagicaCloth2
{
public partial class RenderSetupData
{
/// <summary>
/// PreBuildの共有部分保存データ
/// </summary>
[System.Serializable]
public class ShareSerializationData
{
public ResultCode result;
public string name;
public SetupType setupType;
// Mesh ---------------------------------------------------------------
public Mesh originalMesh;
public int vertexCount;
public bool hasSkinnedMesh;
public bool hasBoneWeight;
public int skinRootBoneIndex;
public int skinBoneCount;
// MeshDataでは取得できないメッシュ情報
public List<Matrix4x4> bindPoseList;
public byte[] bonesPerVertexArray;
public byte[] boneWeightArray;
public Vector3[] localPositions;
public Vector3[] localNormals;
public Vector4[] localTangents; // option
// Bone ---------------------------------------------------------------
public BoneConnectionMode boneConnectionMode;
// Common -------------------------------------------------------------
public int renderTransformIndex;
// --------------------------------------------------------------------
public bool HasTangent => localTangents?.Length > 0;
}
public ShareSerializationData ShareSerialize()
{
var sdata = new ShareSerializationData();
try
{
sdata.result = result;
sdata.name = name;
sdata.setupType = setupType;
// Mesh
sdata.originalMesh = originalMesh;
sdata.vertexCount = vertexCount;
sdata.hasSkinnedMesh = hasSkinnedMesh;
sdata.hasBoneWeight = hasBoneWeight;
sdata.skinRootBoneIndex = skinRootBoneIndex;
sdata.skinBoneCount = skinBoneCount;
sdata.bindPoseList = new List<Matrix4x4>(bindPoseList);
sdata.bonesPerVertexArray = bonesPerVertexArray.MC2ToRawBytes();
sdata.boneWeightArray = boneWeightArray.MC2ToRawBytes();
sdata.localPositions = originalMesh.vertices;
sdata.localNormals = originalMesh.normals;
if (originalMesh.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.Tangent))
sdata.localTangents = originalMesh.tangents;
// Bone
sdata.boneConnectionMode = boneConnectionMode;
// Common
sdata.renderTransformIndex = renderTransformIndex;
}
catch (Exception exception)
{
Debug.LogException(exception);
}
return sdata;
}
public static RenderSetupData ShareDeserialize(ShareSerializationData sdata)
{
var setup = new RenderSetupData();
setup.isManaged = true;
try
{
setup.name = sdata.name;
setup.setupType = sdata.setupType;
// Mesh
setup.originalMesh = sdata.originalMesh;
setup.vertexCount = sdata.vertexCount;
setup.hasSkinnedMesh = sdata.hasSkinnedMesh;
setup.hasBoneWeight = sdata.hasBoneWeight;
setup.skinRootBoneIndex = sdata.skinRootBoneIndex;
setup.skinBoneCount = sdata.skinBoneCount;
setup.bindPoseList = new List<Matrix4x4>(sdata.bindPoseList);
setup.bonesPerVertexArray = NativeArrayExtensions.MC2FromRawBytes<byte>(sdata.bonesPerVertexArray, Allocator.Persistent);
setup.boneWeightArray = NativeArrayExtensions.MC2FromRawBytes<BoneWeight1>(sdata.boneWeightArray, Allocator.Persistent);
// PreBuildではmeshDataArrayを生成しない
// その代わりに保存したlocalPositions/Normalsを復元する
setup.localPositions = new NativeArray<Vector3>(sdata.localPositions, Allocator.Persistent);
setup.localNormals = new NativeArray<Vector3>(sdata.localNormals, Allocator.Persistent);
if (sdata.HasTangent)
setup.localTangents = new NativeArray<Vector4>(sdata.localTangents, Allocator.Persistent);
// Bone
setup.boneConnectionMode = sdata.boneConnectionMode;
// Common
setup.renderTransformIndex = sdata.renderTransformIndex;
setup.result.SetSuccess();
}
catch (Exception exception)
{
Debug.LogException(exception);
setup.result.SetError(Define.Result.PreBuild_InvalidRenderSetupData);
}
return setup;
}
//=========================================================================================
/// <summary>
/// PreBuild固有部分の保存データ
/// </summary>
[System.Serializable]
public class UniqueSerializationData : ITransform
{
public ResultCode result;
// Mesh ---------------------------------------------------------------
public Renderer renderer;
public SkinnedMeshRenderer skinRenderer;
public MeshFilter meshFilter;
public Mesh originalMesh;
// Common -------------------------------------------------------------
public List<Transform> transformList;
public void GetUsedTransform(HashSet<Transform> transformSet)
{
transformList?.ForEach(x =>
{
if (x)
transformSet.Add(x);
});
}
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
{
if (transformList != null)
{
for (int i = 0; i < transformList.Count; i++)
{
var t = transformList[i];
if (t)
{
int id = t.GetInstanceID();
if (id != 0 && replaceDict.ContainsKey(id))
{
transformList[i] = replaceDict[id];
}
}
}
}
}
}
public UniqueSerializationData UniqueSerialize()
{
var sdata = new UniqueSerializationData();
try
{
sdata.result = result;
// Mesh
sdata.renderer = renderer;
sdata.skinRenderer = skinRenderer;
sdata.meshFilter = meshFilter;
sdata.originalMesh = originalMesh;
// Common
sdata.transformList = new List<Transform>(transformList);
}
catch (Exception exception)
{
Debug.LogException(exception);
}
return sdata;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15097613d7348214ca528d3986504ece
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,356 @@
// Magica Cloth 2.
// Copyright (c) 2025 MagicaSoft.
// https://magicasoft.jp
using System;
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
namespace MagicaCloth2
{
[System.Serializable]
public class RenderSetupSerializeData : ITransform
{
public RenderSetupData.SetupType setupType;
public int vertexCount;
public bool hasSkinnedMesh;
public bool hasBoneWeight;
public int skinRootBoneIndex;
public int renderTransformIndex;
public int skinBoneCount;
public int transformCount;
public int useTransformCount;
public int[] useTransformIndexArray;
public Transform[] transformArray;
public float3[] transformPositions;
public quaternion[] transformRotations;
public float3[] transformLocalPositions;
public quaternion[] transformLocalRotations;
public float3[] transformScales;
public float4x4 initRenderLocalToWorld; // 初期化時の基準マトリックス(LtoW)
public float4x4 initRenderWorldtoLocal; // 初期化時の基準マトリックス(WtoL)
public quaternion initRenderRotation; // 初期化時の基準回転
public float3 initRenderScale; // 初期化時の基準スケール
public Mesh originalMesh; // 変更前のオリジナル共有メッシュ(SkinnedMeshRender利用時のみ)
public bool DataValidateMeshCloth(Renderer ren)
{
if (setupType != RenderSetupData.SetupType.MeshCloth)
return false;
if (ren == null)
return false;
if (useTransformIndexArray == null || useTransformIndexArray.Length == 0)
return false;
if (ren is SkinnedMeshRenderer)
{
if (hasSkinnedMesh == false)
return false;
var sren = ren as SkinnedMeshRenderer;
var smesh = sren.sharedMesh;
if (smesh == null)
return false;
// 重いか?
//int bcnt = smesh.bindposes?.Length ?? 0;
//if (skinBoneCount != bcnt)
// return false;
}
else
{
if (hasSkinnedMesh)
return false;
var filter = ren.GetComponent<MeshFilter>();
if (filter == null)
return false;
var smesh = filter.sharedMesh;
if (smesh == null)
return false;
}
if (DataValidateTransform() == false)
return false;
return true;
}
public bool DataValidateBoneCloth(ClothSerializeData sdata, RenderSetupData.SetupType clothType)
{
if (setupType != clothType)
return false;
if (hasSkinnedMesh)
return false;
if (hasBoneWeight)
return false;
if (DataValidateTransform() == false)
return false;
// root bone
foreach (var rootBone in sdata.rootBones)
{
if (rootBone == null || Array.FindIndex(transformArray, x => x == rootBone) < 0)
return false;
}
return true;
}
public bool DataValidateTransform()
{
if (transformCount == 0)
return false;
if (useTransformCount == 0)
return false;
int ucnt = useTransformCount;
if (ucnt != (useTransformIndexArray?.Length ?? 0))
return false;
if (ucnt != (transformArray?.Length ?? 0))
return false;
if (Array.FindIndex(transformArray, x => x == null) >= 0)
return false;
if (ucnt != (transformPositions?.Length ?? 0))
return false;
if (ucnt != (transformRotations?.Length ?? 0))
return false;
if (ucnt != (transformLocalPositions?.Length ?? 0))
return false;
if (ucnt != (transformLocalRotations?.Length ?? 0))
return false;
if (ucnt != (transformScales?.Length ?? 0))
return false;
return true;
}
public bool Serialize(RenderSetupData sd)
{
Debug.Assert(sd != null);
Debug.Assert(sd.TransformCount > 0);
setupType = sd.setupType;
vertexCount = sd.vertexCount;
hasSkinnedMesh = sd.hasSkinnedMesh;
hasBoneWeight = sd.hasBoneWeight;
skinRootBoneIndex = sd.skinRootBoneIndex;
renderTransformIndex = sd.renderTransformIndex;
skinBoneCount = sd.skinBoneCount;
transformCount = sd.TransformCount;
useTransformCount = 0;
originalMesh = null;
if (sd.TransformCount > 0)
{
int tcnt = sd.TransformCount;
using var useTransformIndexList = new NativeList<int>(tcnt, Allocator.TempJob);
if (setupType == RenderSetupData.SetupType.MeshCloth)
{
// MeshClothではウエイトとして利用されているボーンのみパックする
if (hasBoneWeight)
{
var job = new CalcUseBoneArrayJob2()
{
boneCount = skinBoneCount,
boneWeightArray = sd.boneWeightArray,
useBoneIndexList = useTransformIndexList,
};
job.Run();
if (skinRootBoneIndex >= skinBoneCount)
useTransformIndexList.Add(skinRootBoneIndex);
useTransformIndexList.Add(renderTransformIndex);
}
else
{
// 通常メッシュはそのまま
for (int i = 0; i < tcnt; i++)
useTransformIndexList.Add(i);
}
// オリジナルメッシュを記録
if (sd.originalMesh && sd.originalMesh.name.Contains("(Clone)") == false)
{
originalMesh = sd.originalMesh;
}
}
else
{
// BoneCloth系はそのまま
for (int i = 0; i < tcnt; i++)
useTransformIndexList.Add(i);
}
using var tempArray = useTransformIndexList.ToArray(Allocator.TempJob);
useTransformIndexArray = tempArray.ToArray();
int ucnt = useTransformIndexArray.Length;
useTransformCount = ucnt;
transformArray = new Transform[ucnt];
transformPositions = new float3[ucnt];
transformRotations = new quaternion[ucnt];
transformLocalPositions = new float3[ucnt];
transformLocalRotations = new quaternion[ucnt];
transformScales = new float3[ucnt];
for (int i = 0; i < ucnt; i++)
{
int tindex = useTransformIndexArray[i];
transformArray[i] = sd.transformList[tindex];
transformPositions[i] = sd.transformPositions[tindex];
transformRotations[i] = sd.transformRotations[tindex];
transformLocalPositions[i] = sd.transformLocalPositions[tindex];
transformLocalRotations[i] = sd.transformLocalRotations[tindex];
transformScales[i] = sd.transformScales[tindex];
}
}
initRenderLocalToWorld = sd.initRenderLocalToWorld;
initRenderWorldtoLocal = sd.initRenderWorldtoLocal;
initRenderRotation = sd.initRenderRotation;
initRenderScale = sd.initRenderScale;
return true;
}
[BurstCompile]
struct CalcUseBoneArrayJob2 : IJob
{
public int boneCount;
[Unity.Collections.ReadOnly]
public NativeArray<BoneWeight1> boneWeightArray;
public NativeList<int> useBoneIndexList;
public void Execute()
{
var useBoneArray = new NativeArray<byte>(boneCount, Allocator.Temp);
int cnt = boneWeightArray.Length;
int packCnt = 0;
for (int i = 0; i < cnt; i++)
{
var bw1 = boneWeightArray[i];
if (bw1.weight > 0.0f)
{
byte oldFlag = useBoneArray[bw1.boneIndex];
if (oldFlag == 0)
packCnt++;
useBoneArray[bw1.boneIndex] = 1;
}
}
// 利用Boneのインデックスをパックする
for (int i = 0; i < boneCount; i++)
{
byte flag = useBoneArray[i];
if (flag != 0)
{
useBoneIndexList.Add(i);
}
}
useBoneArray.Dispose();
}
}
public int GetLocalHash()
{
int hash = 0;
hash += (int)setupType * 100;
hash += vertexCount;
hash += hasSkinnedMesh ? 1 : 0;
hash += hasBoneWeight ? 1 : 0;
hash += skinRootBoneIndex;
hash += renderTransformIndex;
hash += skinBoneCount;
hash += transformCount;
hash += useTransformCount;
hash += useTransformIndexArray?.Length ?? 0;
hash += transformArray?.Length ?? 0;
hash += transformPositions?.Length ?? 0;
hash += transformRotations?.Length ?? 0;
hash += transformLocalPositions?.Length ?? 0;
hash += transformLocalRotations?.Length ?? 0;
hash += transformScales?.Length ?? 0;
if (transformArray != null)
foreach (var t in transformArray)
hash += t != null ? (456 + t.childCount * 789) : 0;
if (originalMesh != null)
hash += originalMesh.vertexCount;
return hash;
}
public int GetGlobalHash()
{
int hash = 0;
if (transformArray != null)
{
foreach (var t in transformArray)
{
if (t)
{
hash += t.localPosition.GetHashCode();
hash += t.localRotation.GetHashCode();
hash += t.localScale.GetHashCode();
}
}
}
// レンダーワールドスケールのみ監視する
// ワールドスケールはちょっとした移動や回転などで浮動小数点誤差が出るので少数3桁まででハッシュ化する
int3 intScale = (int3)math.round(initRenderScale * 1000);
//Debug.Log($"★initScale:{intScale}");
hash += intScale.GetHashCode();
return hash;
}
public void GetUsedTransform(HashSet<Transform> transformSet)
{
if (transformArray != null)
{
foreach (var t in transformArray)
{
if (t)
transformSet.Add(t);
}
}
}
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
{
if (transformArray == null)
return;
for (int i = 0; i < transformArray.Length; i++)
{
var t = transformArray[i];
if (t && replaceDict.ContainsKey(t.GetInstanceID()))
{
transformArray[i] = replaceDict[t.GetInstanceID()];
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98f83594b09a8c5469b78d1d22047ecd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1678d975c7bf0f343bf9eb89afc158fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2dd0faec9645ac1499b7eceb32ba4f10
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,117 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
namespace MagicaCloth2
{
public partial class TransformData
{
/// <summary>
/// PreBuildの共有部分保存データ
/// </summary>
[System.Serializable]
public class ShareSerializationData
{
public ExSimpleNativeArray<ExBitFlag8>.SerializationData flagArray;
public ExSimpleNativeArray<float3>.SerializationData initLocalPositionArray;
public ExSimpleNativeArray<quaternion>.SerializationData initLocalRotationArray;
}
public ShareSerializationData ShareSerialize()
{
var sdata = new ShareSerializationData();
try
{
sdata.flagArray = flagArray.Serialize();
sdata.initLocalPositionArray = initLocalPositionArray.Serialize();
sdata.initLocalRotationArray = initLocalRotationArray.Serialize();
}
catch (Exception exception)
{
Debug.LogException(exception);
}
return sdata;
}
public static TransformData ShareDeserialize(ShareSerializationData sdata)
{
if (sdata == null)
return null;
var tdata = new TransformData();
try
{
tdata.flagArray = new ExSimpleNativeArray<ExBitFlag8>(sdata.flagArray);
tdata.initLocalPositionArray = new ExSimpleNativeArray<float3>(sdata.initLocalPositionArray);
tdata.initLocalRotationArray = new ExSimpleNativeArray<quaternion>(sdata.initLocalRotationArray);
}
catch (Exception exception)
{
Debug.LogException(exception);
}
return tdata;
}
//=========================================================================================
/// <summary>
/// PreBuild固有部分の保存データ
/// </summary>
[System.Serializable]
public class UniqueSerializationData : ITransform
{
public Transform[] transformArray;
public void GetUsedTransform(HashSet<Transform> transformSet)
{
if (transformArray != null)
{
foreach (var t in transformArray)
{
if (t)
transformSet.Add(t);
}
}
}
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
{
if (transformArray != null)
{
for (int i = 0; i < transformArray.Length; i++)
{
var t = transformArray[i];
if (t)
{
int id = t.GetInstanceID();
if (id != 0 && replaceDict.ContainsKey(id))
{
transformArray[i] = replaceDict[id];
}
}
}
}
}
}
public UniqueSerializationData UniqueSerialize()
{
var sdata = new UniqueSerializationData();
try
{
sdata.transformArray = transformList.ToArray();
}
catch (Exception exception)
{
Debug.LogException(exception);
}
return sdata;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7ae8000d77bdbae4b86315fcc83b2518
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,82 @@
// Magica Cloth 2.
// Copyright (c) 2025 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
[System.Serializable]
public class TransformRecordSerializeData : ITransform
{
public Transform transform; // 利用しないが念の為に記録
public Vector3 localPosition;
public Quaternion localRotation;
public Vector3 position;
public Quaternion rotation;
public Vector3 scale; // lossy scale
public Matrix4x4 localToWorldMatrix;
public Matrix4x4 worldToLocalMatrix;
public void Serialize(TransformRecord tr)
{
Debug.Assert(tr != null);
transform = tr.transform;
localPosition = tr.localPosition;
localRotation = tr.localRotation;
position = tr.position;
rotation = tr.rotation;
scale = tr.scale;
localToWorldMatrix = tr.localToWorldMatrix;
worldToLocalMatrix = tr.worldToLocalMatrix;
}
public void Deserialize(TransformRecord tr)
{
Debug.Assert(tr != null);
// 座標系のみ復元する
tr.localPosition = localPosition;
tr.localRotation = localRotation;
tr.position = position;
tr.rotation = rotation;
tr.scale = scale;
tr.localToWorldMatrix = localToWorldMatrix;
tr.worldToLocalMatrix = worldToLocalMatrix;
}
public int GetLocalHash()
{
int hash = 0;
if (transform)
hash += (123 + transform.childCount * 345);
return hash;
}
public int GetGlobalHash()
{
int hash = 0;
// ローカル姿勢のみ
hash += localPosition.GetHashCode();
hash += localRotation.GetHashCode();
return hash;
}
public void GetUsedTransform(HashSet<Transform> transformSet)
{
if (transform)
transformSet.Add(transform);
}
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
{
int id = transform != null ? transform.GetInstanceID() : 0;
if (id != 0 && replaceDict.ContainsKey(id))
transform = replaceDict[id];
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f4930f42a38b269439caa19e9603c9aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1f85ba9270154ec4ea99adc777266a0f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,64 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// PreBuildの保存アセットデータ
/// </summary>
[CreateAssetMenu(fileName = "Data", menuName = "MagicaCloth2/PreBuildScriptableObject")]
public class PreBuildScriptableObject : ScriptableObject
{
/// <summary>
/// 複数のPreBuildデータを格納可能
/// </summary>
public List<SharePreBuildData> sharePreBuildDataList = new List<SharePreBuildData>();
//=========================================================================================
public bool HasPreBuildData(string buildId)
{
return GetPreBuildData(buildId) != null;
}
public SharePreBuildData GetPreBuildData(string buildId)
{
foreach (var sdata in sharePreBuildDataList)
{
if (sdata.CheckBuildId(buildId))
return sdata;
}
return null;
}
public void AddPreBuildData(SharePreBuildData sdata)
{
int index = sharePreBuildDataList.FindIndex(x => x.buildId == sdata.buildId);
if (index >= 0)
sharePreBuildDataList[index] = sdata;
else
sharePreBuildDataList.Add(sdata);
}
//=========================================================================================
/// <summary>
/// すべてのPreBuildデータをデシリアライズしてマネージャに登録します
/// この処理は負荷が高いため事前に実行しておくことでクロスデータ利用時の負荷を軽減できます
/// Deserialize all PreBuild data and register it with the manager.
/// This process requires a high load, so running it in advance can reduce the load when using cross data.
/// </summary>
public void Warmup()
{
if (Application.isPlaying == false)
return;
sharePreBuildDataList.ForEach(sdata =>
{
MagicaManager.PreBuild.RegisterPreBuildData(sdata, false);
});
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 45b12b58fd27b9a4bae4f50db55b4459
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,101 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// PreBuildの保存データ
/// </summary>
[System.Serializable]
public class PreBuildSerializeData : ITransform
{
/// <summary>
/// 有効状態
/// Valid state.
/// </summary>
public bool enabled = false;
/// <summary>
/// ビルド識別ID
/// </summary>
public string buildId;
/// <summary>
/// ビルドデータの共有部分
/// このデータは複数のインスタンスで共有されるためScriptableObjectとして外部アセットとして保存される
/// </summary>
public PreBuildScriptableObject preBuildScriptableObject = null;
/// <summary>
/// ビルドデータの固有部分
/// このデータはインスタンスごとに固有となる
/// </summary>
public UniquePreBuildData uniquePreBuildData;
//=========================================================================================
/// <summary>
/// PreBuild利用の有無
/// </summary>
/// <returns></returns>
public bool UsePreBuild() => enabled;
/// <summary>
/// PreBuildデータの検証
/// </summary>
/// <returns></returns>
public ResultCode DataValidate()
{
if (uniquePreBuildData == null)
return new ResultCode(Define.Result.PreBuildData_Empty);
var preBuildData = GetSharePreBuildData();
if (preBuildData == null)
return new ResultCode(Define.Result.PreBuildData_Empty);
var result = preBuildData.DataValidate();
if (result.IsFaild())
return result;
result = uniquePreBuildData.DataValidate();
if (result.IsFaild())
return result;
return ResultCode.Success;
}
public SharePreBuildData GetSharePreBuildData()
{
if (preBuildScriptableObject == null)
return null;
if (string.IsNullOrEmpty(buildId))
return null;
return preBuildScriptableObject.GetPreBuildData(buildId); ;
}
/// <summary>
/// ビルドIDを生成する(英数字8文字)
/// </summary>
/// <returns></returns>
public static string GenerateBuildID()
{
Guid g = Guid.NewGuid();
return g.ToString().Substring(0, 8);
}
public void GetUsedTransform(HashSet<Transform> transformSet)
{
uniquePreBuildData.GetUsedTransform(transformSet);
}
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
{
uniquePreBuildData.ReplaceTransform(replaceDict);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c7522d5a2a34f84c9588683c5574fa9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,69 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// PreBuildデータの共有部分
/// </summary>
[System.Serializable]
public class SharePreBuildData
{
public int version;
public string buildId;
public ResultCode buildResult;
public Vector3 buildScale;
public List<RenderSetupData.ShareSerializationData> renderSetupDataList = new List<RenderSetupData.ShareSerializationData>();
public VirtualMesh.ShareSerializationData proxyMesh;
public List<VirtualMesh.ShareSerializationData> renderMeshList = new List<VirtualMesh.ShareSerializationData>();
public DistanceConstraint.ConstraintData distanceConstraintData;
public TriangleBendingConstraint.ConstraintData bendingConstraintData;
public InertiaConstraint.ConstraintData inertiaConstraintData;
//=========================================================================================
public ResultCode DataValidate()
{
if (version != Define.System.LatestPreBuildVersion)
return new ResultCode(Define.Result.PreBuildData_VersionMismatch);
if (buildScale.x < Define.System.Epsilon)
return new ResultCode(Define.Result.PreBuildData_InvalidScale);
if (buildResult.IsFaild())
return buildResult;
return ResultCode.Success;
}
public bool CheckBuildId(string buildId)
{
if (string.IsNullOrEmpty(buildId))
return false;
return this.buildId == buildId;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder(1024);
sb.AppendLine("<<<<< PreBuildData >>>>>");
sb.AppendLine($"Version:{version}");
sb.AppendLine($"BuildID:{buildId}");
sb.AppendLine($"BuildResult:{buildResult.GetResultString()}");
sb.AppendLine($"BuildScale:{buildScale}");
sb.AppendLine(proxyMesh.ToString());
sb.AppendLine($"renderMeshList:{renderMeshList.Count}");
sb.AppendLine($"renderSetupDataList:{renderSetupDataList.Count}");
return sb.ToString();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 280185e34f035f44d999fc83fffe8ab9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,49 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// PreBuildデータの固有部分
/// </summary>
[System.Serializable]
public class UniquePreBuildData : ITransform
{
public int version;
public ResultCode buildResult;
public List<RenderSetupData.UniqueSerializationData> renderSetupDataList = new List<RenderSetupData.UniqueSerializationData>();
public VirtualMesh.UniqueSerializationData proxyMesh;
public List<VirtualMesh.UniqueSerializationData> renderMeshList = new List<VirtualMesh.UniqueSerializationData>();
//=========================================================================================
public ResultCode DataValidate()
{
if (version != Define.System.LatestPreBuildVersion)
return new ResultCode(Define.Result.PreBuildData_VersionMismatch);
if (buildResult.IsFaild())
return buildResult;
return ResultCode.Success;
}
public void GetUsedTransform(HashSet<Transform> transformSet)
{
renderSetupDataList.ForEach(x => x?.GetUsedTransform(transformSet));
proxyMesh?.GetUsedTransform(transformSet);
renderMeshList.ForEach(x => x?.GetUsedTransform(transformSet));
}
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
{
renderSetupDataList.ForEach(x => x?.ReplaceTransform(replaceDict));
proxyMesh?.ReplaceTransform(replaceDict);
renderMeshList.ForEach(x => x?.ReplaceTransform(replaceDict));
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0cee094d81395864ba3ef342016a8de6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,30 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using Unity.Collections;
namespace MagicaCloth2
{
/// <summary>
/// NativeParallelHashMapの拡張メソッド
/// </summary>
public static class NativeParallelHashMap
{
/// <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 NativeParallelHashMap<TKey, TValue> map) where TKey : unmanaged, IEquatable<TKey> where TValue : unmanaged, IEquatable<TValue>
#else
public static void MC2DisposeSafe<TKey, TValue>(ref this NativeParallelHashMap<TKey, TValue> map) where TKey : struct, IEquatable<TKey> where TValue : struct, IEquatable<TValue>
#endif
{
if (map.IsCreated)
map.Dispose();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6dcd839c56f63b42af8231ec3cb1841
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,291 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using System.Collections.Generic;
using System.Text;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;
namespace MagicaCloth2
{
public partial class VirtualMesh
{
/// <summary>
/// PreBuildの共有部分データ
/// </summary>
[System.Serializable]
public class ShareSerializationData
{
public string name;
public MeshType meshType;
public bool isBoneCloth;
// 基本
public ExSimpleNativeArray<int>.SerializationData referenceIndices;
public ExSimpleNativeArray<VertexAttribute>.SerializationData attributes;
public ExSimpleNativeArray<float3>.SerializationData localPositions;
public ExSimpleNativeArray<float3>.SerializationData localNormals;
public ExSimpleNativeArray<float3>.SerializationData localTangents;
public ExSimpleNativeArray<float2>.SerializationData uv;
public ExSimpleNativeArray<VirtualMeshBoneWeight>.SerializationData boneWeights;
public ExSimpleNativeArray<int3>.SerializationData triangles;
public ExSimpleNativeArray<int2>.SerializationData lines;
public int centerTransformIndex;
public float4x4 initLocalToWorld;
public float4x4 initWorldToLocal;
public quaternion initRotation;
public quaternion initInverseRotation;
public float3 initScale;
public int skinRootIndex;
public ExSimpleNativeArray<int>.SerializationData skinBoneTransformIndices;
public ExSimpleNativeArray<float4x4>.SerializationData skinBoneBindPoses;
public TransformData.ShareSerializationData transformData;
public AABB boundingBox;
public float averageVertexDistance;
public float maxVertexDistance;
// プロキシメッシュ
public byte[] vertexToTriangles;
public byte[] vertexToVertexIndexArray;
public byte[] vertexToVertexDataArray;
public byte[] edges;
public byte[] edgeFlags;
public int2[] edgeToTrianglesKeys;
public ushort[] edgeToTrianglesValues;
public byte[] vertexBindPosePositions;
public byte[] vertexBindPoseRotations;
public byte[] vertexToTransformRotations;
public byte[] vertexDepths;
public byte[] vertexRootIndices;
public byte[] vertexParentIndices;
public byte[] vertexChildIndexArray;
public byte[] vertexChildDataArray;
public byte[] vertexLocalPositions;
public byte[] vertexLocalRotations;
public byte[] normalAdjustmentRotations;
public byte[] baseLineFlags;
public byte[] baseLineStartDataIndices;
public byte[] baseLineDataCounts;
public byte[] baseLineData;
public int[] customSkinningBoneIndices;
public ushort[] centerFixedList;
public float3 localCenterPosition;
// マッピングメッシュ
public float3 centerWorldPosition;
public quaternion centerWorldRotation;
public float3 centerWorldScale;
public float4x4 toProxyMatrix;
public quaternion toProxyRotation;
public override string ToString()
{
StringBuilder sb = new StringBuilder(1024);
sb.AppendLine("===== VirtualMesh.SerializeData =====");
sb.AppendLine($"name:{name}");
sb.AppendLine($"meshType:{meshType}");
sb.AppendLine($"isBoneCloth:{isBoneCloth}");
sb.AppendLine($"VertexCount:{attributes.count}");
sb.AppendLine($"TriangleCount:{triangles.count}");
sb.AppendLine($"LineCount:{lines.count}");
return sb.ToString();
}
}
public ShareSerializationData ShareSerialize()
{
var sdata = new ShareSerializationData();
try
{
sdata.name = name;
sdata.meshType = meshType;
sdata.isBoneCloth = isBoneCloth;
// 基本
sdata.referenceIndices = referenceIndices.Serialize();
sdata.attributes = attributes.Serialize();
sdata.localPositions = localPositions.Serialize();
sdata.localNormals = localNormals.Serialize();
sdata.localTangents = localTangents.Serialize();
sdata.uv = uv.Serialize();
sdata.boneWeights = boneWeights.Serialize();
sdata.triangles = triangles.Serialize();
sdata.lines = lines.Serialize();
sdata.centerTransformIndex = centerTransformIndex;
sdata.initLocalToWorld = initLocalToWorld;
sdata.initWorldToLocal = initWorldToLocal;
sdata.initRotation = initRotation;
sdata.initInverseRotation = initInverseRotation;
sdata.initScale = initScale;
sdata.skinRootIndex = skinRootIndex;
sdata.skinBoneTransformIndices = skinBoneTransformIndices.Serialize();
sdata.skinBoneBindPoses = skinBoneBindPoses.Serialize();
sdata.transformData = transformData?.ShareSerialize();
if (boundingBox.IsCreated)
sdata.boundingBox = boundingBox.Value;
if (averageVertexDistance.IsCreated)
sdata.averageVertexDistance = averageVertexDistance.Value;
if (maxVertexDistance.IsCreated)
sdata.maxVertexDistance = maxVertexDistance.Value;
// プロキシメッシュ
sdata.vertexToTriangles = vertexToTriangles.MC2ToRawBytes();
sdata.vertexToVertexIndexArray = vertexToVertexIndexArray.MC2ToRawBytes();
sdata.vertexToVertexDataArray = vertexToVertexDataArray.MC2ToRawBytes();
sdata.edges = edges.MC2ToRawBytes();
sdata.edgeFlags = edgeFlags.MC2ToRawBytes();
(sdata.edgeToTrianglesKeys, sdata.edgeToTrianglesValues) = edgeToTriangles.MC2Serialize();
sdata.vertexBindPosePositions = vertexBindPosePositions.MC2ToRawBytes();
sdata.vertexBindPoseRotations = vertexBindPoseRotations.MC2ToRawBytes();
sdata.vertexToTransformRotations = vertexToTransformRotations.MC2ToRawBytes();
sdata.vertexDepths = vertexDepths.MC2ToRawBytes();
sdata.vertexRootIndices = vertexRootIndices.MC2ToRawBytes();
sdata.vertexParentIndices = vertexParentIndices.MC2ToRawBytes();
sdata.vertexChildIndexArray = vertexChildIndexArray.MC2ToRawBytes();
sdata.vertexChildDataArray = vertexChildDataArray.MC2ToRawBytes();
sdata.vertexLocalPositions = vertexLocalPositions.MC2ToRawBytes();
sdata.vertexLocalRotations = vertexLocalRotations.MC2ToRawBytes();
sdata.normalAdjustmentRotations = normalAdjustmentRotations.MC2ToRawBytes();
sdata.baseLineFlags = baseLineFlags.MC2ToRawBytes();
sdata.baseLineStartDataIndices = baseLineStartDataIndices.MC2ToRawBytes();
sdata.baseLineDataCounts = baseLineDataCounts.MC2ToRawBytes();
sdata.baseLineData = baseLineData.MC2ToRawBytes();
DataUtility.ArrayCopy(customSkinningBoneIndices, ref sdata.customSkinningBoneIndices);
DataUtility.ArrayCopy(centerFixedList, ref sdata.centerFixedList);
if (localCenterPosition.IsCreated)
sdata.localCenterPosition = localCenterPosition.Value;
// マッピングメッシュ
sdata.centerWorldPosition = centerWorldPosition;
sdata.centerWorldRotation = centerWorldRotation;
sdata.centerWorldScale = centerWorldScale;
sdata.toProxyMatrix = toProxyMatrix;
sdata.toProxyRotation = toProxyRotation;
}
catch (Exception exception)
{
Debug.LogException(exception);
}
return sdata;
}
public static VirtualMesh ShareDeserialize(ShareSerializationData sdata)
{
var vmesh = new VirtualMesh();
vmesh.isManaged = true;
try
{
vmesh.name = sdata.name;
vmesh.meshType = sdata.meshType;
vmesh.isBoneCloth = sdata.isBoneCloth;
// 基本
vmesh.referenceIndices.Deserialize(sdata.referenceIndices);
vmesh.attributes.Deserialize(sdata.attributes);
vmesh.localPositions.Deserialize(sdata.localPositions);
vmesh.localNormals.Deserialize(sdata.localNormals);
vmesh.localTangents.Deserialize(sdata.localTangents);
vmesh.uv.Deserialize(sdata.uv);
vmesh.boneWeights.Deserialize(sdata.boneWeights);
vmesh.triangles.Deserialize(sdata.triangles);
vmesh.lines.Deserialize(sdata.lines);
vmesh.centerTransformIndex = sdata.centerTransformIndex;
vmesh.initLocalToWorld = sdata.initLocalToWorld;
vmesh.initWorldToLocal = sdata.initWorldToLocal;
vmesh.initRotation = sdata.initRotation;
vmesh.initInverseRotation = sdata.initInverseRotation;
vmesh.initScale = sdata.initScale;
vmesh.skinRootIndex = sdata.skinRootIndex;
vmesh.skinBoneTransformIndices.Deserialize(sdata.skinBoneTransformIndices);
vmesh.skinBoneBindPoses.Deserialize(sdata.skinBoneBindPoses);
vmesh.transformData = TransformData.ShareDeserialize(sdata.transformData);
vmesh.boundingBox = new NativeReference<AABB>(sdata.boundingBox, Allocator.Persistent);
vmesh.averageVertexDistance = new NativeReference<float>(sdata.averageVertexDistance, Allocator.Persistent);
vmesh.maxVertexDistance = new NativeReference<float>(sdata.maxVertexDistance, Allocator.Persistent);
// プロキシメッシュ
vmesh.vertexToTriangles = NativeArrayExtensions.MC2FromRawBytes<FixedList32Bytes<uint>>(sdata.vertexToTriangles);
vmesh.vertexToVertexIndexArray = NativeArrayExtensions.MC2FromRawBytes<uint>(sdata.vertexToVertexIndexArray);
vmesh.vertexToVertexDataArray = NativeArrayExtensions.MC2FromRawBytes<ushort>(sdata.vertexToVertexDataArray);
vmesh.edges = NativeArrayExtensions.MC2FromRawBytes<int2>(sdata.edges);
vmesh.edgeFlags = NativeArrayExtensions.MC2FromRawBytes<ExBitFlag8>(sdata.edgeFlags);
vmesh.edgeToTriangles = NativeMultiHashMapExtensions.MC2Deserialize(sdata.edgeToTrianglesKeys, sdata.edgeToTrianglesValues);
vmesh.vertexBindPosePositions = NativeArrayExtensions.MC2FromRawBytes<float3>(sdata.vertexBindPosePositions);
vmesh.vertexBindPoseRotations = NativeArrayExtensions.MC2FromRawBytes<quaternion>(sdata.vertexBindPoseRotations);
vmesh.vertexToTransformRotations = NativeArrayExtensions.MC2FromRawBytes<quaternion>(sdata.vertexToTransformRotations);
vmesh.vertexDepths = NativeArrayExtensions.MC2FromRawBytes<float>(sdata.vertexDepths);
vmesh.vertexRootIndices = NativeArrayExtensions.MC2FromRawBytes<int>(sdata.vertexRootIndices);
vmesh.vertexParentIndices = NativeArrayExtensions.MC2FromRawBytes<int>(sdata.vertexParentIndices);
vmesh.vertexChildIndexArray = NativeArrayExtensions.MC2FromRawBytes<uint>(sdata.vertexChildIndexArray);
vmesh.vertexChildDataArray = NativeArrayExtensions.MC2FromRawBytes<ushort>(sdata.vertexChildDataArray);
vmesh.vertexLocalPositions = NativeArrayExtensions.MC2FromRawBytes<float3>(sdata.vertexLocalPositions);
vmesh.vertexLocalRotations = NativeArrayExtensions.MC2FromRawBytes<quaternion>(sdata.vertexLocalRotations);
vmesh.normalAdjustmentRotations = NativeArrayExtensions.MC2FromRawBytes<quaternion>(sdata.normalAdjustmentRotations);
vmesh.baseLineFlags = NativeArrayExtensions.MC2FromRawBytes<ExBitFlag8>(sdata.baseLineFlags);
vmesh.baseLineStartDataIndices = NativeArrayExtensions.MC2FromRawBytes<ushort>(sdata.baseLineStartDataIndices);
vmesh.baseLineDataCounts = NativeArrayExtensions.MC2FromRawBytes<ushort>(sdata.baseLineDataCounts);
vmesh.baseLineData = NativeArrayExtensions.MC2FromRawBytes<ushort>(sdata.baseLineData);
DataUtility.ArrayCopy(sdata.customSkinningBoneIndices, ref vmesh.customSkinningBoneIndices);
DataUtility.ArrayCopy(sdata.centerFixedList, ref vmesh.centerFixedList);
vmesh.localCenterPosition = new NativeReference<float3>(sdata.localCenterPosition, Allocator.Persistent);
// マッピングメッシュ
vmesh.centerWorldPosition = sdata.centerWorldPosition;
vmesh.centerWorldRotation = sdata.centerWorldRotation;
vmesh.centerWorldScale = sdata.centerWorldScale;
vmesh.toProxyMatrix = sdata.toProxyMatrix;
vmesh.toProxyRotation = sdata.toProxyRotation;
vmesh.result.SetSuccess();
}
catch (Exception exception)
{
Debug.LogException(exception);
vmesh.result.SetError(Define.Result.PreBuildData_VirtualMeshDeserializationException);
}
return vmesh;
}
//=========================================================================================
/// <summary>
/// PreBuildの固有部分データ
/// </summary>
[System.Serializable]
public class UniqueSerializationData : ITransform
{
public TransformData.UniqueSerializationData transformData;
public void GetUsedTransform(HashSet<Transform> transformSet)
{
transformData?.GetUsedTransform(transformSet);
}
public void ReplaceTransform(Dictionary<int, Transform> replaceDict)
{
transformData?.ReplaceTransform(replaceDict);
}
}
public UniqueSerializationData UniqueSerialize()
{
var sdata = new UniqueSerializationData();
try
{
sdata.transformData = transformData?.UniqueSerialize();
}
catch (Exception exception)
{
Debug.LogException(exception);
}
return sdata;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0d0b2768c9c7600468b9f1a7b39dd80d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,60 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// VirtualMeshの共有部分と固有部分をつにまとめた情報
/// </summary>
public class VirtualMeshContainer : IDisposable
{
public VirtualMesh shareVirtualMesh;
public VirtualMesh.UniqueSerializationData uniqueData;
public VirtualMeshContainer()
{
}
public VirtualMeshContainer(VirtualMesh vmesh)
{
shareVirtualMesh = vmesh;
uniqueData = null;
}
public void Dispose()
{
shareVirtualMesh?.Dispose();
}
//=========================================================================================
public bool hasUniqueData => uniqueData != null;
//=========================================================================================
public int GetTransformCount()
{
if (hasUniqueData)
return uniqueData.transformData.transformArray.Length;
else
return shareVirtualMesh.TransformCount;
}
public Transform GetTransformFromIndex(int index)
{
if (hasUniqueData)
return uniqueData.transformData.transformArray[index];
else
return shareVirtualMesh.transformData.GetTransformFromIndex(index);
}
public Transform GetCenterTransform()
{
if (hasUniqueData)
return uniqueData.transformData.transformArray[shareVirtualMesh.centerTransformIndex];
else
return shareVirtualMesh.GetCenterTransform();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bac7915dc7b0bda49baed15536766603
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using UnityEditor;
namespace MagicaCloth2
{
/// <summary>
/// インスペクター拡張のベースクラス
/// </summary>
public class MagicaEditorBase : Editor
{
/// <summary>
/// マルチ選択編集の適用
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="changed"></param>
/// <param name="act"></param>
protected void ApplyMultiSelection<T>(bool changed, string undoName, Action<T> act) where T : ClothBehaviour
{
if (changed)
{
foreach (var obj in targets)
{
var tscr = obj as T;
// Undo
Undo.RecordObject(tscr, undoName);
act(tscr);
EditorUtility.SetDirty(tscr);
// OnValidate()手動呼び出し
tscr.GetType().GetMethod("OnValidate", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.Invoke(tscr, null);
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3126cd1eb42b4af4aa38cea3c3836c3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,76 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using UnityEditor;
using UnityEngine;
namespace MagicaCloth2
{
[CustomPropertyDrawer(typeof(SharePreBuildData))]
public class SharePreBuildDataDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
// サイズ
float lineHight = EditorGUIUtility.singleLineHeight;
// 子のフィールドをインデントしない
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
var buildIdProperty = property.FindPropertyRelative("buildId");
var versionProperty = property.FindPropertyRelative("version");
var resultProperty = property.FindPropertyRelative("buildResult.result");
// テキスト幅調整
EditorGUIUtility.labelWidth = position.width;
// build Id
string buildId = string.IsNullOrEmpty(buildIdProperty.stringValue) ? "(Empty)" : buildIdProperty.stringValue;
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), new GUIContent(buildId));
position.y += lineHight;
// インデント+1
EditorGUI.indentLevel = indent + 1;
// result
Define.Result ret = (Define.Result)resultProperty.enumValueIndex;
var result = new ResultCode(ret);
if (result.IsFaild() == false)
{
// バージョン確認
if (versionProperty.intValue != Define.System.LatestPreBuildVersion)
result.SetError(Define.Result.PreBuildData_VersionMismatch);
}
// result text
var backColor = GUI.color;
if (result.IsSuccess())
{
GUI.color = Color.green;
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), new GUIContent($"{result.Result}"));
}
else
{
GUI.color = Color.red;
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), new GUIContent($"Error: {result.Result}"));
}
GUI.color = backColor;
// インデントを元通りに戻します
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float h = EditorGUIUtility.singleLineHeight;
h *= 2;
return h;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c6706416db7bdd14cb7ed3f5195d6498
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d09f86fb6833fb048935d02b3254e292
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,514 @@
// Magica Cloth 2.
// Copyright (c) 2024 MagicaSoft.
// https://magicasoft.jp
using System;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// PreBuildDataの作成
/// </summary>
public static class PreBuildDataCreation
{
/// <summary>
/// PreBuildDataを作成しアセットとして保存する.
/// Create PreBuildData and save it as an asset.
/// </summary>
/// <param name="cloth"></param>
/// <param name="useNewSaveDialog">Show save dialog if ScriptableObject does not exist.</param>
/// <returns></returns>
public static ResultCode CreatePreBuildData(MagicaCloth cloth, bool useNewSaveDialog = true)
{
var sdata = cloth.SerializeData;
var preBuildData = cloth.GetSerializeData2().preBuildData;
string buildId = preBuildData.buildId;
// ビルドIDが存在しない場合はここで新規作成する
if (string.IsNullOrEmpty(buildId))
{
buildId = PreBuildSerializeData.GenerateBuildID();
}
// スクリプタブルオブジェクトへ保存
if (preBuildData.preBuildScriptableObject == null && useNewSaveDialog)
{
string assetName = $"MagicaPreBuild_{buildId}";
// 保存フォルダ読み込み
const string StateKey = "MagicaCloth2_PreBuild_Folder";
string path = SessionState.GetString(StateKey, "Assets/");
string assetPath = EditorUtility.SaveFilePanelInProject("Saving MagicaCloth pre-build data", assetName, "asset", "MagicaCloth pre-build data name", path);
//Debug.Log($"AssetPath:{assetPath}");
if (string.IsNullOrEmpty(assetPath))
return new ResultCode(Define.Result.Cancel);
// 保存フォルダ書き込み
SessionState.SetString(StateKey, System.IO.Path.GetDirectoryName(assetPath));
var sobj = ScriptableObject.CreateInstance<PreBuildScriptableObject>();
AssetDatabase.CreateAsset(sobj, assetPath);
AssetDatabase.Refresh();
preBuildData.preBuildScriptableObject = sobj;
}
var preBuildScriptableObject = preBuildData.preBuildScriptableObject;
if (preBuildScriptableObject == null)
return new ResultCode(Define.Result.PreBuild_InvalidPreBuildData);
// 構築
var sharePreBuildData = new SharePreBuildData();
var uniquePreBuildData = new UniquePreBuildData();
if (sdata.IsValid())
{
MakePreBuildData(cloth, buildId, sharePreBuildData, uniquePreBuildData);
}
else
{
sharePreBuildData.buildResult.SetError(Define.Result.PreBuildData_InvalidClothData);
}
// データシリアライズ
preBuildData.buildId = buildId;
preBuildScriptableObject.AddPreBuildData(sharePreBuildData);
preBuildData.uniquePreBuildData = uniquePreBuildData;
EditorUtility.SetDirty(preBuildScriptableObject);
EditorUtility.SetDirty(cloth);
AssetDatabase.Refresh();
return sharePreBuildData.buildResult;
}
static void MakePreBuildData(MagicaCloth cloth, string buildId, SharePreBuildData sharePreBuildData, UniquePreBuildData uniquePreBuildData)
{
//Debug.Log($"MakePreBuildData().start");
//var span = new TimeSpan("PreBuild");
sharePreBuildData.version = Define.System.LatestPreBuildVersion;
sharePreBuildData.buildId = buildId;
sharePreBuildData.buildResult.SetProcess();
uniquePreBuildData.version = Define.System.LatestPreBuildVersion;
uniquePreBuildData.buildResult.SetProcess();
var setupDataList = new List<RenderSetupData>();
VirtualMesh proxyMesh = null;
var renderMeshList = new List<VirtualMesh>();
try
{
var sdata = cloth.SerializeData;
var sdata2 = cloth.GetSerializeData2();
var clothType = sdata.clothType;
//======================== Initialize ============================
// クロスを生成するための最低限の情報が揃っているかチェックする
if (sdata.IsValid() == false)
{
sharePreBuildData.buildResult.SetResult(sdata.VerificationResult);
throw new MagicaClothProcessingException();
}
// 初期トランスフォーム状態
var clothTransformRecord = new TransformRecord(cloth.ClothTransform, read: true);
// 法線調整用トランスフォーム
var normalAdjustmentTransformRecord = new TransformRecord(
sdata.normalAlignmentSetting.adjustmentTransform ?
sdata.normalAlignmentSetting.adjustmentTransform :
cloth.ClothTransform, read: true);
// セットアップ情報の初期化
if (clothType == ClothProcess.ClothType.MeshCloth)
{
foreach (var ren in sdata.sourceRenderers)
{
if (ren)
{
var setupData = new RenderSetupData(null, ren);
if (setupData.IsFaild())
{
sharePreBuildData.buildResult.Merge(setupData.result);
throw new MagicaClothProcessingException();
}
setupDataList.Add(setupData);
// セットアップ情報のシリアライズ
sharePreBuildData.renderSetupDataList.Add(setupData.ShareSerialize());
uniquePreBuildData.renderSetupDataList.Add(setupData.UniqueSerialize());
}
}
}
else if (clothType == ClothProcess.ClothType.BoneCloth || clothType == ClothProcess.ClothType.BoneSpring)
{
var setupData = new RenderSetupData(
null,
clothType == ClothProcess.ClothType.BoneCloth ? RenderSetupData.SetupType.BoneCloth : RenderSetupData.SetupType.BoneSpring,
clothTransformRecord.transform,
sdata.rootBones,
clothType == ClothProcess.ClothType.BoneCloth ? null : sdata.colliderCollisionConstraint.collisionBones,
clothType == ClothProcess.ClothType.BoneCloth ? sdata.connectionMode : RenderSetupData.BoneConnectionMode.Line,
cloth.name
);
if (setupData.IsFaild())
{
sharePreBuildData.buildResult.Merge(setupData.result);
throw new MagicaClothProcessingException();
}
setupDataList.Add(setupData);
}
// カスタムスキニングのボーン情報
List<TransformRecord> customSkinningBoneRecords = new List<TransformRecord>();
int bcnt = sdata.customSkinningSetting.skinningBones.Count;
for (int i = 0; i < bcnt; i++)
{
customSkinningBoneRecords.Add(new TransformRecord(sdata.customSkinningSetting.skinningBones[i], read: true));
}
//======================== Proxy/Mapping Mesh ============================
// ペイントマップ情報
bool usePaintMap = false;
var paintMapDataList = new List<ClothProcess.PaintMapData>();
if (clothType == ClothProcess.ClothType.MeshCloth && sdata.paintMode != ClothSerializeData.PaintMode.Manual)
{
var ret = cloth.Process.GeneratePaintMapDataList(paintMapDataList);
Develop.DebugLog($"Generate paint map data list. {ret.GetResultString()}");
if (ret.IsError())
{
sharePreBuildData.buildResult.Merge(ret);
throw new MagicaClothProcessingException();
}
//if (paintMapDataList.Count != renderHandleList.Count)
if (paintMapDataList.Count != setupDataList.Count)
{
sharePreBuildData.buildResult.SetError(Define.Result.CreateCloth_PaintMapCountMismatch);
throw new MagicaClothProcessingException();
}
usePaintMap = true;
}
// セレクションデータ
SelectionData selectionData = usePaintMap ? new SelectionData() : sdata2.selectionData.Clone();
bool isValidSelection = selectionData?.IsValid() ?? false;
// プロキシメッシュ作成
proxyMesh = new VirtualMesh("Proxy");
proxyMesh.result.SetProcess();
if (clothType == ClothProcess.ClothType.MeshCloth)
{
// MeshClothではクロストランスフォームを追加しておく
proxyMesh.SetTransform(clothTransformRecord);
if (setupDataList.Count == 0)
{
sharePreBuildData.buildResult.SetError(Define.Result.ClothProcess_InvalidRenderHandleList);
throw new MagicaClothProcessingException();
}
// render mesh import + selection + merge
for (int i = 0; i < setupDataList.Count; i++)
{
VirtualMesh renderMesh = null;
try
{
// レンダーメッシュ作成
var renderSetupData = setupDataList[i];
renderMesh = new VirtualMesh($"[{renderSetupData.name}]");
renderMesh.result.SetProcess();
// import -------------------------------------------------
renderMesh.ImportFrom(renderSetupData, sdata.GetUvChannel());
if (renderMesh.IsError)
{
sharePreBuildData.buildResult.Merge(renderMesh.result);
throw new MagicaClothProcessingException();
}
Develop.DebugLog($"(IMPORT) {renderMesh}");
// selection ----------------------------------------------
// MeshClothでペイントテクスチャ指定の場合はセレクションデータを生成する
SelectionData renderSelectionData = selectionData;
if (usePaintMap)
{
// セレクションデータ生成
var ret = cloth.Process.GenerateSelectionDataFromPaintMap(clothTransformRecord, renderMesh, paintMapDataList[i], out renderSelectionData);
Develop.DebugLog($"Generate selection from paint map. {ret.GetResultString()}");
if (ret.IsError())
{
sharePreBuildData.buildResult.Merge(ret);
throw new MagicaClothProcessingException();
}
// セレクションデータ結合
selectionData.Merge(renderSelectionData);
}
isValidSelection = selectionData?.IsValid() ?? false;
// メッシュの切り取り
if (renderSelectionData?.IsValid() ?? false)
{
// 余白
float mergin = renderMesh.CalcSelectionMergin(sdata.reductionSetting);
mergin = math.max(mergin, Define.System.MinimumGridSize);
// セレクション情報から切り取りの実行
// ペイントマップの場合はレンダラーごとのセレクションデータで切り取り
renderMesh.SelectionMesh(renderSelectionData, clothTransformRecord.localToWorldMatrix, mergin);
if (renderMesh.IsError)
{
sharePreBuildData.buildResult.Merge(renderMesh.result);
throw new MagicaClothProcessingException();
}
Develop.DebugLog($"(SELECTION) {renderMesh}");
}
// レンダーメッシュの作成完了
renderMesh.result.SetSuccess();
// merge --------------------------------------------------
proxyMesh.AddMesh(renderMesh);
// レンダーメッシュ情報を記録
renderMeshList.Add(renderMesh);
renderMesh = null;
}
catch (MagicaClothProcessingException)
{
throw;
}
catch (Exception exception)
{
Debug.LogException(exception);
sharePreBuildData.buildResult.SetError(Define.Result.ClothProcess_Exception);
throw;
}
finally
{
// この時点で作業用renderMeshが存在する場合は中断されているので開放する
renderMesh?.Dispose();
}
}
Develop.DebugLog($"(MERGE) {proxyMesh}");
// リダクション
if (proxyMesh.VertexCount > 1)
{
if (sdata.reductionSetting.IsEnabled)
{
proxyMesh.Reduction(sdata.reductionSetting, System.Threading.CancellationToken.None);
if (proxyMesh.IsError)
{
sharePreBuildData.buildResult.Merge(proxyMesh.result);
throw new MagicaClothProcessingException();
}
Develop.DebugLog($"(REDUCTION) {proxyMesh}");
}
}
}
else if (clothType == ClothProcess.ClothType.BoneCloth || clothType == ClothProcess.ClothType.BoneSpring)
{
// import
var boneClothSetupData = setupDataList[0];
proxyMesh.ImportFrom(boneClothSetupData, 0);
if (proxyMesh.IsError)
{
sharePreBuildData.buildResult.Merge(proxyMesh.result);
throw new MagicaClothProcessingException();
}
Develop.DebugLog($"(IMPORT) {proxyMesh}");
// セレクションデータが存在しない場合は簡易作成する
if (isValidSelection == false)
{
selectionData = new SelectionData(proxyMesh, float4x4.identity);
if (selectionData.Count > 0)
{
// まずすべて移動設定
selectionData.Fill(VertexAttribute.Move);
// 次にルートのみ固定
foreach (int id in boneClothSetupData.rootTransformIdList)
{
int rootIndex = boneClothSetupData.GetTransformIndexFromId(id);
selectionData.attributes[rootIndex] = VertexAttribute.Fixed;
}
isValidSelection = selectionData.IsValid();
}
}
}
// 元の頂点から結合頂点へのインデックスを初期化
if (proxyMesh.joinIndices.IsCreated == false)
{
proxyMesh.joinIndices = new Unity.Collections.NativeArray<int>(proxyMesh.VertexCount, Unity.Collections.Allocator.Persistent);
JobUtility.SerialNumberRun(proxyMesh.joinIndices, proxyMesh.VertexCount); // 連番をつける
}
// optimization
proxyMesh.Optimization();
if (proxyMesh.IsError)
{
sharePreBuildData.buildResult.Merge(proxyMesh.result);
throw new MagicaClothProcessingException();
}
Develop.DebugLog($"(OPTIMIZE) {proxyMesh}");
// attribute
if (isValidSelection)
{
// セレクションデータから頂点属性を付与する
proxyMesh.ApplySelectionAttribute(selectionData);
if (proxyMesh.IsError)
{
sharePreBuildData.buildResult.Merge(proxyMesh.result);
throw new MagicaClothProcessingException();
}
}
// proxy mesh属性決定後に実行
proxyMesh.ConvertProxyMesh(sdata, clothTransformRecord, customSkinningBoneRecords, normalAdjustmentTransformRecord);
if (proxyMesh.IsError)
{
sharePreBuildData.buildResult.Merge(proxyMesh.result);
throw new MagicaClothProcessingException();
}
Develop.DebugLog($"(PROXY) {proxyMesh}");
// ProxyMeshの最終チェック
if (proxyMesh.VertexCount > Define.System.MaxProxyMeshVertexCount)
{
sharePreBuildData.buildResult.SetError(Define.Result.ProxyMesh_Over32767Vertices);
throw new MagicaClothProcessingException();
}
if (proxyMesh.EdgeCount > Define.System.MaxProxyMeshEdgeCount)
{
sharePreBuildData.buildResult.SetError(Define.Result.ProxyMesh_Over32767Edges);
throw new MagicaClothProcessingException();
}
if (proxyMesh.TriangleCount > Define.System.MaxProxyMeshTriangleCount)
{
sharePreBuildData.buildResult.SetError(Define.Result.ProxyMesh_Over32767Triangles);
throw new MagicaClothProcessingException();
}
// finish
if (proxyMesh.IsError)
{
sharePreBuildData.buildResult.Merge(proxyMesh.result);
throw new MagicaClothProcessingException();
}
proxyMesh.result.SetSuccess();
Develop.DebugLog("CreateProxyMesh finish!");
// Mapping(MeshClothのみ)
if (clothType == ClothProcess.ClothType.MeshCloth)
{
foreach (VirtualMesh renderMesh in renderMeshList)
{
renderMesh.Mapping(proxyMesh);
if (renderMesh.IsError)
{
sharePreBuildData.buildResult.Merge(renderMesh.result);
throw new MagicaClothProcessingException();
}
Develop.DebugLog($"(MAPPING) {renderMesh}");
}
}
// ======================= Cloth Data ===============================
// クロスデータ作成
var parameters = cloth.SerializeData.GetClothParameters();
var distanceConstraintData = DistanceConstraint.CreateData(proxyMesh, parameters);
if (distanceConstraintData != null)
{
if (distanceConstraintData.result.IsSuccess())
{
sharePreBuildData.distanceConstraintData = distanceConstraintData;
}
else
{
sharePreBuildData.buildResult.Merge(distanceConstraintData.result);
throw new MagicaClothProcessingException();
}
}
var bendingConstraintData = TriangleBendingConstraint.CreateData(proxyMesh, parameters);
if (bendingConstraintData != null)
{
if (bendingConstraintData.result.IsSuccess())
{
sharePreBuildData.bendingConstraintData = bendingConstraintData;
}
else
{
sharePreBuildData.buildResult.Merge(bendingConstraintData.result);
throw new MagicaClothProcessingException();
}
}
var inertiaConstraintData = InertiaConstraint.CreateData(proxyMesh, parameters);
if (inertiaConstraintData != null)
{
if (inertiaConstraintData.result.IsSuccess())
{
sharePreBuildData.inertiaConstraintData = inertiaConstraintData;
}
else
{
sharePreBuildData.buildResult.Merge(inertiaConstraintData.result);
throw new MagicaClothProcessingException();
}
}
// ======================= Serialize ===============================
sharePreBuildData.buildScale = clothTransformRecord.scale;
sharePreBuildData.proxyMesh = proxyMesh.ShareSerialize();
uniquePreBuildData.proxyMesh = proxyMesh.UniqueSerialize();
foreach (VirtualMesh renderMesh in renderMeshList)
{
sharePreBuildData.renderMeshList.Add(renderMesh.ShareSerialize());
uniquePreBuildData.renderMeshList.Add(renderMesh.UniqueSerialize());
}
// 成功
sharePreBuildData.buildResult.SetSuccess();
Develop.DebugLog(sharePreBuildData);
}
catch (MagicaClothProcessingException)
{
if (sharePreBuildData.buildResult.IsError() == false)
sharePreBuildData.buildResult.SetError(Define.Result.PreBuildData_MagicaClothException);
sharePreBuildData.buildResult.DebugLog();
}
catch (Exception exception)
{
Debug.LogException(exception);
sharePreBuildData.buildResult.SetError(Define.Result.PreBuildData_UnknownError);
}
finally
{
setupDataList.ForEach(x => x.Dispose());
setupDataList.Clear();
renderMeshList.ForEach(x => x?.Dispose());
renderMeshList.Clear();
proxyMesh?.Dispose();
proxyMesh = null;
// 内部情報は外部情報の結果をコピー
uniquePreBuildData.buildResult = sharePreBuildData.buildResult;
}
//Debug.Log(span);
//Debug.Log($"MakePreBuildData().end");
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d37ab6d9c5e31034a9503a7cedd96ee3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Assets/External/VRCDeveloperTool.meta vendored Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 457bd13b309fa6f448bc060c257d7ba7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Assets/External/YAMOScripts.meta vendored Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f43d31ff050db5341a2e7dcb2132b522
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,109 +0,0 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class FindUnusedBones : EditorWindow
{
private List<string> excludeStrings = new List<string>(); // 제외할 문자열 리스트
[MenuItem("Tools/Find Unused Bones")]
public static void ShowWindow()
{
GetWindow<FindUnusedBones>("Find Unused Bones");
}
private void OnGUI()
{
GUILayout.Label("Exclude Strings", EditorStyles.boldLabel);
// 동적으로 문자열 입력 필드와 + - 버튼을 추가
for (int i = 0; i < excludeStrings.Count; i++)
{
GUILayout.BeginHorizontal();
excludeStrings[i] = EditorGUILayout.TextField($"Exclude String {i + 1}", excludeStrings[i]);
if (GUILayout.Button("-", GUILayout.Width(20)))
{
excludeStrings.RemoveAt(i);
}
GUILayout.EndHorizontal();
}
if (GUILayout.Button("+", GUILayout.Width(20)))
{
excludeStrings.Add(string.Empty); // 빈 문자열 입력 필드 추가
}
GUILayout.Space(20);
if (GUILayout.Button("Find and Select Unused Bones"))
{
FindAndSelectUnusedBones();
}
}
private void FindAndSelectUnusedBones()
{
if (Selection.activeGameObject == null)
{
Debug.LogWarning("No GameObject selected!");
return;
}
Transform root = Selection.activeGameObject.transform;
SkinnedMeshRenderer[] skinnedMeshRenderers = root.GetComponentsInChildren<SkinnedMeshRenderer>();
HashSet<Transform> usedBones = new HashSet<Transform>();
HashSet<Transform> excludedObjects = new HashSet<Transform>();
// Add all bones used by SkinnedMeshRenderers to usedBones set
foreach (var skinnedMeshRenderer in skinnedMeshRenderers)
{
foreach (var bone in skinnedMeshRenderer.bones)
{
usedBones.Add(bone);
}
// Add the SkinnedMeshRenderer's gameObject and its parents to excludedObjects set
Transform current = skinnedMeshRenderer.transform;
while (current != null)
{
excludedObjects.Add(current);
current = current.parent;
}
}
List<Transform> unusedBones = new List<Transform>();
Transform[] allBones = root.GetComponentsInChildren<Transform>();
foreach (var bone in allBones)
{
// 문자열 필터링: 사용자가 입력한 문자열을 포함한 오브젝트는 제외
bool excludeBone = false;
foreach (var excludeString in excludeStrings)
{
if (!string.IsNullOrEmpty(excludeString) && bone.name.ToLower().Contains(excludeString.ToLower()))
{
excludeBone = true;
break;
}
}
if (!usedBones.Contains(bone) &&
!excludedObjects.Contains(bone) &&
bone != root &&
!excludeBone) // 필터링된 오브젝트 제외
{
unusedBones.Add(bone);
}
}
if (unusedBones.Count > 0)
{
Selection.objects = unusedBones.ConvertAll(b => b.gameObject).ToArray();
Debug.Log($"Found {unusedBones.Count} unused bones. Selected in the hierarchy.");
}
else
{
Debug.Log("No unused bones found.");
}
}
}

View File

@ -1,99 +0,0 @@
using UnityEngine;
using UnityEditor;
public class ObjectNameModifier : EditorWindow
{
private string prefixText = string.Empty;
private string suffixText = string.Empty;
[MenuItem("Tools/Object Name Modifier")]
public static void ShowWindow()
{
GetWindow<ObjectNameModifier>("Object Name Modifier");
}
private void OnGUI()
{
GUILayout.Label("Modify Object Names", EditorStyles.boldLabel);
// Prefix Text 입력
prefixText = EditorGUILayout.TextField("Prefix", prefixText);
// Suffix Text 입력
suffixText = EditorGUILayout.TextField("Suffix", suffixText);
GUILayout.Space(10);
// Prefix와 Suffix 추가 버튼
if (GUILayout.Button("Apply Prefix and Suffix"))
{
ApplyPrefixAndSuffix();
}
GUILayout.Space(10);
// 문자열 앞/뒤 한 글자씩 제거
if (GUILayout.Button("Remove First Character"))
{
RemoveFirstCharacter();
}
if (GUILayout.Button("Remove Last Character"))
{
RemoveLastCharacter();
}
GUILayout.Space(10);
// 빈칸을 _로 변경
if (GUILayout.Button("Replace Spaces with Underscores"))
{
ReplaceSpacesWithUnderscores();
}
}
// Prefix와 Suffix를 적용하는 메서드
void ApplyPrefixAndSuffix()
{
foreach (GameObject obj in Selection.gameObjects)
{
Undo.RecordObject(obj, "Change Object Name");
obj.name = prefixText + obj.name + suffixText;
}
}
// 첫 글자를 제거하는 메서드
void RemoveFirstCharacter()
{
foreach (GameObject obj in Selection.gameObjects)
{
if (obj.name.Length > 0)
{
Undo.RecordObject(obj, "Remove First Character");
obj.name = obj.name.Substring(1);
}
}
}
// 마지막 글자를 제거하는 메서드
void RemoveLastCharacter()
{
foreach (GameObject obj in Selection.gameObjects)
{
if (obj.name.Length > 0)
{
Undo.RecordObject(obj, "Remove Last Character");
obj.name = obj.name.Substring(0, obj.name.Length - 1);
}
}
}
// 빈칸을 _로 변경하는 메서드
void ReplaceSpacesWithUnderscores()
{
foreach (GameObject obj in Selection.gameObjects)
{
Undo.RecordObject(obj, "Replace Spaces");
obj.name = obj.name.Replace(" ", "_");
}
}
}