XNA(3D - 游戏)中用于相机旋转的矩阵
Matrices in XNA (3D - Game) for Camera rotation
我写了这个旋转和移动相机的代码。
可悲的是,我对矩阵和 3D 编程不是很有经验,因为我几天前才开始:
plLookAt = new Vector3(plPos.X, plPos.Y, plPos.Z - 20);
if (kb.IsKeyDown(Keys.W))
{
plPos.Z++;
}
if (kb.IsKeyDown(Keys.A))
{
plPos.X++;
}
if (kb.IsKeyDown(Keys.S))
{
plPos.Z--;
}
if (kb.IsKeyDown(Keys.D))
{
plPos.X--;
}
view = Matrix.CreateLookAt(new Vector3(0, 0, 0), plLookAt, Vector3.UnitY);
view = view * Matrix.CreateRotationY(MathHelper.ToRadians(rotations.Y)) * Matrix.CreateRotationX(MathHelper.ToRadians(rotations.X));
view = view *Matrix.CreateTranslation(plPos);
if (PrMS.X < ms.X)
{
rotations.Y++;
}
else if (PrMS.X > ms.X)
{
rotations.Y--;
}
if (PrMS.Y < ms.Y)
{
rotations.X++;
}
else if (PrMS.Y > ms.Y)
{
rotations.X--;
}
plPos 是玩家(相机)位置
view 是视图 Matrix
rotations 是保存相机旋转的地方(Vector3)
PrMS为上一帧的MouseState。
这段代码不起作用,我认为这是因为乘法的顺序,但我不确定。旋转相机的最佳方式是什么,这样它才能正常工作,并且我可以朝相机面对的方向移动。
提前谢谢您!
你的问题不在于矩阵乘法的顺序,而是你的旋转需要围绕相机局部轴进行,而你是围绕世界轴进行的。
我认为您所期望的是应用 .CreateRotationX(rotations.X)
和 .CreateRotationY(rotationsY)
会导致相机围绕其自身的局部轴改变俯仰和偏航。但是这些旋转总是会引起围绕世界轴的旋转。如果您相机的局部 X 轴恰好与世界 X 轴对齐并且您执行了 .CreateRotationX()
,那么它将按预期工作。但在您的情况下,您首先围绕 Y 轴旋转相机,这会使相机的局部 X 轴与世界 X 轴不对齐,因此下一次旋转(X)不会按预期进行。即使你先做 X 再做 Y,X 也会把 Y 打乱。尽管矩阵乘法的顺序通常很重要,但在您的特定情况下,问题在于旋转轴。
看来您正在制作位于玩家位置的相机,但可以通过鼠标控制查看 left/right、up/down。这是一个 class,它提供了一种不同的方法来处理该标准:
class Camera
{
public Matrix View { get; set; }
public Matrix Projection { get; set; }
Vector2 centerOfScreen;// the current camera's lookAt in screen space (since the mouse coords are also in screen space)
Vector3 lookAt;
float cameraRotationSpeed;
public Camera()
{
//initialize Projection matrix here
//initialize view matrix here
//initialize centerOfScreen here like this: new Vector2(screenWidth/2, screenHeihgt/2);
cameraRotationSpeed = 0.01f;//set to taste
}
public void Update(Vector3 playerPosition, MouseState currentMouse)
{
Matrix cameraWorld = Matrix.Invert(View);
Vector2 changeThisFrame = new Vector2(currentMouse.X, currentMouse.Y) - centerOfScreen;
Vector3 axis = (cameraWorld.Right * changeThisFrame.X) + (cameraWorld.Up * changeThisFrame.Y);//builds a rotation axis based on camera's local axis, not world axis
float angle = axis.Length() * cameraRotationSpeed;
axis.Normalize();
//rotate the lookAt around the camera's position
lookAt = Vector3.Transform(lookAt - playerPosition, Matrix.CreateFromAxisAngle(axis, angle)) + playerPosition;//this line does the typical "translate to origin, rotate, then translate back" routine
View = Matrix.CreateLookAt(playerPosition, lookAt, Vector3.Up);// your new view matrix that is rotated per the mouse input
}
}
我写了这个旋转和移动相机的代码。
可悲的是,我对矩阵和 3D 编程不是很有经验,因为我几天前才开始:
plLookAt = new Vector3(plPos.X, plPos.Y, plPos.Z - 20);
if (kb.IsKeyDown(Keys.W))
{
plPos.Z++;
}
if (kb.IsKeyDown(Keys.A))
{
plPos.X++;
}
if (kb.IsKeyDown(Keys.S))
{
plPos.Z--;
}
if (kb.IsKeyDown(Keys.D))
{
plPos.X--;
}
view = Matrix.CreateLookAt(new Vector3(0, 0, 0), plLookAt, Vector3.UnitY);
view = view * Matrix.CreateRotationY(MathHelper.ToRadians(rotations.Y)) * Matrix.CreateRotationX(MathHelper.ToRadians(rotations.X));
view = view *Matrix.CreateTranslation(plPos);
if (PrMS.X < ms.X)
{
rotations.Y++;
}
else if (PrMS.X > ms.X)
{
rotations.Y--;
}
if (PrMS.Y < ms.Y)
{
rotations.X++;
}
else if (PrMS.Y > ms.Y)
{
rotations.X--;
}
plPos 是玩家(相机)位置
view 是视图 Matrix
rotations 是保存相机旋转的地方(Vector3)
PrMS为上一帧的MouseState。
这段代码不起作用,我认为这是因为乘法的顺序,但我不确定。旋转相机的最佳方式是什么,这样它才能正常工作,并且我可以朝相机面对的方向移动。
提前谢谢您!
你的问题不在于矩阵乘法的顺序,而是你的旋转需要围绕相机局部轴进行,而你是围绕世界轴进行的。
我认为您所期望的是应用 .CreateRotationX(rotations.X)
和 .CreateRotationY(rotationsY)
会导致相机围绕其自身的局部轴改变俯仰和偏航。但是这些旋转总是会引起围绕世界轴的旋转。如果您相机的局部 X 轴恰好与世界 X 轴对齐并且您执行了 .CreateRotationX()
,那么它将按预期工作。但在您的情况下,您首先围绕 Y 轴旋转相机,这会使相机的局部 X 轴与世界 X 轴不对齐,因此下一次旋转(X)不会按预期进行。即使你先做 X 再做 Y,X 也会把 Y 打乱。尽管矩阵乘法的顺序通常很重要,但在您的特定情况下,问题在于旋转轴。
看来您正在制作位于玩家位置的相机,但可以通过鼠标控制查看 left/right、up/down。这是一个 class,它提供了一种不同的方法来处理该标准:
class Camera
{
public Matrix View { get; set; }
public Matrix Projection { get; set; }
Vector2 centerOfScreen;// the current camera's lookAt in screen space (since the mouse coords are also in screen space)
Vector3 lookAt;
float cameraRotationSpeed;
public Camera()
{
//initialize Projection matrix here
//initialize view matrix here
//initialize centerOfScreen here like this: new Vector2(screenWidth/2, screenHeihgt/2);
cameraRotationSpeed = 0.01f;//set to taste
}
public void Update(Vector3 playerPosition, MouseState currentMouse)
{
Matrix cameraWorld = Matrix.Invert(View);
Vector2 changeThisFrame = new Vector2(currentMouse.X, currentMouse.Y) - centerOfScreen;
Vector3 axis = (cameraWorld.Right * changeThisFrame.X) + (cameraWorld.Up * changeThisFrame.Y);//builds a rotation axis based on camera's local axis, not world axis
float angle = axis.Length() * cameraRotationSpeed;
axis.Normalize();
//rotate the lookAt around the camera's position
lookAt = Vector3.Transform(lookAt - playerPosition, Matrix.CreateFromAxisAngle(axis, angle)) + playerPosition;//this line does the typical "translate to origin, rotate, then translate back" routine
View = Matrix.CreateLookAt(playerPosition, lookAt, Vector3.Up);// your new view matrix that is rotated per the mouse input
}
}