跳转到内容

后处理效果

PostProcess API 在每个相机渲染完成后应用全屏着色器效果。效果通过 PostProcessStack 对象管理,可以绑定到不同的相机,让每个相机拥有不同的效果。

快速开始

import { PostProcess } from 'esengine';
// 创建效果栈
const fx = PostProcess.createStack();
fx.addPass('vignette', PostProcess.createVignette());
fx.setUniform('vignette', 'u_intensity', 0.6);
fx.setUniform('vignette', 'u_softness', 0.5);
// 绑定到相机实体
PostProcess.bind(cameraEntity, fx);

PostProcessStack

PostProcessStack 是可复用的效果链。创建一个 Stack,添加 pass,然后绑定到一个或多个相机:

const fx = PostProcess.createStack();
// 添加效果(按顺序执行)
fx.addPass('blur', PostProcess.createBlur());
fx.addPass('vignette', PostProcess.createVignette());
// 配置 uniform
fx.setUniform('blur', 'u_intensity', 3.0);
fx.setUniform('vignette', 'u_intensity', 0.8);
fx.setUniform('vignette', 'u_softness', 0.3);
// 绑定到相机 — 效果立即生效
PostProcess.bind(cameraEntity, fx);

Stack 方法

方法说明
addPass(name, shader)追加一个命名 pass
removePass(name)按名称移除 pass
clearPasses()移除所有 pass
setEnabled(name, enabled)启用或禁用 pass
setUniform(pass, name, value)设置 float uniform
setUniformVec4(pass, name, value)设置 vec4 uniform
setAllPassesEnabled(enabled)一次性启用或禁用所有 pass
passCountpass 总数
enabledPassCount已启用的 pass 数
destroy()销毁 Stack(自动解绑所有相机)

相机绑定

// 绑定 Stack 到相机
PostProcess.bind(cameraEntity, fx);
// 查询当前 Stack
const stack = PostProcess.getStack(cameraEntity); // 无绑定时返回 null
// 解绑(相机不再应用效果)
PostProcess.unbind(cameraEntity);

内置效果

方法效果Uniform
createBloomExtract()辉光:提取亮像素u_threshold (0–1) — 亮度截断
createBloomKawase(iteration)辉光:Kawase 模糊 passu_radius — 模糊扩散, u_resolution(自动)
createBloomComposite()辉光:合成回原图u_intensity — 辉光强度, u_sceneTexture(自动)
createBlur()高斯模糊u_intensity — 模糊扩散
createVignette()暗角u_intensity (0–1) — 效果强度, u_softness (0–1) — 衰减
createGrayscale()去饱和u_intensity (0–1) — 混合比例
createChromaticAberration()RGB 通道偏移u_intensity — 偏移量

辉光 (Bloom)

Bloom 使用多 pass 管线:提取亮像素、多次 Kawase 模糊迭代、最后合成回原图。比单 pass 方案质量更高:

const fx = PostProcess.createStack();
// 1. 提取亮像素
fx.addPass('bloom_extract', PostProcess.createBloomExtract());
fx.setUniform('bloom_extract', 'u_threshold', 0.4);
// 2. Kawase 模糊(多次迭代产生更宽、更平滑的模糊)
for (let i = 0; i < 5; i++) {
fx.addPass(`bloom_kawase_${i}`, PostProcess.createBloomKawase(i));
fx.setUniform(`bloom_kawase_${i}`, 'u_radius', 1.0);
}
// 3. 将辉光合成回原始场景
fx.addPass('bloom_composite', PostProcess.createBloomComposite());
fx.setUniform('bloom_composite', 'u_intensity', 1.5);
PostProcess.bind(cameraEntity, fx);

模糊 (Blur)

9 次采样高斯模糊。u_intensity 越大模糊越强:

const fx = PostProcess.createStack();
fx.addPass('blur', PostProcess.createBlur());
fx.setUniform('blur', 'u_intensity', 3.0);
PostProcess.bind(cameraEntity, fx);

暗角 (Vignette)

使屏幕边缘变暗:

const fx = PostProcess.createStack();
fx.addPass('vignette', PostProcess.createVignette());
fx.setUniform('vignette', 'u_intensity', 0.6);
fx.setUniform('vignette', 'u_softness', 0.5);
PostProcess.bind(cameraEntity, fx);

灰度 (Grayscale)

在原色和灰度之间混合:

const fx = PostProcess.createStack();
fx.addPass('grayscale', PostProcess.createGrayscale());
fx.setUniform('grayscale', 'u_intensity', 1.0); // 完全灰度
PostProcess.bind(cameraEntity, fx);

色差 (Chromatic Aberration)

偏移 R 和 B 通道以产生镜头畸变效果:

const fx = PostProcess.createStack();
fx.addPass('chromatic', PostProcess.createChromaticAberration());
fx.setUniform('chromatic', 'u_intensity', 2.0);
PostProcess.bind(cameraEntity, fx);

屏幕级后处理

屏幕级效果在所有相机渲染完成后应用于最终合成画面,适用于全局渐变、全屏暗角、电影黑边等效果。

import { PostProcess } from 'esengine';
const screenFx = PostProcess.createStack();
screenFx.addPass('vignette', PostProcess.createVignette());
screenFx.setUniform('vignette', 'u_intensity', 0.8);
// 对最终合成画面应用效果(在所有相机之后)
PostProcess.setScreenStack(screenFx);
// 移除屏幕效果
PostProcess.setScreenStack(null);

后处理 Volume

Volume 允许空间后处理 — 当相机进入指定区域时激活效果。多个 Volume 按优先级混合,类似 Unity 的 Post Process Volume。

Volume 属性

属性类型默认值说明
isGlobalbooleantrue为 true 时忽略形状,全局生效
shape'box' | 'sphere''box'触发区域形状
size{ x, y }{ x: 5, y: 5 }Box 半尺寸 / Sphere 半径
prioritynumber0高优先级覆盖低优先级
weightnumber1混合权重(0–1)
blendDistancenumber0边缘渐入距离(世界单位)

Volume 混合

当多个 Volume 重叠时,系统使用 SDF 距离函数评估每个 Volume 的影响范围,按优先级混合效果参数:

// 全局 Volume — 始终生效,低优先级(基础层)
// 实体 A: PostProcessVolume,isGlobal=true,priority=0
// effects: [{ type: 'vignette', enabled: true, uniforms: { u_intensity: 0.3 } }]
// 局部 Volume — 相机进入区域时激活
// 实体 B: PostProcessVolume,isGlobal=false,shape='sphere',size={x:10,y:10}
// priority=1,blendDistance=3
// effects: [{ type: 'blur', enabled: true, uniforms: { u_intensity: 5.0 } }]

编辑器工作流

在编辑器中为 Camera 实体添加 PostProcessVolume 组件即可可视化配置效果:

  1. 在 Hierarchy 中选中 Camera 实体
  2. 添加组件PostProcessVolume
  3. 配置 Volume 属性:
    • Is Global — 勾选为全局效果,取消勾选为空间触发
    • Priority / Weight — 控制混合顺序和强度
    • Shape / Size / Blend Distance — 定义空间触发区域(非全局时可见)
  4. 点击 添加效果 并从内置效果列表中选择
  5. 使用滑块调整参数

效果在场景视图和游戏视图中都可见。组件数据随场景文件保存。

自定义 Pass

编写自定义片段着色器。顶点着色器使用固定的全屏三角形 — 你只需编写片段着色器:

import { Material, PostProcess } from 'esengine';
const invertShader = Material.createShader(
`#version 300 es
precision highp float;
layout(location = 0) in vec2 a_position;
layout(location = 1) in vec2 a_texCoord;
out vec2 v_texCoord;
void main() {
v_texCoord = a_texCoord;
gl_Position = vec4(a_position, 0.0, 1.0);
}`,
`#version 300 es
precision highp float;
in vec2 v_texCoord;
uniform sampler2D u_texture;
uniform float u_intensity;
out vec4 fragColor;
void main() {
vec4 color = texture(u_texture, v_texCoord);
vec3 inverted = mix(color.rgb, 1.0 - color.rgb, u_intensity);
fragColor = vec4(inverted, color.a);
}`
);
const fx = PostProcess.createStack();
fx.addPass('invert', invertShader);
fx.setUniform('invert', 'u_intensity', 1.0);
PostProcess.bind(cameraEntity, fx);

参见材质与着色器了解更多着色器编写方法。

示例:暂停菜单模糊

游戏暂停时启用模糊和灰度效果:

import { PostProcess } from 'esengine';
const pauseFx = PostProcess.createStack();
pauseFx.addPass('blur', PostProcess.createBlur());
pauseFx.addPass('gray', PostProcess.createGrayscale());
pauseFx.setAllPassesEnabled(false);
PostProcess.bind(cameraEntity, pauseFx);
function setPaused(paused: boolean) {
pauseFx.setAllPassesEnabled(paused);
pauseFx.setUniform('blur', 'u_intensity', 4.0);
pauseFx.setUniform('gray', 'u_intensity', 0.6);
}

示例:不同相机使用不同效果

// 主相机 — 辉光 + 暗角
const mainFx = PostProcess.createStack();
mainFx.addPass('bloom_extract', PostProcess.createBloomExtract());
mainFx.setUniform('bloom_extract', 'u_threshold', 0.4);
for (let i = 0; i < 5; i++) {
mainFx.addPass(`bloom_kawase_${i}`, PostProcess.createBloomKawase(i));
}
mainFx.addPass('bloom_composite', PostProcess.createBloomComposite());
mainFx.setUniform('bloom_composite', 'u_intensity', 1.5);
mainFx.addPass('vignette', PostProcess.createVignette());
mainFx.setUniform('vignette', 'u_intensity', 0.6);
PostProcess.bind(mainCamera, mainFx);
// 小地图相机 — 灰度
const minimapFx = PostProcess.createStack();
minimapFx.addPass('gray', PostProcess.createGrayscale());
minimapFx.setUniform('gray', 'u_intensity', 0.5);
PostProcess.bind(minimapCamera, minimapFx);

生命周期

方法说明
PostProcess.createStack()创建新的效果栈
PostProcess.bind(camera, stack)将 Stack 绑定到相机
PostProcess.unbind(camera)解绑相机的 Stack
PostProcess.getStack(camera)获取已绑定的 Stack(无则返回 null)
PostProcess.setScreenStack(stack)设置屏幕级效果栈(传 null 清除)
PostProcess.screenStack获取当前屏幕级效果栈
PostProcess.init(width, height)初始化管线(自动调用)
PostProcess.shutdown()关闭管线
PostProcess.resize(width, height)更新帧缓冲尺寸(自动调用)
PostProcess.begin()开始捕获场景用于后处理
PostProcess.end()结束捕获并执行所有效果 pass
PostProcess.createBloomExtract()创建辉光亮度提取着色器
PostProcess.createBloomKawase(iteration)创建辉光 Kawase 模糊着色器
PostProcess.createBloomComposite()创建辉光合成着色器
PostProcess.createBlur()创建模糊效果着色器
PostProcess.createVignette()创建暗角效果着色器
PostProcess.createGrayscale()创建灰度效果着色器
PostProcess.createChromaticAberration()创建色差效果着色器

下一步