视频混剪-转场效果是怎么实现的

视频混剪-转场效果是怎么实现的

BaseCut 技术博客第四篇。这篇聊转场------两个画面之间的淡入淡出、滑动、擦除是怎么做的。


什么是转场

最简单的解释:让画面 A 逐渐变成画面 B

没有转场的话,两个片段之间是硬切:

复制代码
时间轴:

片段 A    |    片段 B
oooooooooo|oooooooooo
          ↑
      瞬间切换

有转场的话:

复制代码
片段 A      转场区间      片段 B
ooooooooo[A+B 混合区]ooooooooo
         ↑───────────↑
       起点         终点

转场的历史:电影中的视觉语言

转场不是瞎搞,它是电影百年历史沉淀下来的视觉语言

硬切(Hard Cut)

镜头直接切换,没有任何过渡。

用途:

  • 同一场景的不同角度
  • 紧张、快节奏的剪辑

淡入淡出(Fade In/Out)

画面逐渐变亮或变暗,通常是黑场。

用途:

  • 场景开始/结束
  • 表示时间流逝

叠化(Dissolve)

两个画面叠加在一起,A 逐渐消失,B 逐渐出现。

用途:

  • 平行时空
  • 回忆、梦境
  • 时间流逝

擦除(Wipe)

一条线从一侧推到另一侧,后面露出新画面。

用途:

  • 《星球大战》经典转场
  • 复古风格

转场的数学本质

核心公式:线性插值

不管多复杂的转场,核心都是一个公式:

复制代码
output = A × (1 - progress) + B × progress

其中 progress 从 0 变到 1:

复制代码
progress = 0.0  →  100% A,0% B
progress = 0.5  →  50% A,50% B
progress = 1.0  →  0% A,100% B

这个公式叫 Linear Interpolation ,简称 Lerp,是图形学最常用的公式之一。

不同转场类型

虽然公式一样,但 A 和 B 的"混合方式"可以有很多变化:

类型 混合方式
淡入淡出 整个画面透明度渐变
滑动 B 从画面外推入,A 被推走
擦除 一条线逐渐划过,后面露出 B
缩放 A 缩小消失,B 放大出现

缓动函数(Easing)

如果 progress 匀速从 0 增长到 1,动画会很"机械",像机器人一样。

真实世界的物体都有惯性:

  • 汽车启动:先慢后快(Ease-In)
  • 门关闭:先快后慢(Ease-Out)
  • 弹簧:快-慢-回弹

常用缓动函数

线性(Linear)

javascript 复制代码
function linear(t) {
  return t
}

没有加速度,匀速变化。

缓入(Ease-In)

javascript 复制代码
function easeIn(t) {
  return t * t
}

开始慢,结束快。

缓出(Ease-Out)

javascript 复制代码
function easeOut(t) {
  return 1 - (1 - t) * (1 - t)
}

开始快,结束慢。

缓入缓出(Ease-In-Out)

javascript 复制代码
function easeInOut(t) {
  return t < 0.5
    ? 2 * t * t
    : 1 - Math.pow(-2 * t + 2, 2) / 2
}

两头慢,中间快。最常用。

对比效果

复制代码
时间:  0    0.25   0.5   0.75   1
线性:  0    0.25   0.5   0.75   1.0
缓动:  0    0.12   0.5   0.88   1.0

缓动让动画有"弹性",更自然。


WebGL 实现

双纹理绑定

转场需要同时访问两帧画面,所以要绑定两个纹理:

javascript 复制代码
// 绑定 A 帧到纹理槽位 0
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, textureA)
gl.uniform1i(uTexALocation, 0)

// 绑定 B 帧到纹理槽位 1
gl.activeTexture(gl.TEXTURE1)
gl.bindTexture(gl.TEXTURE_2D, textureB)
gl.uniform1i(uTexBLocation, 1)

// 传入进度
gl.uniform1f(uProgressLocation, progress)

// 渲染
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)

淡入淡出着色器

glsl 复制代码
uniform sampler2D u_texA;
uniform sampler2D u_texB;
uniform float u_progress;

void main() {
  vec4 colorA = texture2D(u_texA, v_texCoord);
  vec4 colorB = texture2D(u_texB, v_texCoord);
  
  // GLSL 内置的 mix 函数就是 Lerp
  gl_FragColor = mix(colorA, colorB, u_progress);
}

滑动着色器

glsl 复制代码
void main() {
  // A 向左移动
  vec2 uvA = v_texCoord + vec2(u_progress, 0.0);
  // B 从右边进来
  vec2 uvB = v_texCoord - vec2(1.0 - u_progress, 0.0);
  
  vec4 colorA = texture2D(u_texA, uvA);
  vec4 colorB = texture2D(u_texB, uvB);
  
  // 根据 UV 坐标判断显示哪个
  if (v_texCoord.x > 1.0 - u_progress) {
    gl_FragColor = colorB;
  } else {
    gl_FragColor = colorA;
  }
}

擦除着色器

glsl 复制代码
void main() {
  vec4 colorA = texture2D(u_texA, v_texCoord);
  vec4 colorB = texture2D(u_texB, v_texCoord);
  
  // 一条竖线从左向右扫过
  if (v_texCoord.x < u_progress) {
    gl_FragColor = colorB;
  } else {
    gl_FragColor = colorA;
  }
}

转场时机判断

播放器在渲染每一帧时,需要判断当前是否处于转场区间:

typescript 复制代码
function render(currentTime: number) {
  // 查找当前时间是否有转场
  const transition = findActiveTransition(currentTime)
  
  if (transition) {
    // 计算进度 (0-1)
    const rawProgress = (currentTime - transition.startTime) / transition.duration
    
    // 应用缓动函数
    const progress = easeInOut(rawProgress)
    
    // 获取两帧画面
    const frameA = getFrame(transition.clipA, currentTime)
    const frameB = getFrame(transition.clipB, currentTime)
    
    // 渲染转场
    webgl.renderTransition(frameA, frameB, progress, transition.type)
  } else {
    // 正常渲染单帧
    const frame = getCurrentFrame(currentTime)
    webgl.renderFrame(frame)
  }
}

下一篇

讲视频导出------怎么把编辑好的内容变成 MP4 文件,以及 WebCodecs 的原理。


系列目录

  1. 技术选型与项目结构
  2. 时间轴数据模型
  3. WebGL 渲染与滤镜
  4. 转场动画实现(本文)
  5. WebCodecs 视频导出
  6. LeaferJS 贴纸系统
相关推荐
电子科技圈1 天前
赋能高端音频功能促进多样化设备创新——XMOS USB Audio平台实现四大功能升级
人工智能·mcu·音视频·智能家居·边缘计算·语音识别·智能硬件
EasyDSS1 天前
视频高清直播点播/云点播/云直播EasyDSS:一站式视频云平台全链路整合,重塑企业视频应用新生态
音视频
jwybobo20071 天前
AV1 码流 RTP 封装
音视频·av1
愚公搬代码1 天前
【愚公系列】《剪映+DeepSeek+即梦:短视频制作》055-即梦+DeepSeek生成AI视频(文生视频案例)
人工智能·音视频
l14372332671 天前
AI电影解说的技术链路拆解:从视频理解到自动剪辑
人工智能·音视频
飞睿科技1 天前
ESP32-S31 高性能 AIoT SoC 在智能音频领域的应用实践
音视频·esp32·智能家居·乐鑫科技·ai智能
AI2512241 天前
免费AI视频生成工具技术解析与功能对比
人工智能·音视频
EasyCVR1 天前
国标GB28181视频监控平台EasyCVR视频质量诊断赋能智慧城市精细化治理
人工智能·音视频·智慧城市
炭烤毛蛋1 天前
rk3588 适配音频解码芯片 es8388
arm开发·音视频·rk3588·es8388
孤岛站岗1 天前
WAN:万象视频,开源视频生成的新标杆
开源·音视频