I’m having a small but irritating issue with the rotation of my actor, whereby there seems to be a lack of precision of the visual mesh relative to it’s actual component transform. Here’s a video of the issue to show what I mean:
Notice how as the rotation slows down, the reticle ‘drifts’ slightly in that direction still. The vehicle mesh should follow it perfectly but it doesn’t. The Reticle and Camera is ‘attached’ to the vehicle transform and also seems to update just fine - but the vehicle mesh stops rotating before the camera does and before the rotation has actually finished.
When the vehicle is moved again, the mesh suddenly ‘jolts’ to the correct rotation. It’s as if the engine isn’t updating the visual mesh transform all the time and is trying to cull the updates somewhere - which I need to change because the effect of that is horrible.
I never noticed this problem before when my movement used the physics engine. My movement system has been rewritten and is now based on a similar one to CharacterMovement, whereby all the ‘physics’ are calculated in the component and applied at the end. Nothing here is actually simulating physics, and the actual values of the transforms and rotations are 100% verified and correct.
This is where I actually apply my rotation (I’ve tried a few different methods, none seem to make a difference). At first I thought it was because of the precision of floats, and multiplying ‘Omega’ by ‘DeltaSeconds’ would yield too small of a value to store accurately, but that wasn’t the issue either (I also tried clamping FPS to 30 to see if that helped, it didn’t).
void UBZGame_VehicleMovement::ApplyVelocities(const float DeltaSeconds)
{
// Check Floor
const FVector Delta = Velocity * DeltaSeconds;
const FVector ScaledOmega = Omega * DeltaSeconds;
const FQuat OmegaQuat = FQuat(FVector::ForwardVector, ScaledOmega.X) * FQuat(FVector::RightVector, ScaledOmega.Y) * FQuat(FVector::UpVector, ScaledOmega.Z);
const FQuat FinalRotation = OmegaQuat * UpdatedComponent->GetComponentQuat();
FHitResult MoveHit = FHitResult(1.f);
SafeMoveUpdatedComponent(Delta, FinalRotation, true, MoveHit);
To prove that the actual component transform is correct, this is the way the reticle position is calculated. Notice how it uses the actual Actor Rotation to determine where to place it, meaning that the actor rotation values ARE correct, it’s just that the Skeletal Mesh isn’t visually following it. The SkeletalMesh is the RootComponent of the actor.
FVector UBZGame_UnitComponent::WeaponConvergeLocation() const
{
const APawn* PawnOwner = Cast<APawn>(GetOwner());
if (PawnOwner)
{
const IBZGame_GameObjectInterface* OwningGO = Cast<IBZGame_GameObjectInterface>(PawnOwner);
ASSERTV_WR(OwningGO != nullptr, FVector::ZeroVector, TEXT("WeaponConvergeLocation: Invalid GO"));
const FVector EyepointLocWS = OwningGO->GetRootMesh()->GetSocketLocation(TEXT("HP_Eyepoint"));
const FVector AimRotation = FRotator(PawnAimOffsets.Y, 0.f, 0.f).Vector();
const FVector AimDir = PawnOwner->GetActorRotation().RotateVector(AimRotation);
FVector ConvergeLocation = EyepointLocWS + (AimDir * CalcWeaponRange());
return ConvergeLocation;
}
return FVector::ZeroVector;
}