Mọi bài viết

Dự án của tôiMột Đời — Lyric VideoDựng cảnh 2D, giữ nền tối

Phân tíchWeb

Dựng cảnh 2D nền tối cho lyric video bằng canvas

Engine canvas 2D cho lyric video: năm loại khối cảnh, chuyển cảnh bằng vệt sáng thay vì màn hình đen, hiệu ứng sáng chạy nổi trên CPU.

Phần hình của lyric video: engine canvas 2D viết tay gồm năm loại khối cảnh, chuyển cảnh bằng vệt sáng cộng màu và tan dần thay cho wipe màn hình đen, cùng loạt hiệu ứng sáng dựng từ sprite sẵn có để giữ chi phí CPU trong tầm kiểm soát.

Phần lời đã khớp tới mức từng chữ. Câu hỏi tiếp theo là hình: làm sao để 5 phút 28 giây ấy vừa tối, vừa đẹp, vừa không có khoảnh khắc nào khiến người xem phải nhíu mày.

Ràng buộc đặt ra trước khi vẽ

Ba điều kiện, theo đúng thứ tự ưu tiên:

  1. Giữ nền tối: đây là tinh thần hình ảnh của dự án, không đổi.
  2. Không có chuyển cảnh màn hình đen: màn hình tối sầm giữa hai câu hát làm nhịp phim đứt.
  3. Không hiện tên nguồn dữ liệu trên hình: người xem không cần biết lời lấy từ đâu hay timing dò bằng công cụ gì.

Và một ràng buộc kỹ thuật: máy render chỉ có CPU. Bản tham chiếu dùng ray-marching 3D, mỗi khung hình tính ánh sáng theo từng điểm ảnh, không chạy nổi. Nên hướng đi là 2D typography cộng hiệu ứng sáng.

Năm loại khối cảnh

Toàn bộ phim là một chuỗi khối, mỗi khối chỉ là một hàm của thời điểm t:

  • Title: mở đầu, tên bài và các dòng thông tin kỹ thuật chạy như log khởi động.
  • Lyric: khối chính gồm câu đang hát, chữ karaoke, dòng kế tiếp mờ phía sau.
  • Interlude: quãng nghỉ ngắn, giữ nền, hạ chữ xuống, để sáng tiếp tục động.
  • Break: quãng nghỉ dài (bài này có một quãng 32,5 giây) với cảnh núi chuyển động và phổ nhạc vẽ thành vòng.
  • Outro: chữ mờ dần rồi hết.

Vì mọi thứ đều là hàm của t, engine tất định: render lại đoạn nào cũng ra đúng khung hình cũ, không lo lệch. Đây là điều kiện để về sau vá lỗi từng đoạn ngắn thay vì render lại cả bài.

Chuyển cảnh: bỏ màn hình đen, thay bằng vệt sáng

Bản đầu tiên chuyển cảnh bằng wipe: bảy dải tối gần đen quét ngang. Nhìn từng khung hình riêng lẻ thì không sao, xem liền mạch thì khó chịu. Lỗi không ở màu tối. Cái làm mắt khựng là độ sáng tụt xuống rồi bật lên.

Cách sửa là bỏ hẳn wipe, thay bằng hai lớp:

  • Vệt sáng chạy chéo: ba dải mỏng màu vàng-xanh nhạt, vẽ ở chế độ hoà trộn cộng sáng (lighter), nên nó chỉ thêm sáng lên nền tối chứ không bao giờ làm tối đi.
  • Tan dần độ trong suốt: cảnh mới hiện vào trong 0,55 giây, cảnh cũ mờ đi trong 0,65 giây.

Kết quả: không còn khung nào tụt về đen, mà mắt vẫn nhận ra chỗ chuyển. Kiểm tra bằng số trên đoạn nghỉ giữa hai câu hát (18,1 giây, khung 4001–4545): độ sáng trung bình là 20,6 trên thang 0–255, cả phim là 24,5; khung tối nhất trong đoạn đó vẫn ở mức 19,4, không khung nào rơi xuống gần đen.

Hiệu ứng, nhưng phải đo được

Yêu cầu là cảnh sống động hơn hẳn. Cách làm là cộng nhiều lớp sáng nhỏ, mỗi lớp rẻ:

  • Sáu dải aurora bám theo năng lượng dải mid/low của nhạc, trôi chậm phía sau chữ.
  • 130 hạt bụi sáng bay lệch pha ở dải cao, mỗi hạt là một sprite gradient dựng sẵn từ đầu, không tạo gradient lại mỗi khung.
  • 48 tia bắn ra mỗi nhịp kick, đổi hướng theo hàm băm nên không lặp lại.
  • Vòng phổ 84 tia quanh tâm ở đoạn nhạc.
  • Zoom nhẹ theo kick, biên độ khoảng ±0,7%, đủ để thấy hình thở.
  • Tách màu ±2,2 điểm ảnh quanh chữ đang hát, tạo cảm giác rung nhẹ như đèn neon.
  • Vệt sáng chạy ngang theo tiến độ của câu hát, như một đầu đọc lướt qua dòng chữ.

Tất cả đều dùng hình dựng sẵn (sprite) hoặc vector, và chế độ hoà trộn cộng sáng, không có phép tính theo từng điểm ảnh nào trong engine. Chi phí đo được: 4,7 khung/giây trước khi thêm, 3,8 khung/giây sau khi thêm. Với 9.848 khung hình của cả bài, chênh lệch đó là khoảng 8 phút rưỡi render, đổi lại được cảnh sống hơn ở đoạn nhạc và ở hai quãng nghỉ dài.

Chữ

Chữ karaoke là thứ tốn công nhất và cũng là thứ người xem nhìn nhiều nhất:

  • Dòng đang hát hiện giữa khung, từng chữ đổi màu theo đúng thời lượng của nó.
  • Chữ đã hát xong chuyển sang màu nền sáng hơn, chữ chưa hát còn mờ.
  • Dòng kế tiếp hiện mờ nhỏ phía dưới, để mắt biết phim đang đi tới đâu.
  • Chữ chính dùng Be Vietnam Pro, các con số kỹ thuật dùng IBM Plex Mono.

Khối mở đầu và khối kết thúc cũng bỏ hết các dòng ghi tên nguồn dữ liệu và tên công cụ: chỉ còn tên bài, số câu, số khung hình và dòng cảm ơn. Hình không nói về quá trình làm ra nó nữa.

Vì sao chỉ cộng sáng lại rẻ và liền mạch

Một thứ tối và sống động không mâu thuẫn nhau: chỉ cần chỉ cộng sáng, không bao giờ trừ sáng, và mọi chuyển cảnh phải giữ nền liền mạch. Hướng này cũng tự nhiên rẻ về CPU, vì cộng sáng chỉ là vẽ thêm lớp mờ, không phải tính lại cả khung hình.

Gắn thẻ

canvas 2dlyric videotypographicrender 1080phiệu ứng sáng

Hỏi đáp

Vì sao chọn 2D thay vì dựng cảnh 3D?

Bản tham chiếu dùng ray-marching 3D, mỗi khung hình phải tính ánh sáng theo từng điểm ảnh, nên cần GPU. Máy render ở đây chỉ có CPU, nên hướng đi là 2D typography cộng hiệu ứng sáng, giữ được tinh thần hình ảnh mà chi phí mỗi khung thấp hơn nhiều lần.

Vì sao không dùng chuyển cảnh màn hình đen?

Vì nhịp phim bị đứt: mắt người xem đang theo chữ, màn hình tối sầm lại rồi bật chữ mới tạo cảm giác khựng. Thay vào đó là vệt sáng chạy chéo (chế độ hoà trộn cộng sáng) kèm tan dần độ trong suốt, nền tối vẫn liền mạch.

Hiệu ứng có làm chậm render nhiều không?

Đo tại 1080p trên CPU: trước khi thêm hiệu ứng là 4,7 khung/giây, sau khi thêm còn 3,8 khung/giây (3,75–3,78 ở lần chạy cả bài). Đổi lại cảnh sống hơn ở đoạn nhạc và ở các quãng nghỉ dài.

Làm sao để tập lệnh render tất định, xem lại đúng khung hình cũ?

Mọi thứ trong khung hình chỉ phụ thuộc thời điểm t, dùng hàm băm có hạt giống thay cho số ngẫu nhiên thật. Cùng một t luôn cho cùng một khung, nên render lại từng đoạn để kiểm tra là chính xác.

Nguồn tham khảo

  1. Canvas API — MDN Web Docs - MDN Web Docs
  2. globalCompositeOperation — MDN Web Docs - MDN Web Docs

Về tác giả

Ban biên tập

Viết cho Nhặt Nhạnh.

  • 159 bài
  • Viết phân tích
  • Quan tâm web