首页/在线代码库/demo12_projection.py

demo12_projection.py

同一个 3D 立方体, 分别用正交投影和透视投影映射到 2D 平面, 对比"近大远小"(透视)与"平行等大"(正交)的区别。

Python 48 行 系列:核心讲义 🔒 源码仅供在线学习,不提供文件下载
完整源码 · 在线查看demo12_projection.py
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
"""演示12: 正交投影 vs 透视投影。

同一个 3D 立方体, 分别用正交投影和透视投影映射到 2D 平面,
对比"近大远小"(透视)与"平行等大"(正交)的区别。
"""
import os
import numpy as np
import matplotlib.pyplot as plt
from figure_style import figures_dir, configure

configure()

OUT = figures_dir()
os.makedirs(OUT, exist_ok=True)

# 立方体 8 顶点
w = 1.0
V = np.array([[x, y, z]
              for x in (-w, w) for y in (-w, w) for z in (-w, w)])
E = [(0,1),(1,3),(3,2),(2,0), (4,5),(5,7),(7,6),(6,4),
     (0,4),(1,5),(2,6),(3,7)]


def ortho(V):
    """正交投影: 直接丢弃 z(或做正射缩放)。"""
    return V[:, :2]


def persp(V, d=3.0):
    """透视投影: x' = d*x/z, y' = d*y/z (相机在原点看向 +z)。"""
    return d * V[:, :2] / V[:, 2:3]


fig, axes = plt.subplots(1, 2, figsize=(10, 5))
for ax, fn, title in zip(axes, (ortho, persp),
                         ("正交投影 (Orthographic)", "透视投影 (Perspective)")):
    P = fn(V)
    for u, v in E:
        ax.plot([P[u, 0], P[v, 0]], [P[u, 1], P[v, 1]], "tab:blue", lw=1.8)
    ax.plot(*P.T, "o", c="tab:red", ms=4)
    ax.set_title(title)
    ax.set_aspect("equal"); ax.grid(alpha=0.3)
fig.suptitle("从 3D 到 2D: 正交 vs 透视 (透视有近大远小)", fontsize=14)
fig.tight_layout(rect=(0, 0, 1, 0.94))
out = os.path.join(OUT, "fig_cg_projection.png")
fig.savefig(out, dpi=150)
print(f"-> {out}")

输出图

fig_cg_projection.png
输出图 · fig_cg_projection.png