Question

My team and I have been trying to display our weapon on the screen for a week now, without success: we really need help with this. What we would like to get is, as in every FPS, the weapon display with a little horizontal offset on the screen as if the player was holding it.

We've already tried to use matrix, but without success: the weapon isn't even visible, it seems to be behind us, and even if we try to play with the values a bit we can't get it working properly.

We know that we need to use the rotation of the camera, as well as its position, but we can't figure out the formula to get the weapon's world matrix.

What we have is, the position of the camera as a Vector3, the rotation of the camera as a Vector3 too, with the y coord being the horizontal rotation, between pi and -pi, and x being the vertical rotation. The weapon is scaled at 0.1f. What should we do?

Thank you very much for your help.

EDIT: Here is some code relative to my problem:

public void Update()
{
    weapon.Rotation = ThisPlayer.Rotation;

    weapon.WorldMatrix = WeaponWorldMatrix(
        ThisPlayer.Position, 
        ThisPlayer.Rotation.Y, 
        ThisPlayer.Rotation.X
    );

}

private Matrix WeaponWorldMatrix(Vector3 Position, float updown, float leftright)
{
    Vector3 xAxis;
    Vector3 yAxis;

    xAxis.X = SceneManager.Game.Camera.View.M11;
    xAxis.Y = SceneManager.Game.Camera.View.M21;
    xAxis.Z = SceneManager.Game.Camera.View.M31;

    yAxis.X = SceneManager.Game.Camera.View.M12;
    yAxis.Y = SceneManager.Game.Camera.View.M22;
    yAxis.Z = SceneManager.Game.Camera.View.M32;

    Position += new Vector3(1, 0, 0) / 5;  //How far infront of the camera The gun will be
    Position += xAxis * 1f;      //X axis offset
    Position += -yAxis * 0.5f;     //Y axis offset
    SceneManager.Game.DebugScreen.Debug(Position.ToString());
    return Matrix.CreateScale(0.1f)                        //Size of the Gun
        * Matrix.CreateFromYawPitchRoll(MathHelper.ToRadians(5), 0, 0)      //Rotation offset
        * Matrix.CreateRotationX(updown)
        * Matrix.CreateRotationY(leftright)
        * Matrix.CreateTranslation(Position);
}
Was it helpful?

Solution

The simplest way to do this is to invert the camera's view matrix which can then be used to represent the world space position and rotation of the camera. This result can be borrowed and altered slightly to become the weapon's world matrix.

Matrix cameraWorld = Matrix.Invert(view);

Matrix weaponWorld = cameraWorld; //gives your weapon a matrix that is co-located and co-rotated with camera


//then simply reposition the weapon matrix as necessary   
    weaponWorld.Translation += (cameraWorld.Forward * distInFrontOfCam) +                       //set to taste. moves the weapon slightly in front of cam
                               (cameraWorld.Down * amountWeaponIsLoweredFromCenterOfScreen) +   //set to taste. moves the weapon from the center of the screen to the lower part
                               (cameraWorld.Right * leftOrRightOffset);                         //set to taste. moves the weapon left or right of center if desired.

Edit. I noticed you are also trying to apply scale to your weapon. My suggestion is to not do that in code. Rather right click the weapon model in the solution explorer and select properties. On the properties window, click the little arrowhead next to 'content processor' to expand the list. Find the scale property and set the scale there (to your 0.1f or whatever). Now you never need to waste cpu cycles to scale that model in code. This causes the scale to be set in the build phase when it converts the fbx to an xnb.

OTHER TIPS

I think the problem you might have is that for the weapon to be in front of you, you will need to use a Z value of -1, as is the value of Vector3.Forward. But there are much simpler ways to calculate an offset like that without using the matrices directly.

XNA already offers simple tools to transform Vectors by using matrices. You could use Vector3.Transform for instance to rotate a point using a rotation matrix (view matrix).

For example, to get the position you need the weapon to be, you will need an Offset vector, which value determines the position of the weapon from where you are looking and your current position.

In a right-handed system as XNA uses by default, you would need to set a negative value to the Z component for the weapon to be in front of the view (Vector3.Forward) and you would need a small negative Y value for the weapon to be below the view. Then for the X value you could add a small value to offset the weapon to the right of the player.

var offset = new Vector3(0.2, -0.2, -1)

Then, you can compute the position for the weapon by rotating that offset vector using the camera's view matrix and add the player's position.

var weaponPosition = Vector3.Transform(Offset, SceneManager.Game.Camera.View)
                     + ThisPlayer.Position;

Finally, using that position you can return a simpler world matrix for the weapon

return Matrix.CreateScale(0.1f)
       * Matrix.CreateRotationX(updown)
       * Matrix.CreateRotationY(leftright)
       * Matrix.Translation(weaponPosition);

If after that the weapon still is not in front of the camera, try changing the offset values around or set higher values. It may also be possible that the weapon gets clipped by the camera's near field, try lowering that value in the camera settings or in the projection matrix parameters. For the CreatePerspectiveFieldOfView function, that value is the third field named nearPlaneDistance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top