Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the DisplacementMapFilter work?

I am a beginner in actionscript. If I understand correctly, the DisplacementMapFilter moves pixels from a 'source image' according to the color of the corresponding pixel position in a 'MAP image'.

The problem is that my destination image contains pixels which are NOT in the source image !

For example, I take a UNICOLOR 10 * 10 pixels 'source image' with this BitMapData:

sourceBitmap = new BitmapData(BITMAP_WIDTH, BITMAP_HEIGHT, false, 0x000002);

produce:

  0   1   2   3   4   5   6   7   8   9
[002,002,002,002,002,002,002,002,002,002] Row 0
[002,002,002,002,002,002,002,002,002,002] Row 1
[002,002,002,002,002,002,002,002,002,002] Row 2
[002,002,002,002,002,002,002,002,002,002] Row 3
[002,002,002,002,002,002,002,002,002,002] Row 4
[002,002,002,002,002,002,002,002,002,002] Row 5
[002,002,002,002,002,002,002,002,002,002] Row 6
[002,002,002,002,002,002,002,002,002,002] Row 7
[002,002,002,002,002,002,002,002,002,002] Row 8
[002,002,002,002,002,002,002,002,002,002] Row 9

Now, I take this BLACK displacement MAP and I add a little BLUE square:

displacementBitmap = new BitmapData(BITMAP_WIDTH,BITMAP_HEIGHT,false,0x000000);
for(i=5;i<10;i++)
    for(j=5;j<10;j++)
        displacementBitmap.setPixel(i,j,255);

produce:

 0   1   2   3   4   5   6   7   8   9 
[000,000,000,000,000,000,000,000,000,000] Row 0
[000,000,000,000,000,000,000,000,000,000] Row 1
[000,000,000,000,000,000,000,000,000,000] Row 2
[000,000,000,000,000,000,000,000,000,000] Row 3
[000,000,000,000,000,000,000,000,000,000] Row 4
[000,000,000,000,000,255,255,255,255,255] Row 5
[000,000,000,000,000,255,255,255,255,255] Row 6
[000,000,000,000,000,255,255,255,255,255] Row 7
[000,000,000,000,000,255,255,255,255,255] Row 8
[000,000,000,000,000,255,255,255,255,255] Row 9

The result:

displacementFilter = new DisplacementMapFilter();
displacementFilter.alpha=0;
displacementFilter.color=0;
displacementFilter.mapPoint=new Point(0,0);
displacementFilter.scaleX=1;
displacementFilter.scaleY=1;
displacementFilter.componentX = flash.display.BitmapDataChannel.BLUE;
displacementFilter.componentY = flash.display.BitmapDataChannel.BLUE;
displacementFilter.mapBitmap = displacementBitmap;

destinationBitmap = new BitmapData(BITMAP_WIDTH,BITMAP_HEIGHT,false,0xFFFFFFFF);
destinationBitmap.applyFilter(
    sourceBitmap.bitmapData,
    new Rectangle(0,0,BITMAP_WIDTH,BITMAP_HEIGHT),
    new Point(0,0),
    displacementFilter
);

produce:        

  0   1   2   3   4   5   6   7   8   9 
[002,002,002,002,002,002,002,002,002,002] Row 0
[002,002,002,002,002,002,002,002,002,002] Row 1
[002,002,002,002,002,002,002,002,002,002] Row 2
[002,002,002,002,002,002,002,002,002,002] Row 3
[002,002,002,002,002,002,002,002,002,002] Row 4
[002,002,002,002,002,001,001,001,001,001] Row 5
[002,002,002,002,002,001,001,001,001,001] Row 6
[002,002,002,002,002,001,001,001,001,001] Row 7
[002,002,002,002,002,001,001,001,001,001] Row 8
[002,002,002,002,002,001,001,001,001,001] Row 9

So I don't understand why I have '001' pixels which don't exists in the source image.

Thanks you very much.

like image 778
Josh Xoder Avatar asked Mar 13 '12 21:03

Josh Xoder


People also ask

How does a displacement map work?

Contrary to those methods, displacement maps help create real 3D geometry; it casts real shadows and looks realistic from every angle. It does so by dividing the model's polygons into a much denser mesh during the rendering process, which is either elevated or depressed on an up/down axis based on your chosen texture.

How does displacement impact a map?

Displacement mapping works by taking the brightness (or luminance) values of the pixels in one layer'"called the displacement map'"and using those values to physically shift, or displace, the position of the pixels in the affected layer.


1 Answers

The displacement map filter decides which pixel to grab from the source bitmap using this formula:

dstPixel[x, y] = srcPixel[x + ((componentX(x, y) - 128) * scaleX) / 256, y + ((componentY(x, y) - 128) *scaleY) / 256)

dstPixel is the destination bitmap, srcPixel is the source bitmap, and componentX/Y is from the displacement bitmap. The mapping is determined by how far away the component channel is from 128. Note that 128 is the neutral value where there is no transformation, and the same source pixel is used.

For example, let's consider the pixel at (1, 1) in your case. Your component channel is blue, and the blue channel at (1, 1) in the displacement map has a value of 0. So we displace by (0 - 128)/256, or -0.5. So the final pixel we grab from the source bitmap is at (0.5, 0.5).

But what does it mean to use half of a pixel? It turns out that Flash uses bilinear filtering to smooth out the results. You end up with a blend of the colors in the four pixels between (0,0) and (1,1).

This is the reason you are seeing odd pixels that aren't in the source image. Even though all of the pixels in your source image are the same color, there seem to be some floating-point inaccuracies when Flash interpolates between colors, so sometimes you get a value that's just slightly off. Notice that if you use a value in your displacement bitmap that divides "cleanly" by 128, such as 0 or 64, then you get the correct result. But if you use a value like 255 or 19, you get some error.

Unfortunately, there doesn't seem to be any way to turn off the filtering and use simple nearest-neighbor sampling. So if you need to guarantee that no new colors are introduced, then you must carefully select the values in your displacement map.

Alternatively, you could use Pixel Bender to create a kernel that does what you need. Pixel Bender allows you to do nearest-neighbor sampling from a source bitmap.

like image 59
Mike Welsh Avatar answered Oct 15 '22 08:10

Mike Welsh