如何让Phaser 3着色器不随摄像机移动?
Phaser全屏后处理水效果固定问题
问题描述
在Phaser游戏中使用PostFXPipeline实现全屏水效果时,移动角色后,水效果会随摄像机同步移动,无法保持固定覆盖在屏幕上。
问题原因
当前代码用gl_FragCoord.xy / uResolution.xy计算UV坐标,但gl_FragCoord对应的是世界空间的像素位置,当摄像机移动时,这个坐标会跟着场景内容偏移,导致效果和场景绑定而非固定屏幕。而Phaser的PostFXPipeline已经通过outTexCoord传递了标准化的屏幕UV坐标(范围0-1,左上角为(0,0),右下角为(1,1)),这才是固定屏幕效果应该用的坐标。
解决方法
- 替换UV计算逻辑:用
outTexCoord替代gl_FragCoord的计算方式 - 移除不必要的
uResolutionuniform:因为outTexCoord本身是标准化坐标,无需再依赖分辨率做转换
修改后的完整代码
着色器代码
const waterFragShader = ` #ifdef GL_ES precision mediump float; #endif uniform float uTime; uniform sampler2D uMainSampler; varying vec2 outTexCoord; void main(void) { vec2 uv = outTexCoord; vec2 distortion = vec2( sin(uv.y * 10.0 + uTime) * 0.002, cos(uv.x * 10.0 + uTime) * 0.002 ); vec4 texture_color = texture2D(uMainSampler, uv + distortion); vec4 k = vec4(uTime)*0.6; k.xy = uv * 7.0; float val1 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.5)); float val2 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.2)); float val3 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.5)); float pattern = pow(min(min(val1,val2),val3), 7.0) * 2.0; vec4 pattern_color = vec4(1, 1, 1, pattern); vec4 color = vec4(pattern, pattern, pattern, pattern); gl_FragColor = mix(texture_color, pattern_color, pattern_color.a); } `;
Pipeline类代码
class WaterPipeline extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline { constructor(game) { super({ game, name: "Water", fragShader: waterFragShader, }); } onPreRender() { this.set1f("uTime", this.game.loop.time / 1000); } }
说明
修改后,水效果会基于固定的屏幕UV坐标生成,无论摄像机如何移动,效果都会稳定覆盖在整个屏幕上,不会随场景内容偏移。
内容的提问来源于stack exchange,提问作者Javier Villanueva
相关产品推荐
相关产品推荐

