Fix : 옵티 미러 옵션 추가
This commit is contained in:
parent
783ab14f71
commit
6793635c7c
@ -331,6 +331,10 @@ public class OptitrackStreamingClient : MonoBehaviour
|
|||||||
//[Tooltip("Timecode Provider")]
|
//[Tooltip("Timecode Provider")]
|
||||||
//public bool TimecodeProvider = false;
|
//public bool TimecodeProvider = false;
|
||||||
|
|
||||||
|
[Header("Mirror Mode")]
|
||||||
|
[Tooltip("모든 스켈레톤 본과 리지드바디의 좌우를 거울 반전합니다.")]
|
||||||
|
public bool MirrorMode = false;
|
||||||
|
|
||||||
|
|
||||||
#region Private fields
|
#region Private fields
|
||||||
//private UInt16 ServerCommandPort = NatNetConstants.DefaultCommandPort;
|
//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>
|
/// <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>();
|
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>
|
/// <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
|
private Dictionary<Int32, OptitrackTMarkersetState> m_latestTMarkersetStates = new Dictionary<Int32, OptitrackTMarkersetState>(); // trained markerset added
|
||||||
|
|
||||||
@ -868,8 +875,20 @@ public class OptitrackStreamingClient : MonoBehaviour
|
|||||||
|
|
||||||
rbState = new OptitrackRigidBodyState();
|
rbState = new OptitrackRigidBodyState();
|
||||||
RigidBodyDataToState( rbData, OptitrackHiResTimer.Now(), rbState );
|
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;
|
return rbState;
|
||||||
@ -914,15 +933,80 @@ public class OptitrackStreamingClient : MonoBehaviour
|
|||||||
deliveryTimestamp = state.DeliveryTimestamp;
|
deliveryTimestamp = state.DeliveryTimestamp;
|
||||||
posOut.Clear();
|
posOut.Clear();
|
||||||
oriOut.Clear();
|
oriOut.Clear();
|
||||||
foreach ( var kvp in state.BonePoses )
|
|
||||||
|
if ( MirrorMode )
|
||||||
{
|
{
|
||||||
posOut[kvp.Key] = kvp.Value.Position;
|
Dictionary<Int32, Int32> mirrorMap = GetOrBuildMirrorBoneIdMap( skeletonId );
|
||||||
oriOut[kvp.Key] = kvp.Value.Orientation;
|
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;
|
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>
|
/// <summary>Get the most recently received state for the specified trained markerset.</summary>
|
||||||
/// <param name="tmarkersetId">
|
/// <param name="tmarkersetId">
|
||||||
@ -1113,6 +1197,7 @@ public class OptitrackStreamingClient : MonoBehaviour
|
|||||||
m_rigidBodyDefinitions.Clear();
|
m_rigidBodyDefinitions.Clear();
|
||||||
m_skeletonDefinitions.Clear();
|
m_skeletonDefinitions.Clear();
|
||||||
m_tmarkersetDefinitions.Clear();
|
m_tmarkersetDefinitions.Clear();
|
||||||
|
m_mirrorBoneIdMaps.Clear(); // 스켈레톤 정의 변경 시 mirror map 캐시 무효화
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// - Translate Rigid Body Definitions
|
// - Translate Rigid Body Definitions
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user