Phaser 着色器 #
着色器概述 #
着色器是运行在 GPU 上的小程序,用于控制图形渲染的各个方面。
text
┌─────────────────────────────────────────────────────────────┐
│ 着色器类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Vertex Shader(顶点着色器) │
│ ├── 处理顶点位置 │
│ ├── 变换坐标 │
│ └── 传递数据到片段着色器 │
│ │
│ Fragment Shader(片段着色器) │
│ ├── 处理像素颜色 │
│ ├── 纹理采样 │
│ └── 计算最终输出 │
│ │
└─────────────────────────────────────────────────────────────┘
基本着色器 #
加载着色器 #
javascript
preload() {
this.load.glsl('bundle', 'assets/shaders/bundle.glsl.js');
}
preload() {
this.load.shader('fire', 'assets/shaders/fire.frag');
this.load.shader('water', 'assets/shaders/water.frag');
}
使用内置着色器 #
javascript
const shader = this.add.shader('Fire', 400, 300, 800, 600);
shader.setUniform('size.value', 0.0);
shader.setUniform('mouse', [pointer.x, pointer.y]);
创建着色器对象 #
javascript
const shader = this.add.shader({
name: 'MyShader',
frag: `
precision mediump float;
uniform vec2 resolution;
uniform float time;
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
gl_FragColor = vec4(uv.x, uv.y, 0.5 + 0.5 * sin(time), 1.0);
}
`
}, 400, 300, 800, 600);
GLSL 基础 #
数据类型 #
glsl
float value = 1.0;
int count = 10;
bool visible = true;
vec2 position = vec2(0.5, 0.5);
vec3 color = vec3(1.0, 0.0, 0.0);
vec4 rgba = vec4(1.0, 0.0, 0.0, 1.0);
mat2 rotation = mat2(1.0, 0.0, 0.0, 1.0);
mat3 transform = mat3(1.0);
mat4 projection = mat4(1.0);
sampler2D texture;
内置变量 #
glsl
gl_FragCoord
gl_FragColor
gl_PointCoord
varying vec2 vTexCoord;
attribute vec2 inPosition;
内置函数 #
glsl
sin(x)
cos(x)
tan(x)
asin(x)
acos(x)
atan(x)
abs(x)
sign(x)
floor(x)
ceil(x)
fract(x)
mod(x, y)
min(x, y)
max(x, y)
clamp(x, min, max)
mix(x, y, a)
step(edge, x)
smoothstep(edge0, edge1, x)
length(x)
distance(x, y)
dot(x, y)
cross(x, y)
normalize(x)
reflect(I, N)
refract(I, N, eta)
texture2D(sampler, coord)
texture2D(sampler, coord, bias)
自定义着色器 #
简单颜色着色器 #
javascript
const fragShader = `
precision mediump float;
uniform vec2 resolution;
uniform float time;
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec3 color = vec3(uv.x, uv.y, 0.5);
gl_FragColor = vec4(color, 1.0);
}
`;
const shader = this.add.shader({
name: 'ColorShader',
frag: fragShader
}, 400, 300, 800, 600);
渐变着色器 #
javascript
const fragShader = `
precision mediump float;
uniform vec2 resolution;
uniform vec3 color1;
uniform vec3 color2;
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec3 color = mix(color1, color2, uv.y);
gl_FragColor = vec4(color, 1.0);
}
`;
const shader = this.add.shader({
name: 'GradientShader',
frag: fragShader,
uniforms: {
color1: { type: 'vec3', value: { x: 1.0, y: 0.0, z: 0.0 } },
color2: { type: 'vec3', value: { x: 0.0, y: 0.0, z: 1.0 } }
}
}, 400, 300, 800, 600);
波纹着色器 #
javascript
const fragShader = `
precision mediump float;
uniform vec2 resolution;
uniform float time;
uniform vec2 center;
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec2 p = uv - center;
float d = length(p);
float wave = sin(d * 20.0 - time * 5.0) * 0.5 + 0.5;
vec3 color = vec3(wave);
gl_FragColor = vec4(color, 1.0);
}
`;
const shader = this.add.shader({
name: 'WaveShader',
frag: fragShader,
uniforms: {
center: { type: 'vec2', value: { x: 0.5, y: 0.5 } }
}
}, 400, 300, 800, 600);
噪声着色器 #
javascript
const fragShader = `
precision mediump float;
uniform vec2 resolution;
uniform float time;
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
float n = noise(uv * 10.0 + time * 0.5);
gl_FragColor = vec4(vec3(n), 1.0);
}
`;
const shader = this.add.shader({
name: 'NoiseShader',
frag: fragShader
}, 400, 300, 800, 600);
纹理着色器 #
基本纹理 #
javascript
const fragShader = `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 resolution;
varying vec2 outTexCoord;
void main() {
vec4 color = texture2D(uMainSampler, outTexCoord);
gl_FragColor = color;
}
`;
灰度效果 #
javascript
const fragShader = `
precision mediump float;
uniform sampler2D uMainSampler;
varying vec2 outTexCoord;
void main() {
vec4 color = texture2D(uMainSampler, outTexCoord);
float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = vec4(vec3(gray), color.a);
}
`;
反色效果 #
javascript
const fragShader = `
precision mediump float;
uniform sampler2D uMainSampler;
varying vec2 outTexCoord;
void main() {
vec4 color = texture2D(uMainSampler, outTexCoord);
gl_FragColor = vec4(1.0 - color.rgb, color.a);
}
`;
模糊效果 #
javascript
const fragShader = `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 resolution;
uniform float blurAmount;
varying vec2 outTexCoord;
void main() {
vec2 texel = vec2(1.0 / resolution.x, 1.0 / resolution.y);
vec4 color = vec4(0.0);
for (int x = -4; x <= 4; x++) {
for (int y = -4; y <= 4; y++) {
vec2 offset = vec2(float(x), float(y)) * texel * blurAmount;
color += texture2D(uMainSampler, outTexCoord + offset);
}
}
color /= 81.0;
gl_FragColor = color;
}
`;
后处理效果 #
使用 Pipeline #
javascript
class GrayScalePipeline extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline {
constructor(game) {
super({
game: game,
name: 'GrayScale',
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
varying vec2 outTexCoord;
void main() {
vec4 color = texture2D(uMainSampler, outTexCoord);
float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = vec4(vec3(gray), color.a);
}
`
});
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
callbacks: {
postBoot: function(game) {
game.renderer.addPipeline('GrayScale', new GrayScalePipeline(game));
}
}
};
this.cameras.main.setPostPipeline('GrayScale');
自定义后处理 #
javascript
class VignettePipeline extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline {
constructor(game) {
super({
game: game,
name: 'Vignette',
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform float radius;
uniform float strength;
varying vec2 outTexCoord;
void main() {
vec4 color = texture2D(uMainSampler, outTexCoord);
vec2 position = outTexCoord - vec2(0.5);
float dist = length(position);
float vignette = smoothstep(radius, radius - strength, dist);
color.rgb *= vignette;
gl_FragColor = color;
}
`
});
}
onPreRender() {
this.set1f('radius', this.radius || 0.8);
this.set1f('strength', this.strength || 0.5);
}
}
着色器 Uniform #
设置 Uniform #
javascript
const shader = this.add.shader('MyShader', 400, 300, 800, 600);
shader.setUniform('time', this.time.now / 1000);
shader.setUniform('resolution', [800, 600]);
shader.setUniform('color', { x: 1.0, y: 0.0, z: 0.0 });
shader.setUniform('matrix', [1, 0, 0, 0, 1, 0, 0, 0, 1]);
Uniform 类型 #
javascript
uniforms: {
floatVal: { type: '1f', value: 1.0 },
vec2Val: { type: 'vec2', value: { x: 0.5, y: 0.5 } },
vec3Val: { type: 'vec3', value: { x: 1.0, y: 0.0, z: 0.0 } },
vec4Val: { type: 'vec4', value: { x: 1.0, y: 1.0, z: 1.0, w: 1.0 } },
intVal: { type: '1i', value: 10 },
mat2Val: { type: 'mat2', value: [1, 0, 0, 1] },
mat3Val: { type: 'mat3', value: [1, 0, 0, 0, 1, 0, 0, 0, 1] },
mat4Val: { type: 'mat4', value: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }
}
着色器动画 #
javascript
create() {
this.shader = this.add.shader('Fire', 400, 300, 800, 600);
}
update() {
this.shader.setUniform('time', this.time.now / 1000);
}
完整示例 #
火焰着色器 #
javascript
const fireShader = `
precision mediump float;
uniform vec2 resolution;
uniform float time;
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(
mix(random(i), random(i + vec2(1.0, 0.0)), u.x),
mix(random(i + vec2(0.0, 1.0)), random(i + vec2(1.0, 1.0)), u.x),
u.y
);
}
float fbm(vec2 st) {
float value = 0.0;
float amplitude = 0.5;
for (int i = 0; i < 5; i++) {
value += amplitude * noise(st);
st *= 2.0;
amplitude *= 0.5;
}
return value;
}
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
uv.y = 1.0 - uv.y;
vec2 q = vec2(0.0);
q.x = fbm(uv + time * 0.1);
q.y = fbm(uv + vec2(1.0));
vec2 r = vec2(0.0);
r.x = fbm(uv + 1.0 * q + vec2(1.7, 9.2) + 0.15 * time);
r.y = fbm(uv + 1.0 * q + vec2(8.3, 2.8) + 0.126 * time);
float f = fbm(uv + r);
vec3 color = mix(
vec3(0.0, 0.0, 0.0),
vec3(0.5, 0.0, 0.0),
clamp(f * 2.0, 0.0, 1.0)
);
color = mix(
color,
vec3(0.9, 0.5, 0.0),
clamp(length(q), 0.0, 1.0)
);
color = mix(
color,
vec3(1.0, 0.9, 0.0),
clamp(length(r.x), 0.0, 1.0)
);
gl_FragColor = vec4(color, 1.0);
}
`;
create() {
this.fireShader = this.add.shader({
name: 'Fire',
frag: fireShader
}, 400, 300, 800, 600);
}
update() {
this.fireShader.setUniform('time', this.time.now / 1000);
}
下一步 #
现在你已经掌握了着色器,接下来学习 插件系统,了解如何扩展 Phaser 的功能!
最后更新:2026-03-29