diff --git a/Source/MoCapPlugin/Private/MCController.cpp b/Source/MoCapPlugin/Private/MCController.cpp index 140e32289f9f21d101b28e883a3999400279e544..b26ecd3be0b85149efd3bafb9ca940815fdf3bbd 100644 --- a/Source/MoCapPlugin/Private/MCController.cpp +++ b/Source/MoCapPlugin/Private/MCController.cpp @@ -42,7 +42,7 @@ void AMCController::BeginPlay() { InputComponent->BindAction("SetMarker", EInputEvent::IE_Pressed, this, &AMCController::SetMarker); InputComponent->BindAction("StartRecording", EInputEvent::IE_Pressed, this, &AMCController::ToggleRecording); InputComponent->BindAction("NextSentence", EInputEvent::IE_Pressed, this, &AMCController::SetMarker); - InputComponent->BindAction("SaveAnimation", EInputEvent::IE_Pressed, this, &AMCController::SaveAnimation); + InputComponent->BindAction("SaveAnimation", EInputEvent::IE_Pressed, this, &AMCController::SaveAnimationEditor); } if (!Pawn || !Pawn->GetActorLocation().Equals(FVector(0, 0, 0)) || !Pawn->GetActorRotation().Equals(FRotator(0, 0, 0))) { @@ -209,9 +209,7 @@ void AMCController::ScaleAnimDataInterval(int start, int end, float DeltaTime) { FProcessedAnimData Data; Data.Timestamp = StartTime + FTimespan::FromSeconds((float)i * NewTime / (float)NewNrFrames); //SmoothStop - //float TransformedI = 1.f - FMath::Pow(1.f - ((float)i / (float)NewNrFrames), 4); - //SmoothStart - float TransformedI = FMath::Pow(((float)i / (float)NewNrFrames), 4); + float TransformedI = 1.f - FMath::Pow(1.f - ((float)i / (float)NewNrFrames), GestureHoldExcessEasingExponent); FTimespan OldTimestamp = StartTime + FTimespan::FromSeconds(TransformedI * OldTime); bool stop = false; @@ -287,7 +285,7 @@ void AMCController::ScaleAnimDataInterval(int start, int end, float DeltaTime) { } -bool AMCController::PreprocessRecording() { +bool AMCController::PreprocessRecording(const TArray<float>& HaltingPoints) { UMCAnimInstance* AI = AnimSaveState.Pawn->GetAnimInstance(); @@ -528,101 +526,161 @@ bool AMCController::PreprocessRecording() { //---find last slow part of the gesture and scale it up--- TArray<float> GestureSpeed; + bool newMethod = true; - if (GestureHoldExcessTime > 0.f) { + if (!newMethod) { + if (GestureHoldExcessTime > 0.f) { - for (int i = 1; i < AnimSaveState.AnimData.Num(); i++) { + for (int i = 1; i < AnimSaveState.AnimData.Num(); i++) { - FProcessedAnimData& AnimData = AnimSaveState.AnimData[i]; + FProcessedAnimData& AnimData = AnimSaveState.AnimData[i]; - if (AnimData.IsMarker || AnimData.IsEnd) { - continue; - } + if (AnimData.IsMarker || AnimData.IsEnd) { + continue; + } + + //process sensor data - //process sensor data + float Speed = 0.f; + int SpeedCount = 0; + int window = 1; - float Speed = 0.f; - int SpeedCount = 0; - int window = 1; + FSensorData& SensorData = AnimData.SensorData; + for (int j = 0; j < EBodyPart::LAST; j++) { - FSensorData& SensorData = AnimData.SensorData; - for (int j = 0; j < EBodyPart::LAST; j++) { + EBodyPart Type = EBodyPart(j); + FSensorDataEntry* Entry = SensorData.GetEntry(Type); - EBodyPart Type = EBodyPart(j); - FSensorDataEntry* Entry = SensorData.GetEntry(Type); + if (Type == EBodyPart::HandL || Type == EBodyPart::HandR) { - if (Type == EBodyPart::HandL || Type == EBodyPart::HandR) { + for (int w = 0; w < window; w++) { + int index = i + w; + if (index - 1 >= 0 && index < AnimSaveState.AnimData.Num()) { + FProcessedAnimData& Data0 = AnimSaveState.AnimData[index - 1]; + FProcessedAnimData& Data1 = AnimSaveState.AnimData[index]; + float Time = (Data1.Timestamp - Data0.Timestamp).GetTotalSeconds(); + Speed += Time * (Data1.SensorData.GetEntry(Type)->Pos - Data0.SensorData.GetEntry(Type)->Pos).Size(); - for (int w = 0; w < window; w++) { - int index = i + w; - if (index - 1 >= 0 && index < AnimSaveState.AnimData.Num()) { - FProcessedAnimData& Data0 = AnimSaveState.AnimData[index - 1]; - FProcessedAnimData& Data1 = AnimSaveState.AnimData[index]; - float Time = (Data1.Timestamp - Data0.Timestamp).GetTotalSeconds(); - Speed += Time * (Data1.SensorData.GetEntry(Type)->Pos - Data0.SensorData.GetEntry(Type)->Pos).Size(); - + } } - } - SpeedCount++; + SpeedCount++; + + } } + GestureSpeed.Push(Speed / (float)SpeedCount); + } - GestureSpeed.Push(Speed / (float)SpeedCount); + //smooth + TArray<float> SmoothedGestureSpeed; + int window = 5; + int Num = GestureSpeed.Num(); + for (int i = 0; i < Num; i++) { + float avg = 0.f; + for (int wInd = -window; wInd <= window; wInd++) { + int w = i + wInd; + if (w < 0) { + avg += (GestureSpeed[0] + GestureSpeed[1] + GestureSpeed[2] + GestureSpeed[3] + GestureSpeed[4]) / 5.f; + } + else if (w >= Num) { + avg += (GestureSpeed[Num - 1] + GestureSpeed[Num - 2] + GestureSpeed[Num - 3] + GestureSpeed[Num - 4] + GestureSpeed[Num - 5]) / 5.f; + } + else { + avg += GestureSpeed[w]; + } + } + avg /= (float)(window * 2 + 1); + SmoothedGestureSpeed.Push(avg); + } - } + GestureSpeed = SmoothedGestureSpeed; - //smooth - TArray<float> SmoothedGestureSpeed; - int window = 5; - int Num = GestureSpeed.Num(); - for (int i = 0; i < Num; i++) { - float avg = 0.f; - for (int wInd = -window; wInd <= window; wInd++) { - int w = i + wInd; - if (w < 0) { - avg += (GestureSpeed[0] + GestureSpeed[1] + GestureSpeed[2] + GestureSpeed[3] + GestureSpeed[4]) / 5.f; - } - else if (w >= Num) { - avg += (GestureSpeed[Num - 1] + GestureSpeed[Num - 2] + GestureSpeed[Num - 3] + GestureSpeed[Num - 4] + GestureSpeed[Num - 5]) / 5.f; + int MaxNumToScale = 30; + + //maximum + int maxWindow = 8; + int ScaleStart; + for (ScaleStart = GestureSpeed.Num() - 1; ScaleStart >= 0 && ScaleStart >= GestureSpeed.Num() - MaxNumToScale; ScaleStart--) { + bool isMax = true; + for (int w = -maxWindow; w <= maxWindow; w++) { + int index = ScaleStart + w; + if (index >= 0 && index < GestureSpeed.Num() && index != ScaleStart) { + if (GestureSpeed[index] >= GestureSpeed[ScaleStart]) { + isMax = false; + break; + } + } } - else { - avg += GestureSpeed[w]; + if (isMax) { + break; } } - avg /= (float)(window * 2 + 1); - SmoothedGestureSpeed.Push(avg); + + ScaleAnimDataInterval(ScaleStart, AnimSaveState.AnimData.Num() - 2, GestureHoldExcessTime); + } + } + else { + if (HaltingPoints.Num() > 0) { - GestureSpeed = SmoothedGestureSpeed; + FTimespan Start; + bool StartTimeInitialized = false; + bool hold = false; + int holdStartingIndex = -1; - int MaxNumToScale = 30; + for (int i = 1; i < AnimSaveState.AnimData.Num(); i++) { + + FProcessedAnimData& AnimData = AnimSaveState.AnimData[i]; + + if (AnimData.IsMarker || AnimData.IsEnd) { + continue; + } + + if (!StartTimeInitialized) { + StartTimeInitialized = true; + Start = AnimData.Timestamp; + } + + //process sensor data + + FSensorData& SensorData = AnimData.SensorData; + for (int j = 0; j < EBodyPart::LAST; j++) { + + EBodyPart Type = EBodyPart(j); + FSensorDataEntry* Entry = SensorData.GetEntry(Type); + + if (Type == EBodyPart::HandL || Type == EBodyPart::HandR + || Type == EBodyPart::LowerArmL || Type == EBodyPart::LowerArmR) { + + if (DoHolding && hold) { + if (Type == EBodyPart::HandL || Type == EBodyPart::HandR) { + Entry->Pos = AnimSaveState.AnimData[i - 1].SensorData.GetEntry(Type)->Pos; + } + Entry->Rot = AnimSaveState.AnimData[i - 1].SensorData.GetEntry(Type)->Rot; + } - //maximum - int maxWindow = 8; - int ScaleStart; - for (ScaleStart = GestureSpeed.Num() - 1; ScaleStart >= 0 && ScaleStart >= GestureSpeed.Num() - MaxNumToScale; ScaleStart--) { - bool isMax = true; - for (int w = -maxWindow; w <= maxWindow; w++) { - int index = ScaleStart + w; - if (index >= 0 && index < GestureSpeed.Num() && index != ScaleStart) { - if (GestureSpeed[index] >= GestureSpeed[ScaleStart]) { - isMax = false; - break; } + } + + //or time unit? + if (!hold && HaltingPoints[0] <= (AnimData.Timestamp - Start).GetTotalSeconds()) { + hold = true; + holdStartingIndex = i; + } + } - if (isMax) { - break; - } - } - ScaleAnimDataInterval(ScaleStart, AnimSaveState.AnimData.Num() - 2, GestureHoldExcessTime); + if (hold && GestureHoldExcessTime > 0.f) { + ScaleAnimDataInterval(holdStartingIndex, AnimSaveState.AnimData.Num() - 2, GestureHoldExcessTime); + } + } } - + //---adjust feet position so that they are located at the green foot indicators--- int amount = 0; @@ -1169,7 +1227,11 @@ void AMCController::SetMarker() { } } -void AMCController::SaveAnimation() { +void AMCController::SaveAnimationEditor() { + SaveAnimation({}, false); +} + +void AMCController::SaveAnimation(const TArray<float>& HaltingPoints, bool skipTranslation) { if (IsSavingToAnim) { return; @@ -1239,14 +1301,17 @@ void AMCController::SaveAnimation() { AnimSaveState.FPS = FramesPerSecond; AnimSaveState.SPF = 1.f / ((float)AnimSaveState.FPS); - IsSavingToAnim = true; + IsSavingToAnim = !skipTranslation; + if (skipTranslation) { + return; + } if (!EditOffsetMode) { AnimSaveState.WaitForAnimInstance = true; } AnimSaveState.Pawn->GetAnimInstance()->AdditionalOffsets = AdditionalOffsets; - bool isValid = PreprocessRecording(); + bool isValid = PreprocessRecording(HaltingPoints); if (!isValid) { IsSavingToAnim = false; return; diff --git a/Source/MoCapPlugin/Public/MCController.h b/Source/MoCapPlugin/Public/MCController.h index 64098b335aeead1ff9e20844e0e871634b51a776..c9aa65a06e4e63e00366c4213811654d45cd761d 100644 --- a/Source/MoCapPlugin/Public/MCController.h +++ b/Source/MoCapPlugin/Public/MCController.h @@ -79,7 +79,7 @@ public: void SetMarker(); UFUNCTION(BlueprintCallable) - void SaveAnimation(); + void SaveAnimationEditor(); UFUNCTION(BlueprintCallable) void NextEditFrame(); @@ -96,9 +96,10 @@ protected: void SaveToAnimMode(); void ScaleAnimDataInterval(int start, int end, float DeltaTime); - bool PreprocessRecording(); + bool PreprocessRecording(const TArray<float>& HaltingPoints); void InputNextFrame(); + void SaveAnimation(const TArray<float>& HaltingPoints, bool skipTranslation = false); void SaveAnimSnapshots(); UAnimSequence* SaveAsAnimSequence(const FSnapshotAnimations& Recording, const FString& AnimName, const FString& FolderName); void SetBonesAnimationInAnimSeq(const FSnapshotAnimations& Recording, UAnimSequence* AnimSequence); @@ -162,9 +163,15 @@ public: UPROPERTY(EditAnywhere, meta = (DisplayName = "Frames per Second", Category = "MotionCapture Anim")) int FramesPerSecond = 60; + UPROPERTY(EditAnywhere, meta = (DisplayName = "Gesture Do Holding", Category = "MotionCapture Anim")) + bool DoHolding = false; + UPROPERTY(EditAnywhere, meta = (DisplayName = "Gesture Hold Scale Excess Time", Category = "MotionCapture Anim")) float GestureHoldExcessTime = 0.f; + UPROPERTY(EditAnywhere, meta = (DisplayName = "Gesture Hold Excess Easing Exponent", Category = "MotionCapture Anim")) + float GestureHoldExcessEasingExponent = 2.f; + UPROPERTY(EditAnywhere, meta = (DisplayName = "Nr of Leg Smoothing Iterations", Category = "MotionCapture Anim")) int LegSmoothTimes = 5;