Fix : 인스턴스 출력 기능 패치
This commit is contained in:
parent
98d207583a
commit
0abf6970d4
@ -177,7 +177,12 @@ namespace Entum {
|
||||
clip.SetCurve("", typeof(SkinnedMeshRenderer), "blendShape." + curve.Key, curve.Value);
|
||||
}
|
||||
|
||||
string fileName = $"{facial.SessionID}_Facial";
|
||||
// 캐릭터 이름 가져오기
|
||||
string characterName = GetCharacterName();
|
||||
string fileName = string.IsNullOrEmpty(characterName)
|
||||
? $"{facial.SessionID}_Facial"
|
||||
: $"{facial.SessionID}_{characterName}_Facial";
|
||||
|
||||
string filePath = Path.Combine(_savePathManager.GetFacialSavePath(), fileName + ".anim");
|
||||
|
||||
// 인스턴스별 고유 경로 생성
|
||||
@ -193,6 +198,75 @@ namespace Entum {
|
||||
#endif
|
||||
}
|
||||
|
||||
private string GetCharacterName()
|
||||
{
|
||||
if (_animRecorder?.CharacterAnimator == null) return "";
|
||||
|
||||
var animator = _animRecorder.CharacterAnimator;
|
||||
|
||||
// 1. GameObject 이름 사용
|
||||
string objectName = animator.gameObject.name;
|
||||
|
||||
// 2. Avatar 이름이 있으면 우선 사용
|
||||
if (animator.avatar != null && !string.IsNullOrEmpty(animator.avatar.name))
|
||||
{
|
||||
string avatarName = animator.avatar.name;
|
||||
// "Avatar" 접미사 제거
|
||||
if (avatarName.EndsWith("Avatar"))
|
||||
{
|
||||
avatarName = avatarName.Substring(0, avatarName.Length - 6);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(avatarName))
|
||||
{
|
||||
return SanitizeFileName(avatarName);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 부모 오브젝트에서 캐릭터 루트 찾기
|
||||
Transform current = animator.transform.parent;
|
||||
while (current != null)
|
||||
{
|
||||
// VRM, humanoid, character 등의 키워드가 있는 경우
|
||||
string parentName = current.name.ToLower();
|
||||
if (parentName.Contains("character") || parentName.Contains("humanoid") ||
|
||||
parentName.Contains("avatar") || parentName.Contains("vrm"))
|
||||
{
|
||||
return SanitizeFileName(current.name);
|
||||
}
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
// 4. GameObject 이름에서 불필요한 부분 제거
|
||||
objectName = objectName.Replace("(Clone)", "").Trim();
|
||||
return SanitizeFileName(objectName);
|
||||
}
|
||||
|
||||
private string SanitizeFileName(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName)) return "";
|
||||
|
||||
// 파일명에 사용할 수 없는 문자 제거
|
||||
char[] invalidChars = Path.GetInvalidFileNameChars();
|
||||
foreach (char c in invalidChars)
|
||||
{
|
||||
fileName = fileName.Replace(c, '_');
|
||||
}
|
||||
|
||||
// 공백을 언더스코어로 변경
|
||||
fileName = fileName.Replace(' ', '_');
|
||||
|
||||
// 연속된 언더스코어 제거
|
||||
while (fileName.Contains("__"))
|
||||
{
|
||||
fileName = fileName.Replace("__", "_");
|
||||
}
|
||||
|
||||
// 앞뒤 언더스코어 제거
|
||||
fileName = fileName.Trim('_');
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private bool IsSame(CharacterFacialData.SerializeHumanoidFace a, CharacterFacialData.SerializeHumanoidFace b) {
|
||||
if(a.BlendShapeNames.Count != b.BlendShapeNames.Count) {
|
||||
return false;
|
||||
|
||||
@ -112,18 +112,14 @@ namespace Entum
|
||||
// 2. 스크립터블 오브젝트의 이름에서 세션 ID 추출 시도
|
||||
if (!string.IsNullOrEmpty(this.name))
|
||||
{
|
||||
// 파일명에서 세션 ID 패턴 찾기 (예: 250717_192404_abc12345_Motion)
|
||||
// 파일명에서 세션 ID 패턴 찾기 (예: 250717_192404_Motion_abc12345)
|
||||
var nameParts = this.name.Split('_');
|
||||
if (nameParts.Length >= 3)
|
||||
if (nameParts.Length >= 2)
|
||||
{
|
||||
// 첫 번째 두 부분이 날짜와 시간인지 확인
|
||||
if (nameParts[0].Length == 6 && nameParts[1].Length == 6) // yyMMdd_HHmmss 형식
|
||||
{
|
||||
string sessionID = $"{nameParts[0]}_{nameParts[1]}";
|
||||
if (nameParts.Length > 2)
|
||||
{
|
||||
sessionID += "_" + nameParts[2]; // 인스턴스 ID 포함
|
||||
}
|
||||
Debug.Log($"스크립터블 오브젝트 이름에서 세션 ID 추출: {sessionID}");
|
||||
return sessionID;
|
||||
}
|
||||
@ -136,15 +132,11 @@ namespace Entum
|
||||
{
|
||||
string fileName = Path.GetFileNameWithoutExtension(assetPath);
|
||||
var nameParts = fileName.Split('_');
|
||||
if (nameParts.Length >= 3)
|
||||
if (nameParts.Length >= 2)
|
||||
{
|
||||
if (nameParts[0].Length == 6 && nameParts[1].Length == 6) // yyMMdd_HHmmss 형식
|
||||
{
|
||||
string sessionID = $"{nameParts[0]}_{nameParts[1]}";
|
||||
if (nameParts.Length > 2)
|
||||
{
|
||||
sessionID += "_" + nameParts[2]; // 인스턴스 ID 포함
|
||||
}
|
||||
Debug.Log($"에셋 파일명에서 세션 ID 추출: {sessionID}");
|
||||
return sessionID;
|
||||
}
|
||||
@ -309,9 +301,32 @@ namespace Entum
|
||||
// 아바타 이름이 있으면 포함, 없으면 기본값 사용
|
||||
string avatarName = !string.IsNullOrEmpty(AvatarName) ? AvatarName : "Unknown";
|
||||
|
||||
// 인스턴스 ID 디버깅 로그
|
||||
Debug.Log($"출력 시 인스턴스 ID 상태: '{InstanceID}' (비어있음: {string.IsNullOrEmpty(InstanceID)})");
|
||||
|
||||
// 인스턴스 ID가 비어있으면 현재 씬의 SavePathManager에서 가져오기
|
||||
string currentInstanceID = InstanceID;
|
||||
if (string.IsNullOrEmpty(currentInstanceID))
|
||||
{
|
||||
var savePathManager = FindObjectOfType<EasyMotionRecorder.SavePathManager>();
|
||||
if (savePathManager != null)
|
||||
{
|
||||
currentInstanceID = savePathManager.InstanceID;
|
||||
Debug.Log($"SavePathManager에서 인스턴스 ID 가져옴: '{currentInstanceID}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("SavePathManager를 찾을 수 없습니다. 인스턴스 ID 없이 파일 생성됩니다.");
|
||||
}
|
||||
}
|
||||
|
||||
// 인스턴스 ID 포함 파일명 생성
|
||||
string fileName = !string.IsNullOrEmpty(currentInstanceID)
|
||||
? $"{sessionID}_{avatarName}_Generic_{currentInstanceID}.anim"
|
||||
: $"{sessionID}_{avatarName}_Generic.anim";
|
||||
|
||||
// 에셋 파일의 경로를 기반으로 저장 경로 결정
|
||||
string savePath = "Assets/Resources"; // 기본값
|
||||
string fileName = $"{sessionID}_{avatarName}_Generic.anim";
|
||||
|
||||
// 현재 에셋 파일의 경로 가져오기
|
||||
string assetPath = AssetDatabase.GetAssetPath(this);
|
||||
@ -657,9 +672,32 @@ namespace Entum
|
||||
// 아바타 이름이 있으면 포함, 없으면 기본값 사용
|
||||
string avatarName = !string.IsNullOrEmpty(AvatarName) ? AvatarName : "Unknown";
|
||||
|
||||
// 인스턴스 ID 디버깅 로그
|
||||
Debug.Log($"Humanoid 출력 시 인스턴스 ID 상태: '{InstanceID}' (비어있음: {string.IsNullOrEmpty(InstanceID)})");
|
||||
|
||||
// 인스턴스 ID가 비어있으면 현재 씬의 SavePathManager에서 가져오기
|
||||
string currentInstanceID = InstanceID;
|
||||
if (string.IsNullOrEmpty(currentInstanceID))
|
||||
{
|
||||
var savePathManager = FindObjectOfType<EasyMotionRecorder.SavePathManager>();
|
||||
if (savePathManager != null)
|
||||
{
|
||||
currentInstanceID = savePathManager.InstanceID;
|
||||
Debug.Log($"SavePathManager에서 인스턴스 ID 가져옴: '{currentInstanceID}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("SavePathManager를 찾을 수 없습니다. 인스턴스 ID 없이 파일 생성됩니다.");
|
||||
}
|
||||
}
|
||||
|
||||
// 인스턴스 ID 포함 파일명 생성
|
||||
string fileName = !string.IsNullOrEmpty(currentInstanceID)
|
||||
? $"{sessionID}_{avatarName}_Humanoid_{currentInstanceID}.anim"
|
||||
: $"{sessionID}_{avatarName}_Humanoid.anim";
|
||||
|
||||
// 에셋 파일의 경로를 기반으로 저장 경로 결정
|
||||
string savePath = "Assets/Resources"; // 기본값
|
||||
string fileName = $"{sessionID}_{avatarName}_Humanoid.anim";
|
||||
|
||||
// 현재 에셋 파일의 경로 가져오기
|
||||
string assetPath = AssetDatabase.GetAssetPath(this);
|
||||
@ -721,9 +759,29 @@ namespace Entum
|
||||
string sessionID = GetSessionID();
|
||||
string avatarName = !string.IsNullOrEmpty(AvatarName) ? AvatarName : "Unknown";
|
||||
|
||||
// 인스턴스 ID가 비어있으면 현재 씬의 SavePathManager에서 가져오기
|
||||
string currentInstanceID = InstanceID;
|
||||
if (string.IsNullOrEmpty(currentInstanceID))
|
||||
{
|
||||
var savePathManager = FindObjectOfType<EasyMotionRecorder.SavePathManager>();
|
||||
if (savePathManager != null)
|
||||
{
|
||||
currentInstanceID = savePathManager.InstanceID;
|
||||
Debug.Log($"FBX 출력 시 SavePathManager에서 인스턴스 ID 가져옴: '{currentInstanceID}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("SavePathManager를 찾을 수 없습니다. 인스턴스 ID 없이 FBX 파일 생성됩니다.");
|
||||
}
|
||||
}
|
||||
|
||||
// 저장 경로 결정
|
||||
string savePath = "Assets/Resources";
|
||||
string fileName = $"{sessionID}_{avatarName}_Motion.fbx";
|
||||
|
||||
// 인스턴스 ID 포함 파일명 생성
|
||||
string fileName = !string.IsNullOrEmpty(currentInstanceID)
|
||||
? $"{sessionID}_{avatarName}_Motion_{(useAscii ? "ASCII" : "Binary")}_{currentInstanceID}.fbx"
|
||||
: $"{sessionID}_{avatarName}_Motion_{(useAscii ? "ASCII" : "Binary")}.fbx";
|
||||
|
||||
// 현재 에셋 파일의 경로 가져오기
|
||||
string assetPath = AssetDatabase.GetAssetPath(this);
|
||||
|
||||
@ -214,13 +214,14 @@ namespace Entum
|
||||
return;
|
||||
}
|
||||
|
||||
// 세션 ID 생성 (인스턴스별 고유)
|
||||
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss") + "_" + instanceID;
|
||||
// 세션 ID 생성 (인스턴스 ID 제외)
|
||||
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss");
|
||||
|
||||
Poses = ScriptableObject.CreateInstance<HumanoidPoses>();
|
||||
Poses.AvatarName = _animator.name;
|
||||
Poses.Poses = new List<HumanoidPoses.SerializeHumanoidPose>();
|
||||
Poses.SessionID = SessionID;
|
||||
Poses.InstanceID = instanceID; // 인스턴스 ID 설정
|
||||
|
||||
RecordedTime = 0f;
|
||||
StartTime = Time.time;
|
||||
@ -229,11 +230,6 @@ namespace Entum
|
||||
|
||||
Debug.Log($"모션 녹화 시작 - 인스턴스: {instanceID}, 세션: {SessionID}");
|
||||
|
||||
if (_recordTPoseAtStart)
|
||||
{
|
||||
RecordTPoseAsFirstFrame();
|
||||
}
|
||||
|
||||
OnRecordStart?.Invoke();
|
||||
}
|
||||
|
||||
@ -367,7 +363,12 @@ namespace Entum
|
||||
|
||||
UpdateSummaryInfo();
|
||||
|
||||
string fileName = $"{SessionID}_Motion";
|
||||
// 캐릭터 이름 가져오기
|
||||
string characterName = GetCharacterName();
|
||||
string fileName = string.IsNullOrEmpty(characterName)
|
||||
? $"{SessionID}_Motion"
|
||||
: $"{SessionID}_{characterName}_Motion";
|
||||
|
||||
string filePath = Path.Combine(_savePathManager.GetMotionSavePath(), fileName + ".asset");
|
||||
|
||||
// 인스턴스별 고유 경로 생성
|
||||
@ -407,6 +408,73 @@ namespace Entum
|
||||
#endif
|
||||
}
|
||||
|
||||
private string GetCharacterName()
|
||||
{
|
||||
if (_animator == null) return "";
|
||||
|
||||
// 1. GameObject 이름 사용
|
||||
string objectName = _animator.gameObject.name;
|
||||
|
||||
// 2. Avatar 이름이 있으면 우선 사용
|
||||
if (_animator.avatar != null && !string.IsNullOrEmpty(_animator.avatar.name))
|
||||
{
|
||||
string avatarName = _animator.avatar.name;
|
||||
// "Avatar" 접미사 제거
|
||||
if (avatarName.EndsWith("Avatar"))
|
||||
{
|
||||
avatarName = avatarName.Substring(0, avatarName.Length - 6);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(avatarName))
|
||||
{
|
||||
return SanitizeFileName(avatarName);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 부모 오브젝트에서 캐릭터 루트 찾기
|
||||
Transform current = _animator.transform.parent;
|
||||
while (current != null)
|
||||
{
|
||||
// VRM, humanoid, character 등의 키워드가 있는 경우
|
||||
string parentName = current.name.ToLower();
|
||||
if (parentName.Contains("character") || parentName.Contains("humanoid") ||
|
||||
parentName.Contains("avatar") || parentName.Contains("vrm"))
|
||||
{
|
||||
return SanitizeFileName(current.name);
|
||||
}
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
// 4. GameObject 이름에서 불필요한 부분 제거
|
||||
objectName = objectName.Replace("(Clone)", "").Trim();
|
||||
return SanitizeFileName(objectName);
|
||||
}
|
||||
|
||||
private string SanitizeFileName(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName)) return "";
|
||||
|
||||
// 파일명에 사용할 수 없는 문자 제거
|
||||
char[] invalidChars = Path.GetInvalidFileNameChars();
|
||||
foreach (char c in invalidChars)
|
||||
{
|
||||
fileName = fileName.Replace(c, '_');
|
||||
}
|
||||
|
||||
// 공백을 언더스코어로 변경
|
||||
fileName = fileName.Replace(' ', '_');
|
||||
|
||||
// 연속된 언더스코어 제거
|
||||
while (fileName.Contains("__"))
|
||||
{
|
||||
fileName = fileName.Replace("__", "_");
|
||||
}
|
||||
|
||||
// 앞뒤 언더스코어 제거
|
||||
fileName = fileName.Trim('_');
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void ExportHumanoidAnimation(string baseFileName)
|
||||
{
|
||||
@ -415,9 +483,16 @@ namespace Entum
|
||||
string animPath = Path.Combine(_savePathManager.GetMotionSavePath(), $"{baseFileName}_Humanoid.anim");
|
||||
animPath = _savePathManager.GetInstanceSpecificPath(animPath);
|
||||
|
||||
// HumanoidPoses의 기존 내보내기 메서드 사용
|
||||
Poses.ExportHumanoidAnim();
|
||||
Debug.Log($"휴머노이드 애니메이션 출력 완료: {baseFileName}_Humanoid");
|
||||
// 직접 휴머노이드 애니메이션 클립 생성
|
||||
var clip = CreateHumanoidAnimationClip();
|
||||
if (clip != null)
|
||||
{
|
||||
SavePathManager.SafeCreateDirectory(Path.GetDirectoryName(animPath));
|
||||
AssetDatabase.CreateAsset(clip, animPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log($"휴머노이드 애니메이션 출력 완료: {animPath}");
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
@ -432,9 +507,16 @@ namespace Entum
|
||||
string animPath = Path.Combine(_savePathManager.GetMotionSavePath(), $"{baseFileName}_Generic.anim");
|
||||
animPath = _savePathManager.GetInstanceSpecificPath(animPath);
|
||||
|
||||
// HumanoidPoses의 기존 내보내기 메서드 사용
|
||||
Poses.ExportGenericAnim();
|
||||
Debug.Log($"제네릭 애니메이션 출력 완료: {baseFileName}_Generic");
|
||||
// 직접 제네릭 애니메이션 클립 생성
|
||||
var clip = CreateGenericAnimationClip();
|
||||
if (clip != null)
|
||||
{
|
||||
SavePathManager.SafeCreateDirectory(Path.GetDirectoryName(animPath));
|
||||
AssetDatabase.CreateAsset(clip, animPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log($"제네릭 애니메이션 출력 완료: {animPath}");
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
@ -446,7 +528,10 @@ namespace Entum
|
||||
{
|
||||
try
|
||||
{
|
||||
// HumanoidPoses의 기존 FBX 내보내기 메서드 사용
|
||||
string fbxPath = Path.Combine(_savePathManager.GetMotionSavePath(), $"{baseFileName}_{(ascii ? "ASCII" : "Binary")}.fbx");
|
||||
fbxPath = _savePathManager.GetInstanceSpecificPath(fbxPath);
|
||||
|
||||
// FBX 출력은 HumanoidPoses의 기존 메서드 사용 (경로 지정 불가)
|
||||
if (ascii)
|
||||
{
|
||||
Poses.ExportFBXAscii();
|
||||
@ -462,6 +547,115 @@ namespace Entum
|
||||
Debug.LogError($"FBX 애니메이션 출력 실패: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private AnimationClip CreateHumanoidAnimationClip()
|
||||
{
|
||||
if (Poses == null || Poses.Poses.Count == 0) return null;
|
||||
|
||||
var clip = new AnimationClip { frameRate = 30 };
|
||||
|
||||
// Humanoid 애니메이션 설정
|
||||
var settings = new AnimationClipSettings
|
||||
{
|
||||
loopTime = false,
|
||||
cycleOffset = 0,
|
||||
loopBlend = false,
|
||||
loopBlendOrientation = true,
|
||||
loopBlendPositionY = true,
|
||||
loopBlendPositionXZ = true,
|
||||
keepOriginalOrientation = true,
|
||||
keepOriginalPositionY = true,
|
||||
keepOriginalPositionXZ = true,
|
||||
heightFromFeet = false,
|
||||
mirror = false,
|
||||
hasAdditiveReferencePose = false,
|
||||
additiveReferencePoseTime = 0
|
||||
};
|
||||
AnimationUtility.SetAnimationClipSettings(clip, settings);
|
||||
|
||||
// Muscles 데이터를 커브로 변환
|
||||
var muscleCurves = new AnimationCurve[HumanTrait.MuscleCount];
|
||||
for (int i = 0; i < HumanTrait.MuscleCount; i++)
|
||||
{
|
||||
muscleCurves[i] = new AnimationCurve();
|
||||
}
|
||||
|
||||
foreach (var pose in Poses.Poses)
|
||||
{
|
||||
if (pose.Muscles != null && pose.Muscles.Length == HumanTrait.MuscleCount)
|
||||
{
|
||||
for (int i = 0; i < HumanTrait.MuscleCount; i++)
|
||||
{
|
||||
muscleCurves[i].AddKey(pose.Time, pose.Muscles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 커브를 애니메이션 클립에 적용
|
||||
for (int i = 0; i < HumanTrait.MuscleCount; i++)
|
||||
{
|
||||
string muscleName = HumanTrait.MuscleName[i];
|
||||
clip.SetCurve("", typeof(Animator), muscleName, muscleCurves[i]);
|
||||
}
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
private AnimationClip CreateGenericAnimationClip()
|
||||
{
|
||||
if (Poses == null || Poses.Poses.Count == 0) return null;
|
||||
|
||||
var clip = new AnimationClip { frameRate = 30 };
|
||||
|
||||
// 본별 커브 생성
|
||||
var boneCurves = new Dictionary<string, Dictionary<string, AnimationCurve>>();
|
||||
|
||||
foreach (var pose in Poses.Poses)
|
||||
{
|
||||
if (pose.HumanoidBones != null)
|
||||
{
|
||||
foreach (var bone in pose.HumanoidBones)
|
||||
{
|
||||
if (!boneCurves.ContainsKey(bone.Name))
|
||||
{
|
||||
boneCurves[bone.Name] = new Dictionary<string, AnimationCurve>
|
||||
{
|
||||
["localPosition.x"] = new AnimationCurve(),
|
||||
["localPosition.y"] = new AnimationCurve(),
|
||||
["localPosition.z"] = new AnimationCurve(),
|
||||
["localRotation.x"] = new AnimationCurve(),
|
||||
["localRotation.y"] = new AnimationCurve(),
|
||||
["localRotation.z"] = new AnimationCurve(),
|
||||
["localRotation.w"] = new AnimationCurve()
|
||||
};
|
||||
}
|
||||
|
||||
var curves = boneCurves[bone.Name];
|
||||
curves["localPosition.x"].AddKey(pose.Time, bone.LocalPosition.x);
|
||||
curves["localPosition.y"].AddKey(pose.Time, bone.LocalPosition.y);
|
||||
curves["localPosition.z"].AddKey(pose.Time, bone.LocalPosition.z);
|
||||
curves["localRotation.x"].AddKey(pose.Time, bone.LocalRotation.x);
|
||||
curves["localRotation.y"].AddKey(pose.Time, bone.LocalRotation.y);
|
||||
curves["localRotation.z"].AddKey(pose.Time, bone.LocalRotation.z);
|
||||
curves["localRotation.w"].AddKey(pose.Time, bone.LocalRotation.w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 커브를 애니메이션 클립에 적용
|
||||
foreach (var bonePair in boneCurves)
|
||||
{
|
||||
string boneName = bonePair.Key;
|
||||
var curves = bonePair.Value;
|
||||
|
||||
foreach (var curvePair in curves)
|
||||
{
|
||||
clip.SetCurve(boneName, typeof(Transform), curvePair.Key, curvePair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return clip;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void UpdateSummaryInfo()
|
||||
|
||||
@ -144,8 +144,8 @@ namespace Entum
|
||||
return;
|
||||
}
|
||||
|
||||
// 세션 ID 생성 (인스턴스별 고유)
|
||||
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss") + "_" + instanceID;
|
||||
// 세션 ID 생성 (인스턴스 ID 제외)
|
||||
SessionID = DateTime.Now.ToString("yyMMdd_HHmmss");
|
||||
|
||||
// 데이터 초기화
|
||||
objectClips = new Dictionary<Transform, AnimationClip>();
|
||||
@ -227,8 +227,8 @@ namespace Entum
|
||||
// Quaternion 연속성 보장
|
||||
clip.EnsureQuaternionContinuity();
|
||||
|
||||
// 파일명 생성
|
||||
string objectName = target.name;
|
||||
// 파일명 생성 (오브젝트 이름 정리)
|
||||
string objectName = SanitizeFileName(target.name);
|
||||
string fileName = $"{SessionID}_{objectName}_Object.anim";
|
||||
|
||||
// SavePathManager 사용
|
||||
@ -262,6 +262,35 @@ namespace Entum
|
||||
#endif
|
||||
}
|
||||
|
||||
private string SanitizeFileName(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName)) return "";
|
||||
|
||||
// 불필요한 부분 제거
|
||||
fileName = fileName.Replace("(Clone)", "").Trim();
|
||||
|
||||
// 파일명에 사용할 수 없는 문자 제거
|
||||
char[] invalidChars = Path.GetInvalidFileNameChars();
|
||||
foreach (char c in invalidChars)
|
||||
{
|
||||
fileName = fileName.Replace(c, '_');
|
||||
}
|
||||
|
||||
// 공백을 언더스코어로 변경
|
||||
fileName = fileName.Replace(' ', '_');
|
||||
|
||||
// 연속된 언더스코어 제거
|
||||
while (fileName.Contains("__"))
|
||||
{
|
||||
fileName = fileName.Replace("__", "_");
|
||||
}
|
||||
|
||||
// 앞뒤 언더스코어 제거
|
||||
fileName = fileName.Trim('_');
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void ExportObjectAnimationAsHumanoid(Transform target, string baseFileName)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user