Remotion LabRemotion Lab
視覺設計Shaders

Shaders

在 Remotion 中使用 WebGL Shaders 建立進階視覺效果。

什麼是 Shader?

Shader 是在 GPU 上執行的小程式,可以做到純 CSS 難以實現的視覺效果:液態效果、光暈、雜訊紋理等。

在 Remotion 中,你可以用 <canvas> 元素搭配 WebGL 來執行 Shader。

基本架構

import { useCurrentFrame, useVideoConfig, AbsoluteFill } from "remotion";
import { useRef, useEffect } from "react";
 
const FRAGMENT_SHADER = `
  precision mediump float;
  uniform float u_time;
  uniform vec2 u_resolution;
 
  void main() {
    vec2 uv = gl_FragCoord.xy / u_resolution;
    float color = sin(uv.x * 10.0 + u_time) * 0.5 + 0.5;
    gl_FragColor = vec4(color, uv.y, 1.0 - color, 1.0);
  }
`;
 
export const ShaderScene: React.FC = () => {
  const frame = useCurrentFrame();
  const { width, height, fps } = useVideoConfig();
  const canvasRef = useRef<HTMLCanvasElement>(null);
 
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
 
    const gl = canvas.getContext("webgl");
    if (!gl) return;
 
    // 建立和編譯 shader...
    // 設定 uniform 值:u_time = frame / fps
    // 繪製
  }, [frame, width, height, fps]);
 
  return (
    <AbsoluteFill>
      <canvas ref={canvasRef} width={width} height={height} />
    </AbsoluteFill>
  );
};

重點:用 frame / fps 作為 shader 的時間輸入(u_time),確保每一幀的結果都是確定性的。

搭配 Three.js

更方便的做法是用 @remotion/three

npm install @remotion/three three @types/three
import { ThreeCanvas } from "@remotion/three";
import { useCurrentFrame } from "remotion";
 
export const ThreeScene: React.FC = () => {
  const frame = useCurrentFrame();
 
  return (
    <ThreeCanvas>
      <ambientLight intensity={0.5} />
      <mesh rotation={[0, frame * 0.05, 0]}>
        <boxGeometry args={[2, 2, 2]} />
        <meshStandardMaterial color="#6366f1" />
      </mesh>
    </ThreeCanvas>
  );
};

注意事項

  • Shader 的時間必須來自 useCurrentFrame(),不能用 Date.now()requestAnimationFrame
  • WebGL 渲染在不同機器上可能有微小差異
  • @remotion/three 提供了 <ThreeCanvas> 確保 Three.js 與 Remotion 正確同步

小結

  • Shader 用於進階視覺效果(液態、光暈、雜訊等)
  • frame / fps 作為 shader 的時間輸入
  • @remotion/three 是在 Remotion 中使用 Three.js 最方便的方式
  • 確保所有動態值都來自 useCurrentFrame()