| layout | single |
|---|---|
| collection | sections |
| title | Custom Effects |
| draft | false |
| menu | main |
| weight | 40 |
Effects are headless fullscreen passes. They can be combined and rendered using the EffectPass. Just like passes, effects may perform initialization tasks, react to render size changes and execute supporting render operations if needed but they don't have access to an output buffer and are not supposed to render to screen by themselves.
TL;DR
shader.frag
uniform vec3 weights;
vec4 mainImage(in vec4 inputColor, in vec2 uv, in GData data) {
return vec4(inputColor.rgb * weights, inputColor.a);
}CustomEffect.js
import { Uniform, Vector3 } from "three";
import { Effect } from "postprocessing";
// Use a bundler plugin like esbuild-plugin-glsl to import shaders as text.
import fragmentShader from "./shader.frag";
export class CustomEffect extends Effect {
constructor() {
super("CustomEffect", fragmentShader, {
uniforms: new Map([
["weights", new Uniform(new Vector3())]
])
});
}
}Every effect must provide a fragment shader that implements at least one of these two functions:
vec4 mainImage(in vec4 inputColor, in vec2 uv, in GData data);
void mainUv(inout vec2 uv);Effects may also provide a vertex shader that implements the following function:
void mainSupport(in vec2 uv);Effects have access to the geometry data of the current fragment via the data parameter of the mainImage function. The EffectPass detects whether an effect reads a value from this struct and only fetches the relevant data from the respective textures when it's actually needed. If you wish to sample depth at another coordinate, use the predefined function float readDepth(in vec2 uv). To calculate the view Z based on depth, you can use the predefined function float getViewZ(in float depth). The GData is defined as follows:
struct GData {
vec3 position;
vec3 normal;
float depth;
float luminance;
float roughness;
}Effects that fetch additional samples from the input buffer inside the fragment shader are considered convolution effects. To prevent bad results, it is not allowed to have more than one convolution effect per EffectPass. These effects are also incompatible with effects that implement the mainUv function. The EffectPass will warn you when it encounters incompatible effects.
All shaders have access to the following uniforms:
uniform vec4 resolution; // screen resolution (xy), texel size (zw)
uniform vec3 cameraParams; // near, far, aspect
uniform float time;The fragment shader has access to the following additional uniforms:
struct GBuffer {
sampler2D color;
sampler2D depth;
sampler2D position;
sampler2D normal;
}
uniform GBuffer gBuffer;The following varyings are reserved:
varying vec2 vUv;Available vertex attributes:
attribute vec3 position;Available macros:
- If the main camera is a
PerspectiveCamera, the macroPERSPECTIVE_CAMERAwill be defined. - If the geometry pass uses a float type color buffer, the macro
FRAMEBUFFER_PRECISION_HIGHwill be defined.
Effects may define custom uniforms, varyings, functions and preprocessor macros as usual, but should not define global variables or constants.
Furthermore, the shader chunks common
and packing are included in the fragment shader by default. The functions packDepthToRGBA(v) and unpackRGBAToDepth(v) are also available under the aliases packFloatToRGBA(v) and unpackRGBAToFloat(v).
Effects can enable WebGL 1 shader extensions via the extensions constructor option. The available WebGLExtensions are DERIVATIVES, FRAG_DEPTH, DRAW_BUFFERS and SHADER_TEXTURE_LOD.
class MyEffect extends Effect {
constructor() {
super(name, fragmentShader, {
extensions: new Set([WebGLExtension.DERIVATIVES])
});
}
}