# 相关类 - TsArkitDataReceiver(ArkitDataReceiver) - TsChingmuMocapReceiverActor(ChingmuMocapReceiverActor) - TsMotionReceiverActor(MotionReceiverActor) => BP_MotionReceiver:定义了MotionNetConfig.ini。 - TsMotionSenderActor(MotionSenderActor) # TsChingmuMocapReceiverActor 1. Init():在Server才会Spawn TsChingmuMocapReceiverActor。 2. ConnectChingMu():**ChingmuComp.StartConnectServer()** 3. Multicast_AligmMotionTime():寻找场景中的BP_MotionReceiver,并且调用Receiver.AlignTimeStamp()。 ## ChingmuMocapReceiverActor ```c++ void AChingmuMocapReceiverActor::BeginPlay() { Super::BeginPlay(); MaxHumanCount = 10; MaxRigidBodyCount = 10; CacheLimit = 240; SampledHumanData = NewObject(); ThreadInterval = 0.002; BackIndexCount = int64(UMotionUtils::BackSampleTime / (1000.0 / CHINGMU_SERVER_FPS));//BackSampleTime = 100ms CHINGMU_SERVER_FPS =120ms ChingmuComp = Cast(GetComponentByClass(UChingMUComponent::StaticClass())); if (ChingmuComp == nullptr) { UE_LOG(LogTemp, Error, TEXT("Chingmu Component is missing!!")); } Thread = new FChingmuThread("Chingmu Data Thread", this); Sender = GetMotionSender(); } ``` ### ***ChingMUComponent*** ### FChingmuThread 用途为: ```c++ uint32 FChingmuThread::Run() { FTransform Tmp; while (bRun) { if (OwnerActor && OwnerActor->UseThread && OwnerActor->ChingmuComp && OwnerActor->ChingmuComp->IsConnected()) { CurTime = ULiveDirectorStatics::GetUnixTime(); // Human for (auto HumanIndex = 0; HumanIndex < OwnerActor->MaxHumanCount; HumanIndex++) { const auto bRes = OwnerActor->ChingmuComp->FullBodyMotionCapBaseBonesLocalSpaceRotation( OwnerActor->ChingmuFullAddress, HumanIndex, TmpTimeCode); if (bRes) { if (!HumanToLastReceiveTime.Contains(HumanIndex))//空数据处理。 { HumanToLastReceiveTime.Add(HumanIndex, 0); } if (HumanToLastReceiveTime[HumanIndex] != TmpTimeCode.Frames)//接收端时间与 { HumanToLastReceiveTime[HumanIndex] = TmpTimeCode.Frames; OwnerActor->OnGetHumanData_NotInGameThread(HumanIndex, CurTime, TmpTimeCode.Frames); } else { // get same frame, skip break; } } } // Rigidbody for (auto RigidBodyIndex = OwnerActor->RigidBodyStartIndex; RigidBodyIndex < OwnerActor->RigidBodyStartIndex + OwnerActor->MaxRigidBodyCount; RigidBodyIndex++) { OwnerActor->ChingmuComp->GetTrackerPoseTC(OwnerActor->ChingmuFullAddress, RigidBodyIndex, Tmp, TmpTimeCode); if (!RigidBodyToLastReceiveTransform.Contains(RigidBodyIndex)) { RigidBodyToLastReceiveTransform.Add(RigidBodyIndex, FTransform::Identity); } // 道具的TmpTimeCode.Frames永远为0,所以无法用帧数判断 // 改为transform判断 if (!RigidBodyToLastReceiveTransform[RigidBodyIndex].Equals(Tmp)) { RigidBodyToLastReceiveTransform[RigidBodyIndex] = Tmp; OwnerActor->OnGetRigidBodyData_NotInGameThread(RigidBodyIndex, Tmp, CurTime, TmpTimeCode.Frames); } } } if (bRun) { FPlatformProcess::Sleep(OwnerActor ? OwnerActor->ThreadInterval : 0.004); } else { break; } } UE_LOG(LogTemp, Warning, TEXT("%s finish work."), *ThreadName) return 0; } ``` ## MocapData ```c++ #define MOCAP_BONE_COUNT 23 enum E_MotionType { Human, RigidBody }; enum E_SourceType { Mocap, CMR, Replay }; struct ST_MocapFrameData { int ID; int64 TimeStamp; int FrameIndex; E_MotionType MotionType; E_SourceType SourceType; FVector BonesWorldPos[MOCAP_BONE_COUNT]; FQuat BonesLocalRot[MOCAP_BONE_COUNT]; }; class LIVEDIRECTOR_API UMocapFrameData : public UObject { GENERATED_BODY() public: UPROPERTY(BlueprintReadWrite, EditAnywhere) int ID; UPROPERTY(BlueprintReadWrite, EditAnywhere) TArray BonesWorldPos; UPROPERTY(BlueprintReadWrite, EditAnywhere) TArray BonesLocalRot; UPROPERTY(BlueprintReadWrite, EditAnywhere) int64 TimeStamp; UPROPERTY(BlueprintReadWrite, EditAnywhere) int FrameIndex; UPROPERTY(BlueprintReadWrite, EditAnywhere) int MotionType; // 0 human; 1 rigidbody UPROPERTY(BlueprintReadWrite, EditAnywhere) int SourceType; // 0 mocap, 1 cmr public: void CopyFrom(const ST_MocapFrameData* Other) { ID = Other->ID; TimeStamp = Other->TimeStamp; FrameIndex = Other->FrameIndex; MotionType = Other->MotionType; SourceType = Other->SourceType; for (auto Index = 0; Index < 23; Index++) { BonesWorldPos[Index] = Other->BonesWorldPos[Index]; BonesLocalRot[Index] = Other->BonesLocalRot[Index]; } } }; class MocapFrames { public: int ID; std::vector Frames = {}; void CalculatePackageAverageInterval(float& Res) { if(Frames.size() > 0) { auto First = Frames[0]; auto Last = Frames[Frames.size() - 1]; if(Last->FrameIndex > First->FrameIndex) { Res = 1.0 * (Last->TimeStamp - First->TimeStamp) / (Last->FrameIndex - First->FrameIndex); } } } }; ``` # TsMotionReceiverActor 只在BeginPlay()中调用了this.MarkAsClientSeamlessTravel(); 具体逻辑在`AMotionReceiverActor` ## MotionReceiverActor