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

基于Java JFrame实现3D立方体:z轴顶点2D坐标计算求助

嘿,这个问题我之前用纯Java 2D做3D绘图的时候也碰到过!不用OpenGL这类第三方库完全没问题,核心就是搞懂透视投影的基本转换逻辑,我给你拆解清楚,直接上能用的代码:

核心原理:3D到2D的透视投影转换

咱们人眼看东西是近大远小,这个效果用数学公式就能模拟。假设我们把"相机"放在z轴的正方向(比如离原点500像素的位置),然后给每个3D顶点计算对应的2D屏幕坐标,公式很简单:

对于3D顶点 (x3d, y3d, z3d),转换后的2D坐标 (x2d, y2d) 计算方式:

x2d = (焦距 * x3d) / z3d + 屏幕中心X坐标
y2d = (焦距 * y3d) / z3d + 屏幕中心Y坐标

几个关键参数的说明:

  • 焦距:控制透视强度的参数,值越大,透视效果越弱(接近正交投影);值越小,近大远小的效果越明显。一般根据窗口大小设为400-800之间就行。
  • 屏幕中心坐标:就是你窗口的中点(getWidth()/2 和 getHeight()/2),这样3D空间的原点会对应屏幕中心,符合我们的视觉习惯。
  • 注意:z3d 不能为0(会除以0报错),而且要保证是正数(因为相机在z正方向,看不到z负方向的点,如果需要看可以调整相机位置)
完整Java代码示例

下面是一个直接能跑的立方体绘图Demo,基于JFrame和JPanel的内置API:

import javax.swing.*;
import java.awt.*;

public class CubeDemo extends JFrame {
    public CubeDemo() {
        setTitle("纯Java 2D绘制3D立方体");
        setSize(800, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(new CubePanel());
        setVisible(true);
    }

    public static void main(String[] args) {
        // Swing要在事件调度线程运行
        SwingUtilities.invokeLater(CubeDemo::new);
    }

    static class CubePanel extends JPanel {
        // 立方体的8个3D顶点(中心在原点,边长200)
        private double[][] vertices3d = {
                {-100, -100, 100}, {100, -100, 100}, {100, 100, 100}, {-100, 100, 100},
                {-100, -100, -100}, {100, -100, -100}, {100, 100, -100}, {-100, 100, -100}
        };
        // 立方体的12条边(存储顶点的索引对)
        private int[][] edges = {
                {0,1}, {1,2}, {2,3}, {3,0}, // 前面
                {4,5}, {5,6}, {6,7}, {7,4}, // 后面
                {0,4}, {1,5}, {2,6}, {3,7}  // 侧面
        };
        // 自定义焦距,可根据效果调整
        private final double focalLength = 500;

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            // 开启抗锯齿,让线条更平滑
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            int screenCenterX = getWidth() / 2;
            int screenCenterY = getHeight() / 2;

            // 先把所有3D顶点转换成2D坐标
            Point[] vertices2d = new Point[vertices3d.length];
            for (int i = 0; i < vertices3d.length; i++) {
                double x3d = vertices3d[i][0];
                double y3d = vertices3d[i][1];
                double z3d = vertices3d[i][2];

                // 应用透视投影公式
                double x2d = (focalLength * x3d) / z3d + screenCenterX;
                double y2d = (focalLength * y3d) / z3d + screenCenterY;

                // 转成整数屏幕坐标
                vertices2d[i] = new Point((int) Math.round(x2d), (int) Math.round(y2d));
            }

            // 绘制立方体的所有边
            g2d.setColor(Color.BLACK);
            for (int[] edge : edges) {
                Point p1 = vertices2d[edge[0]];
                Point p2 = vertices2d[edge[1]];
                g2d.drawLine(p1.x, p1.y, p2.x, p2.y);
            }
        }
    }
}
扩展优化提示

如果想让效果更完善,可以加这些功能:

  • 旋转效果:给3D顶点应用旋转矩阵(绕x、y、z轴),然后再投影,就能实现立方体旋转的动画(可以用Timer定时调用repaint())
  • 遮挡处理:用画家算法,把z值大的面(远的面)先画,z值小的面(近的面)后画,解决面重叠的问题
  • 深度裁剪:过滤掉z值过小(太近)或过大(太远)的顶点,避免出现异常的坐标

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:30:44