Fix : 옵티 미러 옵션 추가
This commit is contained in:
parent
783ab14f71
commit
6793635c7c
@ -331,6 +331,10 @@ public class OptitrackStreamingClient : MonoBehaviour
|
||||
//[Tooltip("Timecode Provider")]
|
||||
//public bool TimecodeProvider = false;
|
||||
|
||||
[Header("Mirror Mode")]
|
||||
[Tooltip("모든 스켈레톤 본과 리지드바디의 좌우를 거울 반전합니다.")]
|
||||
public bool MirrorMode = false;
|
||||
|
||||
|
||||
#region Private fields
|
||||
//private UInt16 ServerCommandPort = NatNetConstants.DefaultCommandPort;
|
||||
@ -361,6 +365,9 @@ public class OptitrackStreamingClient : MonoBehaviour
|
||||
/// <summary>Maps from a streamed skeleton's ID to its most recent available pose data.</summary>
|
||||
private Dictionary<Int32, OptitrackSkeletonState> m_latestSkeletonStates = new Dictionary<Int32, OptitrackSkeletonState>();
|
||||
|
||||
/// <summary>MirrorMode용: 스켈레톤 ID → (boneId → mirrorBoneId) 매핑 캐시.</summary>
|
||||
private Dictionary<Int32, Dictionary<Int32, Int32>> m_mirrorBoneIdMaps = new Dictionary<Int32, Dictionary<Int32, Int32>>();
|
||||
|
||||
/// <summary>Maps from a streamed trained markerset's ID to its most recent available pose data.</summary>
|
||||
private Dictionary<Int32, OptitrackTMarkersetState> m_latestTMarkersetStates = new Dictionary<Int32, OptitrackTMarkersetState>(); // trained markerset added
|
||||
|
||||
@ -868,8 +875,20 @@ public class OptitrackStreamingClient : MonoBehaviour
|
||||
|
||||
rbState = new OptitrackRigidBodyState();
|
||||
RigidBodyDataToState( rbData, OptitrackHiResTimer.Now(), rbState );
|
||||
}
|
||||
|
||||
|
||||
if ( MirrorMode && rbState != null )
|
||||
{
|
||||
rbState = new OptitrackRigidBodyState
|
||||
{
|
||||
DeliveryTimestamp = rbState.DeliveryTimestamp,
|
||||
IsTracked = rbState.IsTracked,
|
||||
Pose = new OptitrackPose
|
||||
{
|
||||
Position = MirrorPosition( rbState.Pose.Position ),
|
||||
Orientation = MirrorOrientation( rbState.Pose.Orientation ),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return rbState;
|
||||
@ -914,15 +933,80 @@ public class OptitrackStreamingClient : MonoBehaviour
|
||||
deliveryTimestamp = state.DeliveryTimestamp;
|
||||
posOut.Clear();
|
||||
oriOut.Clear();
|
||||
|
||||
if ( MirrorMode )
|
||||
{
|
||||
Dictionary<Int32, Int32> mirrorMap = GetOrBuildMirrorBoneIdMap( skeletonId );
|
||||
foreach ( var kvp in state.BonePoses )
|
||||
{
|
||||
Int32 targetId = mirrorMap != null && mirrorMap.TryGetValue( kvp.Key, out Int32 mid ) ? mid : kvp.Key;
|
||||
posOut[targetId] = MirrorPosition( kvp.Value.Position );
|
||||
oriOut[targetId] = MirrorOrientation( kvp.Value.Orientation );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ( var kvp in state.BonePoses )
|
||||
{
|
||||
posOut[kvp.Key] = kvp.Value.Position;
|
||||
oriOut[kvp.Key] = kvp.Value.Orientation;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 본 이름의 L/R 접두사를 반전한 이름을 반환. 대칭 본이면 null.
|
||||
/// 예: "LUArm" → "RUArm", "RShin" → "LShin", "Hip" → null
|
||||
/// </summary>
|
||||
private static string GetMirrorBoneName( string name )
|
||||
{
|
||||
if ( string.IsNullOrEmpty( name ) || name.Length < 2 ) return null;
|
||||
if ( name[0] == 'L' && char.IsUpper( name[1] ) ) return "R" + name.Substring( 1 );
|
||||
if ( name[0] == 'R' && char.IsUpper( name[1] ) ) return "L" + name.Substring( 1 );
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 스켈레톤 정의를 기반으로 boneId → mirrorBoneId 매핑을 빌드하고 캐시에 저장.
|
||||
/// m_frameDataUpdateLock 내에서 호출해야 함.
|
||||
/// </summary>
|
||||
private Dictionary<Int32, Int32> GetOrBuildMirrorBoneIdMap( Int32 skeletonId )
|
||||
{
|
||||
if ( m_mirrorBoneIdMaps.TryGetValue( skeletonId, out var cached ) )
|
||||
return cached;
|
||||
|
||||
OptitrackSkeletonDefinition skelDef = GetSkeletonDefinitionById( skeletonId );
|
||||
if ( skelDef == null ) return null;
|
||||
|
||||
// 이름 → ID 룩업 테이블
|
||||
var nameToId = new Dictionary<string, Int32>( skelDef.Bones.Count );
|
||||
foreach ( var bone in skelDef.Bones )
|
||||
nameToId[bone.Name] = bone.Id;
|
||||
|
||||
var map = new Dictionary<Int32, Int32>( skelDef.Bones.Count );
|
||||
foreach ( var bone in skelDef.Bones )
|
||||
{
|
||||
string mirrorName = GetMirrorBoneName( bone.Name );
|
||||
if ( mirrorName != null && nameToId.TryGetValue( mirrorName, out Int32 mirrorId ) )
|
||||
map[bone.Id] = mirrorId;
|
||||
else
|
||||
map[bone.Id] = bone.Id; // 대칭 본은 자기 자신에 매핑
|
||||
}
|
||||
|
||||
m_mirrorBoneIdMaps[skeletonId] = map;
|
||||
return map;
|
||||
}
|
||||
|
||||
/// <summary>YZ 평면 기준 회전 미러: X, Z 성분 부호 반전.</summary>
|
||||
private static Quaternion MirrorOrientation( Quaternion q )
|
||||
=> new Quaternion( -q.x, q.y, -q.z, q.w );
|
||||
|
||||
/// <summary>YZ 평면 기준 위치 미러: X 성분 부호 반전.</summary>
|
||||
private static Vector3 MirrorPosition( Vector3 pos )
|
||||
=> new Vector3( -pos.x, pos.y, pos.z );
|
||||
|
||||
|
||||
/// <summary>Get the most recently received state for the specified trained markerset.</summary>
|
||||
/// <param name="tmarkersetId">
|
||||
@ -1113,6 +1197,7 @@ public class OptitrackStreamingClient : MonoBehaviour
|
||||
m_rigidBodyDefinitions.Clear();
|
||||
m_skeletonDefinitions.Clear();
|
||||
m_tmarkersetDefinitions.Clear();
|
||||
m_mirrorBoneIdMaps.Clear(); // 스켈레톤 정의 변경 시 mirror map 캐시 무효화
|
||||
|
||||
// ----------------------------------
|
||||
// - Translate Rigid Body Definitions
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user