melonjs-effects-and-shaders 是做什么的?
使用此技能处理 melonJS 中的后期处理效果、自定义着色器、混合模式和色彩分级。涵盖内置 ShaderEffect 预设、在可渲染对象和摄像机上的 addPostEffect、编写自定义双语 GLSL/WGSL 效果、screen_texture 内置变量,以及效果在 Canvas 回退中静默失效的原因。触发关键词:ShaderEffect, addPostEffect, removePostEffect, getPostEffect, VignetteEffect, GlowEffect, BlurEffect, PixelateEffect, ScanlineEffect, shader, GLSL, WGSL, uniform, setUniform, setTexture, setTime, blendMode, colorMatrix, screen_texture, toFrameTexture, post effect, filter。
快速使用
import { ShaderEffect, VignetteEffect } from "@melonjs/melonjs";
// 在摄像机中应用暗角效果
me.game.viewport.addPostEffect(new VignetteEffect());
内置 ShaderEffect 预设
melonJS 提供了一系列可直接使用的内置效果预设:
- VignetteEffect:在屏幕边缘添加暗角效果。
- GlowEffect:添加发光/辉光效果。
- BlurEffect:高斯模糊效果。
- PixelateEffect:像素化效果。
- ScanlineEffect:扫描线/CRT 效果。
所有预设均继承自 ShaderEffect 基类,使用方式一致。
添加与移除效果
在摄像机层级添加
// 添加效果
const blur = new BlurEffect();
me.game.viewport.addPostEffect(blur);
// 稍后移除
me.game.viewport.removePostEffect(blur);
在可渲染对象上添加
const sprite = new me.Sprite(0, 0, { image: "hero" });
sprite.addPostEffect(new GlowEffect());
获取已添加的效果
const effects = me.game.viewport.getPostEffect();
// effects 为 ShaderEffect 实例数组
自定义着色器效果
melonis 支持编写自定义的 GLSL 与 WGSL 双语言着色器效果,确保同时兼容 WebGL 和 WebGPU。
基本结构
class MyCustomEffect extends ShaderEffect {
constructor() {
super({
name: "MyCustomEffect",
vertex: "#version 300 es\n...", // GLSL 顶点着色器
fragment: "#version 300 es\n..." // GLSL 片段着色器
});
// 对于 WebGPU,提供 WGSL 版本
this.wgslVertex = `...`;
this.wgslFragment = `...`;
}
}
传递 Uniform 值
class MyEffect extends ShaderEffect {
constructor() {
super({ ... });
this._intensity = 1.0;
}
setUniforms(shader) {
shader.setUniform("uIntensity", this._intensity);
shader.setUniform("uTime", me.game.getTime());
}
}
使用纹理
// 设置纹理 uniform
shader.setTexture("uTexture", someTexture);
// 使用 screen_texture 访问前一帧的屏幕图像
// 在片段着色器中定义:uniform sampler2D screen_texture;
时间控制
// 在更新循环中更新时间 uniform
shader.setTime(me.game.getTime());
混合模式与色彩矩阵
设置混合模式
// 混合模式影响绘制时的颜色混合行为
renderable.blendMode = me.BlendMode.NORMAL;
// 可选值:NORMAL, ADDITIVE, MULTIPLY, SCREEN 等
色彩矩阵
// 通过 colorMatrix 调整颜色
const matrix = [
0.5, 0.5, 0.5, 0, 0,
0.5, 0.5, 0.5, 0, 0,
0.5, 0.5, 0.5, 0, 0,
0, 0, 0, 1, 0
];
// 应用色彩矩阵作为后期效果
class ColorMatrixEffect extends ShaderEffect {
constructor() {
super({
name: "ColorMatrix",
fragment: `
precision highp float;
uniform sampler2D screen_texture;
uniform mat4 uColorMatrix;
varying vec2 vUv;
void main() {
vec4 color = texture2D(screen_texture, vUv);
gl_FragColor = uColorMatrix * color;
}
`
});
}
setUniforms(shader) {
shader.setUniform("uColorMatrix", matrix);
}
}
帧纹理操作
// 将当前帧渲染为纹理
const frameTex = me.video.renderer.toFrameTexture();
// 可将 frameTex 用于后续效果或纹理
常见陷阱:Canvas 回退中的效果
melonJS 在无法使用 WebGL/WebGPU 时会回退到 Canvas2D 渲染模式。在此模式下,自定义着色器不会执行。效果会静默失败而不会报错。
检查当前渲染器类型:
console.log(me.video.renderer.type);
// "WebGL"、"WebGPU" 或 "Canvas"
建议: 在生产环境中始终检测 WebGL 支持,并在 Canvas 模式下降级使用内置效果。
完整示例
import { ShaderEffect, VignetteEffect } from "@melonjs/melonjs";
class SepiaEffect extends ShaderEffect {
constructor() {
super({
name: "Sepia",
fragment: `
precision highp float;
uniform sampler2D screen_texture;
varying vec2 vUv;
void main() {
vec4 color = texture2D(screen_texture, vUv);
float r = dot(color.rgb, vec3(0.393, 0.769, 0.189));
float g = dot(color.rgb, vec3(0.349, 0.686, 0.168));
float b = dot(color.rgb, vec3(0.272, 0.534, 0.131));
gl_FragColor = vec4(r, g, b, color.a);
}
`
});
}
}
// 应用
const sepia = new SepiaEffect();
me.game.viewport.addPostEffect(sepia);
// 3 秒后移除
setTimeout(() => {
me.game.viewport.removePostEffect(sepia);
}, 3000);
相关链接
注意事项
- 自定义着色器需同时提供 GLSL 和 WGSL 版本以支持 WebGPU。
- screen_texture 是一个特殊的内置 uniform,良用于访问前一帧渲染结果。
- Canvas 回退模式下效果不会抛出错误,应主动检测渲染器类型。
- 建议在文档中记录颜色分量的取值范围(通常为 0.0 到 1.0)。