ADD : I-pose 기능 추가 패치

This commit is contained in:
DESKTOP-S4BOTN2\user 2025-05-03 16:30:57 +09:00
parent 0a7ae6a021
commit e9e1c12284
57 changed files with 2402 additions and 1723 deletions

View File

@ -1,5 +1,5 @@
/*
Copyright © 2016 NaturalPoint Inc.
Copyright <EFBFBD> 2016 NaturalPoint Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,7 +19,7 @@ using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices;
using UnityEngine;
namespace NaturalPoint.NatNetLib
{
@ -252,6 +252,7 @@ namespace NaturalPoint.NatNetLib
public List<sMarkerSetDescription> MarkerSetDescriptions;
public List<sRigidBodyDescription> RigidBodyDescriptions;
public List<sSkeletonDescription> SkeletonDescriptions;
public List<sAssetDescription> AssetDescriptions; // trained markerset added
public List<sForcePlateDescription> ForcePlateDescriptions;
public List<sCameraDescription> CameraDescriptions;
}
@ -472,6 +473,7 @@ namespace NaturalPoint.NatNetLib
Int32 numMarkerSetDescs = 0;
Int32 numRigidBodyDescs = 0;
Int32 numSkeletonDescs = 0;
Int32 numAssetDescs = 0; // trained markerset added
Int32 numForcePlateDescs = 0;
Int32 numCameraDescs = 0;
@ -490,6 +492,9 @@ namespace NaturalPoint.NatNetLib
case (Int32)NatNetDataDescriptionType.NatNetDataDescriptionType_Skeleton:
++numSkeletonDescs;
break;
case (Int32)NatNetDataDescriptionType.NatNetDataDescriptionType_Asset:
++numAssetDescs; // trained markerset added
break;
case (Int32)NatNetDataDescriptionType.NatNetDataDescriptionType_ForcePlate:
++numForcePlateDescs;
break;
@ -504,6 +509,7 @@ namespace NaturalPoint.NatNetLib
MarkerSetDescriptions = new List<sMarkerSetDescription>( numMarkerSetDescs ),
RigidBodyDescriptions = new List<sRigidBodyDescription>( numRigidBodyDescs ),
SkeletonDescriptions = new List<sSkeletonDescription>( numSkeletonDescs ),
AssetDescriptions = new List<sAssetDescription>(numAssetDescs), // trained markerset added
ForcePlateDescriptions = new List<sForcePlateDescription>( numForcePlateDescs ),
CameraDescriptions = new List<sCameraDescription>( numCameraDescs ),
};
@ -527,6 +533,10 @@ namespace NaturalPoint.NatNetLib
sSkeletonDescription skeletonDesc = (sSkeletonDescription)Marshal.PtrToStructure( desc.Description, typeof( sSkeletonDescription ) );
retDescriptions.SkeletonDescriptions.Add( skeletonDesc );
break;
case (Int32)NatNetDataDescriptionType.NatNetDataDescriptionType_Asset: // trained markerset added
sAssetDescription assetDesc = (sAssetDescription)Marshal.PtrToStructure(desc.Description, typeof(sAssetDescription));
retDescriptions.AssetDescriptions.Add( assetDesc );
break;
case (Int32)NatNetDataDescriptionType.NatNetDataDescriptionType_ForcePlate:
sForcePlateDescription forcePlateDesc = (sForcePlateDescription)Marshal.PtrToStructure( desc.Description, typeof( sForcePlateDescription ) );
retDescriptions.ForcePlateDescriptions.Add( forcePlateDesc );

View File

@ -1,5 +1,5 @@
/*
Copyright © 2016 NaturalPoint Inc.
Copyright <EFBFBD> 2016 NaturalPoint Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ using NaturalPoint.NatNetLib;
// Found in NatNetTypes.h
// NOTE: These native structure representations are in some places incomplete
// (e.g. IntPtr to unspecified data) or untested (e.g. the force plate data
// types have not received any testing). See NatNetTypes.h for more info.
@ -40,6 +41,7 @@ namespace NaturalPoint.NatNetLib
public const int MaxModels = 2000;
public const int MaxMarkerSets = 1000;
public const int MaxRigidBodies = 1000;
// Add Assets
public const int MaxAssets = 1000;
@ -65,6 +67,7 @@ namespace NaturalPoint.NatNetLib
// where is client/server msg ids ??
#region Enumerations
internal enum NatNetError
{
@ -93,9 +96,11 @@ namespace NaturalPoint.NatNetLib
NatNetDataDescriptionType_ForcePlate,
NatNetDataDescriptionType_Device,
NatNetDataDescriptionType_Camera,
NatNetDataDescriptionType_Asset,
};
internal enum NatNetVerbosity
{
None = 0,
@ -105,6 +110,7 @@ namespace NaturalPoint.NatNetLib
Error,
};
internal enum AssetTypes
{
Undefined = 0,
@ -118,7 +124,10 @@ namespace NaturalPoint.NatNetLib
// Sender_Server ??
// Packet ??
#region Definition types
// Defns : From MarkerData to CameraDesc
[StructLayout( LayoutKind.Sequential )] // control physical layout of class in memory
// Sequential : laid out in order they are defined
@ -129,9 +138,10 @@ namespace NaturalPoint.NatNetLib
}
[StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi )]
// strings in structure are marshaled as ANSI default
internal struct sServerDescription // following sequence in NatNetTypes.h
internal struct sServerDescription
{
[MarshalAs( UnmanagedType.U1 )] // bool - 1-byte unsigned int, particular reason to
// choose this way of boolean?
@ -141,6 +151,7 @@ namespace NaturalPoint.NatNetLib
// always use SizeConst, character type used with ByValTStr is determined by CharSet
public string HostComputerName;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
// SizeConst in this case is # elements in the array
public byte[] HostComputerAddress;
@ -148,6 +159,7 @@ namespace NaturalPoint.NatNetLib
[MarshalAs( UnmanagedType.ByValTStr, SizeConst = NatNetConstants.MaxNameLength )]
public string HostApp;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
public byte[] HostAppVersion;
@ -165,11 +177,13 @@ namespace NaturalPoint.NatNetLib
[MarshalAs( UnmanagedType.U1 )]
public bool ConnectionMulticast;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
public byte[] ConnectionMulticastAddress;
}
[StructLayout( LayoutKind.Sequential )]
internal struct sDataDescriptions // Array of data descs
{
@ -180,6 +194,7 @@ namespace NaturalPoint.NatNetLib
}
[StructLayout( LayoutKind.Sequential )]
internal struct sDataDescription
{
@ -188,6 +203,7 @@ namespace NaturalPoint.NatNetLib
}
[StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi )]
internal struct sMarkerSetDescription
{
@ -202,6 +218,7 @@ namespace NaturalPoint.NatNetLib
}
[StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi )]
internal struct sRigidBodyDescription
{
@ -213,6 +230,12 @@ namespace NaturalPoint.NatNetLib
public float OffsetX;
public float OffsetY;
public float OffsetZ;
public float OffsetQX;
public float OffsetQY;
public float OffsetQZ;
public float OffsetQW;
public Int32 MarkerCount;
public IntPtr MarkerPositions; // Pointer to float[MarkerCount][3]
public IntPtr MarkerRequiredLabels; // Pointer to int32_t[MarkerCount]
@ -336,6 +359,7 @@ namespace NaturalPoint.NatNetLib
public float Size; // marker size
public Int16 Params; // Host defined parameters. Bit values:
// 0 : Active
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
@ -346,13 +370,12 @@ namespace NaturalPoint.NatNetLib
public Int32 AssetType;
public Int32 AssetID;
public Int32 RigidBodyCount;
public Int32 RigidBodyCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NatNetConstants.MaxSkeletonRigidBodies)]
public sRigidBodyDescription[] RigidBodies;
public Int32 MarkerCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NatNetConstants.MaxMarkers)] // check
public sMarkerDescription[] Markers;
}
@ -362,6 +385,7 @@ namespace NaturalPoint.NatNetLib
// AssetDescription ? - done
// MarkerDescription ? - done
#region Data types
[StructLayout( LayoutKind.Sequential )]
internal struct sFrameOfMocapData
@ -388,6 +412,10 @@ namespace NaturalPoint.NatNetLib
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NatNetConstants.MaxAssets)]
public sAssetData[] Assets;
public Int32 TMarkersetMarkerCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NatNetConstants.MaxLabeledMarkers)]
public sMarker[] TMarkersetMarkers;
public Int32 LabeledMarkerCount;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = NatNetConstants.MaxLabeledMarkers )]
public sMarker[] LabeledMarkers;
@ -406,7 +434,7 @@ namespace NaturalPoint.NatNetLib
public UInt64 CameraMidExposureTimestamp;
public UInt64 CameraDataReceivedTimestamp;
public UInt64 TransmitTimestamp;
// what about PrecisionTimestamps ??
public Int16 Params; // [b0: recording]
// [b1: model list changed]
// [b2: Live/Edit mode (0=Live, 1=Edit)]
@ -490,6 +518,7 @@ namespace NaturalPoint.NatNetLib
[MarshalAs( UnmanagedType.ByValArray, SizeConst = NatNetConstants.MaxAnalogChannels )]
public sAnalogChannelData[] ChannelData;
public Int16 Params;
}
@ -514,8 +543,7 @@ namespace NaturalPoint.NatNetLib
public string ServerAddress;
public string LocalAddress;
public string MulticastAddress;
// subcribed Data ??
// BitstreamVersion ??
};
@ -561,30 +589,27 @@ namespace NaturalPoint.NatNetLib
internal static class NativeMethods
{
// NatNetCAPI.cpp
// Helper methods
[DllImport( NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention )]
public static extern void NatNet_GetVersion( [In, Out, MarshalAs( UnmanagedType.LPArray, SizeConst=4 )] byte[] version );
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern void NatNet_SetLogCallback(NatNetLogCallback pfnCallback);
[DllImport( NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention )]
public static extern void NatNet_DecodeID( Int32 compositeId, out Int32 entityId, out Int32 memberId );
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern void NatNet_DecodeTimecode(UInt32 compositeId, UInt32 timecodeSubframe, out Int32 pOutHour, out Int32 pOutMinute, out Int32 pOutSecond, out Int32 pOutFrame, out Int32 pOutSubFrame);
// TimecodeStringify ??
[DllImport( NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention )]
public static extern void NatNet_SetLogCallback( NatNetLogCallback pfnCallback );
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_CreateAsyncServerDiscovery(out IntPtr discoveryHandle, NatNetServerDiscoveryCallback pfnCallback, IntPtr pUserContext = default(IntPtr), [MarshalAs(UnmanagedType.U1)] bool startImmediately = true);
// Not in NatNet
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention, CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern NatNetError NatNet_AddDirectServerToAsyncDiscovery(IntPtr discoveryHandle, string serverAddress);
// Not in NatNet
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_StartAsyncDiscovery(IntPtr discoveryHandle);
@ -596,6 +621,7 @@ namespace NaturalPoint.NatNetLib
// These functions are not a supported part of the public API, and are
// subject to change without notice.
// client methods
[DllImport( NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention )]
public static extern NatNetError NatNet_Client_Create( out IntPtr clientHandle );
@ -623,8 +649,9 @@ namespace NaturalPoint.NatNetLib
[DllImport( NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention )]
public static extern NatNetError NatNet_Client_SecondsSinceHostTimestamp( IntPtr clientHandle, UInt64 inTimestamp, out double pOutTimeElapsed );
// frame methods
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Client_GetPredictedRigidBodyPose( IntPtr client, Int32 rigidBodyIndex, out sRigidBodyData rigidBodyData, double dt );
public static extern NatNetError NatNet_Frame_GetTransmitTimestamp(IntPtr pFrameOfMocapData, out UInt64 pOutTransmitTimestamp);
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_GetTimecode(IntPtr pFrameOfMocapData, out UInt32 timecode, out UInt32 timecodeSubframe);
@ -635,6 +662,14 @@ namespace NaturalPoint.NatNetLib
[DllImport( NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention )]
public static extern NatNetError NatNet_Frame_GetRigidBody( IntPtr pFrameOfMocapData, Int32 rigidBodyIndex, out sRigidBodyData rigidBodyData );
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Client_GetPredictedRigidBodyPose(IntPtr client, Int32 rigidBodyIndex, out sRigidBodyData rigidBodyData, double dt);
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_GetLabeledMarkerCount(IntPtr pFrameOfMocapData, out Int32 labeledMarkerCount);
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_GetLabeledMarker(IntPtr pFrameOfMocapData, Int32 labeledMarkerIndex, out sMarker labeledMarkerData);
[DllImport( NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention )]
public static extern NatNetError NatNet_Frame_GetSkeletonCount( IntPtr pFrameOfMocapData, out Int32 skeletonCount );
@ -648,15 +683,36 @@ namespace NaturalPoint.NatNetLib
[DllImport( NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention )]
public static extern NatNetError NatNet_Frame_Skeleton_GetRigidBody( IntPtr pFrameOfMocapData, Int32 skeletonIndex, Int32 rigidBodyIndex, out sRigidBodyData rigidBodyData );
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_GetTransmitTimestamp( IntPtr pFrameOfMocapData, out UInt64 pOutTransmitTimestamp );
public static extern NatNetError NatNet_Frame_GetTMarkersetCount(IntPtr pFrameOfMocapData, out Int32 tmarkersetCount);
// trained markerset added
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_GetLabeledMarkerCount( IntPtr pFrameOfMocapData, out Int32 labeledMarkerCount );
public static extern NatNetError NatNet_Frame_TMarkerset_GetId(IntPtr pFrameOfMocapData, Int32 tmarkersetIndex, out Int32 tmarkersetId);
// trained markerset added
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_GetLabeledMarker( IntPtr pFrameOfMocapData, Int32 labeledMarkerIndex, out sMarker labeledMarkerData );
public static extern NatNetError NatNet_Frame_TMarkerset_GetRigidBodyCount(IntPtr pFrameOfMocapData, Int32 tmarkersetIndex, out Int32 rigidBodyCount);
// trained markerset added
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_TMarkerset_GetRigidBody(IntPtr pFrameOfMocapData, Int32 tmarkersetIndex, Int32 rigidBodyIndex, out sRigidBodyData rigidBodyData);
// trained markerset added
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_TMarkerset_GetMarkerCount(IntPtr pFrameOfMocapData, Int32 tmarkersetIndex, out Int32 assetMarkerCount);
// trained markerset added
[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
public static extern NatNetError NatNet_Frame_TMarkerset_GetMarker(IntPtr pFrameOfMocapData, Int32 tmarkersetIndex, Int32 markerIndex, out sMarker markerData);
//// trained markerset added
//[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
//public static extern NatNetError NatNet_Frame_TMarkerset_GetMarkerCount(IntPtr pFrameOfMocapData, out Int32 tmarkMarkerCount);
//// trained markerset added
//[DllImport(NatNetConstants.NatNetLibDllBaseName, CallingConvention = NatNetConstants.NatNetLibCallingConvention)]
//public static extern NatNetError NatNet_Frame_TMarkerset_GetMarker(IntPtr pFrameOfMocapData, Int32 tmarkMarkerIdx, out sMarker markerData);
}
}

Binary file not shown.

View File

@ -1,52 +1,2 @@
fileFormatVersion: 2
guid: 90a37dc4ae5b35a45876059d687031bc
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: x86_64
DefaultValueInitialized: true
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: x86_64
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

BIN
Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/Horse_TM.fbx (Stored with Git LFS) vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,107 @@
fileFormatVersion: 2
guid: 14ec801d62fadf547921258a8b1dadc5
ModelImporter:
serializedVersion: 22200
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importPhysicalCameras: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
strictVertexDataChecks: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: afbc9c9b98650e44f97662b4f503c261
timeCreated: 1470265618
licenseType: Free
NativeFormatImporter:
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 1e09d962f56189d46ad6bcd146c01a77
guid: f6a3494b5f1724443a3bf3aa6741c8a4
PrefabImporter:
externalObjects: {}
userData:

Binary file not shown.

Binary file not shown.

View File

@ -1,93 +1,108 @@
using System;
using System.Collections;
/*
Copyright © 2016 NaturalPoint Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
using UnityEngine;
/// <summary>
/// Implements live tracking of streamed OptiTrack rigid body data onto an object using Rigid Body Name instead of ID,
/// and periodically rechecks the ID.
/// Implements live tracking of streamed OptiTrack rigid body data onto an object.
/// </summary>
public class OptitrackRigidBody : MonoBehaviour
{
[Tooltip("The object containing the OptiTrackStreamingClient script.")]
public OptitrackStreamingClient StreamingClient;
[Tooltip("The ID of the rigid body to track.")]
public int rigidBodyId;
[Tooltip("The name of the rigid body in Motive.")]
public string RigidBodyName;
[Tooltip("Whether to use network compensation for this rigid body.")]
public bool useNetworkCompensation = true;
private float updateInterval = 0.1f;
private OptitrackStreamingClient m_streamingClient;
private bool m_isRigidBodyFound = false;
private int RigidBodyId = -1;
private string lastCheckedName; // 마지막으로 확인한 이름을 저장
[HideInInspector]
public bool isRigidBodyFound = false;
public bool isRigidBodyFound
{
get { return m_isRigidBodyFound; }
}
void Start()
{
// StreamingClient를 찾습니다.
if (this.StreamingClient == null)
m_streamingClient = OptitrackStreamingClient.FindDefaultClient();
if (m_streamingClient == null)
{
this.StreamingClient = OptitrackStreamingClient.FindDefaultClient();
if (this.StreamingClient == null)
{
Debug.LogError(GetType().FullName + ": Streaming client not set, and no " + typeof(OptitrackStreamingClient).FullName + " components found in scene; disabling this component.", this);
this.enabled = false;
Debug.LogError("OptitrackRigidBody: No OptitrackStreamingClient found in scene.", this);
return;
}
m_streamingClient.RegisterRigidBody(this, rigidBodyId);
}
// 주기적으로 RigidBody를 찾는 코루틴 시작
StartCoroutine(CheckRigidBodyIdPeriodically());
#if UNITY_2017_1_OR_NEWER
void OnEnable()
{
Application.onBeforeRender += OnBeforeRender;
}
void Update()
void OnDisable()
{
Application.onBeforeRender -= OnBeforeRender;
}
void OnBeforeRender()
{
UpdatePose();
}
#endif
void UpdatePose()
void Update()
{
if (!isRigidBodyFound) return;
if (m_streamingClient == null)
return;
OptitrackRigidBodyState rbState = StreamingClient.GetLatestRigidBodyState(RigidBodyId);
OptitrackRigidBodyState rbState = m_streamingClient.GetLatestRigidBodyState(rigidBodyId, useNetworkCompensation);
if (rbState != null)
{
this.transform.localPosition = rbState.Pose.Position;
this.transform.localRotation = rbState.Pose.Orientation;
m_isRigidBodyFound = rbState.IsTracked;
if (m_isRigidBodyFound)
{
transform.position = rbState.Pose.Position;
transform.rotation = rbState.Pose.Orientation;
}
}
private IEnumerator CheckRigidBodyIdPeriodically()
{
while (true)
{
// 현재 이름이 마지막으로 확인한 이름과 다르거나, RigidBody를 찾지 못한 상태라면 검색 수행
if (lastCheckedName != RigidBodyName || !isRigidBodyFound)
{
int newRigidBodyId = StreamingClient.GetRigidBodyIdByName(RigidBodyName);
if (newRigidBodyId != -1)
{
if (newRigidBodyId != RigidBodyId)
{
// 새로운 RigidBody 발견
RigidBodyId = newRigidBodyId;
this.StreamingClient.RegisterRigidBody(this, RigidBodyId);
Debug.Log($"RigidBody 재연결 성공: {RigidBodyName} (ID: {RigidBodyId})");
}
isRigidBodyFound = true;
lastCheckedName = RigidBodyName;
}
else
{
// RigidBody를 찾지 못함
isRigidBodyFound = false;
//Debug.LogWarning($"RigidBody를 찾을 수 없음: {RigidBodyName}");
m_isRigidBodyFound = false;
}
}
yield return new WaitForSeconds(updateInterval);
void UpdatePose()
{
OptitrackRigidBodyState rbState = m_streamingClient.GetLatestRigidBodyState(rigidBodyId, useNetworkCompensation);
if (rbState != null)
{
m_isRigidBodyFound = rbState.IsTracked;
if (m_isRigidBodyFound)
{
transform.position = rbState.Pose.Position;
transform.rotation = rbState.Pose.Orientation;
}
}
}
}

View File

@ -137,6 +137,7 @@ public class OptitrackSkeletonAnimator : MonoBehaviour
for (int i = 0; i < m_skeletonDef.Bones.Count; ++i)
{
Int32 boneId = m_skeletonDef.Bones[i].Id;
string boneName = m_skeletonDef.Bones[i].Name;
OptitrackPose bonePose;
GameObject boneObject;
@ -144,36 +145,51 @@ public class OptitrackSkeletonAnimator : MonoBehaviour
bool foundPose = false;
if (StreamingClient.SkeletonCoordinates == StreamingCoordinatesValues.Global)
{
// Use global skeleton coordinates
foundPose = skelState.LocalBonePoses.TryGetValue(boneId, out bonePose);
}
else
{
// Use local skeleton coordinates
foundPose = skelState.BonePoses.TryGetValue(boneId, out bonePose);
}
bool foundObject = m_boneObjectMap.TryGetValue(boneId, out boneObject);
if (foundPose && foundObject)
{
// 손가락 본인 경우 회전 데이터는 무시하고 위치 데이터만 적용
if (IsFingerBone(boneName))
{
boneObject.transform.localPosition = bonePose.Position;
// 회전은 기본값 유지
boneObject.transform.localRotation = Quaternion.identity;
}
else
{
// 손가락이 아닌 다른 본들은 모든 데이터 적용
boneObject.transform.localPosition = bonePose.Position;
boneObject.transform.localRotation = bonePose.Orientation;
}
}
}
// Perform Mecanim retargeting.
if (m_srcPoseHandler != null && m_destPoseHandler != null)
{
// Interpret the streamed pose into Mecanim muscle space representation.
m_srcPoseHandler.GetHumanPose(ref m_humanPose);
// Re-target that muscle space pose to the destination avatar.
m_destPoseHandler.SetHumanPose(ref m_humanPose);
}
}
}
// 손가락 본인지 확인하는 헬퍼 메서드
private bool IsFingerBone(string boneName)
{
return boneName.Contains("Thumb") ||
boneName.Contains("Index") ||
boneName.Contains("Middle") ||
boneName.Contains("Ring") ||
boneName.Contains("Pinky") ||
boneName.Contains("Finger");
}
#region Private methods
/// <summary>

View File

@ -22,6 +22,11 @@ using System.Threading;
using UnityEngine;
using NaturalPoint;
using NaturalPoint.NatNetLib;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using static TMPro.SpriteAssetUtilities.TexturePacker_JsonArray;
/// <summary>Skeleton naming conventions supported by OptiTrack Motive.</summary>
@ -77,6 +82,14 @@ public class OptitrackSkeletonState
public Dictionary<Int32, OptitrackPose> LocalBonePoses;
}
/// <summary>Represents the state of a streamed trained markerset at an instant in time.</summary>
public class OptitrackTMarkersetState // trained markerset added
{
/// <summary>Maps from OptiTrack bone IDs to their corresponding bone poses.</summary>
public Dictionary<Int32, OptitrackPose> BonePoses;
public Dictionary<Int32, OptitrackPose> LocalBonePoses;
}
public class OptitrackRigidBodyDefinition
{
@ -125,6 +138,55 @@ public class OptitrackSkeletonDefinition
public Dictionary<Int32, Int32> BoneIdToParentIdMap;
}
public class OptitrackTMarkersetDefinition // trained markerset added // check where this is coming from
{
public class BoneDefinition
{
/// <summary>The ID of this bone within this trained markerset.</summary>
public Int32 Id;
/// <summary>The ID of this bone's parent bone. A value of 0 means that this is the root bone.</summary>
public Int32 ParentId;
/// <summary>The name of this bone.</summary>
public string Name;
/// <summary>
/// This bone's position offset from its parent in the skeleton's neutral pose.
/// (The neutral orientation is always <see cref="Quaternion.identity"/>.)
/// </summary>
public Vector3 Offset;
}
public class MarkerDefinition
{
/// <summary>The name of this marker.</summary>
public string Name;
public Vector3 Position;
public Int32 Id;
//public float Size;
//public bool Labeled;
//public bool IsActive;
}
/// <summary>Asset ID. Used as an argument to <see cref="OptitrackStreamingClient.GetLatestTMarkersetState"/>.</summary>
public Int32 Id;
/// <summary>Skeleton asset name.</summary>
public string Name;
/// <summary>Bone names, hierarchy, and neutral pose position information.</summary>
public List<BoneDefinition> Bones;
/// <summary>Bone hierarchy information</summary>
public Dictionary<Int32, Int32> BoneIdToParentIdMap;
public List<MarkerDefinition> Markers;
}
public class OptitrackMarkersDefinition
{
/// <summary>The name of this bone.</summary>
@ -236,6 +298,9 @@ public class OptitrackStreamingClient : MonoBehaviour
[Tooltip("Controls whether skeleton data is streamed with local or global coordinates.")]
public StreamingCoordinatesValues SkeletonCoordinates = StreamingCoordinatesValues.Local;
[Tooltip("Controls whether tmarkerset data is streamed with local or global coordinates.")]
public StreamingCoordinatesValues TMarkersetCoordinates = StreamingCoordinatesValues.Local;
[Tooltip("Controls the Bone Naming Convention in the streamed data.")]
public OptitrackBoneNameConvention BoneNamingConvention = OptitrackBoneNameConvention.Motive;
@ -244,6 +309,9 @@ public class OptitrackStreamingClient : MonoBehaviour
[Tooltip("Draws marker visuals in the viewport for debugging and other uses. Using this will increase the data rate in Unicast mode.")]
public bool DrawMarkers = false;
[Tooltip("Draws trained markerset marker visuals in the viewport for debugging and other uses. Using this will increase the data rate in Unicast mode.")]
public bool DrawTMarkersetMarkers = false; // trained markerset added
[Tooltip("Draws camera visuals in the viewport for debugging and other uses. Motive 3.0+ only.")]
public bool DrawCameras = false;
@ -256,6 +324,13 @@ public class OptitrackStreamingClient : MonoBehaviour
[Tooltip("Skips getting data descriptions. Skeletons will not work with this feature turned on, but it will reduce network usage with a large number of rigid bodies.")]
public bool SkipDataDescriptions = false;
[Tooltip("Changes to the version of Natnet used by the server")]
public string ServerNatNetVersion = "";
public string ClientNatNetVersion = "";
//[Tooltip("Timecode Provider")]
//public bool TimecodeProvider = false;
#region Private fields
//private UInt16 ServerCommandPort = NatNetConstants.DefaultCommandPort;
@ -266,6 +341,7 @@ public class OptitrackStreamingClient : MonoBehaviour
private bool m_hasDrawnCameras = false;
private bool m_hasDrawnForcePlates = false;
private bool m_subscribedToMarkers = false;
private bool m_subscribedToTMarkMarkers = false; // trained markerset added
private OptitrackHiResTimer.Timestamp m_lastFrameDeliveryTimestamp;
private Coroutine m_connectionHealthCoroutine = null;
@ -274,6 +350,8 @@ public class OptitrackStreamingClient : MonoBehaviour
private NatNetClient.DataDescriptions m_dataDescs;
private List<OptitrackRigidBodyDefinition> m_rigidBodyDefinitions = new List<OptitrackRigidBodyDefinition>();
private List<OptitrackSkeletonDefinition> m_skeletonDefinitions = new List<OptitrackSkeletonDefinition>();
private List<OptitrackTMarkersetDefinition> m_tmarkersetDefinitions = new List<OptitrackTMarkersetDefinition>(); // trained markerset added
private List<OptitrackMarkersDefinition> m_tmarkmarkersDefinitions = new List<OptitrackMarkersDefinition>(); // trained markerset added
private List<OptitrackMarkersDefinition> m_markersDefinitions = new List<OptitrackMarkersDefinition>();
private List<OptitrackCameraDefinition> m_cameraDefinitions = new List<OptitrackCameraDefinition>();
private List<OptitrackForcePlateDefinition> m_forcePlateDefinitions = new List<OptitrackForcePlateDefinition>();
@ -284,18 +362,30 @@ 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>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
/// <summary>Maps from a streamed marker's ID to its most recent available position.</summary>
private Dictionary<Int32, OptitrackMarkerState> m_latestMarkerStates = new Dictionary<Int32, OptitrackMarkerState>();
/// <summary>Maps from a streamed trained markerset marker's ID to its most recent available position.</summary>
private Dictionary<Int32, OptitrackMarkerState> m_latestTMarkMarkerStates = new Dictionary<Int32, OptitrackMarkerState>(); // trained markerset added
/// <summary>Maps from a streamed rigid body's ID to its component.</summary>
private Dictionary<Int32, MonoBehaviour> m_rigidBodies = new Dictionary<Int32, MonoBehaviour>();
/// <summary>Maps from a streamed skeleton names to its component.</summary>
private Dictionary<string, MonoBehaviour> m_skeletons = new Dictionary<string, MonoBehaviour>();
/// <summary>Maps from a streamed trained markerset names to its component.</summary>
private Dictionary<string, MonoBehaviour> m_tmarkersets = new Dictionary<string, MonoBehaviour>(); // trained markerset added
/// <summary>Maps from a streamed marker's ID to its sphere game object. Used for drawing markers.</summary>
private Dictionary<Int32, GameObject> m_latestMarkerSpheres = new Dictionary<Int32, GameObject>();
/// <summary>Maps from a streamed trained markerset marker's ID to its sphere game object. Used for drawing markers.</summary>
private Dictionary<Int32, GameObject> m_latestTMarkMarkerSpheres = new Dictionary<Int32, GameObject>(); // trained markerset added
/// <summary>
/// Lock held during access to fields which are potentially modified by <see cref="OnNatNetFrameReceived"/> (which
/// executes on a separate thread). Note while the lock is held, any frame updates received are simply dropped.
@ -314,6 +404,7 @@ public class OptitrackStreamingClient : MonoBehaviour
}
List<Int32> markerIds = new List<Int32>();
//Debug.Log("markers: " + m_latestMarkerStates.Count);
lock (m_frameDataUpdateLock)
{
// Move existing spheres and create new ones if necessary
@ -325,7 +416,7 @@ public class OptitrackStreamingClient : MonoBehaviour
}
else
{
var sphere = GameObject.CreatePrimitive( PrimitiveType.Sphere );
var sphere = GameObject.CreatePrimitive( PrimitiveType.Cube );
sphere.transform.parent = this.transform;
sphere.transform.localScale = new Vector3( markerEntry.Value.Size, markerEntry.Value.Size, markerEntry.Value.Size );
sphere.transform.position = markerEntry.Value.Position;
@ -438,6 +529,77 @@ public class OptitrackStreamingClient : MonoBehaviour
}
//if (TimecodeProvider)
//{
// Debug.Log("");
//}
// Trained Markerset Markers if requested to draw // trained markerset added
if (DrawTMarkersetMarkers)
{
//if (m_client != null && ConnectionType == ClientConnectionType.Unicast && !m_subscribedToTMarkMarkers)
//{
// SubscribeTMarkMarkers();
//}
List<Int32> tmarkmarkerIds = new List<Int32>();
//Debug.Log("tmark states: " + m_latestTMarkMarkerStates.Count);
lock (m_frameDataUpdateLock)
{
// Move existing spheres and create new ones if necessary
foreach (KeyValuePair<Int32, OptitrackMarkerState> markerEntry in m_latestTMarkMarkerStates)
{
if (m_latestTMarkMarkerSpheres.ContainsKey(markerEntry.Key))
{
m_latestTMarkMarkerSpheres[markerEntry.Key].transform.position = markerEntry.Value.Position;
}
else
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.parent = this.transform;
cube.transform.localScale = new Vector3(markerEntry.Value.Size, markerEntry.Value.Size, markerEntry.Value.Size);
cube.transform.position = markerEntry.Value.Position;
cube.name = markerEntry.Value.Name;
if (markerEntry.Value.IsActive)
{
// Make active markers cyan colored
cube.GetComponent<Renderer>().material.SetColor("_Color", Color.cyan);
}
m_latestTMarkMarkerSpheres[markerEntry.Key] = cube;
}
tmarkmarkerIds.Add(markerEntry.Key);
}
// find spheres to remove that weren't in the previous frame
List<Int32> markerCubeIdsToDelete = new List<Int32>();
foreach (KeyValuePair<Int32, GameObject> markerCubeEntry in m_latestTMarkMarkerSpheres)
{
if (!tmarkmarkerIds.Contains(markerCubeEntry.Key))
{
// stale marker, tag for removal
markerCubeIdsToDelete.Add(markerCubeEntry.Key);
}
}
// remove stale spheres
foreach (Int32 markerId in markerCubeIdsToDelete)
{
if (m_latestTMarkMarkerSpheres.ContainsKey(markerId))
{
Destroy(m_latestTMarkMarkerSpheres[markerId]);
m_latestTMarkMarkerSpheres.Remove(markerId);
}
}
}
}
else
{
// not drawing markers, remove all marker spheres
foreach (KeyValuePair<Int32, GameObject> markerCubeEntry in m_latestTMarkMarkerSpheres)
{
Destroy(m_latestTMarkMarkerSpheres[markerCubeEntry.Key]);
}
m_latestTMarkMarkerSpheres.Clear();
}
}
@ -449,7 +611,7 @@ public class OptitrackStreamingClient : MonoBehaviour
/// <returns>An arbitrary OptitrackClient from the scene, or null if none are found.</returns>
public static OptitrackStreamingClient FindDefaultClient()
{
OptitrackStreamingClient[] allClients = FindObjectsByType<OptitrackStreamingClient>(FindObjectsSortMode.None);
OptitrackStreamingClient[] allClients = FindObjectsOfType<OptitrackStreamingClient>();
if ( allClients.Length == 0 )
{
@ -519,23 +681,6 @@ public class OptitrackStreamingClient : MonoBehaviour
return rbState;
}
public int GetRigidBodyIdByName(string name)
{
// 먼저 정의 목록을 업데이트
UpdateDefinitions();
// 정의 목록에서 이름으로 Rigid Body ID를 찾음
foreach (var rbDef in m_rigidBodyDefinitions)
{
if (rbDef.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
return rbDef.Id;
}
}
// 이름이 없으면 -1 반환
return -1;
}
/// <summary>Get the most recently received state for the specified skeleton.</summary>
/// <param name="skeletonId">
@ -555,6 +700,25 @@ public class OptitrackStreamingClient : MonoBehaviour
return skelState;
}
/// <summary>Get the most recently received state for the specified trained markerset.</summary>
/// <param name="tmarkersetId">
/// Taken from the corresponding <see cref="OptitrackTMarkersetDefinition.Id"/> field.
/// To find the appropriate skeleton definition, use <see cref="GetTMarkersetDefinitionByName"/>.
/// </param>
/// <returns>The most recent available state, or null if none available.</returns>
public OptitrackTMarkersetState GetLatestTMarkersetState(Int32 tmarkersetId)
{
OptitrackTMarkersetState tmarState;
lock (m_frameDataUpdateLock)
{
m_latestTMarkersetStates.TryGetValue(tmarkersetId, out tmarState);
}
return tmarState;
}
/// <summary>Get the most recently received state for streamed markers.</summary>
/// <returns>The most recent available marker states, or null if none available.</returns>
public List<OptitrackMarkerState> GetLatestMarkerStates()
@ -635,6 +799,68 @@ public class OptitrackStreamingClient : MonoBehaviour
return null;
}
/// <summary>Retrieves the definition of the tmarkerset with the specified asset name.</summary>
/// <param name="TMarkersetName">The name of the tmarkerset for which to retrieve the definition.</param>
/// <returns>The specified tmarkerset definition, or null if not found.</returns> // trained markerset added
public OptitrackTMarkersetDefinition GetTMarkersetDefinitionByName(string TMarkersetName)
{
for (int i = 0; i < m_tmarkersetDefinitions.Count; i++)
{
OptitrackTMarkersetDefinition tmarDef = m_tmarkersetDefinitions[i];
if (tmarDef.Name.Equals(TMarkersetName, StringComparison.InvariantCultureIgnoreCase))
{
return tmarDef;
}
}
return null;
}
/// <summary>Retrieves the definition of the tmarkerset with the specified tmarkerset id.</summary>
/// <param name="tmarkersetId">The id of the tmarkerset for which to retrieve the definition.</param>
/// <returns>The specified tmarkerset definition, or null if not found.</returns> // trained markerset added
public OptitrackTMarkersetDefinition GetTMarkersetDefinitionById(Int32 tmarkersetId)
{
for (int i = 0; i < m_tmarkersetDefinitions.Count; ++i)
{
OptitrackTMarkersetDefinition tmarDef = m_tmarkersetDefinitions[i];
if (tmarDef.Id == tmarkersetId)
{
return tmarDef;
}
}
return null;
}
/// <summary>Get the most recently received state for streamed trained markerset markers.</summary>
/// <returns>The most recent available trained markerset marker states, or null if none available.</returns>
public List<OptitrackMarkerState> GetLatestTMarkMarkerStates() // trained markerset added
{
List<OptitrackMarkerState> tmarkmarkerStates = new List<OptitrackMarkerState>();
Debug.Log("GetLatestTMarkMarker: " + m_latestTMarkMarkerStates.Count);
lock (m_frameDataUpdateLock)
{
foreach (KeyValuePair<Int32, OptitrackMarkerState> markerEntry in m_latestTMarkMarkerStates)
{
OptitrackMarkerState newMarkerState = new OptitrackMarkerState
{
Position = markerEntry.Value.Position,
Labeled = markerEntry.Value.Labeled,
Size = markerEntry.Value.Size,
Id = markerEntry.Value.Id
};
tmarkmarkerStates.Add(newMarkerState);
}
}
return tmarkmarkerStates;
}
/// <summary>Request data descriptions from the host, then update our definitions.</summary>
/// <exception cref="NatNetException">
/// Thrown by <see cref="NatNetClient.GetDataDescriptions"/> if the request to the server fails.
@ -645,6 +871,7 @@ public class OptitrackStreamingClient : MonoBehaviour
UInt32 descriptionTypeMask = 0;
descriptionTypeMask |= (1 << (int)NatNetDataDescriptionType.NatNetDataDescriptionType_RigidBody);
descriptionTypeMask |= (1 << (int)NatNetDataDescriptionType.NatNetDataDescriptionType_Skeleton);
descriptionTypeMask |= (1 << (int)NatNetDataDescriptionType.NatNetDataDescriptionType_Asset); // trained markerset added
if (DrawMarkers)
{
descriptionTypeMask |= (1 << (int)NatNetDataDescriptionType.NatNetDataDescriptionType_MarkerSet);
@ -661,6 +888,7 @@ public class OptitrackStreamingClient : MonoBehaviour
m_rigidBodyDefinitions.Clear();
m_skeletonDefinitions.Clear();
m_tmarkersetDefinitions.Clear();
// ----------------------------------
// - Translate Rigid Body Definitions
@ -735,6 +963,68 @@ public class OptitrackStreamingClient : MonoBehaviour
m_skeletonDefinitions.Add( skelDef );
}
// --------------------------------------------------------------------
// - Translate Trained Markerset Definitions // trained markerset added
// --------------------------------------------------------------------
for (int nativeTmarkDescIdx = 0; nativeTmarkDescIdx < m_dataDescs.AssetDescriptions.Count; ++nativeTmarkDescIdx)
{
sAssetDescription nativeTmark = m_dataDescs.AssetDescriptions[nativeTmarkDescIdx];
// Debug.Log("#rbs: " + nativeTmark.RigidBodyCount); // correct
OptitrackTMarkersetDefinition tmarkDef = new OptitrackTMarkersetDefinition
{
Id = nativeTmark.AssetID,
Name = nativeTmark.Name,
Bones = new List<OptitrackTMarkersetDefinition.BoneDefinition>(nativeTmark.RigidBodyCount),
BoneIdToParentIdMap = new Dictionary<int, int>(),
Markers = new List<OptitrackTMarkersetDefinition.MarkerDefinition>(nativeTmark.MarkerCount),
};
// Populate nested bone definitions.
for (int nativeBoneIdx = 0; nativeBoneIdx < nativeTmark.RigidBodyCount; ++nativeBoneIdx)
{
sRigidBodyDescription nativeBone = nativeTmark.RigidBodies[nativeBoneIdx];
OptitrackTMarkersetDefinition.BoneDefinition boneDef =
new OptitrackTMarkersetDefinition.BoneDefinition
{
Id = nativeBone.Id,
ParentId = nativeBone.ParentId,
Name = nativeBone.Name,
Offset = new Vector3(-nativeBone.OffsetX, nativeBone.OffsetY, nativeBone.OffsetZ),
};
tmarkDef.Bones.Add(boneDef);
tmarkDef.BoneIdToParentIdMap[boneDef.Id] = boneDef.ParentId;
}
// Populate nested marker definitions
for (int nativeMarkerIdx = 0; nativeMarkerIdx < nativeTmark.MarkerCount; ++nativeMarkerIdx)
{
sMarkerDescription nativeMarker = nativeTmark.Markers[nativeMarkerIdx];
//Debug.Log("TMarkerset (X, Y, Z): " + nativeMarker.X + " " + nativeMarker.Y + " " + nativeMarker.Z);
//Debug.Log(nativeMarker.Id + " " + nativeMarker.Name);
OptitrackTMarkersetDefinition.MarkerDefinition markerDef =
new OptitrackTMarkersetDefinition.MarkerDefinition
{
Name = nativeMarker.Name,
Id = nativeMarker.Id,
Position = new Vector3(-nativeMarker.X, nativeMarker.Y, nativeMarker.Z),
};
tmarkDef.Markers.Add(markerDef);
}
//foreach (KeyValuePair<int, int> kvp in tmarkDef.BoneIdToParentIdMap)
//{
// Debug.Log("Key: " + kvp.Key + "Value: " + kvp.Value);
//} // correct
m_tmarkersetDefinitions.Add(tmarkDef);
}
// ----------------------------------
// - Get Marker Definitions (ToDo)
// ----------------------------------
@ -862,6 +1152,18 @@ public class OptitrackStreamingClient : MonoBehaviour
SubscribeSkeleton(component, name);
}
public void RegisterTMarkerset(MonoBehaviour component, string name) // trained markerset added
{
if (m_tmarkersets.ContainsKey(name))
{
return;
}
m_tmarkersets[name] = component;
SubscribeTMarkerset(component, name);
}
/// <summary>
/// (Re)initializes <see cref="m_client"/> and connects to the configured streaming server.
@ -934,6 +1236,10 @@ public class OptitrackStreamingClient : MonoBehaviour
{
SubscribeSkeleton(skel.Value, skel.Key);
}
foreach (KeyValuePair<string, MonoBehaviour> tmark in m_tmarkersets) // trained markerset added
{
SubscribeTMarkerset(tmark.Value, tmark.Key);
}
}
@ -950,6 +1256,9 @@ public class OptitrackStreamingClient : MonoBehaviour
this.enabled = false;
return;
}
byte[] NatNetVersion = m_client.ServerDescription.NatNetVersion;
ServerNatNetVersion = NatNetVersion[0] + "." + NatNetVersion[1] + "." + NatNetVersion[2] + "." + NatNetVersion[3];
ClientNatNetVersion = "" + NatNetClient.NatNetLibVersion;
m_client.NativeFrameReceived += OnNatNetFrameReceived;
m_connectionHealthCoroutine = StartCoroutine( CheckConnectionHealth() );
@ -1077,6 +1386,7 @@ public class OptitrackStreamingClient : MonoBehaviour
result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_GetTimecode(pFrame, out timecode, out timecodeSubframe);
Int32 hour, minute, second, frameNumber, subframeNumber;
NaturalPoint.NatNetLib.NativeMethods.NatNet_DecodeTimecode(timecode, timecodeSubframe, out hour, out minute, out second, out frameNumber, out subframeNumber);
//Debug.Log(hour + "......" + minute + second + frameNumber + subframeNumber);
// ----------------------
// - Update rigid bodies
@ -1174,6 +1484,100 @@ public class OptitrackStreamingClient : MonoBehaviour
}
}
// -----------------------------------------------------
// - Update trained markerset // trained markerset added
// ----------------------------------------------------
//Int32 frameTMarkersetCount = m_dataDescs.AssetDescriptions.Count;
/*result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_GetTMarkersetCount(pFrame, out frameTMarkersetCount);
NatNetException.ThrowIfNotOK(result, "NatNet_Frame_GetTMarkersetCount failed.");*/
for (int tmarkIdx = 0; tmarkIdx < m_dataDescs.AssetDescriptions.Count; ++tmarkIdx)
{
Int32 tmarkersetId = m_dataDescs.AssetDescriptions[tmarkIdx].AssetID;
// Ensure we have a state corresponding to this tmarkerset ID.
OptitrackTMarkersetState tmarkState = GetOrCreateTMarkersetState(tmarkersetId);
// Enumerate this tmarkerset's bone rigid bodies.
Int32 tmarkRbCount = m_dataDescs.AssetDescriptions[tmarkIdx].RigidBodyCount;
for (int boneIdx = 0; boneIdx < tmarkRbCount; ++boneIdx)
{
sRigidBodyData boneData = new sRigidBodyData();
result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_TMarkerset_GetRigidBody(pFrame, tmarkIdx, boneIdx, out boneData);
NatNetException.ThrowIfNotOK(result, "NatNet_Frame_TMarkerset_GetRigidBody failed.");
// In the context of frame data (unlike in the definition data), this ID value is a
// packed composite of both the asset/entity (tmarkerset) ID and member (bone) ID.
Int32 boneTMarkId, boneId;
NaturalPoint.NatNetLib.NativeMethods.NatNet_DecodeID(boneData.Id, out boneTMarkId, out boneId);
// TODO: Could pre-populate this map when the definitions are retrieved.
// Should never allocate after the first frame, at least.
if (tmarkState.BonePoses.ContainsKey(boneId) == false)
{
tmarkState.BonePoses[boneId] = new OptitrackPose();
}
if (tmarkState.LocalBonePoses.ContainsKey(boneId) == false)
{
tmarkState.LocalBonePoses[boneId] = new OptitrackPose();
}
// Flip coordinate handedness from right to left by inverting X and W.
Vector3 bonePos = new Vector3(-boneData.X, boneData.Y, boneData.Z);
Quaternion boneOri = new Quaternion(-boneData.QX, boneData.QY, boneData.QZ, -boneData.QW);
tmarkState.BonePoses[boneId].Position = bonePos;
tmarkState.BonePoses[boneId].Orientation = boneOri;
Vector3 parentBonePos = new Vector3(0, 0, 0);
Quaternion parentBoneOri = new Quaternion(0, 0, 0, 1);
OptitrackTMarkersetDefinition tmarkDef = GetTMarkersetDefinitionById(tmarkersetId);
if (tmarkDef == null)
{
Debug.LogError(GetType().FullName + ": OnNatNetFrameReceived, no corresponding tmarkerset definition for received tmarkerset frame data.", this);
continue;
}
Int32 pId = tmarkDef.BoneIdToParentIdMap[boneId];
if (pId != -1)
{
parentBonePos = tmarkState.BonePoses[pId].Position;
parentBoneOri = tmarkState.BonePoses[pId].Orientation;
}
tmarkState.LocalBonePoses[boneId].Position = bonePos - parentBonePos;
tmarkState.LocalBonePoses[boneId].Orientation = Quaternion.Inverse(parentBoneOri) * boneOri;
}
// --------------------------------------------
// - Update trained markerset markers
// --------------------------------------------
Int32 tmarkMarkerCount = m_dataDescs.AssetDescriptions[tmarkIdx].MarkerCount;
/*result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_TMarkerset_GetMarkerCount(pFrame, tmarkIdx, out tmarkMarkerCount);
NatNetException.ThrowIfNotOK(result, "NatNet_Frame_TMarkerset_GetMarkerCount failed.");*/
//Debug.Log("tmark marker count: " + tmarkMarkerCount); // working finally
m_latestTMarkMarkerStates.Clear();
// Update Trained Markerset Marker data
for (int markerIdx = 0; markerIdx < tmarkMarkerCount; ++markerIdx)
{
sMarker tmarker = new sMarker(); // markerData
result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_TMarkerset_GetMarker(pFrame, tmarkIdx, markerIdx, out tmarker);
NatNetException.ThrowIfNotOK(result, "NatNet_Frame_TMarkerset_GetMarker failed.");
//Debug.Log("result: " + result);
// Flip coordinate handedness
OptitrackMarkerState tmarkerState = GetOrCreateTMarkMarkerState(tmarker.Id);
tmarkerState.Name = GetMarkerName(tmarker);
tmarkerState.Position = new Vector3(-tmarker.X, tmarker.Y, tmarker.Z);
tmarkerState.Size = tmarker.Size;
tmarkerState.Labeled = (tmarker.Params & 0x10) == 0;
tmarkerState.Id = tmarker.Id;
tmarkerState.IsActive = (tmarker.Params & 0x20) != 0;
}
}
// ----------------------
// - Update markers
@ -1183,6 +1587,7 @@ public class OptitrackStreamingClient : MonoBehaviour
NatNetException.ThrowIfNotOK( result, "NatNet_Frame_GetLabeledMarkerCount failed.");
m_latestMarkerStates.Clear();
//Debug.Log("marker count: " + MarkerCount);
for (int markerIdx = 0; markerIdx < MarkerCount; ++markerIdx)
{
@ -1199,6 +1604,7 @@ public class OptitrackStreamingClient : MonoBehaviour
markerState.Id = marker.Id;
markerState.IsActive = (marker.Params & 0x20) != 0;
}
}
catch (Exception ex)
{
@ -1221,6 +1627,7 @@ public class OptitrackStreamingClient : MonoBehaviour
string assetName = "";
OptitrackRigidBodyDefinition rigidBodyDef = GetRigidBodyDefinitionById( assetID );
OptitrackSkeletonDefinition skeletonDef = GetSkeletonDefinitionById( assetID );
OptitrackTMarkersetDefinition tmarkersetDef = GetTMarkersetDefinitionById( assetID );
if (rigidBodyDef != null)
{
@ -1230,6 +1637,10 @@ public class OptitrackStreamingClient : MonoBehaviour
{
assetName = skeletonDef.Name;
}
else if (tmarkersetDef != null)
{
assetName = tmarkersetDef.Name;
}
// Figure out if the marker is labeled or active
bool IsLabeled = (marker.Params & 0x10) == 0;
@ -1348,6 +1759,81 @@ public class OptitrackStreamingClient : MonoBehaviour
}
}
private void SubscribeTMarkerset(MonoBehaviour component, string name) // check the version numbers // trained markerset added
{
if (m_client != null && ConnectionType == ClientConnectionType.Unicast)
{
if (m_client.ServerAppVersion >= new Version(2, 2, 1))
{
// Try subscribing up to 3 times with a 2000 ms timeout before giving up.
bool subscribeSucceeded = m_client.RequestCommand("SubscribeToData,TrainedMarkersets," + name, 2000, 3);
// Log a warning on the first failure.
if (!subscribeSucceeded && !m_doneSubscriptionNotice)
{
Debug.LogError("Failed to subscribe to trained markerset streaming data for component", component);
m_doneSubscriptionNotice = true;
}
}
else if (m_client.ServerAppVersion == new Version(2, 2, 0, 0))
{
// Motive 2.2.0 has a bug were Motive says it subscribes successfully, but doesn't.
// Subscribing to all skeletons still works, so for this version that is done instead.
// Try subscribing up to 3 times with a 2000 ms timeout before giving up.
bool subscribeSucceeded = m_client.RequestCommand("SubscribeToData,TrainedMarkersets,All" + name, 2000, 3);
if (!subscribeSucceeded && !m_doneSubscriptionNotice)
{
Debug.LogError("Failed to subscribe to all trained markersets streaming data some unknown reason.", component);
m_doneSubscriptionNotice = true;
}
}
else
{
Debug.LogWarning("Your version of Motive is too old to support NatNet skeleton data subscription; streaming bandwidth consumption may be higher than necessary. This feature works in Motive 2.2.1+.");
m_doneSubscriptionNotice = true;
}
}
}
private void SubscribeTMarkMarkers()
{
if (m_client != null && ConnectionType == ClientConnectionType.Unicast)
{
bool subscribeSucceeded4 = m_client.RequestCommand("SubscribeToData, TrainedMarkersetMarkers,All", 2000, 3);
//Debug.Log("TMMarkers: " + subscribeSucceeded4);
// Log a warning on the first failure.
if (!subscribeSucceeded4 && !m_doneSubscriptionNotice)
{
if (m_client.ServerDescription.HostApp == "Motive")
{
// Host app is Motive: If new enough to support subscription, failure is an error.
// Otherwise, warn them that they may want to update Motive to reduce bandwidth consumption.
if (m_client.ServerAppVersion >= new Version(2, 2, 0))
{
Debug.LogError("Failed to subscribe to tmark marker streaming data");
}
else
{
Debug.LogWarning("Your version of Motive is too old to support NatNet tmark marker data subscription; streaming bandwidth consumption may be higher than necessary. This feature works in Motive 2.2.0+.");
}
}
else
{
// Not Motive, we don't know whether it "should" support this. Warning instead of error.
Debug.LogWarning("Failed to subscribe to tmark marker streaming data");
}
m_doneSubscriptionNotice = true;
}
}
}
private void SubscribeMarkers( )
{
if (m_client != null && ConnectionType == ClientConnectionType.Unicast)
@ -1356,6 +1842,8 @@ public class OptitrackStreamingClient : MonoBehaviour
bool subscribeSucceeded = m_client.RequestCommand("SubscribeToData,MarkerSetMarkers,All", 2000, 3);
bool subscribeSucceeded2 = m_client.RequestCommand("SubscribeToData,LabeledMarkers,All", 2000, 3);
bool subscribeSucceeded3 = m_client.RequestCommand("SubscribeToData,LegacyUnlabeledMarkers,All", 2000, 3);
//bool subscribeSucceeded4 = m_client.RequestCommand("SubscribeToData, TrainedMarkersetMarkers,All", 2000, 3);
//bool allSubscribeSucceeded = subscribeSucceeded4;
bool allSubscribeSucceeded = subscribeSucceeded && subscribeSucceeded2 && subscribeSucceeded3;
m_subscribedToMarkers = allSubscribeSucceeded;
@ -1447,6 +1935,60 @@ public class OptitrackStreamingClient : MonoBehaviour
return returnedState;
}
private OptitrackTMarkersetState GetOrCreateTMarkersetState(Int32 tmarkersetId)
{
OptitrackTMarkersetState returnedState = null;
if (m_latestTMarkersetStates.ContainsKey(tmarkersetId))
{
returnedState = m_latestTMarkersetStates[tmarkersetId];
}
else
{
OptitrackTMarkersetState newTMarkersetState = new OptitrackTMarkersetState
{
BonePoses = new Dictionary<Int32, OptitrackPose>(),
LocalBonePoses = new Dictionary<int, OptitrackPose>(),
};
m_latestTMarkersetStates[tmarkersetId] = newTMarkersetState;
returnedState = newTMarkersetState;
}
return returnedState;
}
/// <summary>
/// Returns the <see cref="OptitrackMarkerState"/> corresponding to the provided <paramref name="markerId"/>.
/// If the requested state object does not exist yet, it will initialize and return a newly-created one.
/// </summary>
/// <remarks>Makes the assumption that the lock on <see cref="m_frameDataUpdateLock"/> is already held.</remarks>
/// <param name="markerId">The ID of the bone in trained markerset for which to retrieve the corresponding state.</param>
/// <returns>The existing state object, or a newly created one if necessary.</returns>
private OptitrackMarkerState GetOrCreateTMarkMarkerState(Int32 markerId)
{
OptitrackMarkerState returnedState = null;
if (m_latestTMarkMarkerStates.ContainsKey(markerId))
{
returnedState = m_latestTMarkMarkerStates[markerId];
}
else
{
OptitrackMarkerState newMarkerState = new OptitrackMarkerState
{
Position = new Vector3(),
};
m_latestTMarkMarkerStates[markerId] = newMarkerState;
returnedState = newMarkerState;
}
//Debug.Log(returnedState);
return returnedState;
}
/// <summary>
/// Returns the <see cref="OptitrackMarkerState"/> corresponding to the provided <paramref name="markerId"/>.

View File

@ -0,0 +1,190 @@
/*
Copyright © 2016 NaturalPoint Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Implements live tracking of streamed OptiTrack trained markerset data onto an asset in Unity.
/// </summary>
/// <remarks>
/// A hierarchy of GameObjects (see <see cref="m_rootObject"/> and <see cref="m_boneObjectMap"/>) will be created to
/// receive the streaming pose data for the tmarkerset asset specified by <see cref="TMarkersetAssetName"/>.
/// </remarks>
public class OptitrackTrainedMarkerset : MonoBehaviour
{
/// <summary>The client object to use for receiving streamed TMarkerset pose data.</summary>
[Tooltip("The object containing the OptiTrackStreamingClient script.")]
public OptitrackStreamingClient StreamingClient;
/// <summary>The name of the TMarkerset asset in the stream that will provide retargeting source data.</summary>
[Tooltip("The name of markerset asset in Motive.")]
public string TMarkersetAssetName = "TMarkerset1";
#region Private fields
/// <summary>The streamed source tmarkerset definition.</summary>
private OptitrackTMarkersetDefinition m_tmarkersetDef;
/// <summary>The root GameObject of the streamed tmarkerset pose transform hierarchy.</summary>
private GameObject m_rootObject;
/// <summary>Maps between OptiTrack tmarkerset bone IDs and corresponding GameObjects.</summary>
private Dictionary<Int32, GameObject> m_boneObjectMap;
/// <summary>
/// Maps between game object's bone names (keys) and streamed bone names from OptiTrack software (values).
/// </summary>
private Dictionary<string, Transform> m_cachedBoneNameMap = new Dictionary<string, Transform>(); // Optitrack's skeleton's bone names
private Dictionary<Transform, Transform> m_transformMap = new Dictionary<Transform, Transform>();
#endregion Private fields
void Start()
{
// If the user didn't explicitly associate a client, find a suitable default.
if (this.StreamingClient == null)
{
this.StreamingClient = OptitrackStreamingClient.FindDefaultClient();
// If we still couldn't find one, disable this component.
if (this.StreamingClient == null)
{
Debug.LogError(GetType().FullName + ": Streaming client not set, and no " + typeof(OptitrackStreamingClient).FullName + " components found in scene; disabling this component.", this);
this.enabled = false;
return;
}
}
this.StreamingClient.RegisterTMarkerset(this, this.TMarkersetAssetName);
// Retrieve the OptiTrack tmarkerset definition.
m_tmarkersetDef = this.StreamingClient.GetTMarkersetDefinitionByName(this.TMarkersetAssetName);
if (m_tmarkersetDef == null)
{
Debug.LogError(GetType().FullName + ": Could not find trained markerset definition with the name \"" + this.TMarkersetAssetName + "\"", this);
this.enabled = false;
return;
}
// Create a hierarchy of GameObjects that will receive the tmarkerset pose data
string rootObjectName = "OptiTrack TMarkerset - " + this.TMarkersetAssetName;
m_rootObject = new GameObject( rootObjectName );
m_boneObjectMap = new Dictionary<Int32, GameObject>( m_tmarkersetDef.Bones.Count );
for (int boneDefIdx = 0; boneDefIdx < m_tmarkersetDef.Bones.Count; boneDefIdx++)
{
OptitrackTMarkersetDefinition.BoneDefinition boneDef = m_tmarkersetDef.Bones[boneDefIdx];
GameObject boneObject = new GameObject(boneDef.Name);
if (boneDef.ParentId == -1) { boneObject.name = "Root"; } // set the parent name to 'Root' to match the naming in dictionary
boneObject.transform.parent = boneDef.ParentId == -1 ? m_rootObject.transform : m_boneObjectMap[boneDef.ParentId].transform; // parent ID starts at -1 in TM
boneObject.transform.localPosition = boneDef.Offset;
m_boneObjectMap[boneDef.Id] = boneObject;
//Debug.Log("boneDef: " + boneObject.name + " " + boneObject.transform.name); // exact same
m_cachedBoneNameMap[boneObject.transform.name] = boneObject.transform;
}
Setup(rootObjectName);
m_rootObject.transform.parent = this.StreamingClient.transform;
m_rootObject.transform.localPosition = Vector3.zero;
m_rootObject.transform.localRotation = Quaternion.identity;
}
private void Update()
{
OptitrackTMarkersetState tmarState = StreamingClient.GetLatestTMarkersetState( m_tmarkersetDef.Id );
if (tmarState != null)
{
// Update the transforms of the bone GameObjects.
for (int i = 0; i < m_tmarkersetDef.Bones.Count; ++i)
{
Int32 boneId = m_tmarkersetDef.Bones[i].Id;
OptitrackPose bonePose;
GameObject boneObject;
bool foundPose = false;
if (StreamingClient.TMarkersetCoordinates == StreamingCoordinatesValues.Global)
{
// Use global tmarkerset coordinates
foundPose = tmarState.LocalBonePoses.TryGetValue(boneId, out bonePose);
}
else
{
// Use local tmarkerset coordinates
foundPose = tmarState.BonePoses.TryGetValue(boneId, out bonePose);
}
bool foundObject = m_boneObjectMap.TryGetValue(boneId, out boneObject);
if (foundPose && foundObject)
{
boneObject.transform.localPosition = bonePose.Position;
boneObject.transform.localRotation = bonePose.Orientation;
m_transformMap[boneObject.transform].transform.localPosition = bonePose.Position;
m_transformMap[boneObject.transform].transform.localRotation = bonePose.Orientation;
}
}
}
}
#region Private methods
/// <summary>
/// Constructs the source to target mapping of the bones
/// </summary>
/// <param name="rootObjectName"></param>
private void Setup(string rootObjectName)
{
// Set up the mapping between destination Game Object and hierarchy of GameObjects we created with the source streamed data
//Debug.Log("name of gameobject: " + gameObject.name);
GameObject srcObject = GameObject.Find(rootObjectName);
Transform[] srcObjectBones = srcObject.GetComponentsInChildren<Transform>(); // source
Transform[] tarObjectBones = this.GetComponentsInChildren<Transform>(); // target
// Iterate through the bones in source and map onto the destination
foreach (var bone in tarObjectBones)
{
if (bone.name.EndsWith("End"))
{
;
}
else
{
if (m_cachedBoneNameMap.ContainsKey(bone.name) == false)
{
Debug.Log(bone.name + " name exists in target, but does not exist in the source.");
}
else
{
m_transformMap[m_cachedBoneNameMap[bone.name]] = bone;
}
}
}
}
#endregion Private methods
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 07333194d9e70e74692863bb8b2c148a

View File

@ -1,6 +1,6 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-1324386466927670935
--- !u!114 &-6543920408461200634
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
@ -28,11 +28,7 @@ Material:
- _EMISSION
- _NORMALMAP
- _OCCLUSIONMAP
- _SPECULAR_SETUP
m_InvalidKeywords:
- _LIGHTMAPPING_STATIC_LIGHTMAPS
- _UVPRIM_UV1
- _UVSEC_UV1
m_InvalidKeywords: []
m_LightmapFlags: 0
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
@ -111,6 +107,7 @@ Material:
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaTestRef: 0.5
- _AlphaToMask: 0
@ -141,7 +138,7 @@ Material:
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Shininess: 0.41313845
- _Smoothness: 0.15
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
@ -149,7 +146,7 @@ Material:
- _Surface: 0
- _UVPrim: 0
- _UVSec: 0
- _WorkflowMode: 0
- _WorkflowMode: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}

BIN
Assets/External/UniGLTF/Runtime/Resources/I-Pose.pose.asset (Stored with Git LFS) vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c4b8a69c9f45e384d92846d5b5081c1a
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: 7d2617171adc40b41ac50228f101e178
timeCreated: 1546851178
licenseType: Pro
DefaultImporter:
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -6,6 +6,7 @@ namespace UniHumanoid
public class HumanPoseClip : ScriptableObject
{
public const string TPoseResourcePath = "T-Pose.pose";
public const string IPoseResourcePath = "I-Pose.pose";
public Vector3 bodyPosition;

Binary file not shown.

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c50d1706d9c5fce43b5f9ee9bd3c1d59
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 872de359ed282b846ba8b1d2ffd14aac
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,136 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-7164037998396398279
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 9
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: PlaneUV
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 2800000, guid: fb1c6a42d195a80488bb37ada228ebfa, type: 3}
m_Scale: {x: 80, y: 80}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: fb1c6a42d195a80488bb37ada228ebfa, type: 3}
m_Scale: {x: 80, y: 80}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1452bd3d60b905d4499a8e9c99d5b488
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/ResourcesData/Etc/Plane UV/PlaneUV.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: fb1c6a42d195a80488bb37ada228ebfa
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Scenes/Development scene.unity (Stored with Git LFS)

Binary file not shown.

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d987f2b028376dc4a9e670318498ddca
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,138 @@
using UnityEngine;
using UnityEditor;
using System.IO;
using UniHumanoid;
using UniGLTF;
[System.Serializable]
public class HumanPoseData
{
public Vector3 bodyPosition;
public Quaternion bodyRotation;
public float[] muscles;
}
public class HumanPoseClipApplier : EditorWindow
{
private Animator targetAnimator;
private HumanPoseClip poseClip;
private string jsonPath;
private bool useJsonFile = false;
[MenuItem("Tools/Animation/Apply Human Pose Clip")]
public static void ShowWindow()
{
GetWindow<HumanPoseClipApplier>("Human Pose Clip Applier");
}
private void OnGUI()
{
GUILayout.Label("Apply Human Pose Clip to Animator", EditorStyles.boldLabel);
EditorGUILayout.Space();
targetAnimator = (Animator)EditorGUILayout.ObjectField("Target Animator", targetAnimator, typeof(Animator), true);
EditorGUILayout.Space();
useJsonFile = EditorGUILayout.Toggle("Use JSON File", useJsonFile);
if (useJsonFile)
{
EditorGUILayout.BeginHorizontal();
jsonPath = EditorGUILayout.TextField("JSON File Path", jsonPath);
if (GUILayout.Button("Browse", GUILayout.Width(60)))
{
string path = EditorUtility.OpenFilePanel("Select JSON File", "", "json");
if (!string.IsNullOrEmpty(path))
{
jsonPath = path;
}
}
EditorGUILayout.EndHorizontal();
}
else
{
poseClip = (HumanPoseClip)EditorGUILayout.ObjectField("Pose Clip", poseClip, typeof(HumanPoseClip), false);
}
EditorGUILayout.Space();
bool canApply = targetAnimator != null &&
((useJsonFile && !string.IsNullOrEmpty(jsonPath)) || (!useJsonFile && poseClip != null));
GUI.enabled = canApply;
if (GUILayout.Button("Apply Pose Clip"))
{
ApplyPoseClip();
}
GUI.enabled = true;
}
private void ApplyPoseClip()
{
if (targetAnimator == null)
{
EditorUtility.DisplayDialog("Error", "Please select an Animator!", "OK");
return;
}
HumanPose pose;
if (useJsonFile)
{
if (string.IsNullOrEmpty(jsonPath) || !File.Exists(jsonPath))
{
EditorUtility.DisplayDialog("Error", "Please select a valid JSON file!", "OK");
return;
}
// JSON 파일에서 데이터 로드
string jsonContent = File.ReadAllText(jsonPath);
HumanPoseData poseData = JsonUtility.FromJson<HumanPoseData>(jsonContent);
// HumanPose로 변환
pose = new HumanPose
{
bodyPosition = poseData.bodyPosition,
bodyRotation = poseData.bodyRotation,
muscles = poseData.muscles
};
}
else if (poseClip != null)
{
pose = poseClip.GetPose();
}
else
{
EditorUtility.DisplayDialog("Error", "Please select a Pose Clip!", "OK");
return;
}
var animator = targetAnimator;
var avatar = animator.avatar;
if (avatar == null || !avatar.isHuman)
{
EditorUtility.DisplayDialog("Error", "Selected Animator must have a Humanoid Avatar!", "OK");
return;
}
try
{
// HumanPoseHandler를 사용하여 포즈 데이터 적용
var handler = new HumanPoseHandler(avatar, animator.transform);
// 포즈 적용
handler.SetHumanPose(ref pose);
// 변경사항 저장
EditorUtility.SetDirty(animator);
Debug.Log("Pose clip has been applied to the Animator");
EditorUtility.DisplayDialog("Success", "Pose clip has been applied to the Animator", "OK");
}
catch (System.Exception e)
{
Debug.LogError($"Error applying pose clip: {e.Message}");
EditorUtility.DisplayDialog("Error", $"Failed to apply pose clip: {e.Message}", "OK");
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a1fa397be4544444b859d065a7aa33b3

View File

@ -0,0 +1,119 @@
using UnityEngine;
using UnityEditor;
using System.IO;
using UniHumanoid;
public class HumanPoseClipCreator : EditorWindow
{
private Animator selectedAnimator;
private string assetName = "NewPoseClip";
private string savePath = "Assets/Resources";
[MenuItem("Tools/Animation/Create Human Pose Clip")]
public static void ShowWindow()
{
GetWindow<HumanPoseClipCreator>("Human Pose Clip Creator");
}
private void OnGUI()
{
GUILayout.Label("Create Human Pose Clip", EditorStyles.boldLabel);
EditorGUILayout.Space();
selectedAnimator = (Animator)EditorGUILayout.ObjectField("Target Animator", selectedAnimator, typeof(Animator), true);
EditorGUILayout.Space();
assetName = EditorGUILayout.TextField("Asset Name", assetName);
EditorGUILayout.BeginHorizontal();
savePath = EditorGUILayout.TextField("Save Path", savePath);
if (GUILayout.Button("Browse", GUILayout.Width(60)))
{
string path = EditorUtility.SaveFolderPanel("Select Save Location", "Assets", "");
if (!string.IsNullOrEmpty(path))
{
string projectPath = Application.dataPath;
if (path.StartsWith(projectPath))
{
savePath = "Assets" + path.Substring(projectPath.Length);
}
else
{
EditorUtility.DisplayDialog("Error", "Please select a folder inside the Assets directory!", "OK");
}
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
GUI.enabled = selectedAnimator != null;
if (GUILayout.Button("Create Pose Clip"))
{
CreatePoseClip();
}
GUI.enabled = true;
}
private void CreatePoseClip()
{
if (selectedAnimator == null)
{
EditorUtility.DisplayDialog("Error", "Please select an Animator first!", "OK");
return;
}
// 경로가 Assets로 시작하는지 확인
if (!savePath.StartsWith("Assets/"))
{
EditorUtility.DisplayDialog("Error", "Save path must start with 'Assets/'!", "OK");
return;
}
var animator = selectedAnimator;
var avatar = animator.avatar;
if (avatar == null || !avatar.isHuman)
{
EditorUtility.DisplayDialog("Error", "Selected Animator must have a Humanoid Avatar!", "OK");
return;
}
try
{
// HumanPoseHandler를 사용하여 현재 포즈 가져오기
var handler = new HumanPoseHandler(avatar, animator.transform);
HumanPose pose = new HumanPose();
handler.GetHumanPose(ref pose);
// 새로운 HumanPoseClip 생성
HumanPoseClip poseClip = ScriptableObject.CreateInstance<HumanPoseClip>();
poseClip.ApplyPose(ref pose);
// 저장 경로 생성
string fullPath = Path.Combine(savePath, $"{assetName}.pose.asset");
string directory = Path.GetDirectoryName(fullPath);
// 디렉토리가 없으면 생성
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 에셋 저장
AssetDatabase.CreateAsset(poseClip, fullPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log($"Pose clip has been created at: {fullPath}");
EditorUtility.DisplayDialog("Success", $"Pose clip has been created at: {fullPath}", "OK");
}
catch (System.Exception e)
{
Debug.LogError($"Error creating pose clip: {e.Message}");
EditorUtility.DisplayDialog("Error", $"Failed to create pose clip: {e.Message}", "OK");
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 56ea0fa3ec6bb174f85a1ba2d080d85b

View File

@ -580,16 +580,20 @@ namespace KindRetargeting
for (int i = 0; i < 40; i++)
{
int muscleIndex = 55 + i;
string muscleName = HumanTrait.MuscleName[muscleIndex];
// "Spread"가 포함된 머슬만 스킵 (손가락 벌리기 동작)
if (muscleName.Contains("Spread"))
continue;
float targetValue = sourcePose.muscles[muscleIndex];
float currentValue = targetPose.muscles[muscleIndex];
// 모션 필터 적용 (값을 직접 필터링)
if (useMotionFilter)
{
targetValue = ApplyFilter(targetValue, i);
}
// 러프 모션을 Lerp로 적용
if (useFingerRoughMotion && roughMotions.TryGetValue(HumanBodyBones.LeftHand, out RoughMotion rough))
{
float smoothSpeed = 50f - (fingerRoughness * 49f);
@ -968,8 +972,6 @@ namespace KindRetargeting
Avatar avatar = animator.avatar;
Transform transform = animator.transform;
// I포즈 기능 개발해야함 밍글 스튜디오 참고
/*
// HumanPoseClip에 저장된 T-포즈 데이터를 로드하여 적용
var humanPoseClip = Resources.Load<HumanPoseClip>(HumanPoseClip.IPoseResourcePath);
if (humanPoseClip != null)
@ -981,7 +983,6 @@ namespace KindRetargeting
{
Debug.LogWarning("I-Pose 데이터가 존재하지 않습니다.");
}
*/
}
#endregion

View File

@ -147,7 +147,7 @@ Material:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _Resolution: {r: 3840, g: 2160, b: 0, a: 0}
- _Resolution: {r: 1920, g: 1080, b: 0, a: 0}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@ -157,20 +157,6 @@
"m_SlotId": 1
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "af4e86cdd63b47428691d8c7cf6fd511"
},
"m_SlotId": 3
},
"m_InputSlot": {
"m_Node": {
"m_Id": "ad863a97e6f14704b6137da83d1dba35"
},
"m_SlotId": 0
}
},
{
"m_OutputSlot": {
"m_Node": {

BIN
Packages/manifest.json (Stored with Git LFS)

Binary file not shown.

BIN
Packages/packages-lock.json (Stored with Git LFS)

Binary file not shown.

BIN
ProjectSettings/TagManager.asset (Stored with Git LFS)

Binary file not shown.