Canvas通过轴测投影(如等轴测)实现3D效果,核心是将(x,y,z)经线性变换映射为像素坐标,保持平行性;可用setTransform定义坐标系、按z排序处理遮挡、逆变换支持鼠标交互。

Canvas本身不直接支持3D,但通过轴测投影(尤其是等轴测)能把三维结构画得有立体感,关键在于把(x, y, z)正确映射到画布的(x, y)像素位置。这不是简单缩放,而是按固定角度做线性变换——所有平行线保持平行,没有透视衰减,适合建筑示意、游戏地图或数据可视化。
理解等轴测的核心坐标公式
等轴测投影中,x、y、z三轴在画布上互成120°,常用简化实现是让x轴向右下30°、y轴向左下30°、z轴垂直向上。对应转换公式为:
- canvasX = x × cos(30°) − y × cos(30°) = (x − y) × √3/2
- canvasY = z − (x × sin(30°) + y × sin(30°)) = z − (x + y)/2
实际编码中常进一步简化为整数比例,例如Isomer使用的近似:canvasX = x − y,canvasY = (x + y) / 2 − z。注意:最终y值需再翻转适配Canvas原点在左上角——即绘制前用drawY = height − canvasY。
用setTransform实现可复用的轴测坐标系
手动计算每个点太繁琐。更干净的做法是用ctx.setTransform()一次性定义整个轴测空间:
- 先调用
ctx.save()保存原始状态 - 用
ctx.translate(originX, originY)把逻辑原点(比如场景中心)移到画布合适位置 - 再用
ctx.transform(a, b, c, d, e, f)传入轴测变换矩阵,例如:
a = cos(30°), b = sin(30°), c = −cos(30°), d = sin(30°), e = 0, f = 0
这样后续所有fillRect、lineTo都自动按轴测规则绘制 - 结束时
ctx.restore()恢复默认坐标系,不影响其他绘制
处理z轴深度与遮挡关系
轴测图没有自动深度排序,必须人工控制绘制顺序:
- 按z坐标从远到近排序所有图形元素(z值越小越靠后)
- 对立方体等组合图形,拆解为面(front、top、right),分别计算各面顶点并按z均值排序
- 避免用
globalAlpha模拟半透明遮挡——它会破坏轴测清晰度;优先用纯色分层绘制
鼠标交互与坐标反推
用户点击画布时,要还原出对应的(x, y, z)逻辑坐标:
- 先用
getBoundingClientRect()获取canvas真实视口位置,换算出相对于canvas左上角的像素坐标 - 逆用正向变换公式:已知canvasX、canvasY,解二元一次方程组求x和y(z通常由层级或高度预设)
- 例如从简化公式
px = x − y、py = (x + y)/2 − z出发,可得:
x = (2×py + 2×z + px) / 3,y = x − px
不复杂但容易忽略
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xinjizixun/127151.html