Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Effect Merging

Raoul v. R edited this pageFeb 24, 2024 ·19 revisions

How It Works

TheEffect framework defines a simple shader format for easy merging via theEffectPass. Effects are merged into a single compound shader by gathering and prefixing shader functions, varyings, uniforms, macros and blend functions. The shader is then used to process texels from an input buffer which usually contains the rendered scene colors. Texels pass through the effect function chain and intermediate results are blended with previous results. The final result is written to an output buffer or to screen.

Effect Execution Order

Effect merging can drastically improve performance by reducing the amount of fullscreen render operations, but it's sometimes necessary to split effects into separate passes to achieve optimal results. For instance, SMAA is usually applied first to avoid conflicts with other effects but some effects can introduce new aliasing artifacts at a later stage. If that's the case, it can be better to run these effects in a separate pass before SMAA.

TheEffectPass sorts effects based on whether or not they read data from the input buffer or rely on depth. Other effects will be rendered in the order in which they were added. The recommended order for common effects is as follows:

Effect Order

  • SMAA
  • SSR (NYI)
  • SSAO
  • DoF
  • Motion Blur (NYI)
  • Chromatic Aberration
  • Bloom
  • God Rays
  • Vignette
  • Tone Mapping
  • LUT / Color Grading
  • Noise / Film Grain
  • PixelationEffect

Effect Compatibility

TheEffectPass prevents bad combinations of effects and informs the user about potential issues.

While it's technically possible to merge all kinds of effects, some combinations will produce undesired results like visual discontinuities and artifacts. Problematic effects either modify the screen coordinates inside the fragment shader or read additional data from the input buffer. To use such effects together, you'll need to use multipleEffectPass instances. The following table shows which combinations work well together and which don't:

+UV TransformConvolutionOther
UV Transform✔️✔️
Convolution✔️
Other✔️✔️✔️

UV Transform = Modifies screen coordinates
Convolution = Reads data from input buffer

UV Transform + Convolution

The following example shows the result of combining aPixelationEffect with anSMAAEffect:

SMAAwith PixelationExaggerated Pixelation
uv01uv02uv03

ThePixelationEffect transforms the screen coordinates that are passed to theSMAAEffect. The latter calculates its own coordinate offsets to blend texels with neighboring texels from the input buffer. These offsets won't be affected by the pixelation transformation which causes the antialiased lines to show up as artifacts in the final image. To better highlight the artifacts, the image on the right shows an extreme case where thePixelationEffect reduces the scene into a single grey pixel.

There is no feasible way to ensure that all custom texture coordinate calculations go through the same transformation. The best solution is to render these effects in separate passes.

Convolution + Convolution

Combining convolution effects leads to incorrect results because the contents of the input buffer remain unchanged while theEffectPass is running. A convolution effect reads additional data from the input buffer and applies it to the current texel. If two convolution effects are executed in the same shader, then the second one will work with outdated data. To better illustrate this problem, consider the following example:

Merging Convolution Operators

// A 1-dimensional texture with one color channel.constinputBuffer=[60,0,255,127];// A simple convolution algorithm.functionblur(inputColor,i,inputBuffer){// Offset and clamp to edge.constj=Math.max(i-1,0);constk=Math.min(i+1,inputBuffer.length-1);// Calculate the average.return(inputColor+inputBuffer[j]+inputBuffer[k])/3;}// Single pass (wrong way).constoutputColor=blur(inputBuffer[1],1,inputBuffer);// => 105console.log("incorrect:",blur(outputColor,1,inputBuffer));// => 140// Two passes (right way).constoutputBuffer=[0,0,0,0];outputBuffer[0]=blur(inputBuffer[0],0,inputBuffer);// => 40outputBuffer[1]=blur(inputBuffer[1],1,inputBuffer);// => 105outputBuffer[2]=blur(inputBuffer[2],2,inputBuffer);// => 127.33outputBuffer[3]=blur(inputBuffer[3],3,inputBuffer);// => 169.66console.log("correct:",blur(outputBuffer[1],1,outputBuffer));// => 90.77

Clone this wiki locally


[8]ページ先頭

©2009-2025 Movatter.jp