Align sight to camera

Started by
11 comments, last by Fulcrum.013 5 years, 10 months ago

Hi everyone,

I got stuck with my approach to aiming down sights. I've set up my first person arms mesh to be a child of the camera. Added a socket on the right hand of the skeleton to which I attach my weapon and there is a socket in the weapon used to signal the point at which the camera should sit during aiming down sight. When the players aims holding left click what I'm trying to do is to calculate the offset of the sight socket to the root of the FPP Mesh while on the aiming down sights pose and move the camera based on that.

I'm using the code attached below.

It's Unreal Engine but the problem seemed generic enough to qualify as an algebra one. What I'm doing is obtaining the transformations from the camera to the sight bone. That gives me the sight transform relative to the camera. After that I just negate the translation vector and add it to the first child of the camera. I was expecting to have the sight bone sit at the exact same point as the camera.

What happens is that it is almost there but it's not correctly aligned. I believe my math and the general idea is right.

Any ideas why this could be failing?

Here is how I apply the resulting transform and below how I obtain it.

Thank you very much for reading.


FVector Translation = DeltaTransform.GetTranslation();
	Translation.Z = 165.0f;
	/*Translation.X += Translation.Y;
	Translation.Y = Translation.X - Translation.Y;
	Translation.X = Translation.X - Translation.Y;*/
	DeltaTransform *= DefaultMesh1PTransform;
	DeltaTransform.SetTranslation(Translation);
	Mesh1PCamOffsetLocationDelta = DeltaTransform.GetTranslation();
	Mesh1PCamOffsetRotationDelta = DeltaTransform.GetRotation();
	bInterpMesh1PCamOffset = bInterp;

	UE_LOG(LogTemp, Warning, TEXT("DeltaInverse Location x: %f, y: %f, z: %f"), (DeltaTransform).GetLocation().X, (DeltaTransform).GetLocation().Y, (DeltaTransform).GetLocation().Z);

	Mesh1P->SetRelativeLocation(DeltaTransform.GetLocation() * -1);

	UE_LOG(LogTemp, Warning, TEXT("Rotation yaw: %f, pitch: %f, roll: %f"), DeltaTransform.GetRotation().Rotator().Yaw, DeltaTransform.GetRotation().Rotator().Pitch, DeltaTransform.GetRotation().Rotator().Roll);

FTransform HandToComponent;

    HandToComponent.SetIdentity();

    FTransform BoneTransform;

    USkeletalMeshComponent* Mesh1P = CarryingPlayer->Mesh1P;

    // Get transform to weapon attach socket space
    HandToComponent *= FirearmMesh->GetSocketTransform(FName("sight_point_socket"), RTS_ParentBoneSpace);
    HandToComponent *= Mesh1P->GetSocketTransform(Firearm->GetCarrySocket(), RTS_ParentBoneSpace);

    // Get transform from the right hand bone relative to component (root bone)
    FName CurrentBoneName = FName("hand_r");
    while (CurrentBoneName != NAME_None)
    {
        ArmsADSIdleAnimSequence->GetBoneTransform(BoneTransform, Mesh1P->GetBoneIndex(CurrentBoneName), 0.0f, true);
        HandToComponent *= BoneTransform;
        CurrentBoneName = Mesh1P->GetParentBone(CurrentBoneName);
    }

    return HandToComponent;
Advertisement

There is a million ways to do this but the basic math is: Offset = TargetPosition - MovingObjectPosition.

So if gun is at point (1,1,0) on a grid and you want to move it to say (0,5,0) on the grid then: Offset = (0,5,0) - (1,1,0) = (-1,4,0). Meaning it has to move one right and four up.

After you have the Offset, you can divide it by the amount of steps you want to take. So if we want it to reach the target point in 10 steps it is: Offset/ Steps = (-1, 4, 0)/ 10 = (-0.1, 0.4, 0) per step.

Frame rate independent movement:

Spoiler

 

Considering that most games run at 60FPS we can use that to find how many seconds a animation takes. If we wanted to do it in 4 seconds we need to use DeltaTime. DeltaTime / 4. DeltaTime is a function that calculates how long the last frame took in seconds as a float.

If the game runs at 60FPS DeltaTime = 0.016. This means that 16.667/ 4 = 0.004. This means that 0.004 * (240 //the 60*4//) = 0.96 //So 1 with some floating point errors. 

Using  (-1, 4, 0) as the offset we get:  (-1, 4, 0) * (DeltaTime/4) = (-0.004, 0,016, 0) per step so it will take 240 frames or 4 seconds to reach the target point.

 

 

Please look into partial LODs if your gun is a static mesh normal LODs will work if it's a skinned mesh you need partial LODs with a Multi-Part Mesh. As one of the most common problems I see in Indie games is that the Iron sights isn't round enough and looks fake.

Hi @Scouting Ninja, thanks for the answer.

I know how to interpolate it to the position, problem is that position is not matching.

This is where I want the camera to end up relative to the weapon.

unknown.png?width=994&height=560

This is where it is actually ending up relative to the root bone:

unknown.png?width=994&height=560

Positioning is right, it is rotation that is bugging me. 

The images actually make it more confusing.

The best thing to do is to move the object to the right location, and rotate it towards the point you want to look at. The offset vector is also used here:

Offset = SelfPosition - TargetPoint. Then use the LookAt function: FRotationMatrix::MakeFromX(SelfPosition - TargetPoint).Rotator(); Or something like that.

The Offset is obtained and it matches perfectly. Rotation is being problematic. I can't seem to find the correct rotation quaternion.

17 hours ago, Agustin Andreucci said:

Rotation is being problematic. I can't seem to find the correct rotation quaternion.

Why not just copy the rotation from the socket? You could also slerp the camera rotation to the socket rotation.

 

The part that confuses me is that you should only be moving the gun. The rotation of the gun never needs to change, so there should be no problem with rotating.

Socket rotation is in parent bone space. It has to be converted so it can be applied to the first person arms mesh. I'm not moving the camera but the arms. If I moved the camera, any roll the gun could have should be applied inversely to the camera which would have a weird effect on the camera since everything will appear a little bit rolled.

19 minutes ago, Agustin Andreucci said:

I'm not moving the camera but the arms.

That explains it. If you want to do it this way it is often easier to just animate it in 3D software. Have a pose called "IronSights" and use Unreal's animation blueprints to blend between the last pose and the Iron sight pose.

If you do want to use code for it then move the gun, use Inverse Kinematics (IK) to animate the arms based on where the gun is moving. The alternative is to pre-calculate the arm rotations like you would with a robot.

1 minute ago, Scouting Ninja said:

That explains it. If you want to do it this way it is often easier to just animate it in 3D software. Have a pose called "IronSights" and use Unreal's animation blueprints to blend between the last pose and the Iron sight pose.

If you do want to use code for it then move the gun, use Inverse Kinematics (IK) to animate the arms based on where the gun is moving. The alternative is to pre-calculate the arm rotations like you would with a robot.

I have the "IronSights" pose, but I would have to modify every pose to match the center of the screen. Right now the poses I have are close but slightly rotated and translated. What I'm trying to do is offset the arms root bone and rotate it in such a way that I end up with the sights centered while not modifying the pose.

9 minutes ago, Agustin Andreucci said:

What I'm trying to do is offset the arms root bone and rotate it in such a way that I end up with the sights centered while not modifying the pose.

You can offset rotation by using Sin and Cos and you can offset location by making a new vector from the old one with the offset added in. Without the animations I can't tell you the exact amount or formula.

It's easier to change the pose. Unreal was made for this kind of adjustments. If you don't want to use a 3D tool for this you can use a empty and use that to offset the whole rig.

Is this happening because you are using animations from two different animation sets? Because animation re-targeting can be used to quickly fix this.

This topic is closed to new replies.

Advertisement