Trying to implement FPS ADS, but got a problem with Relative Transform.

(3) UE4 Procedural Aim Down Sights Tutorial - YouTube

First, sorry for bad English.
This question has been machine-translated.

While I was switching to C++ code by referring to the tutorial above, I was trying to find out that the code was not suitable for my project, and just get the method and apply it.

I want to implement ADS by bringing the weapon’s AimPoint socket to the origin of the player’s camera, but the problem is the following hierarchy:

image

The weapon exists in a lower layer of the character and is attached to a specific socket on the Mesh1P.

To place the weapon on the camera, I have to calculate the difference between the transform of the weapon and the camera, and move the first-person mesh, Mesh1P, accordingly.

The implementation code is as follows:

void AFPSurvivalCharacter::OnSightAction(bool Pressed)
{
	if(CurrentWeapon != nullptr)
	{
		if(Pressed)
		{
			const FTransform AimPoint = CurrentWeapon->GetMesh()->GetSocketTransform(TEXT("aimPoint"));
			const FTransform CameraTransform = FirstPersonCameraComponent->GetComponentTransform();
			DefaultWeaponRelativeTransform = AimPoint.GetRelativeTransform(CameraTransform);
			
			ButtonPressed["Sight"] = true;
			if(MovementState != EMovementState::Sprinting)
			{
				IsInSight = true;
				AdsTimeline->Play();
			}
		}
		else
		{
			ButtonPressed["Sight"] = false;
			IsInSight = false;
			AdsTimeline->Reverse();
		}
	}
}

void AFPSurvivalCharacter::AdsTimelineReturn(float Value)
{
	FTransform AdsTransform;
	FTransform TargetTransform;
	FTransform ArmToAimTransform;
	auto CurrentWeaponMesh = CurrentWeapon->GetMesh();
	if(CurrentWeaponMesh != nullptr)
	{
		FTransform CameraTransform = FirstPersonCameraComponent->GetComponentTransform();
		FTransform AimPoint = CurrentWeaponMesh->GetSocketTransform(TEXT("aimPoint"));
		FTransform ArmTransform = Mesh1P->GetComponentTransform();

		// FVector3d Temp;
		// if(Value == 1.0f)
		// {
		// 	AdsTransform = AimPoint.GetRelativeTransform(CameraTransform);
		// 	Temp = AdsTransform.Rotator().Euler();
		// }
		AdsTransform = AimPoint.GetRelativeTransform(CameraTransform);
        ArmToAimTransform = AimPoint.GetRelativeTransform(ArmTransform);
		
		FRotator TargetRotation;
		FVector3d DefaultRotator = DefaultArmRelativeTransform.Rotator().Euler();
		FVector3d ArmToAimRotator = ArmToAimTransform.Rotator().Euler();
		FVector3d TargetRotator = DefaultRotator - ArmToAimRotator;
	
		TargetRotation = FRotator::MakeFromEuler(TargetRotator);

		TargetTransform.SetLocation(DefaultArmRelativeTransform.GetLocation() - DefaultWeaponRelativeTransform.GetLocation());
		TargetTransform.SetRotation(TargetRotation.Quaternion());
		TargetTransform.SetScale3D(FVector3d(1, 1, 1));
	}

	FTransform NewTransform;
	if(IsInSight)
	{
		FTransform MeshTransform = Mesh1P->GetRelativeTransform();
		
		NewTransform.SetLocation(FMath::Lerp(MeshTransform.GetLocation(), TargetTransform.GetLocation(), Value));
		NewTransform.SetScale3D(FMath::Lerp(MeshTransform.GetScale3D(), TargetTransform.GetScale3D(), Value));
		NewTransform.SetRotation(FMath::Lerp(MeshTransform.GetRotation(), TargetTransform.GetRotation(), Value));
		Mesh1P->SetRelativeTransform(NewTransform);
	}
	else
	{
		NewTransform.SetLocation(FMath::Lerp(DefaultArmRelativeTransform.GetLocation(), TargetTransform.GetLocation(), Value));
		NewTransform.SetScale3D(FMath::Lerp(DefaultArmRelativeTransform.GetScale3D(), TargetTransform.GetScale3D(), Value));
		NewTransform.SetRotation(FMath::Lerp(DefaultArmRelativeTransform.GetRotation(), TargetTransform.GetRotation(), Value));
		Mesh1P->SetRelativeTransform(NewTransform);
	}
	
}

DefaultArmRelativeTransform is a first-person mesh RelativeTransform with a camera obtained from BeginPlay.

DefaultWeaponRelativeTransform is the RelativeTransform of camera and AimPoint when ADS input is received.

An AimPoint is a socket for the weapon that must eventually have (0, 0, 0) position and (0, 0, -90) rotation values in the camera coordinate system.

(-90 is the value that exists because the first-person mesh is turned -90 degrees… That’s how animation looks like.)

I thought that I could put the weapon in the position I wanted in front of the camera.

Here’s what I thought. As much as AimPoint’s position in the camera’s coordinate system, if I move the Relative Transform of the first-person mesh, the Transform value for the camera in the current AimPoint will be erased and I will have the value I wanted. The idea itself is simple.

To do this, gradually change the Transform of the first-person mesh to the difference between DefaultArmRelativeTransform and DefaultWeaponRelativeTransform using the timeline and interpolation.

I don’t think I can find a problem here, but it’s a problem because the results aren’t coming out right…

This is how the first-person mesh looks when the value of the timeline is 1.0.

Not only is it not the desired result, but in that state, the Relative Transform of the AimPoint and the camera is not (0, 0, 0) position, (0, 0, -90) rotation.

To be exact, the rotation is close (error in two decimal places) but the position has quite a large error value…

Where did the calculation go wrong? I’ve been looking for this for 3 days now… Help me…