透视错觉
templates/ 目录中的模板是完整且可直接运行的场景,请从中选一个作为起点:
street.html是一个日本街道场景,包含电线杆、锥桶、人行横道和红色天空。market.html是一个日本超市场景,包含一条过道、端架、红色购物篮和成排的照明灯。
两者共享相同的相机摇臂、时间线和插画渲染管线。仅场景部分不同。
设置(在每个项目文件夹中)
mkdir -p ~/Movies/edits/<date>-<name>/stills && cd $_
printf '{"type":"module"}' > package.json && npm i [email protected] [email protected]
cp ~/simcraft/skills/perspective-illusion/templates/{street.html,render.mjs} .
node render.mjs street.html x --stills=0.2,1,2,4,6 # 先检查帧(stills/st_<t>.png)
node render.mjs street.html out.mp4 # 7秒循环,1920x1080,4子帧运动模糊(约2.5分钟)
诀窍,分四部分
- 将场景沿一个长轴布局(一条街道或过道沿 -z 方向延伸),物体前后排列:电线杆或柱子在相同的 x 坐标上,末端是一栋建筑或后墙。400 米外的 2° 长焦镜头将所有物体压缩成一幅平面图。排成一线的杆子叠成一个,长侧墙沿边缘消失。
- 切勿倾斜或旋转相机。 它始终沿轴线正前方,保持水平,因此垂直线条保持垂直。对于“俯视”或“仰视”,使用镜头移位(
H,画面中的地平线位置),如同移轴镜头。每个镜头参数为{x, y (相机高度), zf, W, fov, H, lay, cs}。 - 在推拉变焦之间进行变形。 当 fov 变化时,
W始终保持对焦点平面zf的取景。所有参数通过单一单调的三次曲线贯穿所有关键帧,因此速度不会突变。 - 在平面状态下进行作弊。 物体(锥桶、篮子)仅在平面保持期间朝向或远离相机滑动,此时运动是不可见的。这就是一排物体变成一条对角线(“前后互换”)的原因。它们也可以在平面视图(
cs)中绘制得更大。
匹配参考视频(按此操作,不要仅凭目测)
- 在每一个镜头处提取其帧。然后,对于每个镜头,测量:
- 消失点和地平线的位置(由此得出
H), - 两个已知宽度物体的位置(由此得出
x和W), - 一个已知长度物体(例如人行横道)的近端和远端边缘(由此得出相机高度
y、距离和 fov)。 计算出的数值已写在模板注释中。
- 消失点和地平线的位置(由此得出
- 将其帧聚类到一个调色板中(对 4 帧进行 k-means 聚类),并使用这些确切的颜色。
- 在每次更改后,将您的帧与参考视频在同一时间戳下并排比较。
插画渲染流程(为何看起来像手绘而非渲染)
页面渲染三个通道:颜色(双色调卡通着色)、视图空间法线加深度、以及仅太阳光的阴影蒙版。一个最终着色器随后完成三项工作:
- 墨水线条:在深度(二阶差分,因此平视的地面不会被勾线)或法线发生变化的地方绘制。线条粗细随噪声变化,且采样点轻微抖动,因此线条不是笔直的。深度阈值随距离增大而增大。
- 交叉阴影线:仅出现在投射阴影区域:色调偏冷且带有精细的对角线笔触,在几乎边缘可见的表面上淡化。
- 天空(或天花板):在没有几何体的区域平涂。
已遇到的问题,避免您重蹈覆辙
- 在单行语句中添加的
//注释会吞噬scene.add(sun),导致阴影蒙版变黑,整个画面布满交叉线。请使用/* */或换行。 - 重叠的共面地板在远处会闪烁。请确保地板块之间边缘对齐。
- 浅角度掠射墙壁的光线会产生斑驳的自阴影。请将主光源保持在正面约 45° 角,并阻止全高柱子和天花板灯具投射阴影。
- 生成的图像或标志上切勿出现文字。标志仅为形状。
- 在每次完整渲染前检查静帧,并运行运动检查(vox-explainer 的
motion_check.py)。