使用pixi.js复现ShaderToy着色器时遇循环初始化错误求助
用Pixi.js复现ShaderToy着色器的问题解决
1. 修复for循环语法错误
你遇到的'for' : Invalid init declaration错误,是因为GLSL ES 1.0(对应旧版Pixi.js常用的WebGL1环境)不允许在for循环的初始化部分单独使用赋值表达式(O *= 0.)。
原ShaderToy代码里的O*=0.是用来重置颜色变量,但你的代码已经在循环前将O初始化为vec4(0.0),可以直接移除循环初始化里的O *= 0.,修改后的循环如下:
for(; i < 12.; O += length(min(r.y/abs(F),r)) / 300.0*(cos(++t+i+vec4(0,1,2,0))*l+l)) { F *= mat2(cos(l*.2-i++*--t/1e2+vec4(0,33,11,0))); }
如果后续代码需要保留重置逻辑,可将O *= 0.移到循环前面:
O *= 0.; for(; i < 12.; O += length(min(r.y/abs(F),r)) / 300.0*(cos(++t+i+vec4(0,1,2,0))*l+l)) { F *= mat2(cos(l*.2-i++*--t/1e2+vec4(0,33,11,0))); }
2. 关于fragCoord和fragColor的对应关系
ShaderToy里的fragCoord对应GLSL中的gl_FragCoord,fragColor对应gl_FragColor,你代码里的用法是正确的:
gl_FragCoord的原点在画布左下角,和ShaderToy的坐标系统一致;- 你代码中
F += F - r等价于F = 2.0 * gl_FragCoord.xy - iResolution.xy,和原ShaderToy中(fragCoord - 0.5*iResolution)的逻辑类似,仅缩放比例不同,不影响语法正确性。
3. Pixi.js完整适配步骤
编写适配后的片段着色器
修改后的片段着色器(兼容GLSL ES 1.0):
precision mediump float; uniform vec2 uResolution; // Pixi.js默认分辨率uniform uniform float uTime; // Pixi.js默认时间uniform void main(){ vec4 O = vec4(0.0); vec2 F = gl_FragCoord.xy; vec2 r = uResolution.xy; float i = .3; float l = length(F += F - r) / r.y + i; float t = uTime; O *= 0.; for(; i < 12.; O += length(min(r.y/abs(F), r)) / 300.0 * (cos(++t + i + vec4(0,1,2,0)) * l + l)) { F *= mat2(cos(l*.2 - i++ * --t/1e2 + vec4(0,33,11,0))); } gl_FragColor = O; }
在Pixi.js中应用着色器
通过创建Filter来应用自定义着色器:
import { Application, Filter, Sprite, Graphics } from 'pixi.js'; const app = new Application({ width: 800, height: 600 }); document.body.appendChild(app.view); // 使用Pixi默认顶点着色器 const vertexShader = ` attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; uniform mat3 projectionMatrix; varying vec2 vTextureCoord; void main(void) { gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); vTextureCoord = aTextureCoord; } `; // 传入上面修改后的片段着色器代码 const customFilter = new Filter(vertexShader, fragmentShader); // 创建全屏精灵承载滤镜 const sprite = Sprite.from(app.renderer.generateTexture( new Graphics().beginFill(0xffffff).drawRect(0, 0, 800, 600) )); sprite.filters = [customFilter]; app.stage.addChild(sprite); // 实时更新时间和分辨率uniform app.ticker.add(() => { customFilter.uniforms.uTime = app.ticker.lastTime / 1000; customFilter.uniforms.uResolution = [app.screen.width, app.screen.height]; });
4. 版本相关说明
这个错误确实和旧版Pixi.js有关:
- 旧版Pixi.js(v5及更早)默认使用WebGL1(GLSL ES 1.0),对for循环语法限制更严格,不允许在初始化部分使用非声明类表达式;
- 新版Pixi.js(v6+)支持WebGL2(GLSL ES 3.0),语法限制更少,原ShaderToy的循环写法可直接使用。如果项目允许,升级到最新版Pixi.js也能解决该问题。
内容的提问来源于stack exchange,提问作者Stéphane Laurent
相关产品推荐
相关产品推荐

