I want to make the actor look at a certain point in space (observance of the UP vector is not necessary).
Those. you need something like this, but with a smooth change:
const auto TargetRotation = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), ToLocation);
SetActorRotation(TargetRotation);
Wrote the following solution. It works, but sometimes the actor gets stuck looking in the +/- UP direction:
const auto AngularOffset = GetAngularOffsetForLocationVector(OwnerShip, ToLocation);
const auto AngularSpeedDeltaX = FMath::Sign((AngularOffset.X) - CurrentAngularSpeed.X) * AngularAcceleration * DeltaTime;
const auto AngularSpeedDeltaY = FMath::Sign((-AngularOffset.Y) - CurrentAngularSpeed.Y) * AngularAcceleration * DeltaTime;
const auto AngularSpeedDeltaZ = FMath::Sign(AngularOffset.Z - CurrentAngularSpeed.Z) * AngularAcceleration * DeltaTime;
CurrentAngularSpeed = FVector(FMath::Clamp(CurrentAngularSpeed.X + AngularSpeedDeltaX, -MaxAngularSpeed, MaxAngularSpeed), FMath::Clamp(CurrentAngularSpeed.Y + AngularSpeedDeltaY, -MaxAngularSpeed, MaxAngularSpeed), FMath::Clamp(CurrentAngularSpeed.Z + AngularSpeedDeltaZ, -MaxAngularSpeed, MaxAngularSpeed));
const auto OldRotation = OwnerShip->GetActorRotation();
SetActorRotation(FRotator(OldRotation.Pitch + CurrentAngularSpeed.Y * DeltaTime, OldRotation.Yaw + CurrentAngularSpeed.Z * DeltaTime, OldRotation.Roll+ CurrentAngularSpeed.X * DeltaTime));
Angular offset calculation function:
GetAngularOffsetForLocationVector(const AActor* Actor, FVector Location)
{
const auto ActorLocation = Actor->GetActorLocation();
const auto ActorForward = Actor->GetActorForwardVector();
const auto ActorLocationX = FVector(0, ActorLocation.Y, ActorLocation.Z);
auto ActorForwardX = FVector(0, ActorForward.Y, ActorForward.Z);
ActorForwardX.Normalize();
auto PositionOffsetX = FVector(0, Location.Y - ActorLocationX.Y, Location.Z - ActorLocationX.Z);
PositionOffsetX.Normalize();
const float DotX = FVector::DotProduct(ActorForwardX, PositionOffsetX);
const float CrossX = FVector::CrossProduct(ActorForwardX, PositionOffsetX).X;
//
const auto ActorLocationY = FVector(ActorLocation.X, 0, ActorLocation.Z);
auto ActorForwardY = FVector(ActorForward.X, 0, ActorForward.Z);
ActorForwardY.Normalize();
auto PositionOffsetY = FVector(Location.X - ActorLocationY.X, 0, Location.Z - ActorLocationY.Z);
PositionOffsetY.Normalize();
const float DotY = FVector::DotProduct(ActorForwardY, PositionOffsetY);
const float CrossY = FVector::CrossProduct(ActorForwardY, PositionOffsetY).Y;
//
const auto ActorLocationZ = FVector(ActorLocation.X, ActorLocation.Y, 0);
auto ActorForwardZ = FVector(ActorForward.X, ActorForward.Y, 0);
ActorForwardZ.Normalize();
auto PositionOffsetZ = FVector(Location.X - ActorLocationZ.X, Location.Y - ActorLocationZ.Y, 0);
PositionOffsetZ.Normalize();
const float DotZ = FVector::DotProduct(ActorForwardZ, PositionOffsetZ);
const float CrossZ = FVector::CrossProduct(ActorForwardZ, PositionOffsetZ).Z;
return FVector(
UKismetMathLibrary::DegAcos(DotX) * UKismetMathLibrary::SignOfFloat(CrossX),
UKismetMathLibrary::DegAcos(DotY) * UKismetMathLibrary::SignOfFloat(CrossY),
UKismetMathLibrary::DegAcos(DotZ) * UKismetMathLibrary::SignOfFloat(CrossZ));
}