Streamingle_URP/Assets/Scripts/Vrmtool/VRMSpringBoneMoveTool.cs

235 lines
8.4 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
using VRM; // VRMライブラリの名前空間を確認してください。これが正しいかどうかによっては変更が必要です。
public class VRMSpringBoneMoveTool : EditorWindow
{
GameObject sourcePrefab;
GameObject destinationPrefab;
//[MenuItem("Tools/Transfer VRM Spring Bones")]
static void ShowWindow()
{
GetWindow<VRMSpringBoneMoveTool>("VRM Spring Bone Move Tool");
}
void OnGUI()
{
GUILayout.Label("Transfer VRM Spring Bone Components", EditorStyles.boldLabel);
sourcePrefab = EditorGUILayout.ObjectField("Source Prefab", sourcePrefab, typeof(GameObject), true) as GameObject;
destinationPrefab = EditorGUILayout.ObjectField("Destination Prefab", destinationPrefab, typeof(GameObject), true) as GameObject;
if (GUILayout.Button("Transfer"))
{
if (sourcePrefab == null || destinationPrefab == null)
{
EditorUtility.DisplayDialog("Error", "Source and Destination Prefabs must be set.", "OK");
return;
}
TransferVRMSpringBone();
}
}
void TransferVRMSpringBone()
{
if (!EditorUtility.DisplayDialog("확인", "대상 프리팹의 모든 VRMSpringBone이 삭제됩니다. 계속하시겠습니까?", "예", "아니오"))
{
return;
}
// Secondary 오브젝트 찾기 또는 생성
Transform destSecondary = destinationPrefab.transform.Find("Secondary");
if (destSecondary == null)
{
GameObject secondaryObj = new GameObject("Secondary");
secondaryObj.transform.SetParent(destinationPrefab.transform, false);
destSecondary = secondaryObj.transform;
Debug.Log("Secondary 오브젝트가 생성되었습니다.");
}
// 기존 VRMSpringBone 컴포넌트 제거
var existingBones = destinationPrefab.GetComponentsInChildren<VRMSpringBone>(true);
foreach (var bone in existingBones)
{
DestroyImmediate(bone);
}
int successCount = 0;
int failCount = 0;
// 소스의 VRMSpringBone 컴포넌트 복사
var springBones = sourcePrefab.GetComponentsInChildren<VRMSpringBone>(true);
foreach (var springBone in springBones)
{
try
{
// Secondary 오브젝트에 새로운 VRMSpringBone 컴포넌트 추가
VRMSpringBone newSpringBone = destSecondary.gameObject.AddComponent<VRMSpringBone>();
if (CopyVRMSpringBoneComponents(springBone, newSpringBone))
{
successCount++;
}
else
{
DestroyImmediate(newSpringBone);
failCount++;
}
}
catch (System.Exception e)
{
Debug.LogError($"스프링본 복사 중 오류 발생: {e.Message}");
failCount++;
}
}
if (successCount > 0)
{
EditorUtility.SetDirty(destinationPrefab);
AssetDatabase.SaveAssets();
}
EditorUtility.DisplayDialog("작업 완료",
$"성공: {successCount}개\n실패: {failCount}개", "확인");
}
bool CopyVRMSpringBoneComponents(VRMSpringBone original, VRMSpringBone copy)
{
try
{
// 기본 속성 복사
copy.m_comment = original.m_comment;
copy.m_stiffnessForce = original.m_stiffnessForce;
copy.m_gravityPower = original.m_gravityPower;
copy.m_gravityDir = original.m_gravityDir;
copy.m_dragForce = original.m_dragForce;
copy.m_hitRadius = original.m_hitRadius;
copy.m_updateType = original.m_updateType;
// Center 본 찾기 및 설정
if (original.m_center != null)
{
copy.m_center = FindCorrespondingTransform(original.m_center, destinationPrefab.transform);
if (copy.m_center == null)
{
Debug.LogError($"Center 본을 찾을 수 없습니다: {original.m_center.name}");
return false;
}
}
// Root 본들 찾기 및 설정
List<Transform> newRootBones = new List<Transform>();
foreach (var rootBone in original.RootBones)
{
if (rootBone == null) continue;
var correspondingBone = FindCorrespondingTransform(rootBone, destinationPrefab.transform);
if (correspondingBone != null)
{
newRootBones.Add(correspondingBone);
}
else
{
Debug.LogError($"Root 본을 찾을 수 없습니다: {rootBone.name}");
return false;
}
}
if (newRootBones.Count == 0)
{
Debug.LogError("Root 본이 하나도 설정되지 않았습니다.");
return false;
}
copy.RootBones = newRootBones;
// Collider Groups 찾기 및 설정
if (original.ColliderGroups != null && original.ColliderGroups.Length > 0)
{
List<VRMSpringBoneColliderGroup> newColliderGroups = new List<VRMSpringBoneColliderGroup>();
foreach (var colliderGroup in original.ColliderGroups)
{
if (colliderGroup == null) continue;
var correspondingCollider = FindCorrespondingColliderGroup(colliderGroup, destinationPrefab.transform);
if (correspondingCollider != null)
{
newColliderGroups.Add(correspondingCollider);
}
else
{
Debug.LogWarning($"Collider Group을 찾을 수 없습니다: {colliderGroup.name}");
}
}
copy.ColliderGroups = newColliderGroups.ToArray();
}
return true;
}
catch (System.Exception e)
{
Debug.LogError($"컴포넌트 복사 중 오류 발생: {e.Message}");
return false;
}
}
Transform FindCorrespondingTransform(Transform original, Transform searchRoot)
{
if (original == null) return null;
// 먼저 전체 경로로 시도
var path = GetTransformPath(original, sourcePrefab.transform);
var result = searchRoot.Find(path);
// 경로로 찾지 못한 경우 이름으로 재시도
if (result == null)
{
// 대상 프리팹에서 같은 이름을 가진 모든 Transform을 찾음
var allTransforms = searchRoot.GetComponentsInChildren<Transform>(true);
result = allTransforms.FirstOrDefault(t => t.name == original.name);
if (result != null)
{
Debug.Log($"이름으로 매칭된 본 찾음: {original.name}");
}
}
return result;
}
string GetTransformPath(Transform current, Transform root)
{
if (current == root)
{
return ""; // ルートに到達したら終了
}
var path = current.name;
while (current.parent != null && current.parent != root)
{
current = current.parent;
path = current.name + "/" + path; // 親の名前をパスに追加
}
return path;
}
VRMSpringBoneColliderGroup FindCorrespondingColliderGroup(VRMSpringBoneColliderGroup original, Transform searchRoot)
{
if (original == null)
{
return null;
}
var path = GetTransformPath(original.transform, sourcePrefab.transform);
var correspondingTransform = searchRoot.Find(path);
return correspondingTransform != null ? correspondingTransform.GetComponent<VRMSpringBoneColliderGroup>() : null;
}
void SetTransform(Transform newTransform, Transform originalTransform)
{
newTransform.localPosition = originalTransform.localPosition;
newTransform.localRotation = originalTransform.localRotation;
newTransform.localScale = originalTransform.localScale;
}
}