Communitygithub.com

低多边形PS1风格短片

通过Blender脚本完全用代码制作30-60秒竖屏低多边形PS1风格3D短片(块状CC0角色、扁平像素面、颗粒感抖动效果、单词高亮字幕、同步音效、AI语音),渲染成本为0。

低多边形PS1风格短片 是什么?

本技能允许Claude或其他AI助手使用Blender在用户本地机器上完全通过代码生成低多边形PS1风格3D短片。无需视频生成器——Claude编写一个Blender脚本来构建场景、渲染帧、修复问题,然后使用Python脚本合成音效、AI语音和字幕。该技能遵循严格的流水线,包括编写hook问题脚本、录制配音、生成单词时间戳、创建分镜头、预览循环(用户可在时间线上留备注,仅重新渲染有变化的镜头)、最终渲染以360x640分辨率输出、声音后期处理、以及应用PS1抖动和像素化效果的最终合成。用户只需确保安装了Blender 4.2+、Python 3.10+、Quaternius的免费CC0角色包等必要依赖。该技能已通过"示例/电梯火箭/"(“如果电梯像火箭一样快会怎样?”34秒)验证,作为模板使用。整个过程成本为零,仅配音约需0.10美元。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mr-render/lowpoly-shorts/tree/HEAD

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

低多边形PS1风格短片 是做什么的?

一切皆代码:Claude为每个短片编写一个Blender脚本,在用户机器上渲染,查看帧并修复,然后构建声音和字幕。无需视频生成器。

已在 examples/lift-rocket/(“如果电梯像火箭一样快会怎样?”,34秒)上验证。在编写新短片之前先阅读该示例:它是模板。

要求(先检查,缺失则安装)

  • Blender 4.2+(在5.3上测试过)。找到它:blender 在 PATH 上,否则 C:\Program Files\Blender Foundation\<ver>\blender.exe / /Applications/Blender.app/Contents/MacOS/Blender。
  • Python 3.10+ 并安装 numpy pillow soundfile faster-whisper;ffmpeg 在 PATH 上。
  • 角色:Quaternius "Ultimate Modular Men"(CC0,免费,quaternius.com)。解压到 assets/quaternius-modular-men/ 或设置 LOWPOLY_PACK 指向其 Individual Characters/Blends 文件夹。
  • 一个TTS语音(ElevenLabs或用户拥有的任何工具)。可选:earshot MCP 来检查声音。

流水线(每个短片一个文件夹,复制 examples/lift-rocket/ 作为起点)

#步骤文件 / 命令完成条件
1脚本script.mdHook问题 + 后果链,每个更糟更有趣 + 真实数字 + 干巴巴的梗。60-110词,对应30-40秒。每个数字都核对来源并写在事实列表中。
2配音vo/takeA.mp3录制2次,选择单词时间戳清晰的那次。充满活力的创作者声音,不是平静的(平静 = “无聊”反馈)。
3单词时间戳python ../../scripts/words.py vo/takeA.mp3takeA_words.json 中无零长度单词。
4分镜头列表script.md 中的表格每句VO一个镜头,每1-3秒一个新画面,每个镜头对应一个单词时间。
5场景build.py(Blender)blender -b -P build.py -- frames --still 30,120,... 渲染静帧;在完整渲染前查看每个静帧。
6预览+备注先 python ../../scripts/preview.py . render 然后 serve用户没有未处理的备注(见预览循环)。
7渲染blender -b -P build.py -- frames360x640 EEVEE PNG,f_0001.png...
8声音python build_mix.py音效放在画面上,VO在上,低保真背景在下,闪避处理。输出 mix_raw.wav + cues.json。
9后期python post.pyPS1抖动、效果、单词高亮字幕、统计呼出 -> out/ 目录下1080x1920。
10混流见下方short.mp4,然后测量并检查同步。

帧规则通用:24 fps,第1帧 = t 0,F = lambda t: int(round(t * 24)) + 1。

混流指令:

ffmpeg -y -framerate 24 -i out/f_%04d.png -i mix_raw.wav -c:v libx264 -crf 16 -pix_fmt yuv420p \
  -af "loudnorm=I=-15:TP=-1.5:LRA=11,aresample=48000" -c:a aac -b:a 192k -shortest short.mp4

稍后切换配音而不重新剪辑画面: python ../../scripts/words.py vo/takeB.mp3 然后 python ../../scripts/align.py vo/takeA_words.json vo/takeB.mp3 --end 34(--end = VO背景音结束位置;输出长度为此结束时间加2秒。如果不加:最后一个单词加1.5秒,这会导致文件比画面短) -> takeB_aligned.wav + takeB_aligned_words.json。将 build_mix.py(VO环境变量)和 post.py 指向它们。

预览循环(在完整渲染之前)

在浏览器中快速低分辨率预览,用户在时间线上留下备注,Claude修复并仅重新渲染内容发生变化的镜头。镜头 = build.py 中的摄像机标记。

操作命令(在短片文件夹内运行)
渲染预览python ../../scripts/preview.py . render(首次:所有镜头;之后:仅变化的镜头)
打开备注页面python ../../scripts/preview.py . serve -> http://127.0.0.1:8765
读取备注python ../../scripts/preview.py . notes(按镜头分组,带有帧号)
修复后编辑 build.py,再次运行 render,然后 python ../../scripts/preview.py . done 3 5 --reply "你更改的内容"
强制重渲染某镜头render --shots c_press,c_slam 或 render --all
  • build.py 必须接受 --blend-only(构建场景,保存,不渲染)。参见示例。
  • 变化检测:每个预览帧获得一个指纹(活动摄像机、每个可见对象的变换、骨架姿态、面部交换、材质、灯光、网格数据)。仅当某个镜头的一帧发生变化时才重新渲染。未变化的镜头保留旧帧。
  • preview.json 中的设置(可选):scale 50(%),step 2(每2帧),samples 1, audio(默认 mix_raw.wav,否则为VO),final = 完整流水线命令。页面的 "批准并渲染最终版" 按钮运行它们;notes 在用户点击后打印 APPROVED。
  • 逐一修复备注,回复每一条,重新渲染,并告诉用户无需刷新:页面 会自动重新加载视频。重复出现的同类备注会成为此文件中的规则。
  • 在 lift-rocket 上测量(RTX 3070 Ti 笔记本,820帧):首次预览76秒,一个镜头变化13秒, 无变化12秒。大部分帧渲染时间是固定开销,因此降低分辨率比减少渲染帧数帮助更小。

工具 API(scripts/lowpoly_kit.py,在Blender内部导入)

  • load_character(scn, "Suit") -> (armature, meshes, actions)。角色:Adventurer, Beach, Casual_2, Casual_Hoodie, Farmer, King, Punk, Spacesuit, Suit, Swat, Worker。
  • 动作(原地,24种):Death, HitRecieve, HitRecieve_2, Idle, Idle_Neutral, Interact, Kick_Left/Right, Punch_Left/Right, Roll, Run, Run_Back/Left/Right, Walk, Wave, Gun_Shoot, Idle_Gun*, Idle_Sword, Sword_Slash, Run_Shoot。
  • add_faces(scn, arm, head, tag, kinds, spec, drop) 在移动骨架之前使用。种类: neutral, blink, side, shock, grimace, squint, dazed, xeyes。drop 删除包中的3D眼睛/眉毛。
  • show_faces(faces, [(frame, kind), ...]):硬切换,每个面部保持到下一个。
  • nla(arm, [(action, start, end, blend[, influence]), ...]):后面的条目在更高的轨道上。
  • drive_root(arm, [(frame, x, y, yaw, ease), ...], last):yaw 0 面向 -Y(默认摄像机方向)。
  • new_cam,aim,yaw_to,ps1_render_settings(scn, outdir)。
  • 场景集:scripts/set_lift_lobby.py(以 BUILD_ONLY=True 执行,返回 box,uv_world,mat)。 新场景集遵循相同模式:带像素纹理的盒子(interpolation = "Closest")。

视觉效果规则

  • 渲染 360x640,filter_size 0,AgX Punchy,平面着色;后期:15位色彩 + Bayer抖动,x3最近邻放大。
  • 面部是扁平 32x28 像素贴花,硬切换;绝不平滑动画脸部。
  • 受力时通过关键帧骨架缩放(z向下,xy向上)实现挤压。喜剧节拍:快进(2-3帧),保持。
  • 字幕:1-3个词,粗体无衬线字体,白色黑描边,当前词黄色,底部三分之一(y 1300 of 1920)。
  • 统计呼出:红色圆角框,顶部三分之一,4帧弹出,每个真实数字一个。

声音规则

  • 每个音效都放置在它的峰值落在画面上时(at(name, frame, db, peak=...))。
  • 语音必须突出:VO标准化到 0 dBFS,音效总线 -11 dB,音乐 -7 dB,加上侧链闪避 语音说话时(音效 -5 dB,音乐 -9 dB)。电梯短片的v1版本音效为-3,音乐为0:“我 听不到旁白”。
  • 在大的停顿拍子上切断音乐,之后重新引入。寂静成就了笑点。
  • 主输出:loudnorm -15 LUFS,真峰值 -1.5 dBTP。
  • 检查:使用 earshot 的 timeline 检查 mp4 与 cues.json(目标:每个提示在100毫秒内),measure 检查 LUFS。

已遇过的错误(不要重复)

  • 包网格默认渲染隐藏:hide_render = False(工具包已处理)。
  • 门网格已经位于关闭位置:只动画偏移量,否则它们会以0.7米的间隙关闭。
  • 天花板低于约2.75米会在电梯大小的车厢内隐藏摄像机视野中的墙面显示器。
  • 尚未应出现的角色:将其 location.z = -50 直至轮到他的镜头。
  • NLA单次动作过渡到保持:设置剪辑的 blend_out = 0,否则姿势会弹出1帧。
  • 反向镜头变黑(未照亮的顶棚):添加前灯和一点顶棚发射。尽早渲染反向角度。
  • faster-whisper 在 mp3 上可能因 PyAV 不匹配而失败:words.py 先用 ffmpeg 解码。
  • 从 -0.04 秒开始的短语在对齐中导致空切片:用 max(0.0, ...) 夹紧(已处理)。

成本(电梯短片,RTX 3070 Ti 笔记本)

渲染820帧耗时92秒,后期17秒,$0。角色、音效、音乐:$0(CC0 + 代码合成)。 配音:ElevenLabs 每次约 $0.10,每次短片录2次。

在交付之前

  • 查看最终帧的缩略图(每约2秒一张),而不仅仅是静帧。
  • 测量响度,检查同步,检查字幕与配音文本是否一致(拼写修正放入 post.py 的 FIX 中)。
  • 告知用户测量了什么以及哪些未经过人类听觉检查。

相关技能