Add : 페이셜 녹화 안되는 버그 해결
This commit is contained in:
parent
57ff5e65a7
commit
d05ec6738f
1759
3ds max script/MixamoToBiped_Converter - y up.ms
Normal file
1759
3ds max script/MixamoToBiped_Converter - y up.ms
Normal file
File diff suppressed because it is too large
Load Diff
1759
3ds max script/MixamoToBiped_Converter - z up.ms
Normal file
1759
3ds max script/MixamoToBiped_Converter - z up.ms
Normal file
File diff suppressed because it is too large
Load Diff
1759
3ds max script/MixamoToBiped_Converter.ms
Normal file
1759
3ds max script/MixamoToBiped_Converter.ms
Normal file
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,9 @@ namespace EasyMotionRecorder
|
||||
[SerializeField]
|
||||
public List<float> BlendShapeValues = new List<float>();
|
||||
|
||||
[SerializeField]
|
||||
public List<string> SkinnedMeshRendererNames = new List<string>();
|
||||
|
||||
[SerializeField]
|
||||
public int FrameCount;
|
||||
|
||||
|
||||
@ -50,7 +50,11 @@ namespace Entum {
|
||||
|
||||
private int _frameCount = 0;
|
||||
|
||||
CharacterFacialData.SerializeHumanoidFace _past = new CharacterFacialData.SerializeHumanoidFace();
|
||||
CharacterFacialData.SerializeHumanoidFace _past = new CharacterFacialData.SerializeHumanoidFace() {
|
||||
BlendShapeNames = new List<string>(),
|
||||
BlendShapeValues = new List<float>(),
|
||||
SkinnedMeshRendererNames = new List<string>()
|
||||
};
|
||||
|
||||
private float _recordedTime = 0f;
|
||||
private float _startTime;
|
||||
@ -152,29 +156,90 @@ namespace Entum {
|
||||
var clip = new AnimationClip();
|
||||
clip.frameRate = 30;
|
||||
|
||||
var blendShapeNames = facial.Faces[0].BlendShapeNames;
|
||||
var curves = new Dictionary<string, AnimationCurve>();
|
||||
// 블렌드쉐이프와 렌더러별로 애니메이션 커브를 그룹화
|
||||
var rendererCurves = new Dictionary<string, Dictionary<string, AnimationCurve>>();
|
||||
|
||||
for(int i = 0; i < blendShapeNames.Count; i++) {
|
||||
curves[blendShapeNames[i]] = new AnimationCurve();
|
||||
// 첫 번째 프레임에서 모든 블렌드쉐이프와 렌더러 정보 수집
|
||||
if (facial.Faces.Count > 0)
|
||||
{
|
||||
var firstFace = facial.Faces[0];
|
||||
|
||||
// 기존 데이터 호환성 체크 (SkinnedMeshRendererNames가 없는 경우)
|
||||
bool hasRendererNames = firstFace.SkinnedMeshRendererNames != null &&
|
||||
firstFace.SkinnedMeshRendererNames.Count > 0;
|
||||
|
||||
for(int i = 0; i < firstFace.BlendShapeNames.Count; i++) {
|
||||
var blendShapeName = firstFace.BlendShapeNames[i];
|
||||
var rendererName = hasRendererNames && i < firstFace.SkinnedMeshRendererNames.Count
|
||||
? firstFace.SkinnedMeshRendererNames[i]
|
||||
: "DefaultRenderer"; // 기존 데이터 호환성을 위한 기본값
|
||||
|
||||
if (!rendererCurves.ContainsKey(rendererName)) {
|
||||
rendererCurves[rendererName] = new Dictionary<string, AnimationCurve>();
|
||||
}
|
||||
|
||||
if (!rendererCurves[rendererName].ContainsKey(blendShapeName)) {
|
||||
rendererCurves[rendererName][blendShapeName] = new AnimationCurve();
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasRendererNames) {
|
||||
Debug.LogWarning("기존 데이터 형식 감지: SkinnedMeshRenderer 정보가 없습니다. 기본 경로를 사용합니다.");
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < facial.Faces.Count; i++) {
|
||||
var face = facial.Faces[i];
|
||||
// 모든 프레임의 데이터를 커브에 추가
|
||||
for(int frameIdx = 0; frameIdx < facial.Faces.Count; frameIdx++) {
|
||||
var face = facial.Faces[frameIdx];
|
||||
var time = face.Time;
|
||||
|
||||
// 기존 데이터 호환성 체크
|
||||
bool hasRendererNames = face.SkinnedMeshRendererNames != null &&
|
||||
face.SkinnedMeshRendererNames.Count > 0;
|
||||
|
||||
for(int j = 0; j < face.BlendShapeNames.Count; j++) {
|
||||
var blendShapeName = face.BlendShapeNames[j];
|
||||
var value = face.BlendShapeValues[j];
|
||||
for(int i = 0; i < face.BlendShapeNames.Count; i++) {
|
||||
var blendShapeName = face.BlendShapeNames[i];
|
||||
var value = face.BlendShapeValues[i];
|
||||
var rendererName = hasRendererNames && i < face.SkinnedMeshRendererNames.Count
|
||||
? face.SkinnedMeshRendererNames[i]
|
||||
: "DefaultRenderer"; // 기존 데이터 호환성을 위한 기본값
|
||||
|
||||
if(curves.ContainsKey(blendShapeName)) {
|
||||
curves[blendShapeName].AddKey(time, value);
|
||||
if (rendererCurves.ContainsKey(rendererName) &&
|
||||
rendererCurves[rendererName].ContainsKey(blendShapeName)) {
|
||||
rendererCurves[rendererName][blendShapeName].AddKey(time, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var curve in curves) {
|
||||
clip.SetCurve("", typeof(SkinnedMeshRenderer), "blendShape." + curve.Key, curve.Value);
|
||||
// 렌더러별로 애니메이션 커브를 클립에 추가
|
||||
foreach(var rendererPair in rendererCurves) {
|
||||
var rendererName = rendererPair.Key;
|
||||
var curves = rendererPair.Value;
|
||||
|
||||
string rendererPath;
|
||||
|
||||
// 기존 데이터 호환성: DefaultRenderer인 경우 빈 경로 사용
|
||||
if (rendererName == "DefaultRenderer") {
|
||||
rendererPath = "";
|
||||
Debug.Log($"기존 데이터 호환성: 빈 경로로 {curves.Count}개 블렌드쉐이프 커브 추가");
|
||||
} else {
|
||||
// 해당 렌더러의 Transform 경로 찾기
|
||||
rendererPath = FindRendererPath(root.transform, rendererName);
|
||||
|
||||
if (string.IsNullOrEmpty(rendererPath)) {
|
||||
Debug.LogWarning($"렌더러 '{rendererName}'의 경로를 찾을 수 없습니다. 루트 경로를 사용합니다.");
|
||||
rendererPath = rendererName;
|
||||
}
|
||||
|
||||
Debug.Log($"렌더러 '{rendererName}' ({rendererPath})에 {curves.Count}개 블렌드쉐이프 커브 추가");
|
||||
}
|
||||
|
||||
foreach(var curvePair in curves) {
|
||||
var blendShapeName = curvePair.Key;
|
||||
var curve = curvePair.Value;
|
||||
|
||||
clip.SetCurve(rendererPath, typeof(SkinnedMeshRenderer), "blendShape." + blendShapeName, curve);
|
||||
}
|
||||
}
|
||||
|
||||
// 캐릭터 이름 가져오기
|
||||
@ -198,6 +263,29 @@ namespace Entum {
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 지정된 렌더러 이름의 Transform 경로를 찾습니다.
|
||||
/// </summary>
|
||||
private string FindRendererPath(Transform root, string rendererName) {
|
||||
if (root.name == rendererName) {
|
||||
return "";
|
||||
}
|
||||
|
||||
for (int i = 0; i < root.childCount; i++) {
|
||||
var child = root.GetChild(i);
|
||||
if (child.name == rendererName) {
|
||||
return child.name;
|
||||
}
|
||||
|
||||
string childPath = FindRendererPath(child, rendererName);
|
||||
if (!string.IsNullOrEmpty(childPath)) {
|
||||
return child.name + "/" + childPath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetCharacterName()
|
||||
{
|
||||
if (_animRecorder?.CharacterAnimator == null) return "";
|
||||
@ -272,10 +360,25 @@ namespace Entum {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(a.SkinnedMeshRendererNames.Count != b.SkinnedMeshRendererNames.Count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < a.BlendShapeNames.Count; i++) {
|
||||
if(a.BlendShapeValues[i] != b.BlendShapeValues[i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(a.BlendShapeNames[i] != b.BlendShapeNames[i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SkinnedMeshRenderer 이름도 비교
|
||||
if(i < a.SkinnedMeshRendererNames.Count && i < b.SkinnedMeshRendererNames.Count) {
|
||||
if(a.SkinnedMeshRendererNames[i] != b.SkinnedMeshRendererNames[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -300,6 +403,7 @@ namespace Entum {
|
||||
var current = new CharacterFacialData.SerializeHumanoidFace();
|
||||
current.BlendShapeNames = new List<string>();
|
||||
current.BlendShapeValues = new List<float>();
|
||||
current.SkinnedMeshRendererNames = new List<string>();
|
||||
|
||||
for(int i = 0; i < _smeshs.Length; i++) {
|
||||
var mesh = _smeshs[i];
|
||||
@ -324,6 +428,7 @@ namespace Entum {
|
||||
var weight = mesh.GetBlendShapeWeight(j);
|
||||
current.BlendShapeNames.Add(blendShapeName);
|
||||
current.BlendShapeValues.Add(weight);
|
||||
current.SkinnedMeshRendererNames.Add(mesh.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user