Skip to content

Custom Effects

Raoul v. R edited this page Nov 1, 2018 · 19 revisions

Introduction

Effects are lightweight fullscreen passes. They can be combined 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

Code Example

shader.frag
uniform vec3 weights;

void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {

	outputColor = vec4(inputColor.rgb * weights, inputColor.a);

}
CustomEffect.js
import { Uniform, Vector3 } from "three";
import { Effect } from "postprocessing";

// Using rollup-plugin-string to import text files.
import fragment from "./shader.frag";

export class CustomEffect extends Effect {

	constructor() {

		super("CustomEffect", fragment, {

			uniforms: new Map([
				["weights", new Uniform(new Vector3())]
			])

		});

	}

}

Function Signatures

Every effect must provide a fragment shader that implements at least one of these two functions:

void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor);
void mainUv(inout vec2 uv);

If the effect relies on depth, it can choose to implement a slightly different mainImage function:

void mainImage(const in vec4 inputColor, const in vec2 uv,
	const in float depth, out vec4 outputColor);

Effects may also provide a vertex shader that implements the following function:

void mainSupport();

However, most effects do not need a vertex shader.

Effect Attributes

Some effects perform special operations inside the fragment shader or require additional resources. There are currently two EffectAttributes available: CONVOLUTION and DEPTH. Most effects do not need to specify any attributes.

Attributes can be concatenated using the bitwise OR operator.

class MyEffect extends Effect {

	constructor() {

		super(name, fragmentShader, {
			attributes: EffectAttribute.CONVOLUTION | EffectAttribute.DEPTH
		});

	}

}

Convolution

Effects that fetch additional samples from the input buffer inside the fragment shader must specify the CONVOLUTION attribute. To prevent bad results, it is not allowed to have more than one effect with this attribute per EffectPass. Convolution effects are also incompatible with effects that implement the mainUv function. The EffectPass will warn you when it encounters incompatible effects.

Depth

The DEPTH attribute must be specified by effects that require a depth texture. When the EffectPass encounters an effect with this attribute, it will request a depth texture from the EffectComposer. If your fragment shader implements the depth variant of the mainImage function, depth will be read automatically and the value will be provided to your mainImage function. In case you wish to sample depth at another coordinate, use the predefined float readDepth(const in vec2 uv) function.

Uniforms, Macros and Varyings

All shaders have access to the following uniforms:

uniform vec2 resolution;
uniform vec2 texelSize;
uniform float cameraNear;
uniform float cameraFar;
uniform float aspect;
uniform float time;

The fragment shader has access to the following additional uniforms:

uniform sampler2D inputBuffer;
uniform sampler2D depthBuffer;

Effects may define custom uniforms, varyings, functions and preprocessor macros as usual, but should not define global variables or constants.

If the camera of the associated EffectPass is a PerspectiveCamera, the macro PERSPECTIVE_CAMERA will be defined. Furthermore, the shader chunks common and packing are included in the fragment shader.

Clone this wiki locally