Canvas 布料模拟+图像变换
Canvas transform on cloth simulation + image
我正在使用 verlet.js 插件,以便在 canvas 上使用纹理图像创建布料模拟。
我唯一没有做到的(也是最重要的顺便说一句)部分是我需要倾斜 drawImage 以使其适合正确的位置。
//Drawing the rectangle
ctx.save();
ctx.beginPath();
ctx.moveTo(cloth.particles[i1].pos.x, cloth.particles[i1].pos.y);
ctx.lineTo(cloth.particles[i1+1].pos.x, cloth.particles[i1+1].pos.y);
ctx.lineTo(cloth.particles[i2].pos.x, cloth.particles[i2].pos.y);
ctx.lineTo(cloth.particles[i2-1].pos.x, cloth.particles[i2-1].pos.y);
ctx.lineTo(cloth.particles[i1].pos.x, cloth.particles[i1].pos.y);
ctx.strokeStyle = "#fff";
ctx.stroke();
ctx.restore();
//Wrapping the image
ctx.save();
var off = cloth.particles[i2].pos.x - cloth.particles[i1].pos.x;
//THIS IS WHAT I TRY TO SOLVE TO FIT TO THE RECTANGLES
//ctx.transform(1,0.5,0,1,0,0);
ctx.drawImage(img, cloth.particles[i1].pos.x,cloth.particles[i1].pos.y, off, off, cloth.particles[i1].pos.x,cloth.particles[i1].pos.y, off ,off);
ctx.restore();
}
我试过调整其他布料模拟但没有成功。有什么线索可以让我找到一些信息来完成这项工作吗?
仅当单元格是平行四边形时,使用倾斜(或更确切地说是剪切)填充图块才有效,因为 2D 仿射变换仅支持这种形状。
这是一种方法:
- 计算上线的角度
- 计算左线的角度
- 计算单元格的宽度和高度
在平行四边形中底线等于上线,当然右线等于左线。
然后将这些角度设置为与平移到左上角相结合的变换的倾斜参数。
然后对每个单元格重复。
例子
var img = new Image;
img.onload = function() {
var ctx = document.querySelector("canvas").getContext("2d"),
tile1 = [
{x: 10, y: 10}, // upper left corner
{x: 210, y: 50}, // upper right
{x: 230, y: 150}, // bottom right
{x: 30, y: 110} // bottom left
],
tile2 = [
{x: 210, y: 50},
{x: 410, y: 5},
{x: 430, y: 105},
{x: 230, y: 150}
];
renderTile(this, tile1);
renderTile(this, tile2);
function renderTile(img, tile) {
var dx, dy, a1, a2, w, h, i = 1;
// reference shape (remove this section):
ctx.setTransform(1,0,0,1,0,0);
ctx.moveTo(tile[0].x, tile[0].y);
while(i < 4) ctx.lineTo(tile[i].x, tile[i++].y);
ctx.closePath();
ctx.strokeStyle = "#0c0";
ctx.lineWidth = 2;
ctx.stroke();
// calc horizontal angle
dx = tile[1].x - tile[0].x; // horizontal diff.
dy = tile[1].y - tile[0].y; // vertical diff.
a1 = Math.atan2(dy, dx); // angle, note dy,dx order here
w = dx|0; // width based on diff for x
// calc vertical angle
dx = tile[3].x - tile[0].x;
dy = tile[3].y - tile[0].y;
a2 = Math.atan2(dx, dy); // note dx,dy order here
h = dy|0;
// draw image to fit parallelogram
ctx.setTransform(1, a1, a2, 1, tile[0].x, tile[0].y);
ctx.drawImage(img, 0, 0, w, h);
}
};
img.src = "http://i.imgur.com/rUeQDjE.png";
<canvas width=500 height=160/>
注意:如果您的布料模拟产生了平行四边形以外的其他形状(即四边形),这很可能是物理模拟,这种方法将无法正常工作.在那种情况下,您需要计算量更大的不同技术。出于这个原因,WebGL 更适合。只是我的两分钱..
我正在使用 verlet.js 插件,以便在 canvas 上使用纹理图像创建布料模拟。
我唯一没有做到的(也是最重要的顺便说一句)部分是我需要倾斜 drawImage 以使其适合正确的位置。
//Drawing the rectangle
ctx.save();
ctx.beginPath();
ctx.moveTo(cloth.particles[i1].pos.x, cloth.particles[i1].pos.y);
ctx.lineTo(cloth.particles[i1+1].pos.x, cloth.particles[i1+1].pos.y);
ctx.lineTo(cloth.particles[i2].pos.x, cloth.particles[i2].pos.y);
ctx.lineTo(cloth.particles[i2-1].pos.x, cloth.particles[i2-1].pos.y);
ctx.lineTo(cloth.particles[i1].pos.x, cloth.particles[i1].pos.y);
ctx.strokeStyle = "#fff";
ctx.stroke();
ctx.restore();
//Wrapping the image
ctx.save();
var off = cloth.particles[i2].pos.x - cloth.particles[i1].pos.x;
//THIS IS WHAT I TRY TO SOLVE TO FIT TO THE RECTANGLES
//ctx.transform(1,0.5,0,1,0,0);
ctx.drawImage(img, cloth.particles[i1].pos.x,cloth.particles[i1].pos.y, off, off, cloth.particles[i1].pos.x,cloth.particles[i1].pos.y, off ,off);
ctx.restore();
}
我试过调整其他布料模拟但没有成功。有什么线索可以让我找到一些信息来完成这项工作吗?
仅当单元格是平行四边形时,使用倾斜(或更确切地说是剪切)填充图块才有效,因为 2D 仿射变换仅支持这种形状。
这是一种方法:
- 计算上线的角度
- 计算左线的角度
- 计算单元格的宽度和高度
在平行四边形中底线等于上线,当然右线等于左线。
然后将这些角度设置为与平移到左上角相结合的变换的倾斜参数。
然后对每个单元格重复。
例子
var img = new Image;
img.onload = function() {
var ctx = document.querySelector("canvas").getContext("2d"),
tile1 = [
{x: 10, y: 10}, // upper left corner
{x: 210, y: 50}, // upper right
{x: 230, y: 150}, // bottom right
{x: 30, y: 110} // bottom left
],
tile2 = [
{x: 210, y: 50},
{x: 410, y: 5},
{x: 430, y: 105},
{x: 230, y: 150}
];
renderTile(this, tile1);
renderTile(this, tile2);
function renderTile(img, tile) {
var dx, dy, a1, a2, w, h, i = 1;
// reference shape (remove this section):
ctx.setTransform(1,0,0,1,0,0);
ctx.moveTo(tile[0].x, tile[0].y);
while(i < 4) ctx.lineTo(tile[i].x, tile[i++].y);
ctx.closePath();
ctx.strokeStyle = "#0c0";
ctx.lineWidth = 2;
ctx.stroke();
// calc horizontal angle
dx = tile[1].x - tile[0].x; // horizontal diff.
dy = tile[1].y - tile[0].y; // vertical diff.
a1 = Math.atan2(dy, dx); // angle, note dy,dx order here
w = dx|0; // width based on diff for x
// calc vertical angle
dx = tile[3].x - tile[0].x;
dy = tile[3].y - tile[0].y;
a2 = Math.atan2(dx, dy); // note dx,dy order here
h = dy|0;
// draw image to fit parallelogram
ctx.setTransform(1, a1, a2, 1, tile[0].x, tile[0].y);
ctx.drawImage(img, 0, 0, w, h);
}
};
img.src = "http://i.imgur.com/rUeQDjE.png";
<canvas width=500 height=160/>
注意:如果您的布料模拟产生了平行四边形以外的其他形状(即四边形),这很可能是物理模拟,这种方法将无法正常工作.在那种情况下,您需要计算量更大的不同技术。出于这个原因,WebGL 更适合。只是我的两分钱..