fix ; 리타겟팅 스크립트 최적화
This commit is contained in:
parent
a2e080414f
commit
420301c441
@ -57,6 +57,10 @@ namespace KindRetargeting
|
||||
private HumanPose sourcePose;
|
||||
private HumanPose targetPose;
|
||||
|
||||
// 최적화: 프레임당 한 번만 GetHumanPose 호출하기 위한 플래그
|
||||
private bool isSourcePoseCachedThisFrame = false;
|
||||
private bool isTargetPoseCachedThisFrame = false;
|
||||
|
||||
// 본별 회전 오프셋을 저장하는 딕셔너리
|
||||
private Dictionary<HumanBodyBones, Quaternion> rotationOffsets = new Dictionary<HumanBodyBones, Quaternion>();
|
||||
|
||||
@ -184,8 +188,9 @@ namespace KindRetargeting
|
||||
}
|
||||
}
|
||||
|
||||
// 각 손가락 관절별로 필터 버퍼를 관리하는 Dictionary 추가
|
||||
private Dictionary<int, Queue<float>> fingerFilterBuffers = new Dictionary<int, Queue<float>>();
|
||||
// 각 손가락 관절별로 필터 버퍼를 관리하는 Dictionary 추가 (GC 최적화: 배열 재사용)
|
||||
private Dictionary<int, float[]> fingerFilterBuffers = new Dictionary<int, float[]>();
|
||||
private Dictionary<int, int> fingerFilterIndices = new Dictionary<int, int>();
|
||||
|
||||
// CopyFingerPoseByMuscle에서 사용할 본 Transform 저장용 (메모리 재사용)
|
||||
private Dictionary<HumanBodyBones, (Vector3 position, Quaternion rotation)> savedBoneTransforms =
|
||||
@ -487,6 +492,30 @@ namespace KindRetargeting
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 소스 포즈를 캐싱하여 반환합니다. 프레임당 한 번만 GetHumanPose 호출.
|
||||
/// </summary>
|
||||
private void EnsureSourcePoseCached()
|
||||
{
|
||||
if (!isSourcePoseCachedThisFrame && sourcePoseHandler != null)
|
||||
{
|
||||
sourcePoseHandler.GetHumanPose(ref sourcePose);
|
||||
isSourcePoseCachedThisFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 타겟 포즈를 캐싱하여 반환합니다. 프레임당 한 번만 GetHumanPose 호출.
|
||||
/// </summary>
|
||||
private void EnsureTargetPoseCached()
|
||||
{
|
||||
if (!isTargetPoseCachedThisFrame && targetPoseHandler != null)
|
||||
{
|
||||
targetPoseHandler.GetHumanPose(ref targetPose);
|
||||
isTargetPoseCachedThisFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 원본과 대상 아바타의 각 본 간 회전 오프셋을 계산하여 저장합니다.
|
||||
/// </summary>
|
||||
@ -1144,8 +1173,8 @@ namespace KindRetargeting
|
||||
{
|
||||
int stretchedMuscleIndex = muscleIndices.stretchedMuscle;
|
||||
|
||||
// 소스 아바타의 현재 머슬 값 가져오기
|
||||
sourcePoseHandler.GetHumanPose(ref sourcePose);
|
||||
// 소스 아바타의 현재 머슬 값 가져오기 (최적화: 캐싱된 포즈 사용)
|
||||
EnsureSourcePoseCached();
|
||||
float currentMuscle = sourcePose.muscles[stretchedMuscleIndex];
|
||||
|
||||
// 캘리브레이션 데이터가 있으면 정규화
|
||||
@ -1295,6 +1324,10 @@ namespace KindRetargeting
|
||||
/// </summary>
|
||||
void Update()
|
||||
{
|
||||
// 최적화: 프레임 시작 시 포즈 캐시 플래그 리셋
|
||||
isSourcePoseCachedThisFrame = false;
|
||||
isTargetPoseCachedThisFrame = false;
|
||||
|
||||
// 포즈 복사 및 동기화
|
||||
CopyPoseToTarget();
|
||||
|
||||
@ -1342,9 +1375,9 @@ namespace KindRetargeting
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 머슬 데이터 업데이트
|
||||
sourcePoseHandler.GetHumanPose(ref sourcePose);
|
||||
targetPoseHandler.GetHumanPose(ref targetPose);
|
||||
// 2. 머슬 데이터 업데이트 (최적화: 캐싱된 포즈 사용)
|
||||
EnsureSourcePoseCached();
|
||||
EnsureTargetPoseCached();
|
||||
|
||||
for (int i = 0; i < 40; i++)
|
||||
{
|
||||
@ -1388,37 +1421,38 @@ namespace KindRetargeting
|
||||
|
||||
private float ApplyFilter(float value, int fingerIndex)
|
||||
{
|
||||
// 해당 손가락 관절의 필터 버퍼가 없없으면 생성
|
||||
if (!fingerFilterBuffers.ContainsKey(fingerIndex))
|
||||
// 해당 손가락 관절의 필터 버퍼가 없으면 생성 (GC 최적화: 배열 재사용)
|
||||
if (!fingerFilterBuffers.TryGetValue(fingerIndex, out float[] buffer))
|
||||
{
|
||||
fingerFilterBuffers[fingerIndex] = new Queue<float>();
|
||||
buffer = new float[filterBufferSize];
|
||||
fingerFilterBuffers[fingerIndex] = buffer;
|
||||
fingerFilterIndices[fingerIndex] = 0;
|
||||
// 초기값으로 버퍼를 채움
|
||||
for (int i = 0; i < filterBufferSize; i++)
|
||||
{
|
||||
fingerFilterBuffers[fingerIndex].Enqueue(value);
|
||||
buffer[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
var buffer = fingerFilterBuffers[fingerIndex];
|
||||
// 현재 인덱스 가져오기
|
||||
int currentIndex = fingerFilterIndices[fingerIndex];
|
||||
|
||||
// 가장 오래된 값 제거
|
||||
if (buffer.Count >= filterBufferSize)
|
||||
{
|
||||
buffer.Dequeue();
|
||||
}
|
||||
// 새 값을 현재 위치에 덮어쓰기 (순환 버퍼)
|
||||
buffer[currentIndex] = value;
|
||||
|
||||
// 새 값 추가
|
||||
buffer.Enqueue(value);
|
||||
// 다음 인덱스로 이동 (순환)
|
||||
fingerFilterIndices[fingerIndex] = (currentIndex + 1) % filterBufferSize;
|
||||
|
||||
// 가중 평균 계산
|
||||
// 가중 평균 계산 (배열 직접 순회, ToArray 제거)
|
||||
float sum = 0f;
|
||||
float weight = 1f;
|
||||
float totalWeight = 0f;
|
||||
float[] values = buffer.ToArray();
|
||||
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
// 가장 오래된 값부터 순회 (currentIndex+1이 가장 오래된 값)
|
||||
for (int i = 0; i < filterBufferSize; i++)
|
||||
{
|
||||
sum += values[i] * weight;
|
||||
int idx = (currentIndex + 1 + i) % filterBufferSize;
|
||||
sum += buffer[idx] * weight;
|
||||
totalWeight += weight;
|
||||
weight *= 1.5f; // 최근 값에 더 높은 가중치 부여
|
||||
}
|
||||
@ -1495,8 +1529,8 @@ namespace KindRetargeting
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 타겟 포즈 가져오기
|
||||
targetPoseHandler.GetHumanPose(ref targetPose);
|
||||
// 2. 타겟 포즈 가져오기 (최적화: 캐싱된 포즈 사용)
|
||||
EnsureTargetPoseCached();
|
||||
|
||||
// 3. 각 손가락 본에 대해 정규화된 값을 머슬에 적용
|
||||
for (int boneIndex = 24; boneIndex <= 53; boneIndex++)
|
||||
|
||||
@ -89,15 +89,8 @@ namespace KindRetargeting
|
||||
if (sourceBone != null && targetBone != null)
|
||||
{
|
||||
Quaternion offset = Quaternion.Inverse(sourceBone.rotation) * targetBone.rotation;
|
||||
|
||||
if (rotationOffsets.ContainsKey(bone))
|
||||
{
|
||||
rotationOffsets[bone] = offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
rotationOffsets.Add(bone, offset);
|
||||
}
|
||||
// 최적화: ContainsKey + 인덱서 이중 조회 대신 인덱서 직접 사용
|
||||
rotationOffsets[bone] = offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,11 +104,8 @@ namespace KindRetargeting
|
||||
/// <returns>회전 오프셋 (없으면 Identity)</returns>
|
||||
public Quaternion GetRotationOffset(HumanBodyBones bone)
|
||||
{
|
||||
if (rotationOffsets.ContainsKey(bone))
|
||||
{
|
||||
return rotationOffsets[bone];
|
||||
}
|
||||
return Quaternion.identity;
|
||||
// 최적화: TryGetValue로 단일 조회
|
||||
return rotationOffsets.TryGetValue(bone, out Quaternion offset) ? offset : Quaternion.identity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -126,11 +116,10 @@ namespace KindRetargeting
|
||||
/// <returns>오프셋이 적용된 회전값</returns>
|
||||
public Quaternion ApplyRotationOffset(HumanBodyBones bone, Quaternion originalRotation)
|
||||
{
|
||||
if (rotationOffsets.ContainsKey(bone))
|
||||
{
|
||||
return originalRotation * rotationOffsets[bone];
|
||||
}
|
||||
return originalRotation;
|
||||
// 최적화: TryGetValue로 단일 조회
|
||||
return rotationOffsets.TryGetValue(bone, out Quaternion offset)
|
||||
? originalRotation * offset
|
||||
: originalRotation;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -1,8 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
|
||||
namespace KindRetargeting
|
||||
{
|
||||
@ -33,29 +29,35 @@ namespace KindRetargeting
|
||||
private Transform rightShoulder;
|
||||
private Transform leftUpperArm;
|
||||
private Transform rightUpperArm;
|
||||
// 최적화: 팔꿈치(LowerArm) Transform 캐싱 추가
|
||||
private Transform leftLowerArm;
|
||||
private Transform rightLowerArm;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
retargetingScript = GetComponent<CustomRetargetingScript>();
|
||||
|
||||
|
||||
leftShoulder = retargetingScript.targetAnimator.GetBoneTransform(HumanBodyBones.LeftShoulder);
|
||||
rightShoulder = retargetingScript.targetAnimator.GetBoneTransform(HumanBodyBones.RightShoulder);
|
||||
leftUpperArm = retargetingScript.targetAnimator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
|
||||
rightUpperArm = retargetingScript.targetAnimator.GetBoneTransform(HumanBodyBones.RightUpperArm);
|
||||
// 최적화: 팔꿈치 Transform도 Start에서 캐싱
|
||||
leftLowerArm = retargetingScript.targetAnimator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
|
||||
rightLowerArm = retargetingScript.targetAnimator.GetBoneTransform(HumanBodyBones.RightLowerArm);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 왼쪽 어깨 보정
|
||||
Vector3 leftElbowPos = retargetingScript.targetAnimator.GetBoneTransform(HumanBodyBones.LeftLowerArm).position;
|
||||
// 왼쪽 어깨 보정 (최적화: 캐싱된 Transform 사용)
|
||||
Vector3 leftElbowPos = leftLowerArm.position;
|
||||
float leftHeightDiff = leftElbowPos.y - leftShoulder.position.y;
|
||||
float leftRawBlend = Mathf.Clamp01(
|
||||
Mathf.InverseLerp(minHeightDifference, maxHeightDifference, leftHeightDiff) * blendStrength
|
||||
);
|
||||
leftBlendWeight = shoulderCorrectionCurve.Evaluate(leftRawBlend) * maxShoulderBlend;
|
||||
|
||||
// 오른쪽 어깨 보정
|
||||
Vector3 rightElbowPos = retargetingScript.targetAnimator.GetBoneTransform(HumanBodyBones.RightLowerArm).position;
|
||||
// 오른쪽 어깨 보정 (최적화: 캐싱된 Transform 사용)
|
||||
Vector3 rightElbowPos = rightLowerArm.position;
|
||||
float rightHeightDiff = rightElbowPos.y - rightShoulder.position.y;
|
||||
float rightRawBlend = Mathf.Clamp01(
|
||||
Mathf.InverseLerp(minHeightDifference, maxHeightDifference, rightHeightDiff) * blendStrength
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user