着色器
你可以通过渲染到 <canvas> 元素在 Remotion 中使用 WebGL 着色器。
所有动画必须由 useCurrentFrame() 驱动,以确保在预览和最终输出期间具有确定性的渲染。
🌐 You can use WebGL shaders in Remotion by rendering to a <canvas> element.
All animations must be driven by useCurrentFrame() to ensure deterministic rendering during both preview and final output.
获取 WebGL 上下文
🌐 Retrieving a WebGL context
使用 useRef() 获取对 <canvas> 元素的引用,然后调用 canvas.getContext("webgl") 以获取 WebGLRenderingContext。初始化一次 GL 状态(例如编译着色器,设置缓冲区),然后每帧根据从 useCurrentFrame() 和 useVideoConfig() 获取的当前时间更新 uniform 值。
🌐 Get a reference to a <canvas> element using useRef(), then call canvas.getContext("webgl") to obtain a WebGLRenderingContext. Initialize the GL state once (e.g. compile shaders, set up buffers), then update uniforms each frame based on the current time derived from useCurrentFrame() and useVideoConfig().
示例
🌐 Example
以下组件渲染一个动画着色器。
time uniform 是由 frame / fps 计算得出的,使动画帧精确且确定性。
🌐 The following component renders an animated shader.
The time uniform is computed from frame / fps, making the animation frame-accurate and deterministic.
BurlFigure.tsximport {useCurrentFrame ,useVideoConfig ,AbsoluteFill } from 'remotion'; import {useCallback ,useRef ,useEffect } from 'react'; constVERTEX_SHADER = ` attribute vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); } `; constFRAGMENT_SHADER = ` #ifdef GL_ES precision mediump float; #endif uniform float time; uniform vec2 resolution; const float Pi = 3.14159; void main() { vec2 p = 0.001 * gl_FragCoord.xy; for(int i = 1; i < 7; i++) { vec2 newp = p; newp.x += 0.6 / float(i) * cos(float(i) * p.y + (time * 20.0) / 10.0 + 0.3 * float(i)) + 400.0 / 20.0; newp.y += 0.6 / float(i) * cos(float(i) * p.x + (time * 20.0) / 10.0 + 0.3 * float(i + 10)) - 400.0 / 20.0 + 15.0; p = newp; } vec3 col = vec3(0.5 * sin(3.0 * p.x) + 0.5, 0.5 * sin(3.0 * p.y) + 0.5, sin(p.x + p.y)); gl_FragColor = vec4(col, 1.0); } `; export constBurlFigure :React .FC = () => { constframe =useCurrentFrame (); const {fps ,width ,height } =useVideoConfig (); constcanvasRef =useRef <HTMLCanvasElement >(null); constglRef =useRef <{gl :WebGLRenderingContext ;timeLoc :WebGLUniformLocation ;resLoc :WebGLUniformLocation ; } | null>(null); constinitGl =useCallback ((canvas :HTMLCanvasElement ) => { constgl =canvas .getContext ('webgl'); if (!gl ) return null; constcompile = (type : number,src : string) => { consts =gl .createShader (type )!;gl .shaderSource (s ,src );gl .compileShader (s ); returns ; }; constprogram =gl .createProgram ()!;gl .attachShader (program ,compile (gl .VERTEX_SHADER ,VERTEX_SHADER ));gl .attachShader (program ,compile (gl .FRAGMENT_SHADER ,FRAGMENT_SHADER ));gl .linkProgram (program );gl .useProgram (program ); constbuf =gl .createBuffer ();gl .bindBuffer (gl .ARRAY_BUFFER ,buf );gl .bufferData (gl .ARRAY_BUFFER , newFloat32Array ([-1, -1, 1, -1, -1, 1, 1, 1]),gl .STATIC_DRAW ); constpos =gl .getAttribLocation (program , 'position');gl .enableVertexAttribArray (pos );gl .vertexAttribPointer (pos , 2,gl .FLOAT , false, 0, 0); return {gl ,timeLoc :gl .getUniformLocation (program , 'time')!,resLoc :gl .getUniformLocation (program , 'resolution')!, }; }, []);useEffect (() => { constcanvas =canvasRef .current ; if (!canvas ||glRef .current ) return;glRef .current =initGl (canvas ); }, [initGl ]);useEffect (() => { constctx =glRef .current ; if (!ctx ) return; const {gl ,timeLoc ,resLoc } =ctx ; consttime =frame /fps ;gl .viewport (0, 0,gl .canvas .width ,gl .canvas .height );gl .uniform1f (timeLoc ,time );gl .uniform2f (resLoc ,gl .canvas .width ,gl .canvas .height );gl .drawArrays (gl .TRIANGLE_STRIP , 0, 4); }, [frame ,fps ]); return ( <AbsoluteFill > <canvas ref ={canvasRef }width ={width }height ={height } /> </AbsoluteFill > ); };
着色器源代码:GLSL Sandbox。
将着色器绘制到 DOM 元素上
🌐 Drawing a shader to a DOM element
WebGL 着色器只能渲染到 <canvas> 元素。
你不能将着色器作为后期处理效果应用到任意 DOM 元素上。
🌐 WebGL shaders can only render into a <canvas> element.
You cannot apply a shader as a post-processing effect to arbitrary DOM elements.
渲染
🌐 Rendering
在渲染使用 WebGL 的视频时,你需要传递 --gl=angle 以确保无头浏览器使用 GPU:
🌐 When rendering a video that uses WebGL, you need to pass --gl=angle to ensure the headless browser uses the GPU:
npx remotion render MyComp --gl=angle如果没有这个标志,无头浏览器可能无法获得 WebGL 上下文。
🌐 Without this flag, the headless browser may not have a WebGL context available.
另请参阅
🌐 See also