Jump to content
Search Community

Creating a 'plastic pillow' dimple effect

ScottJenson test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

I'd like to take a canvas with an image in it and where I touch, the image 'dimples in' as if the surface was soft. As I then run my finger across the image, the dimple follows under my finger. It's like the image is on a soft plastic pillow.


I was curious if anyone has done this animation before I give it a shot. I searched the examples (as this forum) and found nothing. 


Assuming there is nothing, can anyone give me, as a novice GreenSock programmer, a hint as to which way I should approach this problem? As I see it these are the things I'll need to do:

1) Initialize a canvas with an image (easy)

2) Create a depression in the image at a location (the core ask)

3) Animate the depression as the touch location changes (again, likely easy)


Link to comment
Share on other sites

Hi and welcome to the GreenSock forums,


This sounds like you could use Pixi.js (for canvas rendering) and its displacement filter to do the majority of the heavy lifting.

All Pixi and GSAP questions lead to the @OSUblake's CodePen profile



I think if you can figure out how to move one of the bubbles (3rd demo) with your pointer you'll be pretty close to what you need.



I'd spend some time studying these examples below and then if you have a question about GSAP, let us know.




See the Pen ZbRVPY by osublake (@osublake) on CodePen

See the Pen gmPQWX?editors=0010 by osublake (@osublake) on CodePen

See the Pen qmXPMm by osublake (@osublake) on CodePen


  • Like 5
Link to comment
Share on other sites

  • 2 weeks later...

OK, I'm digging into the 3rd example (GSAP Pixi Plugin) and I'm just fiddling with each line learning what each does. The critical bit is the multi step process of:

  • Loading displacementmap.png
  • Creating the displacementSprite using resources.displacement.texture

My goal is to create the opposite of this, pushing into the surface instead of magnifying it larger. Is there any tutorial on how to create a displacement PNG?  I've attached the PNG that creates the bubble magnification effect. I can make this. I just need to know what each color+transparency means. I don't need hand holding, just point to to the spec that describes what RBGA values do what in the displacement map.  @OSUblake do you have any suggestions on where to find docs on how to create displacement maps for PIXI? 






Edited by ScottJenson
Link to comment
Share on other sites

Hi @ScottJenson



There's really no spec for this. The filters in Pixi are shaders, little programs that run on the GPU. The displacement filter is a fragment shader, which runs every pixel through a function to get it's color. That's what gl_FragColor returns. To learn more about shaders, The Book of Shaders is a good place to start.



varying vec2 vFilterCoord;
varying vec2 vTextureCoord;

uniform vec2 scale;

uniform sampler2D uSampler;
uniform sampler2D mapSampler;

uniform vec4 filterArea;
uniform vec4 filterClamp;

void main(void)
  vec4 map =  texture2D(mapSampler, vFilterCoord);

  map -= 0.5;
  map.xy *= scale / filterArea.xy;

  gl_FragColor = texture2D(uSampler, clamp(vec2(vTextureCoord.x + map.x, vTextureCoord.y + map.y), filterClamp.xy, filterClamp.zw));



The colors used in the displacement map aren't too important. What matters are the channels in the color. In an image, each pixel is an rgba value. In the displacement map, each pixel represents an xy value. A 2D vector.


// color channels from 0-255
var color = {
  r: 100,
  g: 200,
  b: 0,
  a: 255

// convert to values from -0.5 to 0.5
var map = {
  x: (color.r / 255) - 0.5,
  y: (color.g / 255) - 0.5



So the red and green channel are what matters. The red channel is the x displacement, and the green channel is the y displacement. The displacement values will be from -0.5 to 0.5. If the channel is 0, the displacement value will be -0.5. If the channel is 128, the displacement will be 0. If the channel is 255, the displacement value will be 0.5.


The filter uses the coordinates of the texture pixel being processed and offsets it by the corresponding displacement and scale value in the map, and returns the color of the texture at those coordinates. So if the red and green channel are both 128, it's going to return the same pixel. It's neutral. If the red channel is less than 128, it's going to return a pixel to the left of it. If the green channel is less than 128, it's going to return a pixel above it.


This displacement map will work almost like the one you posted.




The gray background has an rgb value of 128, 128, 128. The brownish background in the image you posted has an rgb value of 128, 128, 0. The red and green channels are what matters, so no displacement happens in those areas.


Here are some terms worth knowing as they are kind of related.

Displacement mapping - https://en.wikipedia.org/wiki/Displacement_mapping

Heightmap - https://en.wikipedia.org/wiki/Heightmap

Normal mapping - https://en.wikipedia.org/wiki/Normal_mapping


A normal map is used for lighting, but it's similar to a displacement map.




This tutorial shows the relationship between a normal map and a displacement map.



And here's a demo I made for some fabric. You can drag the letter. The displacement map is black and white.


See the Pen 900f1d51ce254239bf8e5225e97e771a by osublake (@osublake) on CodePen




  • Like 6
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...