SoPostEffectCustomPass

InventorModule
author MeVis Medical Solutions AG
package MeVisLab/Standard
dll SoRenderers
definition SoRenderers.def

Purpose

The SoPostEffectCustomPass allows to implement an own effect for the SoPostEffectRenderer module using GLSL shaders.

The module allows to access any number of named buffers as inputs and writes the output to the given output buffer.

The user provides a GLSL shader which is applied to a screen-space quad of the size of the output buffer. The GLSL shader will thus be called for each pixel/texel of the output buffer.

If one of the input buffers is the same as the output buffer, an extra output buffer will be generated and will be swapped after the shader was applied. This allows to easily write to buffers that the shader also reads from.

Details

The user-provided shader is basically a standard GLSL fragment shader (the vertex shader is provided by the module itself), which gets called for each output pixel/texel.

Buffers

In addition to standard GLSL, there is a special syntax to reference buffers:

@buffer bufferName param1=value1 ...

A concrete example to reference buffers is:

@buffer colorBuffer filter=linear;
@buffer depthBuffer;

This will allow to use the colorBuffer and depthBuffer inside of the shader. Note that the filter=linear parameter turns linear filtering on, so that accessing the colorBuffer will use linear texture sampling. The default is filter=nearest.

All buffers are just simple 2D textures using sampler2D, so you can get a value from a buffer using texture2D.

GLSL Shader

The following shows a simple GLSL shader that just outputs the input colors:

@buffer colorBuffer;
varying vec2 samplePos;

void main()
{
  gl_FragColor = texture2D(colorBuffer, samplePos);
}

This will just copy the colorBuffer to the output buffer. The built-in varying samplePos provides the center position of the current output pixel/texel.

Additional uniforms that are provided are:

// for the output buffer:
uniform vec2 outputTexelSize // the size of one texel in the output buffer (relative 0..1)
uniform vec2 outputSize      // the size of the output buffer

// for each @buffer:
uniform vec2 "bufferName" + TexelSize // the size of one texel in the given buffer (relative 0..1)
uniform vec2 "bufferName" + Size      // the size of the given buffer

// for multiple iterations:
uniform int  iteration;               // the iteration from 0 to iterations-1
uniform vec2 iterationDirection;      // (1.,0.) for even iterations, (0., 1.) for odd iterations

The most useful uniform is the outputTexelSize, since it can be used to access neighboring texels. The following shows how to access the 8 neighbors:

@buffer colorBuffer;
varying vec2 samplePos;

void main()
{
  vec4 color0 = texture2D(colorBuffer, samplePos + outputTexelSize * vec2(1.,0.));
  vec4 color1 = texture2D(colorBuffer, samplePos + outputTexelSize * vec2(0.,1.));
  vec4 color2 = texture2D(colorBuffer, samplePos + outputTexelSize * vec2(-1.,0.));
  vec4 color3 = texture2D(colorBuffer, samplePos + outputTexelSize * vec2(0.,-1.));
  vec4 color4 = texture2D(colorBuffer, samplePos + outputTexelSize * vec2(1.,1.));
  vec4 color5 = texture2D(colorBuffer, samplePos + outputTexelSize * vec2(-1.,-1.));
  vec4 color6 = texture2D(colorBuffer, samplePos + outputTexelSize * vec2(-1.,1.));
  vec4 color7 = texture2D(colorBuffer, samplePos + outputTexelSize * vec2(1.,-1.));
  gl_FragColor = (color0 + color1 + color2 + color3 + color4 + color5 + color6 + color7) / 8.;
}

This can be used to do filtering/averaging/edge detection or whatever effect is desired.

GLSL Shader Parameters

In addition to using the input buffers, you can provide any number of shader parameters and samplers using the input scene of this module, e.g. SoShaderParameter1f, SoMLSampler2D, …

Have a look at the GLSL shader framework for details. Note that the shader parameters are collected only once when using multiple iterations.

Tool functions

Some tool functions are provided which can be used in the GLSL shader. Currently these are:

// get the linear depth from 0 (eye) to 1 (far plane)
float getLinearEyeToFarDepth(sampler2D depthTexture, vec2 samplePos)

// get the linear depth from near to far in eye space
float getLinearDepth(sampler2D depthTexture, vec2 samplePos)

// pack the given normal into a positive vec3 to store it in RGB8/10.
vec3 packNormal(vec3 normal)

// unpack the normal which was packed by packNormal and read from a RGB8/10 buffer
vec3 unpackNormal(vec3 normal)

// Get the 3D eye position from the given depth, relative screenPos (0-1) and the
// inverse projection matrix.
// Example:
// float depth = texture2D(depthBuffer, samplePos).r;
// vec3 pos = getEyePositionFromDepth(depth, samplePos, gl_ProjectionMatrixInverse);
vec3 getEyePositionFromDepth(float depth, vec2 screenPos, mat4 inverseProjection)

Input Fields

child

name: child, type: SoNode

The input scene, which can be used to provide shader parameters and texture samplers using the GLSL shader framework (see GLSL shader framework).

Parameter Fields

Field Index

Blend Mode: Enum Output Buffer Name: String
Clear Alpha: Float Output Buffer Scale: Float
Clear Color: Color Output Buffer Type: Enum
Enabled: Bool Output Mode: Enum
fragmentShader: String resultShaderString: String
Iterations: Integer  
needsEmissive: Bool  
needsNormals: Bool  

Visible Fields

Enabled

name: enabled, type: Bool, default: TRUE

Enables/disables the effect.

Output Buffer Name

name: outputBufferName, type: String, default: colorBuffer

Select the output buffer name.

Output Buffer Scale

name: outputBufferScale, type: Float, default: 1

Select the scale of the output buffer (1. means screen size, 0.5 will be half the screen size, etc.).

Clear Alpha

name: clearAlpha, type: Float, default: 0

The alpha clear value.

Clear Color

name: clearColor, type: Color, default: 0 0 0

The clear color.

Iterations

name: iterations, type: Integer, default: 1, minimum: 1

The number of iterations that the shader is applied. The following uniform is updated from 0 to iterations-1:

uniform int iteration;

This makes most sense when using the same input and output buffer, this will cause input/output buffer swapping on each iteration. It can be used to implement e.g. separable filters with a horizontal and vertical pass or a growing kernel size on each pass.

Output Mode

name: outputMode, type: Enum, default: UseExistingBuffer

Selects the output mode.

Values:

Title Name Description
Use Existing Buffer UseExistingBuffer Uses an existing buffer.
Create Buffer CreateBuffer Creates a new buffer.

Output Buffer Type

name: outputBufferType, type: Enum, default: RGBA8

Choose the type of the output buffer.

Values:

Title Name
Rgb8 RGB8
Rgba8 RGBA8
Rgb16f RGB16F
Rgba16f RGBA16F
Rgb10 A2 RGB10_A2
R8 R8
R16f R16F
R32f R32F
Rgb32f RGB32F
Rgba32f RGBA32F
Rg16f RG16F
Rg32f RG32F

Blend Mode

name: blendMode, type: Enum, default: Replace

Chooses the blend mode that is used to blend the shader result over the output buffer.

Values:

Title Name
Replace Replace
Screen Screen
Add Add
Blend Blend
Premultiplied Blend PremultipliedBlend
Min Min
Max Max

Hidden Fields

needsNormals

name: needsNormals, type: Bool, default: FALSE

needsEmissive

name: needsEmissive, type: Bool, default: FALSE

fragmentShader

name: fragmentShader, type: String, default: // used input buffers:, @buffer colorBuffer filter=linear;, , // the current output texel position, varying vec2 samplePos;, , //uniform vec2 outputTexelSize;, //uniform vec2 outputSize;, , void main(), {,   // just multiply input buffer with red and return the result,   gl_FragColor = texture2D(colorBuffer, samplePos) * vec4(1.,0.,0.,1.);, },

resultShaderString

name: resultShaderString, type: String, persistent: no