Reputation: 3790
I'm trying to work out a way of doing pseudo 3d, distorting textures with the javascript canvas.
The best method for my needs so far has been to use displacement maps which I'm largely following from this tutorial and source code example.
The basic principle is to use the channel level (RGBA) from a selected pixel in the displacement map then applying a pixel shifting algorithm... all good so far.
The problem is that this method of shifting the texture image's pixels is very binary and renders a slightly 'jagged' edge due to the fact that - it's simply shifting 'full' pixels.
When compared to PhotoShop or some of the ImageMagick examples here the javascript method looks much less realistic. This is due to PS & IMs sub-pixel processing abilities whereby medians can be derived for inter-pixel data.
Question: Can anyone suggest a step which can be integrated into my algorithm to produce a gaussian/aliased smoothness to the output?
Perhaps I can simply run the imagedata through an FFT and back again? are there any examples of this in action?
I'm a little stumped and would very much appreciate some pointers.
Upvotes: 2
Views: 1433
Reputation: 19294
1) You are mentionning two very differents algorithms : Displacement mapping is a 3D technique, so it involves 'Z', and projection, and the other one is a 2D pixel shifting algorithm way way simpler.
(The soundstep link provided uses the word 'displacement mapping', yet it is a pixel shifting technique.)
2) Whatever the size of your MVC project, the algorithm should be isolated, and have a signature like :
var pixelShift = function (sourceCanvas, shiftCanvas, xOffset, yOffset)
and either return a new canvas OR change sourceCanvas in place.
If there's no such function, please do not talk about MVC, unless the M stands for 'Mess'. ;-) -
3) The algorithm is quite simple in fact, you must iterate through the destination pixel and look the color of the pixel they should come from (and not the other way around) :
var pixelShift = function (sourceCanvas, shiftCanvas, xOffset, yOffset) {
var shiftXY = { xS:0, yS:0 };
var shiftCanvasWidth = shiftCanvas.width ;
var shiftCanvasHeight = shiftCanvas.height;
for ( var x=0 ; x < shiftCanvasWidth ; x ++) {
for ( var y = 0 ; y < shiftCanvasHeight ; y++ ) {
readShift ( shiftCanvas, x, y, shiftXY );
var sourceColor = readPixelColor ( sourceCanvas,
xOffset + shiftXY.xS,
yOffset + shiftXY.yS) ;
writePixel(sourceCanvas, xOffset + x , yOffset + y, sourceColor );
}
}
};
// sourceColor represents the color within a 32 bits integer (r,g,b,a * 8 bits).
it would be too long to write everything here but :
-- within pixelShift loop you should not deal with the source canvas, but a with 32 bits performance array.
-- the shift canvas should be converted ONCE into a Int8Array array, and stored as this.
this array size is shiftWidth * shiftHeight
odd index contains x shift, even contains y shift.
the array is pre-processed, and contains the shift value - 128.
for this shiftArray :
shiftX (x,y) = shiftArray [ 2 * (x + y * shiftWidth) ] ;
shiftY (x,y) = shiftArray [ 2 * (x + y * shiftWidth) + 1 ] ;
-- So pixelShift should look like :
var pixelShift = function (sourceCanvas,
shiftArray, shiftWidth, shiftHeight, xOffset, yOffset) {
[ Get a 32 bit performance array out of the canvas's target area ]
[ process this array using the shiftArray ]
[ write back the processed array onto the canvas's target area ]
}
-- And the core loop can be processed in a linear fashion :
var areaSize = shiftWidth * shiftHeight ;
for ( pixelIndex=0 ; pixelIndex < areaSize ; pixelIndex++ ) {
var linearShift = shiftArray [ 2*pixelIndex ]
+ shiftWidth * shiftArray [ 2*pixelIndex + 1 ] ;
targetAreaArray [ pixelIndex ] = targetAreaArray [ pixelIndex + linearShift ] ;
}
-- Rq : you might want to perform a boundary check on (pixelIndex + linearShift) within [0, areaSize[.
-- I think now you cannot get any faster.
The performance bottleneck will be the getImageData and putImageData you need to get/put the target area, but as far as i know, there's no other way to get a binary view on a Canvas than those two slooooow functions.
Upvotes: 2