如何为Matrix4x4旋转添加相机并正确实现立方体三维旋转?
嘿,你已经靠自己实现了立方体旋转,这很棒!让我帮你解决这两个困扰你的问题:
1. 添加相机与透视效果
要实现透视,你需要引入视图矩阵(模拟相机位置和朝向)和投影矩阵(把3D空间投影到2D屏幕的透视效果),和你现有的世界旋转矩阵组合起来用。
具体步骤:
- 创建视图矩阵:用
Matrix4x4.CreateLookAt来定义相机的位置、看向的目标和向上方向。比如把相机放在Z轴正方向,看向立方体中心:var cameraPosition = new Vector3(0, 0, 5); // 相机在(0,0,5)位置 var lookAtTarget = Vector3.Zero; // 看向立方体中心(原点) var upDirection = Vector3.Up; // Y轴为向上方向 Matrix4x4 viewMatrix = Matrix4x4.CreateLookAt(cameraPosition, lookAtTarget, upDirection); - 创建透视投影矩阵:用
Matrix4x4.CreatePerspectiveFieldOfView生成带透视效果的投影矩阵,需要传入视场角、屏幕宽高比、近远裁剪面:float fov = MathF.PI / 4; // 45度视场角 float aspectRatio = (float)screenWidth / screenHeight; // 替换成你的SDL窗口宽高 float nearPlane = 0.1f; // 近裁剪面,太近的物体不渲染 float farPlane = 100f; // 远裁剪面,太远的物体不渲染 Matrix4x4 projectionMatrix = Matrix4x4.CreatePerspectiveFieldOfView(fov, aspectRatio, nearPlane, farPlane); - 组合变换矩阵:因为
System.Numerics.Matrix4x4是列主序矩阵,变换顺序是世界→视图→投影,所以矩阵相乘的顺序是投影 * 视图 * 世界:Matrix4x4 worldMatrix = Matrix4x4.Identity; worldMatrix *= Matrix4x4.CreateRotationX(deg); worldMatrix *= Matrix4x4.CreateRotationY(deg); worldMatrix *= Matrix4x4.CreateRotationZ(deg); // 组合三个矩阵 Matrix4x4 combinedMatrix = Matrix4x4.Multiply(Matrix4x4.Multiply(projectionMatrix, viewMatrix), worldMatrix); - 变换顶点并转屏幕坐标:用组合矩阵变换顶点后,需要做齐次除法(把向量的x/y/z除以w分量)得到标准化设备坐标,再转成SDL屏幕坐标:
foreach (var vertex in cubeVertices) { // 把Vector3转成Vector4(w=1.0) Vector4 transformed = Vector4.Transform(new Vector4(vertex, 1.0f), combinedMatrix); // 齐次除法 float ndcX = transformed.X / transformed.W; float ndcY = transformed.Y / transformed.W; // 转屏幕坐标(SDL的Y轴向下,所以要翻转) int screenX = (int)((ndcX + 1) * screenWidth / 2); int screenY = (int)((1 - ndcY) * screenHeight / 2); // 用screenX和screenY绘制顶点/连线 }
2. 修复CreateFromAxisAngle的拉伸变形问题
问题出在你传入的轴向量没有归一化!CreateFromAxisAngle要求轴向量是单位长度向量(长度为1),如果向量长度不是1,生成的矩阵会隐含缩放因子,导致立方体拉伸变形。
解决方法:
先把轴向量归一化,再传入方法:
// 先归一化轴向量 Vector3 axis = Vector3.Normalize(new Vector3(2, 2, 2)); // 再创建旋转矩阵 matrix *= Matrix4x4.CreateFromAxisAngle(axis, (float)rad);
Vector3.Normalize会把向量缩放到长度为1,这样生成的矩阵就只会做纯旋转,不会引入缩放,立方体就不会变形了。
内容的提问来源于stack exchange,提问作者CodeOrElse
相关产品推荐
相关产品推荐

