跳转至

相机几何与投影

查看与投影矩阵

场景中的 3D 点先以世界坐标表示。写成齐次坐标 \(p_h = (x, y, z, 1)^T\) 后,依序套用查看矩阵 \(V\) 与投影矩阵 \(P\):\(c = P V p_h\)。透视除法得到 \(n = (c_x / c_w, c_y / c_w, c_z / c_w)\),再映射到宽 \(W\)、高 \(H\) 的画布:

\[ x_{\text{px}} = (n_x + 1) W / 2, \quad y_{\text{px}} = (1 - n_y) H / 2. \]

纵坐标的反号让 SVG 与位图输出都采左上原点。

可见范围与深度排序

查看坐标中的深度为 \(d = -z_{\text{view}}\),只有位于 near 与 far 之间的几何会留下。绘图元素(图元)由远到近稳定排序,相同深度保留场景顺序。

法矢量与着色

三角形法矢量为 \(n = (p_1 - p_0) \times (p_2 - p_0)\)。面积为零的三角形会移除;只显示正面的表面以 \(n \cdot v\) 判断背面;漫反射与镜面项在输出前逐面计算。

Camera3D(
    *,
    id='camera',
    opacity=1.0,
    z=0.0,
    visible=True,
    semantics=None,
    position=Vec3(x=5.0, y=-7.0, z=4.0),
    target=Vec3(x=0.0, y=0.0, z=0.0),
    up=Vec3(x=0.0, y=0.0, z=1.0),
    projection='perspective',
    fov=0.6981317007977318,
    ortho_height=6.0,
    near=0.1,
    far=1000.0,
)

为透视或正交输出创建查看矩阵与投影矩阵。

Surface3D(
    *,
    id,
    opacity=1.0,
    z=0.0,
    visible=True,
    semantics=None,
    color=...,
    material=...,
    edge_color=None,
    edge_width=0.5,
    two_sided=True,
    grid=...,
    colorscale=None,
    value_range=None,
)

保存规则高度场,并把网格单元转成顺序一致的投影面。

Mesh3D(
    *,
    id,
    opacity=1.0,
    z=0.0,
    visible=True,
    semantics=None,
    color=...,
    material=...,
    edge_color=None,
    edge_width=0.5,
    two_sided=True,
    mesh=...,
)

保存索引式 3D 几何;输出前会裁切、背面剔除、着色并依深度排序各个面。

输出格式的一致性

因此 由 KineticKit 矢量绘图端投影并排序深度的 3D 曲面 在动态 SVG、代表 PNG 与 GIF 帧中的几何一致。

评论