You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

正交投影数学修复:相机旋转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]为负,投影后的坐标会反转,同时没有做背面剔除,所以身后的物体会被错误投影到屏幕上。

修复步骤:

  1. 切换到真正的正交投影
    正交投影不需要依赖Z轴的倒数缩放,直接丢弃Z分量并缩放即可。替换投影矩阵部分的代码:

    // 替换原来的投影计算逻辑
    double[][] projection = new double[][]{
        {1, 0, 0},
        {0, 1, 0},
    };
    double[] projected2d = multiplyMatrices(projection, rotated);
    

    这样就不会因为Z轴符号变化导致坐标反转。

  2. 添加背面剔除逻辑
    即使是正交投影,也需要判断物体是否在相机视野前方。在旋转后检查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;
    

    这样就能避免显示相机后方的立方体。

  3. 调整旋转顺序(可选)
    当前的旋转顺序是Y→X→Z,可能会导致旋转方向不符合直觉。如果操作反转的问题仍然存在,可以尝试调整旋转顺序为Z→X→Y,或者检查旋转矩阵的方向是否正确(比如是否应该使用左乘还是右乘)。

内容的提问来源于stack exchange,提问作者Edward Simpson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 13:30:33