GPU Displace actor

  • Following some demands concerning a GPU displace actor, I propose a first shader. Its a little bit primitive but it works as waited.

    Feel free to adapt it, you can add a color sensibility. If you have a alpha layer in input 1 and you need to output it, its necessary to premultiply the alpha layer (not made here).


    a Displace Shader Actor

    proposed by Jacques Hoepffner

    after isadora Werkstatt 2017

    [MFC EDIT] Please note that this will not give the same results as Isadora's built in displace actor.


    // 2 texture inputs

    uniform sampler2D tex0;

    uniform sampler2D tex1;

    // offset input

    // ISADORA_FLOAT_PARAM(offsetX, offx, 0.0, 10.0, 5.0, "offset on X");

    // ISADORA_FLOAT_PARAM(offsetY, offy, 0.0, 10.0, 5.0, "offset on Y");

    uniform float offsetX;

    uniform float offsetY;

    uniform vec2 resolution;

    vec2 coord = gl_FragCoord.xy/resolution.xy;

    void main(void) {

    // displace  tex0 pixels, according to the brightness of tex1 pixels

    coord.x = coord.x + texture2D(tex1, coord).x * offsetX /10.0;

    coord.y = coord.y + texture2D(tex1, coord).y * offsetY /10.0;

    vec4 color = texture2D(tex0, coord);

    gl_FragColor = color;


  • Jacques,

    thank you very much. Works fantastic.



  • Tech Staff

    This is fantastic!

    One note, simply by changing the comments for the Isadora params to a range of -10.0,10.0 for the offset x and y, 

    the shader works perfectly with both positive and negative offsets :)

    // ISADORA_FLOAT_PARAM(offsetX, offx, -10.0, 10.0, 5.0, "offset on X");

    // ISADORA_FLOAT_PARAM(offsetY, offy, -10.0, 10.0, 5.0, "offset on Y");

  • Dear @jhoepffner 

    Thank you for this. But, I need to point out the following:

    This will not give the same results as Isadora's Displace actor.

    I have edited your code to add a comment to indicate this to avoid confusion among the users. In fact, your algorithm is much closer to the functionality of the Scanner actor.

    The code for the displace actor looks something like this.

    float brightness_of_displace_pixel = (calculate brightness of displace texture, 0.0 to 1.0)
    float dst_pixel_x = (cos(angle) + 1.0)/2.0 * displace_amount * brightness_of_displace_pixel;
    float dst_pixel_y = (sin(angle) + 1.0)/2.0 * displace_amount * brightness_of_displace_pixel;

    But here is where you encounter the problem. You want to write to the pixel at texture0[dst_pixel_x][dst_pixel_y], but you can't do that – you can only output to the current pixel as defined by the gl_FragCoord.xy built-in variable. (The inability to write to an arbitrary pixel within a Shader is covered by this Stack Overflow post.) Writing to an arbitrary pixel on the CPU is easy because it's just a two dimensional array.

    Jacques, if you have an idea of how to accomplish the functionality of the Displace actor, please share it with me. The Stack Overflow post suggets the idea of an array of points that equals the resolution of the image in both dimensions. I suppose you could analyze the brightness of the image, output the x coordinate to one texture and then the y coordinate to a second texture, and then use those two textures to modulate the vertices. But I'm sorry to admit that this is a bit beyond my skill level with shaders.

    Best Wishes,

  • Dear All,

    Here is a version that accepts a displace amount from 0 to 100 and an angle between 0 and 360.


    a Displace Shader Actor
    proposed by Jacques Hoepffner
    after isadora Werkstatt 2017

    updated by Mark Coniglio to move the pixels based
    on an a displace amount and an angle instead of
    separate x/y inputs

    this version also calculates the actual greyscale
    brightness of the pixel using standard a conversion

    Note that this code will not produce the same results
    as the built-in Isadora Displace actor.


    // greyscale weights for RGB to gray conversion
    const vec4 sGrayScaleWeights = vec4(0.3086, 0.6094, 0.0820, 0.0);

    // used to convert from degrees to radians
    const float sDegreesToRadians = 0.01745329252;

    // 2 texture inputs
    uniform sampler2D tex0;
    uniform sampler2D tex1;

    // ISADORA_FLOAT_PARAM(amount, amtt, 0.0, 100.0, 50.0, "Displace amount.");
    uniform float amount;

    // ISADORA_FLOAT_PARAM(angle, angl, 0.0, 360.0, 0.0, "Displace angle");
    uniform float angle;

    void main(void) {

    float radians = (angle/360.0) * sDegreesToRadians;

    vec2 offset_max = vec2( (sin(radians) + 1.0) / 2.0, (cos(radians) + 1.0) / 2.0 );

    // displace tex0 pixels, according to the brightness of tex1 pixels

    vec4 c1 = texture2D(tex1, gl_TexCoord[0].st);
    vec4 greyColor = c1 * sGrayScaleWeights;
    float luminance = greyColor.r + greyColor.g + greyColor.b;

    vec2 src_coord = gl_TexCoord[0].st + offset_max * luminance * (amount/100.0);
    vec4 color = texture2D(tex0, src_coord);

    gl_FragColor = color;


Log in to reply

Looks like your connection to TroikaTronix Community Forum was lost, please wait while we try to reconnect.