2#include "TimerManager.h"
4DECLARE_CYCLE_STAT(TEXT(
"TickGesture ~ TickingGesture"), STAT_TickGesture, STATGROUP_TickGesture);
7 : Super(ObjectInitializer)
9 PrimaryComponentTick.bCanEverTick =
false;
26 if (!SplineComponent || Gesture.
Samples.Num() < 2)
29 UWorld* InWorld = GEngine->GetWorldFromContextObject(SplineComponent, EGetWorldErrorMode::LogAndReturnNull);
34 SplineComponent->ClearSplinePoints(
false);
36 FVector PointOffset = FVector::ZeroVector;
38 if (bScaleToBounds && OptionalBounds > 0.0f)
40 Scaler = OptionalBounds / Gesture.
GestureSize.GetSize().GetMax();
43 if (bCenterPointsOnSpline)
49 for (
int i = Gesture.
Samples.Num() - 1; i >= 0; --i)
51 SplineComponent->AddSplinePoint((Gesture.
Samples[i] + PointOffset) * Scaler, ESplineCoordinateSpace::Local,
false);
53 SplineComponent->SetSplinePointType(curIndex, bUseCurvedPoints ? ESplinePointType::Curve : ESplinePointType::Linear,
false);
57 SplineComponent->UpdateSpline();
59 if (bFillInSplineMeshComponents && Mesh !=
nullptr && MeshMat !=
nullptr)
61 TArray<USplineMeshComponent *> CurrentSplineChildren;
63 TArray<USceneComponent*> Children;
64 SplineComponent->GetChildrenComponents(
false, Children);
65 for (
auto Child : Children)
67 USplineMeshComponent* SplineMesh = Cast<USplineMeshComponent>(Child);
68 if (SplineMesh !=
nullptr && !SplineMesh->IsPendingKill())
70 CurrentSplineChildren.Add(SplineMesh);
74 if (CurrentSplineChildren.Num() > SplineComponent->GetNumberOfSplinePoints() - 1)
76 int diff = CurrentSplineChildren.Num() - (CurrentSplineChildren.Num() - (SplineComponent->GetNumberOfSplinePoints() -1));
78 for (
int i = CurrentSplineChildren.Num()- 1; i >= diff; --i)
80 if (!CurrentSplineChildren[i]->IsBeingDestroyed())
82 CurrentSplineChildren[i]->SetVisibility(
false);
83 CurrentSplineChildren[i]->Modify();
84 CurrentSplineChildren[i]->DestroyComponent();
85 CurrentSplineChildren.RemoveAt(i);
91 for (
int i = CurrentSplineChildren.Num(); i < SplineComponent->GetNumberOfSplinePoints() -1; ++i)
93 USplineMeshComponent * newSplineMesh = NewObject<USplineMeshComponent>(SplineComponent);
95 newSplineMesh->RegisterComponentWithWorld(InWorld);
96 newSplineMesh->SetMobility(EComponentMobility::Movable);
97 CurrentSplineChildren.Add(newSplineMesh);
98 newSplineMesh->SetStaticMesh(Mesh);
99 newSplineMesh->SetMaterial(0, (UMaterialInterface*)MeshMat);
101 newSplineMesh->AttachToComponent(SplineComponent, FAttachmentTransformRules::SnapToTargetIncludingScale);
102 newSplineMesh->SetVisibility(
true);
107 for(
int i=0; i<SplineComponent->GetNumberOfSplinePoints() - 1; i++)
109 CurrentSplineChildren[i]->SetStartAndEnd(SplineComponent->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::Local),
110 SplineComponent->GetTangentAtSplinePoint(i, ESplineCoordinateSpace::Local),
111 SplineComponent->GetLocationAtSplinePoint(i + 1, ESplineCoordinateSpace::Local),
112 SplineComponent->GetTangentAtSplinePoint(i + 1, ESplineCoordinateSpace::Local),
130 if (!bDrawAsSpline || !bDrawGesture)
164 this->SetComponentTickEnabled(
true);
187 bool bClearLatestSpline =
false;
192 bClearLatestSpline =
true;
207 if (bClearLatestSpline)
214 bool bFoundEmptyMesh =
false;
215 USplineMeshComponent * MeshComp =
nullptr;
222 if (MeshComp ==
nullptr)
227 MeshComp->RegisterComponentWithWorld(GetWorld());
228 MeshComp->SetMobility(EComponentMobility::Movable);
231 bFoundEmptyMesh =
true;
234 else if (!MeshComp->IsVisible())
236 bFoundEmptyMesh =
true;
241 if (!bFoundEmptyMesh)
244 MeshComp = newSplineMesh;
245 MeshComp->RegisterComponentWithWorld(GetWorld());
246 MeshComp->SetMobility(EComponentMobility::Movable);
252 MeshComp->AttachToComponent(
TargetCharacter->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
255 if (MeshComp !=
nullptr)
267 MeshComp->SetStartAndEnd(NewSample,
276 MeshComp->SetRelativeLocationAndRotation(
StartVector, FQuat::Identity);
279 MeshComp->SetVisibility(
true);
291 SCOPE_CYCLE_COUNTER(STAT_TickGesture);
327 float minDist = MAX_FLT;
329 int OutGestureIndex = -1;
330 bool bMirrorGesture =
false;
334 float FinalScaler = Scaler;
349 float d =
dtw(inputGesture, exampleGesture, bMirrorGesture, FinalScaler) / (exampleGesture.
Samples.Num());
358 bMirrorGesture =
true;
361 float d =
dtw(inputGesture, exampleGesture, bMirrorGesture, FinalScaler) / (exampleGesture.
Samples.Num());
386 if (OutGestureIndex != -1)
406 int RowCount = seq1.
Samples.Num() + 1;
407 int ColumnCount = seq2.
Samples.Num() + 1;
409 TArray<float> LookupTable;
410 LookupTable.AddZeroed(ColumnCount * RowCount);
413 SlopeI.AddZeroed(ColumnCount * RowCount);
415 SlopeJ.AddZeroed(ColumnCount * RowCount);
417 for (
int i = 1; i < (ColumnCount * RowCount); i++)
419 LookupTable[i] = MAX_FLT;
424 int icol = 0, icolneg = 0;
427 for (
int i = 1; i < RowCount; i++)
429 for (
int j = 1; j < ColumnCount; j++)
431 icol = i * ColumnCount;
432 icolneg = icol - ColumnCount;
435 LookupTable[icol + (j - 1)] < LookupTable[icolneg + (j - 1)] &&
436 LookupTable[icol + (j - 1)] < LookupTable[icolneg + j] &&
440 SlopeI[icol + j] = SlopeJ[icol + j - 1] + 1;
441 SlopeJ[icol + j] = 0;
444 LookupTable[icolneg + j] < LookupTable[icolneg + j - 1] &&
445 LookupTable[icolneg + j] < LookupTable[icol + j - 1] &&
449 SlopeI[icol + j] = 0;
450 SlopeJ[icol + j] = SlopeJ[icolneg + j] + 1;
455 SlopeI[icol + j] = 0;
456 SlopeJ[icol + j] = 0;
462 float bestMatch = FLT_MAX;
464 for (
int i = 1; i < seq1.
Samples.Num() + 1; i++)
466 if (LookupTable[(i*ColumnCount) + seq2.
Samples.Num()] < bestMatch)
467 bestMatch = LookupTable[(i*ColumnCount) + seq2.
Samples.Num()];
477 UWorld* InWorld = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
479 if (InWorld !=
nullptr)
482 if (GEngine->GetNetMode(InWorld) != NM_DedicatedServer && GestureToDraw.
Samples.Num() > 1)
485 FVector MirrorVector = FVector(1.f, -1.f, 1.f);
488 ULineBatchComponent*
const LineBatcher = (InWorld ? ((DepthPriority == SDPG_Foreground) ? InWorld->ForegroundLineBatcher : ((bPersistentLines || (LifeTime > 0.f)) ? InWorld->PersistentLineBatcher : InWorld->LineBatcher)) : NULL);
490 if (LineBatcher != NULL)
492 float const LineLifeTime = (LifeTime > 0.f) ? LifeTime : LineBatcher->DefaultLifeTime;
494 TArray<FBatchedLine> Lines;
497 Line.Thickness = Thickness;
498 Line.RemainingLifeTime = LineLifeTime;
499 Line.DepthPriority = DepthPriority;
501 FVector FirstLoc = bMirrorGesture ? GestureToDraw.
Samples[GestureToDraw.
Samples.Num() - 1] * MirrorVector : GestureToDraw.
Samples[GestureToDraw.
Samples.Num() - 1];
503 for (
int i = GestureToDraw.
Samples.Num() - 2; i >= 0; --i)
505 Line.Start = bMirrorGesture ? GestureToDraw.
Samples[i] * MirrorVector : GestureToDraw.
Samples[i];
508 FirstLoc = Line.Start;
510 Line.End = StartTransform.TransformPosition(Line.End);
511 Line.Start = StartTransform.TransformPosition(Line.Start);
516 LineBatcher->DrawLines(Lines);
525 for (
int i = 0; i <
Gestures.Num(); ++i)
535 if (HostSplineComponent->GetNumberOfSplinePoints() < 2)
538 NewGesture.
Name = GestureName;
540 FVector FirstPointPos = HostSplineComponent->GetLocationAtSplinePoint(0, ESplineCoordinateSpace::Local);
542 float LastDistance = 0.f;
543 float ThisDistance = 0.f;
544 FVector LastDistanceV;
545 FVector ThisDistanceV;
547 float DistAlongSegment = 0.f;
550 FTransform Realignment = FTransform(FRotator(0.f, 90.f, 0.f), -FirstPointPos);
553 NewGesture.
Samples.Add(Realignment.TransformPosition(HostSplineComponent->GetLocationAtSplinePoint(HostSplineComponent->GetNumberOfSplinePoints() - 1, ESplineCoordinateSpace::Local)));
556 for (
int i = HostSplineComponent->GetNumberOfSplinePoints() - 2; i >= 0; --i)
558 if (bKeepSplineCurves)
560 LastDistance = HostSplineComponent->GetDistanceAlongSplineAtSplinePoint(i + 1);
561 ThisDistance = HostSplineComponent->GetDistanceAlongSplineAtSplinePoint(i);
563 DistAlongSegment = FMath::Abs(ThisDistance - LastDistance);
567 LastDistanceV = Realignment.TransformPosition(HostSplineComponent->GetLocationAtSplinePoint(i + 1, ESplineCoordinateSpace::Local));
568 ThisDistanceV = Realignment.TransformPosition(HostSplineComponent->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::Local));
570 DistAlongSegment = FVector::Dist(ThisDistanceV, LastDistanceV);
571 DistNormal = ThisDistanceV - LastDistanceV;
572 DistNormal.Normalize();
576 float SegmentCount = FMath::FloorToFloat(DistAlongSegment / SegmentLen);
577 float OverFlow = FMath::Fmod(DistAlongSegment, SegmentLen);
579 if (SegmentCount < 1)
584 float DistPerSegment = (DistAlongSegment / SegmentCount);
586 for (
int j = 0; j < SegmentCount; j++)
588 if (j == SegmentCount - 1 && i > 0)
589 DistPerSegment += OverFlow;
591 if (bKeepSplineCurves)
593 LastDistance -= DistPerSegment;
594 if (j == SegmentCount - 1 && i > 0)
596 LastDistance = ThisDistance;
598 FVector loc = Realignment.TransformPosition(HostSplineComponent->GetLocationAtDistanceAlongSpline(LastDistance, ESplineCoordinateSpace::Local));
600 if (!loc.IsNearlyZero())
605 LastDistanceV += DistPerSegment * DistNormal;
607 if (j == SegmentCount - 1 && i > 0)
609 LastDistanceV = ThisDistanceV;
612 if (!LastDistanceV.IsNearlyZero())
613 NewGesture.
Samples.Add(LastDistanceV);
687 Super::BeginDestroy();
697 if (GestureDB !=
nullptr)
710 this->SetComponentTickEnabled(
false);
729 Recording.
Name = RecordingName;
DECLARE_CYCLE_STAT(TEXT("TickGesture ~ TickingGesture"), STAT_TickGesture, STATGROUP_TickGesture)
FTransform OffsetComponentToWorld
UPROPERTY(BlueprintReadOnly, Transient, Category = "VRExpansionLibrary")
UCLASS(BlueprintType, Category = "VRGestures")
void RecalculateGestures(bool bScaleToDatabase=true)
UFUNCTION(BlueprintCallable, Category = "VRGestures")
bool ImportSplineAsGesture(USplineComponent *HostSplineComponent, FString GestureName, bool bKeepSplineCurves=true, float SegmentLen=10.0f, bool bScaleToDatabase=true)
UFUNCTION(BlueprintCallable, Category = "VRGestures")
void FillSplineWithGesture(UPARAM(ref) FVRGesture &Gesture, USplineComponent *SplineComponent, bool bCenterPointsOnSpline=true, bool bScaleToBounds=false, float OptionalBounds=0.0f, bool bUseCurvedPoints=true, bool bFillInSplineMeshComponents=true, UStaticMesh *Mesh=nullptr, UMaterial *MeshMat=nullptr)
UFUNCTION(BlueprintCallable, Category = "VRGestures")
TArray< FVRGesture > Gestures
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
float TargetGestureScale
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
UMaterialInterface * SplineMaterial
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
FVRGesture GestureLog
UPROPERTY(BlueprintReadOnly, Category = "VRGestures")
bool bRecordingFlattenGesture
void CaptureGestureFrame()
UStaticMesh * SplineMesh
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
bool bDrawRecordingGestureAsSpline
AVRBaseCharacter * TargetCharacter
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
FTransform OriginatingTransform
void BeginRecording(bool bRunDetection, bool bFlattenGesture=true, bool bDrawGesture=true, bool bDrawAsSpline=false, int SamplingHTZ=30, int SampleBufferSize=60, float ClampingTolerance=0.01f)
UFUNCTION(BlueprintCallable, Category = "VRGestures")
void ClearRecording()
UFUNCTION(BlueprintCallable, Category = "VRGestures")
FVRGesture EndRecording()
UFUNCTION(BlueprintCallable, Category = "VRGestures")
EVRGestureState CurrentState
UPROPERTY(BlueprintReadOnly, Category = "VRGestures")
void RecognizeGesture(FVRGesture inputGesture)
float SameSampleTolerance
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
bool bDrawRecordingGesture
UVRGestureComponent(const FObjectInitializer &ObjectInitializer)
float dtw(FVRGesture seq1, FVRGesture seq2, bool bMirrorGesture=false, float Scaler=1.f)
void DrawDebugGesture(UObject *WorldContextObject, UPARAM(ref) FTransform &StartTransform, FVRGesture GestureToDraw, FColor const &Color, bool bPersistentLines=false, uint8 DepthPriority=0, float LifeTime=-1.f, float Thickness=0.f)
UFUNCTION(BlueprintCallable, Category = "VRGestures", meta = (WorldContext = "WorldContextObject"))
FVRGestureSplineDraw RecordingGestureDraw
void RecalculateGestureSize(UPARAM(ref) FVRGesture &InputGesture, UGesturesDatabase *GestureDB)
UFUNCTION(BlueprintCallable, Category = "VRGestures")
int maxSlope
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
FTimerHandle TickGestureTimer_Handle
FVRGestureDetectedSignature OnGestureDetected_Bind
UPROPERTY(BlueprintAssignable, Category = "VRGestures")
UGesturesDatabase * GesturesDB
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
FVector2D SplineMeshScaler
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
float GetGestureDistance(FVector Seq1, FVector Seq2, bool bMirrorGesture=false)
float RecordingClampingTolerance
bool bGetGestureInWorldSpace
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
EVRGestureMirrorMode MirroringHand
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
void OnGestureDetected(uint8 GestureType, FString &DetectedGestureName, int &DetectedGestureIndex, UGesturesDatabase *GestureDatabase)
UFUNCTION(BlueprintImplementableEvent, Category = "BaseVRCharacter")
void BeginDestroy() override
void SaveRecording(UPARAM(ref) FVRGesture &Recording, FString RecordingName, bool bScaleRecordingToDatabase=true)
UFUNCTION(BlueprintCallable, Category = "VRGestures")
bool bDrawSplinesCurved
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
USTRUCT(BlueprintType, Category = "VRGestures")
FVRGestureSettings GestureSettings
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture")
FBox GestureSize
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "VRGesture")
TArray< FVector > Samples
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "VRGesture")
void CalculateSizeOfGesture(bool bAllowResizing=false, float TargetExtentSize=1.f)
FString Name
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture")
EVRGestureMirrorMode MirrorMode
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture|Advanced")
float firstThreshold
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture|Advanced")
bool bEnableScaling
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture|Advanced")
float FullThreshold
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture|Advanced")
int Minimum_Gesture_Length
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture|Advanced")
bool bEnabled
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture|Advanced")
USplineComponent * SplineComponent
UPROPERTY()
TArray< USplineMeshComponent * > SplineMeshes
UPROPERTY()