diff --git a/02-Note/DAWA/ASoul/流程笔记/动捕&面捕.md b/02-Note/DAWA/ASoul/动画相关/动捕&面捕.md similarity index 100% rename from 02-Note/DAWA/ASoul/流程笔记/动捕&面捕.md rename to 02-Note/DAWA/ASoul/动画相关/动捕&面捕.md diff --git a/02-Note/DAWA/ASoul/动画相关/动捕逻辑.md b/02-Note/DAWA/ASoul/动画相关/动捕逻辑.md index 922839b..aa3fb91 100644 --- a/02-Note/DAWA/ASoul/动画相关/动捕逻辑.md +++ b/02-Note/DAWA/ASoul/动画相关/动捕逻辑.md @@ -10,10 +10,186 @@ 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*** -### 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 +