可用canvas 2d实现动态光影旋转正方体:通过三维顶点旋转、正交/透视投影、面法向量光照计算、深度排序绘制及requestanimationframe动画,达成可控伪3d效果。

直接用 Canvas 2D 上下文无法真正渲染 3D 光影,但可以通过数学投影 + 手动光照计算 + requestAnimationFrame 实现视觉上逼真的、带动态光影的旋转正方体——本质是「伪3D」,但效果足够直观且完全可控。
1. 建立三维顶点与正交/透视投影
先定义正方体 8 个顶点的三维坐标(如 ±1 范围),再通过矩阵或手动公式将其投影到二维画布平面:
- 正交投影:直接丢弃 z 坐标,(x, y, z) → (x, y),适合清晰展示结构
- 透视投影:用 x' = x / (d − z), y' = y / (d − z)(d 为观察距离,如 5),z 越大(越靠近观察者)显得越大,增强纵深感
- 所有顶点需统一绕 x/y/z 轴做旋转变换(用欧拉角或四元数更稳),推荐先用三个独立旋转矩阵相乘更新顶点
2. 计算面片法向量与动态光照
正方体有 6 个面,每个面由 4 个顶点组成。对每个面:
- 取面内两个非平行边向量(如 v1 = p1−p0,v2 = p2−p0),叉乘得单位法向量 n
- 设定一个固定光源方向(如 light = [0, -1, -1],从左上方后方来),归一化
- 用点积 diffuse = max(0, n · light) 得基础漫反射强度(0~1)
- 可叠加环境光(如 0.2)避免全黑:finalLight = 0.2 + 0.8 × diffuse
这样每个面会随旋转实时变亮变暗,形成自然光影过渡。
3. 渲染顺序与抗锯齿优化
Canvas 默认无深度缓冲,需手动按「离观察者远近」排序面片再绘制(画家算法):
- 对每个面,计算其 4 个顶点的平均 z 值(投影前),作为深度参考
- 按平均 z 从大到小排序(z 越大越靠前),逆序绘制(先画远的,再盖近的)
- 用 ctx.lineJoin = 'round' 和 ctx.lineWidth = 1.5 减轻边缘锯齿
- 填充时用 ctx.fillStyle = `rgb(${r}, ${g}, ${b})`,其中 r/g/b 按光照强度缩放原始颜色(如 base=[120,180,255] → [120×l, 180×l, 255×l])
4. 平滑动画与交互控制
用 requestAnimationFrame 驱动循环,每帧微调旋转角度(如 angleX += 0.01):
- 避免 setInterval,保证帧率稳定;加入时间差 delta 计算可实现匀速(不依赖帧率)
- 监听鼠标拖拽:记录起始位置,移动时更新 yaw/pitch 角度,让模型随用户视角转动
- 添加键盘控制(如 ←→↑↓ 调整旋转速度,+/- 改变光源高度)提升可玩性
- 开启 ctx.imageSmoothingEnabled = false 可防止缩放失真(尤其像素风需求)
不复杂但容易忽略:光照计算必须在投影前进行(用原始三维法向量),否则 z 压缩会导致明暗错误;另外,顶点旋转建议使用 Float32Array 存储并复用数组,避免每帧新建对象影响性能。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











