3D相机实现异常:相机未在空间旋转,反而旋转3D物体
3D相机旋转异常问题:相机未按预期旋转,反而导致物体旋转
正在实现3D空间,开发可在自定义3D空间中移动的3D相机,但遇到异常:相机未按预期在空间中旋转,反而导致3D物体旋转,无法定位问题所在。
相关代码实现
Camera3D类代码
public class Camera3D { public Vector3D Pos { get; set; } public Vector3D Target { get; set; } public Vector3D Up { get; set; } public double CameraSpeed { get; set; } public Camera3D(Vector3D pos, Vector3D target, Vector3D up) { Pos = pos; Target = target; Up = up; Pos.Normalize(); Target.Normalize(); Up.Normalize(); } public Camera3D() { Pos = new Vector3D(0, 0, 3); Target = new Vector3D(0, 0, 0); Up = new Vector3D(0, 1, 0); } private Vector3D GetCameraDirection(Vector3D pos, Vector3D target) { Vector3D dir = pos - target; dir.Normalize(); return dir; } private Vector3D GetRight(Vector3D pos, Vector3D target, Vector3D up) { Vector3D right = Vector3D.CrossProduct(Up, GetCameraDirection(pos, up)); right.Normalize(); return right; } private Vector3D GetCameraUp(Vector3D pos, Vector3D target, Vector3D up) { Vector3D vup = Vector3D.CrossProduct(GetCameraDirection(pos, target), GetRight(pos, target, up)); return vup; } public Matrix3D LookAt(Vector3D pos, Vector3D target, Vector3D up) { // translation matrix for camera Matrix3D translation = new Matrix3D ( 1, 0, 0, -Pos.X, 0, 1, 0, -Pos.Y, 0, 0, 1, -Pos.Z, 0, 0, 0, 1 ); Vector3D vRight = GetRight(pos, target, up); Vector3D vUp = GetCameraUp(pos, target, up); Vector3D vDir = GetCameraDirection(pos, target); Matrix3D m = new Matrix3D ( vRight.X, vRight.Y, vRight.Z, 0, vUp.X, vUp.Y, vUp.Z, 0, vDir.X, vDir.Y, vDir.Z, 0, 0, 0, 0, 1 ); return m * translation; } }
主窗口相关字段及构造函数
// just temporary field for test rotating Camera double a = 0; Vector3D Translate = new Vector3D(1, 1, 1); Vector3D Rotation = new Vector3D(0, 0, 0); Vector3D Scaling = new Vector3D(1, 1, 1); CTransform3D cTransform; // class for transform operations Camera3D c = new Camera3D(); public MainWindow() { InitializeComponent(); cTransform = new CTransform3D(Rotation, Translate, Scaling); cTransform.Camera = c; // camera for transformations // load the mesh o.Mesh.LoadFromObjectFile("D:\\de\\test\\ship.obj"); }
绘制物体的核心Draw方法
public void Draw() { try { // util classes MatrixUtil mu = new MatrixUtil(); cv.Children.Clear(); // clear canvas foreach (var triangle in o.Mesh.Triangles) { Triangle tProjected = new Triangle(), tTransformed = new Triangle(), tViewed = new Triangle(); // just init for right compile tProjected.Points = new Vector3D[3] { new Vector3D(0, 0, 0), new Vector3D(0, 0, 0), new Vector3D(0, 0, 0) }; tTransformed.Points = new Vector3D[3] { new Vector3D(0, 0, 0), new Vector3D(0, 0, 0), new Vector3D(0, 0, 0) }; tViewed.Points = new Vector3D[3] { new Vector3D(0, 0, 0), new Vector3D(0, 0, 0), new Vector3D(0, 0, 0) }; // project and transform matrices Matrix3D ProjectionMatrix = cTransform.ProjectionMatrix(5, Width, Height, 0.1, 1000); // just projection matrix Matrix3D TransformMatrix = RotationMatrices.RotatationYMatrix(Rotation.Y); // rotate y Matrix3D CameraMatrix = cTransform.GetCameraTransform(); // camera matrix that contains only LookAt c.Pos = new Vector3D(Math.Sin(a), 0, Math.Cos(a)); // change position of camera // transform points tTransformed.Points[0] = mu.Matrix_MulVector(TransformMatrix, triangle.Points[0]); tTransformed.Points[1] = mu.Matrix_MulVector(TransformMatrix, triangle.Points[1]); tTransformed.Points[2] = mu.Matrix_MulVector(TransformMatrix, triangle.Points[2]); // multiple camera matrix to transformed points tViewed.Points[0] = mu.Matrix_MulVector(CameraMatrix, tTransformed.Points[0]); tViewed.Points[1] = mu.Matrix_MulVector(CameraMatrix, tTransformed.Points[1]); tViewed.Points[2] = mu.Matrix_MulVector(CameraMatrix, tTransformed.Points[2]); // project the object tProjected.Points[0] = mu.Matrix_MulVector(ProjectionMatrix, tViewed.Points[0]); tProjected.Points[1] = mu.Matrix_MulVector(ProjectionMatrix, tViewed.Points[1]); tProjected.Points[2] = mu.Matrix_MulVector(ProjectionMatrix, tViewed.Points[2]); // just draw the result new CTriangle( triangle.Points[0].X + o.Position.X, triangle.Points[0].Y + o.Position.Y , triangle.Points[1].X + o.Position.X, triangle.Points[1].Y + o.Position.Y , triangle.Points[2].X + o.Position.X, triangle.Points[2].Y + o.Position.Y , cv, Brushes.Gray, Brushes.Black); } a+= .1; Rotation.X += 0.05f; Rotation.Y += 0.05f; Rotation.Z += 0.05f; } catch (Exception ex) { MessageBox.Show(ex.ToString()); } }
CTransform类的ProjectionMatrix方法
public Matrix3D ProjectionMatrix(double fov, double width, double height, double near, double far) { int fAspectRatio = (int)(width / height); double fFovRad = 1.0f / Math.Tan(fov * 0.5f / 180.0f * 3.14159f); return new Matrix3D ( fAspectRatio * fFovRad, 0, 0, 0, 0, fFovRad, 0, 0, 0, 0, far / (far - near), 1, 0, 0, (-far * near) / (far - near), 1 ); }
CTransform类的GetCameraTransform方法
public Matrix3D GetCameraTransform() { Matrix3D cameraLookAt = Camera.LookAt(camera.Pos, camera.Target, camera.Up); return cameraLookAt; }
CTransform类的相机字段
private Camera3D camera; public Camera3D Camera { get { return camera; } set { camera = value; } }
MatrixUtil类的矩阵向量乘法方法
public Vector3D Matrix_MulVector(Matrix3D m, Vector3D v) { Vector3D res = new Vector3D(); // additional W component of vector usually will 1. So just add offsets res.X = v.X * m.M11 + v.Y * m.M21 + v.Z * m.M31 + m.OffsetX; res.Y = v.X * m.M12 + v.Y * m.M22 + v.Z * m.M32 + m.OffsetY; res.Z = v.X * m.M13 + v.Y * m.M23 + v.Z * m.M33 + m.OffsetZ; return res; }
已尝试的解决措施
- 更改流水线中矩阵与三角形的乘法顺序,问题更严重;
- 修改相机平移矩阵,无变化;
- 修改LookAt方法,无变化;
- 检查并修改其他物体变换矩阵,无变化。
需求
希望理解3D相机在3D图形中的工作原理,并解决当前实现问题。
内容的提问来源于stack exchange,提问作者White
相关产品推荐
相关产品推荐

