如何在浏览器中实时抠绿幕:Oil Motion 的 WebGL 色键视频渲染完全指南
【免费下载链接】oil-motion设计并实现随滚动、拖动、指针或状态变化响应的网页动画,覆盖素材、时间轴和运行时。项目地址: https://gitcode.com/gh_mirrors/oi/oil-motion
Oil Motion 是一个交互动画 Skill,负责设计动作、生成连续画面并把结果接入网页的滚动、鼠标和触摸操作。其中最有意思的能力之一,是在浏览器中实时抠掉绿幕:视频里的人物或产品站在绿色背景上,页面加载时却直接呈现出透明效果的主体,背后可以换成任意背景。这篇指南带你读懂 Oil Motion 的 WebGL 色键视频渲染原理,不需要任何图形学基础。
为什么要在浏览器里实时抠绿幕?
传统做法有两个问题:
- 提前抠好的透明图集太大:把几百帧画面逐帧抠成透明图(Alpha WebP 图集),文件体积和内存占用都很高,长动画根本放不下。
- 直接放绿幕视频太丑:绿色背景会直接暴露给用户,无法与页面融合。
Oil Motion 的折中方案是:视频保留绿色背景,但在网页上用 WebGL 逐帧实时抠色。绿色背景只是"运输包装",到了浏览器里立刻被剥掉,只留下透明主体。这样视频压缩率极高(绿幕视频非常好压),页面又能获得任意背景。
这条路线的完整说明在 references/chroma-video.md 中,它明确规定:只有当"背景归属页面"(background_owner: page)且预算脚本选中chroma-video时才走这条路。
渲染流程:一张图看懂 4 步
整个实时抠色过程可以概括为 4 步,全部在 GPU 上完成:
- 取帧:从隐藏的
<video>元素中取出当前画面,作为纹理上传给 WebGL。 - 判断"像不像绿":对画面中的每个像素,比较它和抠色目标色的距离,距离越近越透明。
- 修正溢色:绿色背景会"反光"污染主体边缘,算法会把主体边缘偏绿的部分拉回来。
- 输出透明 Canvas:把处理后的画面画进透明画布,页面背景从画布后面透出来。
对应的两个核心文件是:
- 渲染器源码:assets/chroma-video-renderer.ts
- 帧控制器(负责按交互定位帧):assets/interactive-motion.ts
核心原理:GPU 着色器如何判断"绿色"
抠色的大脑是一个片段着色器(Fragment Shader),它会被 GPU 对画面的每个像素执行一次。Oil Motion 使用的算法叫dominance-v2,分三层判断:
第一层:色度距离。不是简单比较 RGB 值,而是先把颜色转换到"色度空间",再计算它与抠色目标色的距离。这样即使绿色背景存在明暗变化(亮绿、暗绿),也能被稳定识别。距离小于similarity阈值的像素直接变透明,similarity + smoothness范围内的像素做半透明过渡,形成柔和边缘。
第二层:主导度(Dominance)。如果一个像素的绿色通道明显压过红蓝通道,说明它是"纯绿色残留"——这类像素即使颜色略有偏差也必须抠掉。着色器通过比较G - max(R, B)来检测这种主导性,防止绿幕边缘留下脏边。
第三层:溢色抑制(Spill Removal)。绿色背景的光会反射到主体边缘,让人物轮廓泛绿。着色器会把受污染像素的绿色分量混入红蓝通道,视觉上"洗掉"这层绿雾。
这三个参数(similarity、smoothness、spill)都来自编译期写入的配置文件,页面不允许自己乱调。为什么?因为编译阶段已经用同一套参数逐帧模拟过抠色效果,页面再改参数就会导致实际效果与验收结果不一致。
编译阶段:抠色在发布前就要验收
实时抠色不是"碰运气"。视频在编译进页面之前,scripts/compile_scroll_video.py 会做一次完整的预演:
| 编译动作 | 目的 |
|---|---|
| 按策略保留原始帧或插帧 | 控制动画节奏与体积 |
| 检查整段代表帧的色键颜色与边缘均匀度 | 确保绿幕足够均匀 |
| 逐帧模拟运行时抠色 | 用与 WebGL 相同的dominance-v2参数检查残留、误删和溢色 |
| 生成 Alpha 接触表和静态降级图 | 出问题时的兜底素材 |
如果模拟结果显示绿幕块残留、边缘溢色或主体内部被误抠,母版会被直接拒收——禁止靠放大阈值来掩盖素材缺陷。这套硬门规则同样写在 references/chroma-video.md 的"抠色硬门"一节。
最终,编译产物compile.json中会带上runtime.keying参数和background-matrix,浏览器运行时只读取这些配置,不做任何"创造性发挥"。
页面接入:隐藏视频 + 透明画布
页面结构非常简单,只有两个元素:
- 一个隐藏的
<video>:负责解码色键视频,用户永远看不到它。 - 一个透明 Canvas:WebGL 把抠好色的主体画在这里,页面背景(CSS 设置的
--page-background)从画布后面透出来。
这意味着一个好处:更换页面背景不需要重新生成任何素材——背景本来就不在视频里,改 CSS 即可。
运行时还有两个贴心设计:
- 逐帧定位:滚动条移动时,控制器调用
render(frame)精确 seek 到对应帧,动画严格跟随手势前进、后退或停住。 - 自动降级:如果 WebGL 创建失败、视频解码失败或用户开启了"减少动态效果"(
prefers-reduced-motion),页面会显示编译时准备好的静态 Alpha 降级图,绝不让用户看到绿色母版。
什么时候该用色键视频?
不是所有动画都适合实时抠色。Oil Motion 用 scripts/motion_budget.py 根据显示尺寸、帧数和访问时间模式自动决策,规则来自 references/delivery-selection.md:
- 小尺寸、随机跳转、二维参数→ Alpha WebP 图集(构建时抠好,随机访问快)
- 大尺寸、长一维时间轴、顺序滚动→ 绿幕全关键帧 MP4 + WebGL 实时抠色(省内存、压缩率高)
- 背景与主体必须一起连续→ 直接烘焙场景视频,不抠色
选型细节还可以参考 assets/motion-manifest.example.json 中的示例清单。
小结
Oil Motion 的实时绿幕抠色,本质是把传统影视后期里的色键工作搬进了 GPU 着色器:色度距离找背景、主导度防脏边、溢色抑制洗绿雾,再配合编译期的逐帧预验收,让"绿幕视频 + 任意网页背景"这条路线既省体积又稳定可控。
对于想学习 Web 图形学的读者,assets/chroma-video-renderer.ts 中那段不足百行的 Shader 是一个极佳的实战样本——它展示了如何用 WebGL 在几毫秒内完成一整帧视频的颜色处理。
【免费下载链接】oil-motion设计并实现随滚动、拖动、指针或状态变化响应的网页动画,覆盖素材、时间轴和运行时。项目地址: https://gitcode.com/gh_mirrors/oi/oil-motion
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考