Oy! Turns out I opened my mouth when we were talking about Tilt-Shift photo effect at work and my fellow WebApp team devs challenged me to implement such effect in Canvas.
Very nice.
Maybe you can help me quicken up a script I'm working on. It takes 4 points and draws an image in a perspective view. It looks great but it takes 30 seconds to finish.
The technique is lifted from Ben Joffe's canvas skew, which is no longer on the internet. I saved it a couple years ago and found it was the only example i could find to create a billboard type effect.
The only other example I've found is at this link. http://wd-testnet.world-direct.at/mozilla/dhtml/funo/fish2.htm
Maybe you know who the author of this script is. I've been playing with it and have all four sides working but the clipping is messed up. I would love to ask them how to make it work. The server doesn't lead anywhere so I have no clue who's site it is.
I can't post the script until I hear back from Mr. Joffe, whom I've emailed for permission. He might refuse to allow me to use it so I don't want be responsible for any damages, plus, he's a great scripter and I respect his intellectual property. I assume he posted the test so people could learn from it and he asks to be informed if the script is reused. I'm fairly certain I'll be able to share the script soon.
Your script would be an awesome addition to this for making convincing perspective.
May I use some of your techniques?
racerX: Ben, "Mr. Joffe", is a cool guy. I've worked, and partied, with him. I really doubt he'd have any problem as your code is not a total ripoff of his.
What are you doing for it to take 30 seconds ? Computing the pesrpective and doing 600-1200 drawImage of a 1pixel slice shouldn't take so long.
Feel free to use some of the techniques from my tilt-shift experiment. But bare in mind that's it's not optimized for speed.
OK here's the code. I picked out the parts of his script that deal with the image and the points.
I might have it looping too many times or have something in the wrong order. It would be awesome if you could see what I'm doing wrong.
const Refinement=1//sets size of slices less for better refinement
const x=100
const y=200
var pic=new Image();
pic.src="http://www.ozoneasylum.com/images/layouts/ozoneasylum/logos/default.jpg"
CanvasRenderingContext2D.prototype.skew=function(src, co){
this.save();var height=src.height;var width=src.width;var cr8ctx=document.createElement('CANVAS').getContext('2d');
var leftSpace=Math.min(co[0][0], conumber2[0]);//topleftX or bottmleftX return smallest
var totalWidth=Math.max(cont[0], coStrezz[0])-leftSpace;// top right or bottom right return biggest - smallest
cr8ctx.canvas.setAttribute('width', totalWidth);//biggest-smallest
cr8ctx.canvas.setAttribute('height', height);// actual image height
if (conumber2[0]<co[0][0]) cr8ctx.translate(co[0][0]-conumber2[0], 0);// if BL<TL translate(TL-BL,0)
var topWidth=cont[0]-co[0][0];//TR-TL
var botWidth=coStrezz[0]-conumber2[0];//BR-BL
var leftChange=conumber2[0]-co[0][0];//BL-TL
for (var i=0; i<height; i+=Refinement)
cr8ctx.drawImage(src, 0, i, width, Refinement, leftChange*i/height, i, Math.abs((topWidth*(height-i)+botWidth*i)/height), Refinement);
var leftTop=co[0]nt-(contnt-co[0]nt)*(co[0][0]-leftSpace)/(cont[0]-co[0][0]);
var rightTop=contnt+(contnt-co[0]nt)*(leftSpace+totalWidth-cont[0])/(cont[0]-co[0][0]);
var leftBot=conumber2nt-(coStrezznt-conumber2nt)*(conumber2[0]-leftSpace)/(coStrezz[0]-conumber2[0])-leftTop;
var rightBot=coStrezznt+(coStrezznt-conumber2nt)*(leftSpace+totalWidth-coStrezz[0])/(coStrezz[0]-conumber2[0])-rightTop;
for (var i=0; i<totalWidth; i+=Refinement)
this.drawImage(cr8ctx.canvas, i, 0, Refinement, height, leftSpace+i, (leftTop*(totalWidth-i)+rightTop*i)/totalWidth, Refinement, (leftBot*(totalWidth-i)+rightBot*i)/totalWidth);
this.restore(); }
function skewpic(dot){
var canvas=document.getElementById('canvas').getContext('2d');
for (var i=0; i<4; i++) {canvas.skew(pic, dot);} }
//
//Number.prototype.sqr=function(){return this*this}; |0 [0][0]=p0x 1 nt[0]=p1x
// topleft topright bottomleft bottomright | [0]nt=p0y ntnt=p1y
//THIS SCRIPT ADAPTED FROM BEN JOFFES'S CANVAS SKEW. PLEASE RETAIN THIS NOTICE. THANK(YOU)
//var dot=[[30,30],[380,100],[130,280],[180,80]]; |2 number2[0]=p2x 3 Strezz[0]=p3x
// | number2nt=p2x Strezznt=p3x
//-->
</SCRIPT>
</HEAD>
<BODY onload="skewpic([[30,240],[440,180],[200,460],[540,260]])">
I was hoping you could help me figure out how to straighten the lines. Although I really like how it looks curled like this and I want to be able to do this when I need to, I want to figure out how make the lines straight
Here's a clip of what you should see.
Probably only works in mozilla.
I haven't gotten around to playing with opera lately.
hehe figured it out. There's no reason to be looping canvas.skew(pic,dot). Duhhh.
it only needs to be called once. The loop was left over from the older script.
Now it only take a few seconds to draw the images really big. under 300px and it loads in about 1 second.
Thanks poi, I'm going to try to use the tilt-shift now. Wish me luck hahah
I just optimized the Tilt-Shift a little. Now I only generate the most blurry image and combine it with the original, thus saving in memory and dividing the number of drawImage for the actual render by 2
racerX: Sorry I haven't had time to check the source codes you pasted above.
Good luck with the code.
Hey poi,
I've thought of an optimisation for the tilt-shift, instead of using 240 drawImage calls you could draw a gradient over 'dof' from transparent to white and back with globalCompositionOperation set to destination-out. Then the temporary canvas could be pasted to the output with just one drawImage.
benjoffe: mmh ... good point about the gradient + globalCompositeOperation. There's got to be a way to use them and update the output in real time.
Alas in the last link you pasted they do every thing with quads, which is completely retarded in an affine world. Using quads creates lots of approximations and thus requires much higher subdivision level to get a decent result than when dealing with triangles.
Hi racerx,
Thanks for sharing your code. I need exactly same functionality to be done. However is there anyway we can implement it with excanvas so it can be rendered by IE? I have tried to use excanvas togheter with your script but it doesn't work.
I want to do something using some of the methods above, but much simpler I beliew... I simply want to take an image and skew it so that it looks like it has 3-dimensional perspective to it. You can see an example here of what I am trying to accomplish here: