I want to draw (for instance) a line on HTML5 canvas. Then I want to add an image bevel effect to that line. So it looks 3D, like a piece of string sitting on the canvas. Has anyone seen an image processing effect that can do something along that line?
I think the only way to do that kind of drawing is to draw step by step the curve, and apply at each step a texture perpendicular to the local tangent.
But you seem to want another feature : be able to 'twist' the texture depending on the part of the curve. Here there are so mant options to parameterize this i can't guess how you'll store/interpolate the twist of the texture. So below i just had the texture 'turn' with t, the parameter of the bezier curve.
http://jsfiddle.net/gamealchemist/YPKV9/
Example : Image showing a texture applied to the curve, and below the same curve with the same texture that turns along with the curve.
// ----------------------------------------------
// Draw bezier curve filled with
// with txCv used as perpendicular texture
// signature : drawTexturedBezier ( txCv, a, b, c, d, twisted )
// a,b,c,d are control points, twisted means
// do we have to twist the curve.
// Width of the bezier is == to txCv.width/2
// when the draw resolution is tx.height (lower = nicer+slower, 3 seems fine )
// ----------------------------------------------
function drawTexturedBezier() {
// build onnly once local vars
var pt = {
x: 0,
y: 0
};
var tg = {
x: 0,
y: 0
};
var lastPt = {
x: 0,
y: 0
};
drawTexturedBezier = function (txCv, a, b, c, d, twisted) {
var lineHeight = txCv.height;
var t = 0;
var incr = 1 / 1000;
var pointCount = 0;
pt.x = a.x;
pt.y = a.y;
var thisCoordsForT = coordsForT.bind(null, a, b, c, d);
var thisTgtForT = tangentForT.bind(null, a, b, c, d);
// scan the bezier curve by increment of lineHeight distance
// on the curve.
do {
// update last point
lastPt.x = pt.x;
lastPt.y = pt.y;
// seek next point far enough from previous point
// just compute one point ahead
// using average estimate for t of '1 point ahead'
thisCoordsForT(t + incr, pt);
var dx = pt.x - lastPt.x;
dx *= dx;
var dy = pt.y - lastPt.y;
dy *= dy;
// compute distance to previous point
var dist = Math.sqrt(dx + dy);
// compute required t increment
// considering curve is locally linear
// 0.92 compensates for the error.
var tIncrement = 0.92 * incr * (lineHeight / dist);
t += tIncrement;
// compute point
thisCoordsForT(t, pt);
pointCount++;
// update regular increment with local one
incr = 0.2 * incr + 0.8 * tIncrement;
// compute tangent for current point
thisTgtForT(t, tg);
// draw with perpendicular texture
drawTexturedLine(txCv, pt, tg, t, twisted);
} while (t < 1);
};
return drawTexturedBezier.apply(this, arguments);
}
With
// draws a rect centered on pt, for a curve having tg as local tangent
// having size of : txCv.width/2 X txCv.height
// using the txCv horizontal pattern as pattern.
function drawTexturedLine(txCv, pt, tg, t, twisted) {
var lineWidth = txCv.width / 2;
var lineHeight = txCv.height;
context.save();
context.beginPath();
context.lineWidth = 2;
context.translate(pt.x, pt.y);
context.rotate(Math.PI + Math.atan2(-tg.x, tg.y));
var twistFactor = 0;
if (twisted) {
twistFactor = (2 * t + animating * Date.now() / 2000) % 1;
}
context.drawImage(txCv,
twistFactor * lineWidth, 0, lineWidth, lineHeight, -0.5 * lineWidth, -0.5 * lineHeight, lineWidth, lineHeight);
context.restore();
}