Canvas通过数学投影将3D点(x,y,z)转为2D坐标x′=xd/(z+d)、y′=yd/(z+d),缩放因子s=d/(z+d);实现分建模、变换(平移→旋转→透视投影)、绘制三步;需裁剪z范围并优化性能。
Canvas 本身是二维的,不原生支持 3D 渲染,但可以通过数学变换模拟出带透视效果的 3D 视觉感——本质是把三维空间中的点(x, y, z)投影到二维画布上,再用 2D 方法绘制。关键不在“画 3D”,而在“正确算出投影后的位置和缩放”。
透视投影的核心公式
假设相机在原点,朝向 -z 方向,投影平面在 z = d(d > 0,即“近平面”距离),一个空间点 (x, y, z) 投影到画布上的坐标为:
x′ = x × d / (z + d)
y′ = y × d / (z + d)
缩放因子 s = d / (z + d),用于控制大小随距离衰减
注意:z 值越大(越远离相机),分母越大,x′/y′ 越小,物体越小;z = -d 是不可达的“投影平面后方”,实际中需限制 z > -d(如 z ≥ 0 或 z ≥ -d + ε)。
在 Canvas 中实现的三步操作
以绘制一个旋转立方体为例:
立即学习
“
前端免费学习笔记(深入)
”;
建模
:定义立方体 8 个顶点的三维坐标(如 ±1, ±1, ±1)
变换
:对每个顶点依次做平移 → 旋转(绕 x/y/z 轴用欧拉角或四元数)→ 透视投影(套用上面公式)
绘制
:用
、
、
连接投影后的 2D 点;按深度排序面(如 Painter’s Algorithm)或简单按 z 平均值排序,保证远的先画、近的后画
避免常见失真与性能陷阱
纯数学投影容易忽略视觉合理性:
不加裁剪时,z 接近 -d 的点会飞到无限远——务必对 z 做
近远平面裁剪
(如 z ∈ [0.1, 100]),投影前丢弃 z 超界的点
直接用 canvas 2D 绘制大量线段易卡顿——可预先计算顶点投影,用
对每条边单独缩放+平移,或批量写入
提升性能
透视下平行线应汇聚于“灭点”:比如所有 z 轴方向的边,其投影延长线应交于 (0, 0)(中心透视),若没出现,说明投影原点或公式符号有误
轻量级辅助:用 transform 模拟局部透视缩放
对单个图形(如一张卡片翻转),不需要完整 3D 引擎,可用 CSS 风格的 2D 变换逼近:
用
手动设置仿射矩阵
加入非线性缩放项(需自行拼接透视矩阵的前两行)——更稳妥做法是:先算好目标四边形四个角的投影坐标,再用
配合
的九参数变形(
不够,需用
+
+
或第三方
quadratic warp
工具
真正可控又简洁的方式,仍是手动投影顶点 + 用
连线——它透明、可调试、不依赖额外库。
beginPath()lineTo()stroke()setTransform()Path2Dctx.setTransform(a, b, c, d, e, f)transformdrawImagedrawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)setTransformdrawImageclip()lineTo