如何在JS文件中借助WebGL与GLSL运行来自Shadertoy的着色器?
Shadertoy代码移植到原生WebGL的适配说明
不能直接把Shadertoy的片元代码复制到你自己的WebGL片元着色器里直接用,Shadertoy做了大量底层封装,你需要做以下几处适配调整:
1. 替换片元着色器入口与内置变量
Shadertoy的默认渲染入口是void mainImage( out vec4 fragColor, in vec2 fragCoord ),和原生WebGL的标准结构有差异,你需要做对应替换:
- 把
mainImage函数改成main函数,删除两个参数定义 - Shadertoy的输出参数
fragColor直接替换为原生WebGL的内置输出变量gl_FragColor(WebGL1默认支持,WebGL2需要自行声明输出变量) - Shadertoy的输入参数
fragCoord对应原生WebGL的内置输入变量gl_FragCoord
示例修改前后对比:
// Shadertoy原版代码 void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord/iResolution.xy; fragColor = vec4(uv,0.0,1.0); }
// 适配后的WebGL片元着色器代码 void main() { vec2 uv = gl_FragCoord.xy/iResolution.xy; gl_FragColor = vec4(uv,0.0,1.0); }
2. 手动传入Shadertoy内置uniform变量
Shadertoy默认封装了常用的全局uniform参数,你需要在JS层手动给WebGL程序传递这些值,常用参数包括:
iResolution:vec3类型,对应画布的宽度、高度、像素比,每次画布尺寸变化时更新即可iTime:float类型,着色器运行的总时长,单位为秒,每帧渲染时用requestAnimationFrame返回的时间戳换算更新即可iMouse:vec4类型,对应鼠标坐标和点击状态,需要自行监听鼠标事件更新数值iChannel0~iChannel3:采样器类型,对应Shadertoy的4个输入纹理,需要自行加载纹理、绑定到对应纹理单元,再把纹理单元编号传给uniform
JS层传值的示例代码片段:
// 先获取uniform的位置 const iResolutionLoc = gl.getUniformLocation(program, 'iResolution'); const iTimeLoc = gl.getUniformLocation(program, 'iTime'); // 每帧渲染时更新uniform function render(time) { gl.uniform3f(iResolutionLoc, gl.canvas.width, gl.canvas.height, window.devicePixelRatio); gl.uniform1f(iTimeLoc, time / 1000); // 时间戳转秒 // 这里写你的绘制调用逻辑 requestAnimationFrame(render); } requestAnimationFrame(render);
3. 处理语法与特殊功能差异
- Shadertoy默认使用GLSL ES 300语法,如果你的WebGL环境用的是GLSL ES 100(WebGL1默认版本),需要把
texture采样函数改成texture2D,同时删除Shadertoy代码头部的版本声明 - 如果用到Shadertoy的多Pass缓冲、音频输入、视频输入等特殊功能,需要自行实现对应逻辑,比如多帧缓冲渲染、音频频谱分析等
内容的提问来源于stack exchange,提问作者GottaGaming
相关产品推荐
相关产品推荐

