[ANSWERED] 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.
best
Jean-François
-
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,
Mark -
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 2017updated by Mark Coniglio to move the pixels based
on an a displace amount and an angle instead of
separate x/y inputsthis version also calculates the actual greyscale
brightness of the pixel using standard a conversion
algorithmNote 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;
}
-
I get these errors when I compile your code, above:
FRAG 0(2) : error C0000:-1 syntax error, unexpected '*' at token "*"
FRAG 0(29) : warning C1503:-1 undefined variable "sGrayScaleWeights"Thanks,
Hugh
-
ChatGPT to the rescue :)
Disclaimer: I have no idea if this still does what it's supposed to, but the result looks cool and it compiles so ¯\_(ツ)_/¯/* 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 algorithm 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.0 * 3.14159265359 / 360.0; // 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 * sDegreesToRadians; vec2 offset_max = vec2(sin(radians), cos(radians)); // displace tex0 pixels, according to the brightness of tex1 pixels vec4 c1 = texture2D(tex1, gl_TexCoord[0].st); float luminance = dot(c1.rgb, sGrayScaleWeights.rgb);
vec2 src_coord = gl_TexCoord[0].st + offset_max * luminance * (amount/100.0); vec4 color = texture2D(tex0, src_coord); gl_FragColor = color;
}
-
Here's another version where the angle input works a bit better I think:
/* a Displace Shader Actor proposed by Jacques Hoepffner after isadora Werkstatt 2017 updated by Mark Coniglio to move the pixels based on 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 algorithm 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 vec3 sGrayScaleWeights = vec3(0.3086, 0.6094, 0.0820); // 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) { // Convert angle to radians float radians = angle * sDegreesToRadians; // Calculate offset direction based on angle vec2 offset_direction = vec2(sin(radians), cos(radians)); // Sample the brightness from tex1 vec4 c1 = texture2D(tex1, gl_TexCoord[0].st);
// Convert the sampled color to luminance float luminance = dot(c1.rgb, sGrayScaleWeights); // Calculate the displacement offset vec2 displacement = offset_direction * (luminance - 0.5) * (amount / 100.0); // Calculate the source coordinates in tex0 vec2 src_coord = gl_TexCoord[0].st + displacement; // Sample the color from tex0 at the displaced coordinates vec4 color = texture2D(tex0, src_coord); // Output the final color gl_FragColor = color;
}
-
I needed to do some Displacing yesterday and the CPU Displace was too heavy. I found a workaround using the displace function of Rutt Etra actor and setting the Draw Mode to Image Plane. It's pretty Displacey.
-
-
@woland said:
/* a Displace Shader Actor proposed by Jacques Hoepffner after isadora Werkstatt 2017 updated by Mark Coniglio to move the pixels based on 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 algorithm 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 vec3 sGrayScaleWeights = vec3(0.3086, 0.6094, 0.0820); // 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) { // Convert angle to radians float radians = angle * sDegreesToRadians; // Calculate offset direction based on angle vec2 offset_direction = vec2(sin(radians), cos(radians)); // Sample the brightness from tex1 vec4 c1 = texture2D(tex1, gl_TexCoord[0].st); // Convert the sampled color to luminance float luminance = dot(c1.rgb, sGrayScaleWeights); // Calculate the displacement offset vec2 displacement = offset_direction * (luminance - 0.5) * (amount / 100.0); // Calculate the source coordinates in tex0 vec2 src_coord = gl_TexCoord[0].st + displacement; // Sample the color from tex0 at the displaced coordinates vec4 color = texture2D(tex0, src_coord); // Output the final color gl_FragColor = color; }
Thanks for the code Impro