正交投影数学修复:相机旋转180度后显示身后立方体问题
问题:正交投影相机旋转180度时显示异常
我的正交投影逻辑多数情况下正常,但相机旋转180度时,屏幕会显示所有身后的立方体。操作看似反转但功能正常,立方体仍按正确位置绘制,只是显示在屏幕上。我曾尝试将立方体x、y、z坐标设为绝对值,但无变化。问题出在旋转,立方体旋转180度时表现正常,但屏幕显示和操作反转。
正交投影计算代码
public double[][] draw() { double [][] rotationZ = new double [][]{ {cos(angleZ), -sin(angleZ), 0}, {sin(angleZ), cos(angleZ), 0}, {0, 0, 1}, }; double [][] rotationX = new double [][]{ {1, 0, 0}, {0, cos(angleX), -sin(angleX)}, {0, sin(angleX), cos(angleX)}, }; double [][] rotationY = new double [][]{ {cos(angleY), 0, sin(angleY)}, {0, 1, 0}, {-sin(angleY), 0, cos(angleY)}, }; double[][] projected = new double[8][]; for(int i = 0; i < points.size(); i ++) { double[] rotated = multiplyMatrices(rotationY, points.get(i).toMatrix()); rotated = multiplyMatrices(rotationX, rotated); rotated = multiplyMatrices(rotationZ, rotated); double z = 1 / rotated[2]; double[][] projection = new double[][]{ {z, 0, 0}, {0, z, 0}, }; double[] projected2d = multiplyMatrices(projection, rotated); projected2d = scaleMatrix(projected2d, 200); projected[i] = projected2d; } return(projected); }
矩阵乘法代码
private double[][] multiplyMatrices(double A[][], double B[][]) { int row1 = A.length; int col1 = A[0].length; int row2 = B.length; int col2 = B[0].length; double C[][] = new double[row1][col2]; for (int i = 0; i < row1; i++) { for (int j = 0; j < col2; j++) { for (int k = 0; k < row2; k++) C[i][j] += A[i][k] * B[k][j]; } } return(C); } private double[] multiplyMatrices(double A[][], double B[]) { int colsA = A[0].length; int rowsA = A.length; int rowsB = B.length; double[] result = new double[rowsA]; for (int j = 0; j < rowsA; j ++) { double sum = 0; for (int n = 0; n < colsA; n ++) { sum += A[j][n] * B[n]; } result[j] = sum; } return result; }
问题分析与解决办法
你当前的投影逻辑本质是透视投影而非正交投影,这是核心问题。当相机旋转180度后,rotated[2](Z轴分量)会变为负数,导致z = 1 / rotated[2]为负,投影后的坐标会反转,同时没有做背面剔除,所以身后的物体会被错误投影到屏幕上。
修复步骤:
切换到真正的正交投影
正交投影不需要依赖Z轴的倒数缩放,直接丢弃Z分量并缩放即可。替换投影矩阵部分的代码:// 替换原来的投影计算逻辑 double[][] projection = new double[][]{ {1, 0, 0}, {0, 1, 0}, }; double[] projected2d = multiplyMatrices(projection, rotated);这样就不会因为Z轴符号变化导致坐标反转。
添加背面剔除逻辑
即使是正交投影,也需要判断物体是否在相机视野前方。在旋转后检查rotated[2]的符号,如果为负(表示在相机后方),则跳过该点的绘制:double[] rotated = multiplyMatrices(rotationY, points.get(i).toMatrix()); rotated = multiplyMatrices(rotationX, rotated); rotated = multiplyMatrices(rotationZ, rotated); // 添加背面剔除:只处理相机前方的点 if (rotated[2] < 0) { projected[i] = null; // 后续绘制时跳过null的点 continue; } // 正交投影计算 double[][] projection = new double[][]{ {1, 0, 0}, {0, 1, 0}, }; double[] projected2d = multiplyMatrices(projection, rotated); projected2d = scaleMatrix(projected2d, 200); projected[i] = projected2d;这样就能避免显示相机后方的立方体。
调整旋转顺序(可选)
当前的旋转顺序是Y→X→Z,可能会导致旋转方向不符合直觉。如果操作反转的问题仍然存在,可以尝试调整旋转顺序为Z→X→Y,或者检查旋转矩阵的方向是否正确(比如是否应该使用左乘还是右乘)。
内容的提问来源于stack exchange,提问作者Edward Simpson
相关产品推荐
相关产品推荐

