深入解析KAI设计部门官网:WebGL线条模糊、视频拖拽与3D动画技术揭秘

本文深入探讨了KAI设计部门官网背后的核心技术实现,包括使用WebGL模拟具有景深效果的自然模糊线条、实现跨浏览器平滑响应的视频拖拽交互,以及利用Blender导出数据实现3D线条与视频的同步动画。

Behind the KAI Design Dept. Experience: WebGL Line Blur, Video Scrubbing, and 3D Animation

A look at the technical insights behind the KAI Design Dept. site, covering WebGL line DoF, video scrubbing, and Blender integration.

该项目展示了为日本KAI公司设计部门创建的网站。该公司拥有117年基于刀具制造的工艺历史。该网站反映了该品牌在其悠久历史中培养的精炼美学感性。

KAI不仅制造产品,还考虑使用其工具的人们的动作。从这个想法中产生了主要文案:“切割的锐利描绘我们的生活。”视觉和交互都围绕这一概念精心塑造。围绕产品的线条充当运动指引线——象征着人类姿态如何描绘和塑造日常生活。通过交互式视频拖拽,访问者可以体验使用这些工具的触感。该网站将KAI的美学呈现为一种“可触摸的视频”体验。

两大技术挑战

开发过程中存在两个主要技术障碍:

  1. 表现具有景深(DoF)的自然模糊线条
  2. 实现平滑响应拖拽交互的视频拖拽

以下部分解释了如何应对每个挑战。

线条的自然景深效果

网络上典型的景深实现通常会在堆叠的模糊层下留下锐利的核心,造成不自然的结果。例如,下图是由Gemini生成的图像,说明了这个常见问题:

与传统3DCG软件中使用的依赖于深度图的景深技术不同,纯粹在WebGL中实现干净、自然的模糊被证明具有挑战性。因此,我探索了一种不同的方法(不过我很想知道是否有人知道更好的方法):

  1. 将清晰、未模糊的线条渲染到FBO中。
  2. 渲染第二个FBO,该FBO按模糊半径放大线条,并将其RGB通道中的额外数据进行编码:
    • G = 模糊区域
    • R = 模糊强度
  3. 将两者结合,并使用垂直和水平两遍处理应用平面高斯模糊。

为了处理线条交叉点,该过程执行了两次——一次用于前景,一次用于背景——由原点分隔。

视频拖拽

在现代Mac/Chrome环境中,拖拽可以简单地实现为:

1
video.currentTime = sec;

然而,为了实现跨浏览器兼容性,还需要两个额外的步骤。首先,使用ffmpeg仔细地重新编码每个视频。并非每个参数都是必需的,但最重要的因素是缩短关键帧间隔。虽然-g 1(全I帧)将每一帧都变成了I帧,但由此产生的文件大小不切实际,因此我选择了该值的一半。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
ffmpeg \
  -i INPUT.mov \
  -hide_banner \
  -c:v libx264 \
  -crf 24 \
  -y \
  -pix_fmt yuv420p \
  -an -sn -dn \ # 移除音轨、字幕轨和数据轨
  -map 0:v:0 \  # 仅保留主视频轨
  -profile:v baseline \  # 轻量级解码配置
  -level 3.1 \  # 移动设备兼容性
  -g 12 -keyint_min 12 -sc_threshold 0 \  # 更短的关键帧间隔以实现更平滑的拖拽
  -bf 0 -refs 1 \
  -tune fastdecode \  # 降低解码成本
  -x264-params "no-deblock=1:weightp=0:mbtree=0:rc-lookahead=0:aq-mode=0:subme=1:trellis=0:me=dia:partitions=none" \  # 禁用繁重的解码功能
  -video_track_timescale 24000 \  # 将tbn固定为24000以实现24fps一致性
  -movflags +faststart \  # 针对Web优化的头部
  OUTPUT.mp4

尽管如此,Firefox的兼容性问题仍然存在,因此我添加了一个基于WebCodecs的备用方案。我最初考虑使用mp4box,但最终选择了mediabunny,因为它维护积极且更易于使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { ALL_FORMATS, BlobSource, Input, VideoSampleSink } from 'mediabunny';

...

const blobForDecode = await loadVideo(name, suffix);
this._input = new Input({
  source: new BlobSource(blobForDecode),
  formats: ALL_FORMATS,
});
const vtrack = await this._input.getPrimaryVideoTrack();
this._sink = new VideoSampleSink(vtrack);

this._canvas = document.createElement('canvas');
this._ctx = this._canvas.getContext('2d');
this._canvasTexture = new CanvasTexture(this._canvas);
this._canvas.width = vtrack.displayWidth;
this._canvas.height = vtrack.displayHeight;

...

this._sink.getSample(sec).then((sample) => {
  const vFrame = sample.toVideoFrame();
  this._ctx.drawImage(vFrame, 0, 0, this._canvas.width, this._canvas.height);
  vFrame.close();
  sample.close();
  this._canvasTexture.needsUpdate = true;
});

与视频同步的线条动画

为了以3D形式动画化线条并使其与视频保持同步,使用了Blender。在与参考镜头相同的时间轴上,在Blender中构建了以下元素,并通过Python导出了一个轻量级JSON:

  • 线条轨迹
  • 出现和消失的时机(通过沿线条移动立方体来控制)

关于 mount inc.

我们mount inc.策划并制作广泛的创意作品,主要是网站——从传达产品吸引力的活动和推广网站,到时装品牌的品牌信息网站和在线商店。我们还涉及电影、印刷和其他媒体。在每一个项目中,我们都力求不做妥协。我们真诚地面对每一个挑战,旨在创造出我们可以自豪地向任何人展示的作品——我们自己真正热爱的作品。以这种精神为核心,我们继续创作能为客户和世界带来有意义价值的作品。

请访问我们的公司网站,查看更多项目。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计