void ACinemotusPlayerController::AbsoluteTick(float DeltaTime) { TotalYawAbs += addYaw; UPrimitiveComponent* prim = GetPawn()->GetMovementComponent()->UpdatedComponent; //USceneComponent* sComponent = GetPawn()->GetRootComponent(); //sComponent->SetRelativeLocation; bool SetPrimDirectly = true; FQuat finalQuat; if (((currentCaptureState&ECinemotusCaptureState::EAbsolute) == ECinemotusCaptureState::EAbsolute) && ((currentCaptureState&ECinemotusCaptureState::EAbsoluteOff) == 0)) { finalQuat = FRotator(0, TotalYawAbs, 0).Quaternion()*(HydraLatestData->controllers[CAM_HAND].quat); } else { finalQuat = FRotator(0, addYaw, 0).Quaternion()*prim->GetComponentQuat(); } SetControlRotation(finalQuat.Rotator()); if (SetPrimDirectly && prim) { prim->SetWorldLocationAndRotation(prim->GetComponentLocation(), finalQuat);// not sure need } HandleMovementAbs(DeltaTime, ((currentCaptureState&ECinemotusCaptureState::EAbsolute) == ECinemotusCaptureState::EAbsolute)); }
void URotatingMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { // skip if we don't want component updated when not rendered or if updated component can't move if ( ShouldSkipUpdate(DeltaTime) ) { return; } // Compute new rotation const FQuat OldRotation = UpdatedComponent->GetComponentQuat(); const FQuat DeltaRotation = (RotationRate * DeltaTime).Quaternion(); const FQuat NewRotation = bRotationInLocalSpace ? (OldRotation * DeltaRotation) : (DeltaRotation * OldRotation); // Compute new location FVector DeltaLocation = FVector::ZeroVector; if (!PivotTranslation.IsZero()) { const FVector OldPivot = OldRotation.RotateVector(PivotTranslation); const FVector NewPivot = NewRotation.RotateVector(PivotTranslation); DeltaLocation = (OldPivot - NewPivot); // ConstrainDirectionToPlane() not necessary because it's done by MoveUpdatedComponent() below. } const bool bEnableCollision = false; MoveUpdatedComponent(DeltaLocation, NewRotation.Rotator(), bEnableCollision); }
bool UPerceptionNeuronBPLibrary::NeuronGetReferencePoseLocalBoneRotation(USkeletalMeshComponent *Mesh, FRotator& Rotation, int32 BoneIndex) { if (Mesh == nullptr && Mesh->SkeletalMesh == nullptr) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Mesh is invalid."))); } Rotation.Yaw = Rotation.Pitch = Rotation.Roll = 0; return false; } if (BoneIndex > Mesh->LocalAtoms.Num()) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("BoneIndex %d exceeds maximum available bones %d."), BoneIndex, Mesh->LocalAtoms.Num())); } Rotation.Yaw = Rotation.Pitch = Rotation.Roll = 0; return false; } const FReferenceSkeleton& refskel(Mesh->SkeletalMesh->RefSkeleton); FQuat Quat = refskel.GetRefBonePose()[BoneIndex].GetRotation(); Rotation = Quat.Rotator(); return true; }
void UOculusFunctionLibrary::GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition, bool bUseOrienationForPlayerCamera, bool bUsePositionForPlayerCamera, const FVector PositionScale) { #if OCULUS_SUPPORTED_PLATFORMS FHeadMountedDisplay* OculusHMD = GetOculusHMD(); if (OculusHMD && OculusHMD->IsHeadTrackingAllowed()) { FQuat OrientationAsQuat; OculusHMD->GetCurrentHMDPose(OrientationAsQuat, DevicePosition, bUseOrienationForPlayerCamera, bUsePositionForPlayerCamera, PositionScale); DeviceRotation = OrientationAsQuat.Rotator(); NeckPosition = OculusHMD->GetNeckPosition(OrientationAsQuat, DevicePosition, PositionScale); //UE_LOG(LogUHeadMountedDisplay, Log, TEXT("POS: %.3f %.3f %.3f"), DevicePosition.X, DevicePosition.Y, DevicePosition.Z); //UE_LOG(LogUHeadMountedDisplay, Log, TEXT("NECK: %.3f %.3f %.3f"), NeckPosition.X, NeckPosition.Y, NeckPosition.Z); //UE_LOG(LogUHeadMountedDisplay, Log, TEXT("ROT: sYaw %.3f Pitch %.3f Roll %.3f"), DeviceRotation.Yaw, DeviceRotation.Pitch, DeviceRotation.Roll); } else #endif // #if OCULUS_SUPPORTED_PLATFORMS { DeviceRotation = FRotator::ZeroRotator; DevicePosition = FVector::ZeroVector; } }
/* * Spawns the hitbox and processes the actors within it */ void AHero::AttackTrace() { //Actors that overlap the box stored in this array TArray<struct FOverlapResult> OutOverlaps; //Orient the box in the direction of the character FQuat Rotation = Instigator->GetTransform().GetRotation(); FVector Start = Instigator->GetTransform().GetLocation() + Rotation.Rotator().Vector() * 100.0f; FCollisionShape CollisionHitShape; FCollisionQueryParams CollisionParams; //Have the hitbox ignore the player CollisionParams.AddIgnoredActor(Instigator); //Set what will respond to the collision FCollisionObjectQueryParams CollisionObjectTypes; CollisionObjectTypes.AddObjectTypesToQuery(ECollisionChannel::ECC_PhysicsBody); CollisionObjectTypes.AddObjectTypesToQuery(ECollisionChannel::ECC_Pawn); CollisionObjectTypes.AddObjectTypesToQuery(ECollisionChannel::ECC_WorldStatic); //Create the hitbox and get the actors within CollisionHitShape = FCollisionShape::MakeBox(FVector(100.0f, 60.0f, 0.5f)); GetWorld()->OverlapMulti(OutOverlaps, Start, Rotation, CollisionHitShape, CollisionParams, CollisionObjectTypes); //Process all hit actors for (int i = 0; i < OutOverlaps.Num(); i++) { if (OutOverlaps[i].GetActor() && !HitActors.Contains(OutOverlaps[i].GetActor())) { //Check if hit registered GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("hit")); //Now call the function that does something to our unfortunate actor... ProcessHitActor(OutOverlaps[i].GetActor()); } } }
void UCustomMovementComponent::UpdateCapsuleRotation(float DeltaTime, const FVector& TargetUpVector, bool bInstantRot, float RotationSpeed) { const FVector CapsuleUp = CapsuleComponent->GetUpVector(); const FQuat DeltaQuat = FQuat::FindBetween(CapsuleUp, TargetUpVector); const FQuat TargetQuat = DeltaQuat * CapsuleComponent->GetComponentRotation().Quaternion(); CurrentCapsuleRotation = bInstantRot ? TargetQuat.Rotator() : FMath::RInterpTo(CurrentCapsuleRotation, TargetQuat.Rotator(), DeltaTime, RotationSpeed); CapsuleComponent->SetWorldRotation(CurrentCapsuleRotation); }
void ACinemotusPlayerController::RelativeTick(float DeltaTime) { UPrimitiveComponent* prim = GetPawn()->GetMovementComponent()->UpdatedComponent; bool SetPrimDirectly = true; FQuat finalQuat; if ((currentCaptureState & ECinemotusCaptureState::ERelativeRotation) == ECinemotusCaptureState::ERelativeRotation) { FRotator rot = HydraLatestData->controllers[CAM_HAND].angular_velocity; const FQuat OldRotation = prim->GetComponentQuat();//GetControlRotation().Quaternion(); //TODO: hold onto a quaternion potentially const FRotator OldRotationRotator = OldRotation.Rotator(); FRotator worldRotator = FRotator(0, DeadZone(rot.Yaw*DeltaTime, 0.0) + addYaw, 0); FRotator worldRotator1 = FRotator(DeadZone(rot.Pitch*DeltaTime, 0.0), 0, 0); FRotator localRotator = FRotator(0, 0, DeadZone(rot.Roll*DeltaTime, 0.0)); const FQuat WorldRot = worldRotator.Quaternion(); const FQuat pitchRot = worldRotator1.Quaternion(); const FQuat LocalRot = localRotator.Quaternion(); ////This one does roll around local forward, pitch around world right flattened and yaw around world up //// FQuat finalQuat = pitchRot*WorldRot*((OldRotation*LocalRot)); finalQuat = WorldRot*((OldRotation*LocalRot)*pitchRot); } else { finalQuat = FRotator(0, addYaw, 0).Quaternion()*prim->GetComponentQuat(); } SetControlRotation(finalQuat.Rotator()); if (SetPrimDirectly && prim) { prim->SetWorldLocationAndRotation(prim->GetComponentLocation(), finalQuat);// not sure need } HandleMovementAbs(DeltaTime, (currentCaptureState & ECinemotusCaptureState::ERelativeTranslation) == ECinemotusCaptureState::ERelativeTranslation); }
void UAnimGraphNode_ModifyBone::DoRotation(const USkeletalMeshComponent* SkelComp, FRotator& Rotation, FAnimNode_Base* InOutAnimNode) { FAnimNode_ModifyBone* ModifyBone = static_cast<FAnimNode_ModifyBone*>(InOutAnimNode); if (Node.RotationMode != EBoneModificationMode::BMM_Ignore) { FQuat DeltaQuat = ConvertCSRotationToBoneSpace(SkelComp, Rotation, ModifyBone->ForwardedPose, Node.BoneToModify.BoneName, Node.RotationSpace); FQuat PrevQuat(ModifyBone->Rotation); FQuat NewQuat = DeltaQuat * PrevQuat; ModifyBone->Rotation = NewQuat.Rotator(); Node.Rotation = ModifyBone->Rotation; } }
void UOSVRInputComponent::InitializeComponent() { Super::InitializeComponent(); WorldToMetersScale = 100.f; UWorld* w = GetWorld(); if (w != nullptr) { AWorldSettings* ws = w->GetWorldSettings(); if (ws != nullptr) { WorldToMetersScale = ws->WorldToMeters; } } auto InterfaceCollection = IOSVR::Get().GetEntryPoint()->GetInterfaceCollection(); OSVRInterfaceCollection::RegistrationToken RegToken = InterfaceCollection->RegisterOnStateChangedCallback( [=](OSVRInterface* Interface, uint32 State) { /* FTransform Pose; if (((State & OSVRInterface::POSE_STATE_AVAILABLE) > 0) && Interface->GetPose(Pose, false)) { Pose.ScaleTranslation(WorldToMetersScale); OnPoseChanged.Broadcast(Interface->GetName(), Pose); } */ FVector Position; if (((State & OSVRInterface::POSITION_STATE_AVAILABLE) > 0) && Interface->GetPosition(Position, false)) OnPositionChanged.Broadcast(Interface->GetName(), Position * WorldToMetersScale); FQuat Orientation; if (((State & OSVRInterface::ORIENTATION_STATE_AVAILABLE) > 0) && Interface->GetOrientation(Orientation, false)) OnOrientationChanged.Broadcast(Interface->GetName(), Orientation.Rotator()); float Analog; if (((State & OSVRInterface::ANALOG_STATE_AVAILABLE) > 0) && Interface->GetAnalogState(Analog, false)) OnAnalogValueChanged.Broadcast(Interface->GetName(), Analog); uint8 Button; if (((State & OSVRInterface::BUTTON_STATE_AVAILABLE) > 0) && Interface->GetButtonState(Button, false)) OnButtonStateChanged.Broadcast(Interface->GetName(), EButtonState::Type(Button)); }); RegistrationToken = RegToken.Token; }
void ABaseCharacter::CheckAttackOverlap(){ //Overlapping actors for each box spawned will be stored here TArray<struct FOverlapResult> OutActorOverlaps; //Hit other actors only once TArray<AActor*> ProcessedActors; //The initial rotation of our box is the same as our character rotation FQuat Rotation = GetTransform().GetRotation(); FVector Start = GetTransform().GetLocation() + Rotation.Rotator().Vector() * 100.0f; FCollisionShape CollisionHitShape; FCollisionQueryParams CollisionParams; //We do not want the character to hit itself, don't store this character in the array, to ignore it's collision CollisionParams.AddIgnoredActor(this); //Set the channels that will respond to the collision FCollisionObjectQueryParams CollisionObjectTypes; CollisionObjectTypes.AddObjectTypesToQuery(ECollisionChannel::ECC_PhysicsBody); CollisionObjectTypes.AddObjectTypesToQuery(ECollisionChannel::ECC_Pawn); //CollisionObjectTypes.AddObjectTypesToQuery(ECollisionChannel::ECC_WorldStatic); // uncomment to enable bashing objects //Create the box and get the overlapping actors CollisionHitShape = FCollisionShape::MakeBox(AttackBox); GetWorld()->OverlapMulti(OutActorOverlaps, Start, Rotation, CollisionHitShape, CollisionParams, CollisionObjectTypes); AActor* ActorToProcess; //Process all hit actors for (int i = 0; i < OutActorOverlaps.Num(); ++i) { ActorToProcess = OutActorOverlaps[i].GetActor(); //We process each actor only once per Attack execution if (ActorToProcess && !ProcessedActors.Contains(ActorToProcess)) { //Add this actor to the array because we are spawning one box per tick and we don't want to hit the same actor twice during the same attack animation ProcessedActors.AddUnique(ActorToProcess); if ( dynamic_cast<APatrollingEnemyCharacter*>(ActorToProcess) ){ APatrollingEnemyCharacter* ennemy = (APatrollingEnemyCharacter*)ActorToProcess; ennemy->OnHit(this); } } } }
FRotator UKismetMathLibrary::RLerp(FRotator A, FRotator B, float Alpha, bool bShortestPath) { FRotator DeltaAngle = B - A; // if shortest path, we use Quaternion to interpolate instead of using FRotator if( bShortestPath ) { FQuat AQuat(A); FQuat BQuat(B); FQuat Result = FQuat::Slerp(AQuat, BQuat, Alpha); Result.Normalize(); return Result.Rotator(); } return A + Alpha*DeltaAngle; }
FRotator ULibraries::GetQRotation() { float q1, q2, q3, q4; bool sent = FemtoduinoPointer->WriteData("w\n", 32); char parse1[10], parse2[10], parse3[10], parse4[10]; char incomingData[250]; int dataLength = 250; //Sleep(50); FemtoduinoPointer->ReadData(incomingData, dataLength); _memccpy(&parse1, incomingData,',' ,8); _memccpy(&parse2, &incomingData[9],',', 8); _memccpy(&parse3, &incomingData[18], ',', 8); _memccpy(&parse4, &incomingData[27], ',', 8); hexasciitofloat(q1, parse1); hexasciitofloat(q2, parse2); hexasciitofloat(q3, parse3); hexasciitofloat(q4, parse4); FQuat newQ = FQuat(q2,q3,q4,q1); if (!hq.Equals(FQuat::Identity)) { return (hq*newQ).Rotator(); } //newQ.Normalize(1.1); //FQuat hq = FQuat::Identity; //FQuat next = newQ*hq; //FQuat::Slerp(newQ,current.Quaternion(),.5); //FRotator test = next.Rotator(); return newQ.Rotator(); }
void VRPNTrackerInputDevice::Update() { if(InputDevice){ { FScopeLock ScopeLock(&CritSect); InputDevice->mainloop(); } for(auto &InputPair : TrackerMap) { TrackerInput &Input = InputPair.Value; if(Input.TrackerDataDirty) { // Before firing events, transform the tracker into the right coordinate space FVector NewPosition; FQuat NewRotation; TransformCoordinates(Input, NewPosition, NewRotation); FRotator NewRotator = NewRotation.Rotator(); FAnalogInputEvent AnalogInputEventX(Input.MotionXKey, FSlateApplication::Get().GetModifierKeys(), 0, 0, 0, 0, NewPosition.X); FSlateApplication::Get().ProcessAnalogInputEvent(AnalogInputEventX); FAnalogInputEvent AnalogInputEventY(Input.MotionYKey, FSlateApplication::Get().GetModifierKeys(), 0, 0, 0, 0, NewPosition.Y); FSlateApplication::Get().ProcessAnalogInputEvent(AnalogInputEventY); FAnalogInputEvent AnalogInputEventZ(Input.MotionZKey, FSlateApplication::Get().GetModifierKeys(), 0, 0, 0, 0, NewPosition.Z); FSlateApplication::Get().ProcessAnalogInputEvent(AnalogInputEventZ); FAnalogInputEvent AnalogInputEventRotX(Input.RotationYawKey, FSlateApplication::Get().GetModifierKeys(), 0, 0, 0, 0, NewRotator.Yaw); FSlateApplication::Get().ProcessAnalogInputEvent(AnalogInputEventRotX); FAnalogInputEvent AnalogInputEventRotY(Input.RotationPitchKey, FSlateApplication::Get().GetModifierKeys(), 0, 0, 0, 0, NewRotator.Pitch); FSlateApplication::Get().ProcessAnalogInputEvent(AnalogInputEventRotY); FAnalogInputEvent AnalogInputEventRotZ(Input.RotationRollKey, FSlateApplication::Get().GetModifierKeys(), 0, 0, 0, 0, NewRotator.Roll); FSlateApplication::Get().ProcessAnalogInputEvent(AnalogInputEventRotZ); Input.TrackerDataDirty = false; } } } }
// Read motion data from Axis Neuron bool UNeuronBPFunctionLibrary::NeuronReadMotion(AThirdPersonNeuronController *Controller, FVector& Translation, FRotator& Rotation, FVector AddTranslation, FRotator AddRotation, int32 BoneIndex, ENeuronSkeletonEnum SkeletonType) { bool bExit = false; if (Controller == NULL) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Controller is invalid."))); } bExit = true; } else if (!Controller->bConnected) { bExit = true; } else if (BoneIndex > Controller->BoneNr) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Boneindex %d exceeds maximum available bones %d."), BoneIndex, Controller->BoneNr)); } bExit = true; } else if ((BoneIndex * 6) > Controller->FloatCount) { bExit = true; } if (bExit == true) { Rotation.Yaw = Rotation.Pitch = Rotation.Roll = 0; Translation.X = Translation.Y = Translation.Z = 0; return false; } // // Translation // // Read translation values and remove BVH reference position float X = Controller->MotionLine[(BoneIndex * 6) + Controller->Skeleton[BoneIndex].XPos] - Controller->Skeleton[BoneIndex].Offset[0]; float Y = Controller->MotionLine[(BoneIndex * 6) + Controller->Skeleton[BoneIndex].YPos] - Controller->Skeleton[BoneIndex].Offset[1]; float Z = Controller->MotionLine[(BoneIndex * 6) + Controller->Skeleton[BoneIndex].ZPos] - Controller->Skeleton[BoneIndex].Offset[2]; // Map BVH right hand system to local bone coordinate system switch (SkeletonType) { case ENeuronSkeletonEnum::VE_Neuron: // Neuron BVH skeleton { if (BoneIndex == 0) { // Hips Translation = FVector(X, -Y, Z); } else if ((BoneIndex >= 1) && (BoneIndex <= 6)) { // Legs Translation = FVector(X, Y, -Z); } else if ((BoneIndex >= 7) && (BoneIndex <= 12)) { // Spine,... Translation = FVector(X, -Y, -Z); } else if ((BoneIndex >= 13) && (BoneIndex <= 35)) { // Right arm Translation = FVector(-Z, X, Y); } else if ((BoneIndex >= 36) && (BoneIndex <= 58)) { // Left arm Translation = FVector(Z, -X, Y); } break; } case ENeuronSkeletonEnum::VE_TPP_Hero: // Hero_TPP, Old blue Unreal default skeleton with T-Pose case ENeuronSkeletonEnum::VE_Mannequin: // Mannequin, New Unreal default skeleton with A-Pose { if (BoneIndex == 0) { // Hips Translation = FVector(Y, Z, -X); } // Ignore other bones } } // Add additional translation Translation.X += AddTranslation.X; Translation.Y += AddTranslation.Y; Translation.Z += AddTranslation.Z; // // Rotation // // Read rotation values and map to pitch, yaw, roll (y, z, x) float XR = Controller->MotionLine[(BoneIndex * 6) + Controller->Skeleton[BoneIndex].XRot] * PI / 180.f; float YR = Controller->MotionLine[(BoneIndex * 6) + Controller->Skeleton[BoneIndex].YRot] * PI / 180.f; float ZR = Controller->MotionLine[(BoneIndex * 6) + Controller->Skeleton[BoneIndex].ZRot] * PI / 180.f; float SX = sin(XR); float CX = cos(XR); float SY = sin(YR); float CY = cos(YR); float SZ = sin(ZR); float CZ = cos(ZR); FMatrix RotMatrix; switch (Controller->Skeleton[BoneIndex].RotOrder) { case XYZ: { RotMatrix.M[0][0] = CY*CZ; RotMatrix.M[0][1] = -CY*SZ; RotMatrix.M[0][2] = SY; RotMatrix.M[0][3] = 0; RotMatrix.M[1][0] = CZ*SX*SY + CX*SZ; RotMatrix.M[1][1] = CX*CZ - SX*SY*SZ; RotMatrix.M[1][2] = -CY*SX; RotMatrix.M[1][3] = 0; RotMatrix.M[2][0] = SX*SZ - CX*CZ*SY; RotMatrix.M[2][1] = CZ*SX + CX*SY*SZ; RotMatrix.M[2][2] = CX*CY; RotMatrix.M[2][3] = 0; break; } case ZXY: { RotMatrix.M[0][0] = CY*CZ - SX*SY*SZ; RotMatrix.M[0][1] = -CX*SZ; RotMatrix.M[0][2] = CZ*SY + CY*SX*SZ; RotMatrix.M[0][3] = 0; RotMatrix.M[1][0] = CZ*SX*SY + CY*SZ; RotMatrix.M[1][1] = CX*CZ; RotMatrix.M[1][2] = SY*SZ - CY*CZ*SX; RotMatrix.M[1][3] = 0; RotMatrix.M[2][0] = -CX*SY; RotMatrix.M[2][1] = SX; RotMatrix.M[2][2] = CX*CY; RotMatrix.M[2][3] = 0; break; } case YXZ: default: { RotMatrix.M[0][0] = CY*CZ + SX*SY*SZ; RotMatrix.M[0][1] = CZ*SX*SY - CY*SZ; RotMatrix.M[0][2] = CX*SY; RotMatrix.M[0][3] = 0; RotMatrix.M[1][0] = CX*SZ; RotMatrix.M[1][1] = CX*CZ; RotMatrix.M[1][2] = -SX; RotMatrix.M[1][3] = 0; RotMatrix.M[2][0] = CY*SX*SZ - CZ*SY; RotMatrix.M[2][1] = CY*CZ*SX + SY*SZ; RotMatrix.M[2][2] = CX*CY; RotMatrix.M[2][3] = 0; break; } } RotMatrix.M[3][0] = 0; RotMatrix.M[3][1] = 0; RotMatrix.M[3][2] = 0; RotMatrix.M[3][3] = 1; // Rotation Matrix => Quaternion and map to each bone coordinate systems dependend on skeleton type FQuat Quat = RotMatrix.ToQuat(); switch (SkeletonType) { case ENeuronSkeletonEnum::VE_Neuron: // Neuron BVH skeleton { if ((BoneIndex >= 1) && (BoneIndex <= 6)) { // Legs Quat.Z *= -1.f; } else if ((BoneIndex >= 13) && (BoneIndex <= 35)) { // Right Arm float X = Quat.X; float Y = Quat.Y; float Z = Quat.Z; Quat.X = -Z; Quat.Y = X; Quat.Z = Y; } else if ((BoneIndex >= 36) && (BoneIndex <= 58)) { // Left Arm float X = Quat.X; float Y = Quat.Y; float Z = Quat.Z; Quat.X = Z; Quat.Y = -X; Quat.Z = Y; } else { Quat.Y *= -1.f; } break; } case ENeuronSkeletonEnum::VE_TPP_Hero: // Hero_TPP, Old blue Unreal default skeleton with T-Pose case ENeuronSkeletonEnum::VE_Mannequin: // Mannequin, New Unreal default skeleton with A-Pose { if ((BoneIndex >= 1) && (BoneIndex <= 3)) { // Right Leg float X = Quat.X; float Y = Quat.Y; float Z = Quat.Z; Quat.X = -Y; Quat.Y = -Z; Quat.Z = -X; } else if (BoneIndex == 16) { // Right Hand Quat.Y *= -1.f; } else if ((BoneIndex >= 13) && (BoneIndex <= 19)) { // Right Arm and Thumb float Y = Quat.Y; float Z = Quat.Z; Quat.Y = -Z; Quat.Z = -Y; } else if ((BoneIndex >= 20) && (BoneIndex <= 35)) { // Right Finger Quat.Y *= -1.f; } else if (BoneIndex == 39) { // Left Hand Quat.Z *= -1.f; } else if ((BoneIndex >= 36) && (BoneIndex <= 42)) { // Left Arm and Thumb float Y = Quat.Y; float Z = Quat.Z; Quat.Y = Z; Quat.Z = Y; } else if ((BoneIndex >= 43) && (BoneIndex <= 58)) { // Left Finger Quat.Z *= -1.f; } else { // Left Leg, Hips, Spine, Neck, Head float X = Quat.X; float Y = Quat.Y; float Z = Quat.Z; Quat.X = Y; Quat.Y = Z; Quat.Z = -X; } } break; } Rotation = Quat.Rotator(); // Add additional rotation Rotation.Yaw += AddRotation.Yaw; Rotation.Pitch += AddRotation.Pitch; Rotation.Roll += AddRotation.Roll; return true; }
FQuat FAnimNode_RotationMultiplier::MultiplyQuatBasedOnSourceIndex(const FTransform& RefPoseTransform, const FTransform& LocalBoneTransform, const EBoneAxis Axis, float InMultiplier, const FQuat& ReferenceQuat) { // Find delta angle for source bone. FQuat DeltaQuat = ExtractAngle(RefPoseTransform, LocalBoneTransform, Axis); // Turn to Axis and Angle FVector RotationAxis; float RotationAngle; DeltaQuat.ToAxisAndAngle(RotationAxis, RotationAngle); const FVector DefaultAxis = GetAxisVector(Axis); // See if we need to invert angle - shortest path if( (RotationAxis | DefaultAxis) < 0.f ) { RotationAxis = -RotationAxis; RotationAngle = -RotationAngle; } // Make sure it is the shortest angle. RotationAngle = FMath::UnwindRadians(RotationAngle); // New bone rotation FQuat OutQuat = ReferenceQuat * FQuat(RotationAxis, RotationAngle* InMultiplier); // Normalize resulting quaternion. OutQuat.Normalize(); #if 0 //DEBUG_TWISTBONECONTROLLER UE_LOG(LogSkeletalControl, Log, TEXT("\t RefQuat: %s, Rot: %s"), *ReferenceQuat.ToString(), *ReferenceQuat.Rotator().ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t NewQuat: %s, Rot: %s"), *OutQuat.ToString(), *OutQuat.Rotator().ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t RollAxis: %s, RollAngle: %f"), *RotationAxis.ToString(), RotationAngle ); #endif return OutQuat; }
FQuat FAnimNode_RotationMultiplier::ExtractAngle(const FTransform& RefPoseTransform, const FTransform& LocalBoneTransform, const EBoneAxis Axis) { // local bone transform with reference rotation FTransform ReferenceBoneTransform = RefPoseTransform; ReferenceBoneTransform.SetTranslation(LocalBoneTransform.GetTranslation()); // find delta angle between the two quaternions X Axis. const FVector RotationAxis = GetAxisVector(Axis); const FVector LocalRotationVector = LocalBoneTransform.GetRotation().RotateVector(RotationAxis); const FVector ReferenceRotationVector = ReferenceBoneTransform.GetRotation().RotateVector(RotationAxis); const FQuat LocalToRefQuat = FQuat::FindBetween(LocalRotationVector, ReferenceRotationVector); checkSlow( LocalToRefQuat.IsNormalized() ); // Rotate parent bone atom from position in local space to reference skeleton // Since our rotation rotates both vectors with shortest arc // we're essentially left with a quaternion that has angle difference with reference skeleton version const FQuat BoneQuatAligned = LocalToRefQuat* LocalBoneTransform.GetRotation(); checkSlow( BoneQuatAligned.IsNormalized() ); // Find that delta angle const FQuat DeltaQuat = (ReferenceBoneTransform.GetRotation().Inverse()) * BoneQuatAligned; checkSlow( DeltaQuat.IsNormalized() ); #if 0 //DEBUG_TWISTBONECONTROLLER UE_LOG(LogSkeletalControl, Log, TEXT("\t ExtractAngle, Bone: %s"), *SourceBone.BoneName.ToString()); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t Bone Quat: %s, Rot: %s, AxisX: %s"), *LocalBoneTransform.GetRotation().ToString(), *LocalBoneTransform.GetRotation().Rotator().ToString(), *LocalRotationVector.ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t BoneRef Quat: %s, Rot: %s, AxisX: %s"), *ReferenceBoneTransform.GetRotation().ToString(), *ReferenceBoneTransform.GetRotation().Rotator().ToString(), *ReferenceRotationVector.ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t LocalToRefQuat Quat: %s, Rot: %s"), *LocalToRefQuat.ToString(), *LocalToRefQuat.Rotator().ToString() ); const FVector BoneQuatAlignedX = LocalBoneTransform.GetRotation().RotateVector(RotationAxis); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t BoneQuatAligned Quat: %s, Rot: %s, AxisX: %s"), *BoneQuatAligned.ToString(), *BoneQuatAligned.Rotator().ToString(), *BoneQuatAlignedX.ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaQuat Quat: %s, Rot: %s"), *DeltaQuat.ToString(), *DeltaQuat.Rotator().ToString() ); FTransform BoneAtomAligned(BoneQuatAligned, ReferenceBoneTransform.GetTranslation()); const FQuat DeltaQuatAligned = FQuat::FindBetween(BoneAtomAligned.GetScaledAxis( EAxis::X ), ReferenceBoneTransform.GetScaledAxis( EAxis::X )); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaQuatAligned Quat: %s, Rot: %s"), *DeltaQuatAligned.ToString(), *DeltaQuatAligned.Rotator().ToString() ); FVector DeltaAxis; float DeltaAngle; DeltaQuat.ToAxisAndAngle(DeltaAxis, DeltaAngle); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaAxis: %s, DeltaAngle: %f"), *DeltaAxis.ToString(), DeltaAngle ); #endif return DeltaQuat; }
void UStretchGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) { // Call parent implementation (updates hover animation) Super::UpdateGizmoHandleGroup(LocalToWorld, LocalBounds, ViewLocation, bAllHandlesVisible, DraggingHandle, HoveringOverHandles, AnimationAlpha, GizmoScale, GizmoHoverScale, GizmoHoverAnimationDuration, bOutIsHoveringOrDraggingThisHandleGroup ); for (int32 HandleIndex = 0; HandleIndex < Handles.Num(); ++HandleIndex) { FGizmoHandle& Handle = Handles[ HandleIndex ]; UStaticMeshComponent* StretchingHandle = Handle.HandleMesh; if (StretchingHandle != nullptr) // Can be null if no handle for this specific placement { const FTransformGizmoHandlePlacement HandlePlacement = MakeHandlePlacementForIndex( HandleIndex ); float GizmoHandleScale = GizmoScale; const float OffsetFromSide = GizmoHandleScale * (0.0f + // @todo vreditor tweak: Hard coded handle offset from side of primitive (1.0f - AnimationAlpha) * 10.0f); // @todo vreditor tweak: Animation offset // Make the handle bigger while hovered (but don't affect the offset -- we want it to scale about it's origin) GizmoHandleScale *= FMath::Lerp( 1.0f, GizmoHoverScale, Handle.HoverAlpha ); FVector HandleRelativeLocation = FVector::ZeroVector; for (int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex) { if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Negative) // Negative direction { HandleRelativeLocation[AxisIndex] = LocalBounds.Min[AxisIndex] - OffsetFromSide; } else if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Positive) // Positive direction { HandleRelativeLocation[AxisIndex] = LocalBounds.Max[AxisIndex] + OffsetFromSide; } else // ETransformGizmoHandleDirection::Center { HandleRelativeLocation[AxisIndex] = LocalBounds.GetCenter()[AxisIndex]; } } StretchingHandle->SetRelativeLocation( HandleRelativeLocation ); int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); FRotator Rotator = FRotator::ZeroRotator; { // Back bottom left if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) { Rotator.Yaw = 0.0f; Rotator.Pitch = 0.0f; } // Back bottom right else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) { Rotator.Yaw = -90.0f; Rotator.Pitch = 0.0f; } // Back top left else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) { Rotator.Yaw = 0.0f; Rotator.Pitch = -90.0f; } // Back top right else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) { Rotator.Yaw = -90.0f; Rotator.Pitch = -90.0f; } // Front bottom left else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) { Rotator.Yaw = 0.0f; Rotator.Pitch = 90.0f; } // Front bottom right else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) { Rotator.Yaw = 90.0f; Rotator.Pitch = 90.0f; } // Front top left else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) { Rotator.Yaw = 0.0f; Rotator.Pitch = -180.0f; } // Front top right else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) { Rotator.Yaw = 180.0f; Rotator.Pitch = -90.0f; } // Back left/right edge else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] != ETransformGizmoHandleDirection::Center) { Rotator.Yaw = 0.0f; Rotator.Pitch = 90.0f; } // Back bottom/top edge else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] != ETransformGizmoHandleDirection::Center) { Rotator.Yaw = 90.0f; Rotator.Pitch = 0.0f; } // Front left/right edge else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] != ETransformGizmoHandleDirection::Center) { Rotator.Yaw = 0.0f; Rotator.Pitch = 90.0f; } // Front bottom/top edge else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] != ETransformGizmoHandleDirection::Center) { Rotator.Yaw = 90.0f; Rotator.Pitch = 0.0f; } else { // Facing out from center of a face if (CenterHandleCount == 2) { const FQuat GizmoSpaceOrientation = GetAxisVector( FacingAxisIndex, HandlePlacement.Axes[FacingAxisIndex] ).ToOrientationQuat(); Rotator = GizmoSpaceOrientation.Rotator(); } else { // One of the left/right bottom or top edges } } } StretchingHandle->SetRelativeRotation( Rotator ); StretchingHandle->SetRelativeScale3D( FVector( GizmoHandleScale ) ); // Update material UpdateHandleColor( FacingAxisIndex, Handle, DraggingHandle, HoveringOverHandles ); } } }
void FOculusInput::SendControllerEvents() { const double CurrentTime = FPlatformTime::Seconds(); // @todo: Should be made configurable and unified with other controllers handling of repeat const float InitialButtonRepeatDelay = 0.2f; const float ButtonRepeatDelay = 0.1f; const float AnalogButtonPressThreshold = TriggerThreshold; IOculusRiftPlugin& OculusRiftPlugin = IOculusRiftPlugin::Get(); ovrSession OvrSession = OculusRiftPlugin.GetSession(); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: OvrSession = %p"), OvrSession); if (OvrSession) { ovrInputState OvrInput; ovrTrackingState OvrTrackingState; const ovrResult OvrRes = ovr_GetInputState(OvrSession, ovrControllerType_Touch, &OvrInput); const bool bOvrGCTRes = OculusRiftPlugin.GetCurrentTrackingState(&OvrTrackingState); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ovr_GetInputState() ret = %d, GetCurrentTrackingState ret = %d"), int(OvrRes), int(bOvrGCTRes)); if (OvrRes == ovrSuccess && bOvrGCTRes) { UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ConnectedControllerTypes 0x%X"), OvrInput.ConnectedControllerTypes); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ButtonState = 0x%X"), OvrInput.Buttons); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Touches = 0x%X"), OvrInput.Touches); for (FOculusTouchControllerPair& ControllerPair : ControllerPairs) { for( int32 HandIndex = 0; HandIndex < ARRAY_COUNT( ControllerPair.ControllerStates ); ++HandIndex ) { FOculusTouchControllerState& State = ControllerPair.ControllerStates[ HandIndex ]; const bool bIsLeft = (HandIndex == (int32)EControllerHand::Left); bool bIsCurrentlyTracked = (bIsLeft ? (OvrInput.ConnectedControllerTypes & ovrControllerType_LTouch) != 0 : (OvrInput.ConnectedControllerTypes & ovrControllerType_RTouch) != 0); #if OVR_TESTING bIsCurrentlyTracked = true; static float _angle = 0; OvrTrackingState.HandPoses[HandIndex].ThePose.Orientation = OVR::Quatf(OVR::Vector3f(0, 0, 1), _angle); _angle += 0.1f; OvrTrackingState.HandPoses[HandIndex].ThePose = OvrTrackingState.HeadPose.ThePose; UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Error, TEXT("SendControllerEvents: OVR_TESTING is enabled!")); #endif if (bIsCurrentlyTracked) { State.bIsCurrentlyTracked = true; const float OvrTriggerAxis = OvrInput.IndexTrigger[HandIndex]; const float OvrGripAxis = OvrInput.HandTrigger[HandIndex]; UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTrigger[%d] = %f"), int(HandIndex), OvrTriggerAxis); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandTrigger[%d] = %f"), int(HandIndex), OvrGripAxis); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ThumbStick[%d] = { %f, %f }"), int(HandIndex), OvrInput.Thumbstick[HandIndex].x, OvrInput.Thumbstick[HandIndex].y ); if (OvrTriggerAxis != State.TriggerAxis) { State.TriggerAxis = OvrTriggerAxis; MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_TriggerAxis : FGamepadKeyNames::MotionController_Right_TriggerAxis, ControllerPair.UnrealControllerIndex, State.TriggerAxis); } if (OvrGripAxis != State.GripAxis) { State.GripAxis = OvrGripAxis; MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Grip1Axis : FGamepadKeyNames::MotionController_Right_Grip1Axis, ControllerPair.UnrealControllerIndex, State.GripAxis); } if (OvrInput.Thumbstick[HandIndex].x != State.ThumbstickAxes.X) { State.ThumbstickAxes.X = OvrInput.Thumbstick[HandIndex].x; MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Thumbstick_X : FGamepadKeyNames::MotionController_Right_Thumbstick_X, ControllerPair.UnrealControllerIndex, State.ThumbstickAxes.X); } if (OvrInput.Thumbstick[HandIndex].y != State.ThumbstickAxes.Y) { State.ThumbstickAxes.Y = OvrInput.Thumbstick[HandIndex].y; // we need to negate Y value to match XBox controllers MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Thumbstick_Y : FGamepadKeyNames::MotionController_Right_Thumbstick_Y, ControllerPair.UnrealControllerIndex, -State.ThumbstickAxes.Y); } for (int32 ButtonIndex = 0; ButtonIndex < (int32)EOculusTouchControllerButton::TotalButtonCount; ++ButtonIndex) { FOculusButtonState& ButtonState = State.Buttons[ButtonIndex]; check(!ButtonState.Key.IsNone()); // is button's name initialized? // Determine if the button is pressed down bool bButtonPressed = false; switch ((EOculusTouchControllerButton)ButtonIndex) { case EOculusTouchControllerButton::Trigger: bButtonPressed = State.TriggerAxis >= AnalogButtonPressThreshold; break; case EOculusTouchControllerButton::Grip: bButtonPressed = State.GripAxis >= AnalogButtonPressThreshold; break; case EOculusTouchControllerButton::XA: bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_X) != 0 : (OvrInput.Buttons & ovrButton_A) != 0; break; case EOculusTouchControllerButton::YB: bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_Y) != 0 : (OvrInput.Buttons & ovrButton_B) != 0; break; case EOculusTouchControllerButton::Thumbstick: bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_LThumb) != 0 : (OvrInput.Buttons & ovrButton_RThumb) != 0; break; default: check(0); break; } // Update button state if (bButtonPressed != ButtonState.bIsPressed) { const bool bIsRepeat = false; ButtonState.bIsPressed = bButtonPressed; if (ButtonState.bIsPressed) { MessageHandler->OnControllerButtonPressed(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat); // Set the timer for the first repeat ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay; } else { MessageHandler->OnControllerButtonReleased(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat); } } // Apply key repeat, if its time for that if (ButtonState.bIsPressed && ButtonState.NextRepeatTime <= CurrentTime) { const bool bIsRepeat = true; MessageHandler->OnControllerButtonPressed(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat); // Set the timer for the next repeat ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay; } } // Handle Capacitive States for (int32 CapTouchIndex = 0; CapTouchIndex < (int32)EOculusTouchCapacitiveAxes::TotalAxisCount; ++CapTouchIndex) { FOculusTouchCapacitiveState& CapState = State.CapacitiveAxes[CapTouchIndex]; float CurrentAxisVal = 0.f; switch ((EOculusTouchCapacitiveAxes)CapTouchIndex) { case EOculusTouchCapacitiveAxes::XA: { const uint32 mask = (bIsLeft) ? ovrTouch_X : ovrTouch_A; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::YB: { const uint32 mask = (bIsLeft) ? ovrTouch_Y : ovrTouch_B; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::Thumbstick: { const uint32 mask = (bIsLeft) ? ovrTouch_LThumb : ovrTouch_RThumb; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::Trigger: { const uint32 mask = (bIsLeft) ? ovrTouch_LIndexTrigger : ovrTouch_RIndexTrigger; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::IndexPointing: { const uint32 mask = (bIsLeft) ? ovrTouch_LIndexPointing : ovrTouch_RIndexPointing; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::ThumbUp: { const uint32 mask = (bIsLeft) ? ovrTouch_LThumbUp : ovrTouch_RThumbUp; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } default: check(0); } if (CurrentAxisVal != CapState.State) { MessageHandler->OnControllerAnalog(CapState.Axis, ControllerPair.UnrealControllerIndex, CurrentAxisVal); CapState.State = CurrentAxisVal; } } const ovrPosef& OvrHandPose = OvrTrackingState.HandPoses[HandIndex].ThePose; FVector NewLocation; FQuat NewOrientation; if (OculusRiftPlugin.PoseToOrientationAndPosition(OvrHandPose, /* Out */ NewOrientation, /* Out */ NewLocation)) { // OK, we have up to date positional data! State.Orientation = NewOrientation; State.Location = NewLocation; UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandPOSE[%d]: Pos %.3f %.3f %.3f"), HandIndex, NewLocation.X, NewLocation.Y, NewLocation.Y); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandPOSE[%d]: Yaw %.3f Pitch %.3f Roll %.3f"), HandIndex, NewOrientation.Rotator().Yaw, NewOrientation.Rotator().Pitch, NewOrientation.Rotator().Roll); } else { // HMD wasn't ready. This can currently happen if we try to grab motion data before we've rendered at least one frame UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: PoseToOrientationAndPosition returned false")); } } else { // Controller isn't available right now. Zero out input state, so that if it comes back it will send fresh event deltas State = FOculusTouchControllerState((EControllerHand)HandIndex); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Controller for the hand %d is not tracked"), int(HandIndex)); } } } } } UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("")); }
// Read motion data from Axis Neuron // Deprecated bool UPerceptionNeuronBPLibrary::NeuronReadMotion(APerceptionNeuronController *Controller, FVector& Translation, FRotator& Rotation, FVector AdditionalTranslation, FRotator AdditionalRotation, int32 BoneIndex, ENeuronSkeletonEnum SkeletonType) { if (Controller == nullptr) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Controller is invalid."))); } Rotation.Yaw = Rotation.Pitch = Rotation.Roll = 0; Translation.X = Translation.Y = Translation.Z = 0; return false; } else if ((Controller->bConnected == false) && (Controller->bPlay == false)) { Rotation.Yaw = Rotation.Pitch = Rotation.Roll = 0; Translation.X = Translation.Y = Translation.Z = 0; return false; } else if (BoneIndex >= Controller->Skeleton.BoneNr) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Boneindex %d exceeds maximum available bones %d."), BoneIndex, Controller->Skeleton.BoneNr)); } Rotation.Yaw = Rotation.Pitch = Rotation.Roll = 0; Translation.X = Translation.Y = Translation.Z = 0; return false; } int32 FloatsPerBone = 6; // 3 for x,y,z translation and 3 for x,y,z rotation if (Controller->bDisplacement == false) { FloatsPerBone = 3; // If there is no displacement (translation) info we have only 3 floats for rotation left } if ((BoneIndex * FloatsPerBone) > Controller->FloatCount) { Rotation.Yaw = Rotation.Pitch = Rotation.Roll = 0; Translation.X = Translation.Y = Translation.Z = 0; return false; } // // Translation // if (Controller->bDisplacement == true) { // Read translation values and remove BVH reference position float X = Controller->MotionLine[(BoneIndex * FloatsPerBone) + Controller->Skeleton.Bones[BoneIndex].XPos] - Controller->Skeleton.Bones[BoneIndex].Offset[0]; float Y = Controller->MotionLine[(BoneIndex * FloatsPerBone) + Controller->Skeleton.Bones[BoneIndex].YPos] - Controller->Skeleton.Bones[BoneIndex].Offset[1]; float Z = Controller->MotionLine[(BoneIndex * FloatsPerBone) + Controller->Skeleton.Bones[BoneIndex].ZPos] - Controller->Skeleton.Bones[BoneIndex].Offset[2]; // Map BVH right hand system to local bone coordinate system switch (SkeletonType) { case ENeuronSkeletonEnum::VE_Neuron: // Neuron BVH skeleton { if (BoneIndex == 0) { // Hips Translation = FVector(X, -Y, Z); } else if ((BoneIndex >= 1) && (BoneIndex <= 6)) { // Legs Translation = FVector(X, Y, -Z); } else if ((BoneIndex >= 7) && (BoneIndex <= 12)) { // Spine,... Translation = FVector(X, -Y, -Z); } else if ((BoneIndex >= 13) && (BoneIndex <= 35)) { // Right arm Translation = FVector(-Z, X, Y); } else if ((BoneIndex >= 36) && (BoneIndex <= 58)) { // Left arm Translation = FVector(Z, -X, Y); } break; } case ENeuronSkeletonEnum::VE_TPP_Hero: // Hero_TPP, Old blue Unreal default skeleton with T-Pose case ENeuronSkeletonEnum::VE_Mannequin: // Mannequin, New Unreal default skeleton with A-Pose { if (BoneIndex == 0) { // Hips Translation = FVector(Y, Z, -X); } // Ignore other bones break; } case ENeuronSkeletonEnum::VE_Map: // Map to configured bone map { // Map translation with configured Bonemap float Map[3] = { X, Y, Z }; Translation = FVector(Map[Controller->Bonemap[BoneIndex].XYZ[0]] * Controller->Bonemap[BoneIndex].Sign[0], Map[Controller->Bonemap[BoneIndex].XYZ[1]] * Controller->Bonemap[BoneIndex].Sign[1], Map[Controller->Bonemap[BoneIndex].XYZ[2]] * Controller->Bonemap[BoneIndex].Sign[2]); break; } case ENeuronSkeletonEnum::VE_UE4: // Map to UE4 world coordinate system { Translation = FVector(X, Z, Y); break; } case ENeuronSkeletonEnum::VE_None: // Map to nothing, use BVH translation as it is default: { Translation = FVector(X, Y, Z); break; } } } else { Translation.X = Translation.Y = Translation.Z = 0; } // Add additional translation Translation.X += AdditionalTranslation.X; Translation.Y += AdditionalTranslation.Y; Translation.Z += AdditionalTranslation.Z; // // Rotation // // Read rotation values and map to pitch, yaw, roll (y, z, x) float XR = Controller->MotionLine[(BoneIndex * FloatsPerBone) + Controller->Skeleton.Bones[BoneIndex].XRot] * PI / 180.f; float YR = Controller->MotionLine[(BoneIndex * FloatsPerBone) + Controller->Skeleton.Bones[BoneIndex].YRot] * PI / 180.f; float ZR = Controller->MotionLine[(BoneIndex * FloatsPerBone) + Controller->Skeleton.Bones[BoneIndex].ZRot] * PI / 180.f; // Calculate Rotation Matrix and map to Quaternion FQuat Quat = CalculateQuat(XR, YR, ZR, Controller->Skeleton.Bones[BoneIndex].RotOrder); // Map BVH coordinate system to each bone coordinate system dependend on skeleton type switch (SkeletonType) { case ENeuronSkeletonEnum::VE_Neuron: // Neuron BVH skeleton { if ((BoneIndex >= 1) && (BoneIndex <= 6)) { // Legs Quat.Z *= -1.f; } else if ((BoneIndex >= 13) && (BoneIndex <= 35)) { // Right Arm float X = Quat.X; float Y = Quat.Y; float Z = Quat.Z; Quat.X = -Z; Quat.Y = X; Quat.Z = Y; } else if ((BoneIndex >= 36) && (BoneIndex <= 58)) { // Left Arm float X = Quat.X; float Y = Quat.Y; float Z = Quat.Z; Quat.X = Z; Quat.Y = -X; Quat.Z = Y; } else { Quat.Y *= -1.f; } break; } case ENeuronSkeletonEnum::VE_TPP_Hero: // Hero_TPP, Old blue Unreal default skeleton with T-Pose case ENeuronSkeletonEnum::VE_Mannequin: // Mannequin, New Unreal default skeleton with A-Pose { if ((BoneIndex >= 1) && (BoneIndex <= 3)) { // Right Leg float X = Quat.X; float Y = Quat.Y; float Z = Quat.Z; Quat.X = -Y; Quat.Y = -Z; Quat.Z = -X; } else if (BoneIndex == 16) { // Right Hand Quat.Y *= -1.f; } else if ((BoneIndex >= 13) && (BoneIndex <= 19)) { // Right Arm and Thumb float Y = Quat.Y; float Z = Quat.Z; Quat.Y = -Z; Quat.Z = -Y; } else if ((BoneIndex >= 20) && (BoneIndex <= 35)) { // Right Finger Quat.Y *= -1.f; } else if (BoneIndex == 39) { // Left Hand Quat.Z *= -1.f; } else if ((BoneIndex >= 36) && (BoneIndex <= 42)) { // Left Arm and Thumb float Y = Quat.Y; float Z = Quat.Z; Quat.Y = Z; Quat.Z = Y; } else if ((BoneIndex >= 43) && (BoneIndex <= 58)) { // Left Finger Quat.Z *= -1.f; } else { // Left Leg, Hips, Spine, Neck, Head float X = Quat.X; float Y = Quat.Y; float Z = Quat.Z; Quat.X = Y; Quat.Y = Z; Quat.Z = -X; } break; } case ENeuronSkeletonEnum::VE_Map: // Map to configured bone map { // Map Quat.X/Y/Z with configured Bonemap float Map[3] = { Quat.X, Quat.Y, Quat.Z }; Quat.X = Map[Controller->Bonemap[BoneIndex].XYZ[0]] * Controller->Bonemap[BoneIndex].Sign[0]; Quat.Y = Map[Controller->Bonemap[BoneIndex].XYZ[1]] * Controller->Bonemap[BoneIndex].Sign[1]; Quat.Z = Map[Controller->Bonemap[BoneIndex].XYZ[2]] * Controller->Bonemap[BoneIndex].Sign[2]; break; } case ENeuronSkeletonEnum::VE_UE4: // Map to UE4 world coordinate system { float Y = Quat.Y; float Z = Quat.Z; Quat.Y = Z; Quat.Z = Y; break; } case ENeuronSkeletonEnum::VE_None: // Map to nothing, use BVH rotation as it is default: { // Nothing to do, Quaternion is already BVH break; } } // Convert to Rotator Rotation = Quat.Rotator(); // Add additional rotation Rotation.Yaw += AdditionalRotation.Yaw; Rotation.Pitch += AdditionalRotation.Pitch; Rotation.Roll += AdditionalRotation.Roll; Rotation.Normalize(); return true; }
bool VRPNTrackerInputDevice::GetControllerOrientationAndPosition(const int32 ControllerIndex, const EControllerHand DeviceHand, FRotator& OutOrientation, FVector& OutPosition) const { for(auto &InputPair : TrackerMap) { const TrackerInput &Tracker = InputPair.Value; if(Tracker.PlayerIndex == ControllerIndex && Tracker.Hand == DeviceHand) { if(InputDevice) { FScopeLock ScopeLock(&CritSect); InputDevice->mainloop(); } FVector NewPosition; FQuat NewRotation; TransformCoordinates(Tracker, NewPosition, NewRotation); OutOrientation = NewRotation.Rotator(); OutPosition = NewPosition; return true; } } return false; }