Need some help with having the player rotating a object infront of the camera.

Hey, i’m currently working on a first person game in which the player can go around and investigate various items. When the player finds an object that he can investigate the object flies up infront on the camera and the player can rotate the object around.
But i’m currently have some issues making it so that it feels good to rotate the object, usually after a while it gets very confusing to rotate it around since it will have such a wierd angle and you wont know which key will make the rotate in a certain direction.

This is the code i’m currently using, for both yaw and pitch.


if (MyHUD->Investigating && Val != 0.0f)
{
	if (InterObject != nullptr)
	{
		FRotator AxisRotation = FRotator(Val * RotateSpeed * GetWorld()->GetDeltaSeconds(), 0.0f, 0.0f);
		FRotator ActorRotation = InterObject->GetActorRotation();

		FQuat AQuat = FQuat(AxisRotation);
		FQuat BQuat = FQuat(ActorRotation);

		FRotator FinalRot = FRotator(BQuat*AQuat);
		FinalRot.Roll = 0.0f;
		InterObject->SetActorRotation(FinalRot);
	}
}

Here is a image of how it looks in game.
IQavWQx.png

Do anyone have any idea on how i can handle the rotating so it is easier for the player to understand?

Ether One’s Item System

This is how Ether One (UE4 Version)'s item system works. I’ve commented some of the more important bits. It was also written long before I got to grips with C++ so please don’t judge the quality.

UpdateItem() is called from the component tick.

We use the camera’s rotation as the starting point always, and then add the rotational values on each time, rather than recalculating from where the item currently is. It seems to feel okay this way.


//Inline function in the header file. I've definitely stolen this from somewhere.
FORCEINLINE FRotator AddTwoRotators(FRotator A, FRotator B)
{
	FQuat PQ = FRotator(A.Pitch, 0, 0).Quaternion();
	FQuat YQ = FRotator(0, A.Yaw, 0).Quaternion();
	FQuat RQ = FRotator(0, 0, A.Roll).Quaternion();
	B = (B.Quaternion() * PQ * YQ * RQ).Rotator();

	return B;
}

//This is from a custom subclass of staticmeshcomponent, owned by an itemzone actor.

//DistanceFromCamera is typically 32.f
//InitialLocation is either the itemzone actor location or a designated anchor location.

void UEtherPickupComponent::UpdateItem()
{
	FRotator TargetRotation = FRotator(0, 0, 0);

	//EChar is character reference.
	if (EChar && EChar->IsValidLowLevel())
	{
		FVector CamLoc;

		CamLoc = EChar->CurrentCameraLocation;

		//Set the targetrotation initially to the camera rotation.
		TargetRotation = EChar->CurrentCameraRotation;

		if (bFromPlayerInventory == false) TargetLocation = CamLoc + FRotationMatrix(TargetRotation).GetScaledAxis(EAxis::X) * DistanceFromCamera;
		else TargetLocation = EChar->GetRootComponent()->GetComponentLocation();
	}

	if (ItemAnchor != NULL)
	{
		//Set InitialLocation to be the anchor's location.
		InitialLocation = ItemAnchor->GetRootComponent()->GetComponentLocation();
	}
	else
	{
		//Constantly update the InitialLocation, as the root may have moved.
		InitialLocation = GetAttachParent()->GetComponentLocation();
		InitialLocation.Z += HeightOffset;
	}

	FVector NewLoc;

	if (bToPlayer)
	{
		NewLoc.X = FMath::Lerp(InitialLocation.X, TargetLocation.X, TravelTime);
		NewLoc.Y = FMath::Lerp(InitialLocation.Y, TargetLocation.Y, TravelTime);
		NewLoc.Z = FMath::Lerp(InitialLocation.Z, TargetLocation.Z, TravelTime);
	}
	else
	{
		NewLoc.X = FMath::Lerp(TargetLocation.X, InitialLocation.X, TravelTime);
		NewLoc.Y = FMath::Lerp(TargetLocation.Y, InitialLocation.Y, TravelTime);
		NewLoc.Z = FMath::Lerp(TargetLocation.Z, InitialLocation.Z, TravelTime);
	}

	SetWorldLocation(NewLoc);



	//Add the mouse movement if the item can be rotated.
	if (bNoRotation == false)
	{
		//PickupPitch and PickupYaw are fed to from axis bound functions provided we are examining.
		TargetRotation = AddTwoRotators(FRotator(PickupPitch, -PickupYaw, 0), TargetRotation);
	}

	//InitialRotation is the rotation of the meshcomponent in component space at the point of initialization.
	//Add the InitialRotation on top of the camera's rotation.
	TargetRotation = AddTwoRotators(InitialRotation, TargetRotation);

	//Add on any additional angle change
	if (ViewAngleModifier != FRotator(0, 0, 0))
	{
		//This angle is used to get the item to face a certain angle when picked up.
		TargetRotation = AddTwoRotators(ViewAngleModifier, TargetRotation);
	}

	FRotator WorldRotation;

	//Get the component's original rotation in world space
	if (ItemAnchor != NULL)
	{
		//If there is an anchor, override this base rotation with the anchor's rotation.
		WorldRotation = ItemAnchor->GetRootComponent()->GetComponentRotation();
	}
	else
	{
		//Otherwise we just get the itemzone's rotation.
		WorldRotation = GetAttachParent()->GetComponentRotation();
		WorldRotation = AddTwoRotators(InitialRotation, WorldRotation);
	}

	//TravelTime is updated via component tick
	if (bToPlayer)
	{
		//If the item is coming towards the player, we lerp the resulting rotation from the base rotation
		TargetRotation = RLerp(WorldRotation, TargetRotation, TravelTime, true);
	}
	else
	{
		//And when putting it back we do the opposite.
		TargetRotation = RLerp(TargetRotation, WorldRotation, TravelTime, true);
	}

	//This is specific to when we place item reels in zones, and they are set to spin.
	TargetRotation = AddTwoRotators(FRotator(-ReelAngle, 0, 0), TargetRotation);

	//Finally with our resulting rotation we set the rotation in world space.
	SetWorldRotation(TargetRotation);

}

So yeah, start with the camera’s rotation and add your total rotations on to that.

I have been testing around a bit using your code as an example but i do not really understand some things.
I tried picking out the things that seem necessary for what i’m trying to do. I currently have so that it’s the player code that rotates the object.



FRotator TargetRotation = FRotator(0, 0, 0);

// Camera rotation
TargetRotation.Yaw = FirstPersonCameraComponent->AttachParent->RelativeRotation.Yaw;
TargetRotation.Pitch = FirstPersonCameraComponent->RelativeRotation.Pitch;

//Add the mouse movement
TargetRotation = AddTwoRotators(FRotator(PitchAxis, -YawAxis, 0), TargetRotation);

// Orignal rotation of the actor when it is spawned in.
TargetRotation = AddTwoRotators(InterObject->OriginalRotation, TargetRotation);

//Get the component's original rotation in world space
FRotator WorldRotation;
WorldRotation = InterObject->OriginalRotation;

//If the item is coming towards the player, we lerp the resulting rotation from the base rotation
TargetRotation = RLerp(WorldRotation, TargetRotation, 1.0f, true);
		
//Finally with our resulting rotation we set the rotation in world space.
InterObject->SetActorRotation(TargetRotation);


When i run this code the object initially rotates to the set rotation and then if i try to rotate it using the mouse the objects starts rotating and then very quickly snaps back. So it can’t rotate anywhere. What can i do so that it wont snap back the rotation when i try to rotate the object, i tried setting the world rotation to the current objects rotation but it does not seem to work.

Add to your total inputs, don’t set to the deltas.

This is because you’re only adding your delta inputs, the ones that were captured since the last update, instead of adding your deltas to existing values and then adding those on top of your camera values.

If you don’t do that the object will snap, as it’s only adding a tiny amount and then resetting back to nothing when you let go.


void AEtherCharacter::AddControllerPitchInput(float Value)
{
	if (HeldPickup != NULL && HeldPickup->IsValidLowLevel())
	{
		HeldPickup->PickupPitch += Value * 5;
	}
	else
	{
		Super::AddControllerPitchInput(Value);
	}
}

In this case PickupPitch is only added to the input from your input event, it never replaces it. You then just add that on top of your camera values and you should be sorted.

In short, +=, not =.

It’s also worth nothing you aren’t currently lerping your end object rotation at all, unless you’ve just got it set to 1.0f to test the TargetRotation.

Awesome, got it working. Thanks!
It feel much better to rotate the object around now.