本文主要包含HTML5 ,3D衣服摇摆,动画特效等相关知识,匿名希望在学习及工作中可以帮助到您
这又是一款基于HTML5 Canvas的3D动画杰作,它是一个可以随风飘动的3D衣服摇摆动画特效,非常逼真。当我们将鼠标滑过衣服时,衣服将会出现摇摆的动画,点击鼠标时,衣服将会更加剧烈地摆动。

在线演示源码下载
HTML代码
<p style="width:500px;margin:10px auto"> <canvas id="cv" width="480" height="300"></canvas> <p>"3D on 2D Canvas" demo</p> <p>move cursor to pan / click to swing</p> </p>
P3D库JS代码,主要用来处理3D效果的
window.P3D = {
texture: null,
g: null
};
P3D.clear = function(f, w, h) {
var g = this.g;
g.beginPath();
g.fillStyle = f;
g.fillRect(0, 0, w, h);
}
P3D.num_cmp = function(a,b){return a-b;}
P3D.drawTriangle = function(poss, uvs, shade_clr) {
var w = this.texture.width;
var h = this.texture.height;
var g = this.g;
var vAd = [ poss[1].x - poss[0].x , poss[1].y - poss[0].y ];
var vBd = [ poss[2].x - poss[0].x , poss[2].y - poss[0].y ];
var vA = [ uvs[1].u - uvs[0].u , uvs[1].v - uvs[0].v ];
var vB = [ uvs[2].u - uvs[0].u , uvs[2].v - uvs[0].v ];
vA[0] *= w;
vA[1] *= h;
vB[0] *= w;
vB[1] *= h;
var m = new M22();
m._11 = vA[0];
m._12 = vA[1];
m._21 = vB[0];
m._22 = vB[1];
var im = m.getInvert();
if (!im) return false;
var a = im._11 * vAd[0] + im._12 * vBd[0];
var b = im._21 * vAd[0] + im._22 * vBd[0];
var c = im._11 * vAd[1] + im._12 * vBd[1];
var d = im._21 * vAd[1] + im._22 * vBd[1];
var wu = uvs[0].u * w;
var hv = uvs[0].v * h;
var du = wu * a + hv * b;
var dv = wu * c + hv * d;
g.save();
g.beginPath();
g.moveTo(poss[0].x, poss[0].y);
g.lineTo(poss[1].x, poss[1].y);
g.lineTo(poss[2].x, poss[2].y);
g.clip();
g.transform(a, c, b, d, poss[0].x - du, poss[0].y - dv);
// bounds
var bx = [wu, wu+vA[0], wu+vB[0]];
var by = [hv, hv+vA[1], hv+vB[1]];
bx.sort(P3D.num_cmp);
by.sort(P3D.num_cmp);
var bw = bx[2] - bx[0];
var bh = by[2] - by[0];
if ((bx[0]+bw) <= (w-1)) bw++;
if ((by[0]+bh) <= (h-1)) bh++;
if (bx[0] >= 1) {bx[0]--; bw++;}
if (by[0] >= 1) {by[0]--; bh++;}
g.drawImage(this.texture, bx[0], by[0], bw, bh, bx[0], by[0], bw, bh);
if (shade_clr) {
g.fillStyle = shade_clr;
g.fillRect(bx[0], by[0], bw, bh);
}
g.restore();
return true;
}
P3D.drawTestByIndexBuffer = function(pos_buf, ix_buf, culling) {
var g = this.g;
if ((ix_buf.length%3) != 0)
throw "invalid index buffer length!";
var len = ix_buf.length/3;
var i, ibase, vbase;
var poss = [{},{},{}];
g.strokeWidth = 1;
for (i = 0, ibase = 0;i < len;++i)
{
vbase = ix_buf[ibase++] << 2;
poss[0].x = pos_buf[vbase++];
poss[0].y = pos_buf[vbase ];
vbase = ix_buf[ibase++] << 2;
poss[1].x = pos_buf[vbase++];
poss[1].y = pos_buf[vbase ];
vbase = ix_buf[ibase++] << 2;
poss[2].x = pos_buf[vbase++];
poss[2].y = pos_buf[vbase ];
// z component of cross product < 0 ?
var Ax = poss[1].x - poss[0].x;
var Ay = poss[1].y - poss[0].y;
var Cx = poss[2].x - poss[1].x;
var Cy = poss[2].y - poss[1].y;
var cull = ( (((Ax * Cy) - (Ay * Cx))*culling) < 0);
g.beginPath();
g.strokeStyle = cull ? "#592" : "#0f0";
g.moveTo(poss[0].x, poss[0].y);
g.lineTo(poss[1].x, poss[1].y);
g.lineTo(poss[2].x, poss[2].y);
g.lineTo(poss[0].x, poss[0].y);
g.stroke();
}
}
P3D.drawByIndexBuffer = function(pos_buf, ix_buf, tx_buf, culling, z_clip) {
var w, h;
var color_polygon = !this.texture;
if (this.texture) {
w = this.texture.width;
h = this.texture.height;
}
var g = this.g;
var m = new M22();
if (!culling) culling = 0;
if ((ix_buf.length%3) != 0)
throw "invalid index buffer length!";
var i, ibase, vbase, tbase, poss = [{},{},{}];
var len = ix_buf.length/3;
var uv_0u, uv_0v, uv_1u, uv_1v, uv_2u, uv_2v;
for (i = 0, ibase = 0;i < len;++i)
{
tbase = ix_buf[ibase++] << 1
vbase = tbase << 1;
poss[0].x = pos_buf[vbase++]; uv_0u = tx_buf[tbase++];
poss[0].y = pos_buf[vbase++]; uv_0v = tx_buf[tbase];
if (z_clip && (pos_buf[vbase] < 0 || pos_buf[vbase] > 1)) {ibase += 2; continue;}
tbase = ix_buf[ibase++] << 1
vbase = tbase << 1;
poss[1].x = pos_buf[vbase++]; uv_1u = tx_buf[tbase++];
poss[1].y = pos_buf[vbase++]; uv_1v = tx_buf[tbase];
if (z_clip && (pos_buf[vbase] < 0 || pos_buf[vbase] > 1)) {++ibase; continue;}
tbase = ix_buf[ibase++] << 1
vbase = tbase << 1;
poss[2].x = pos_buf[vbase++]; uv_2u = tx_buf[tbase++];
poss[2].y = pos_buf[vbase++]; uv_2v = tx_buf[tbase];
if (z_clip && (pos_buf[vbase] < 0 || pos_buf[vbase] > 1)) {continue;}
var vAd = [ poss[1].x - poss[0].x , poss[1].y - poss[0].y ];
var vBd = [ poss[2].x - poss[0].x , poss[2].y - poss[0].y ];
var vCd = [ poss[2].x - poss[1].x , poss[2].y - poss[1].y ];
// z component of cross product < 0 ?
if( (((vAd[0] * vCd[1]) - (vAd[1] * vCd[0]))*culling) < 0)
continue;
if (color_polygon) {
g.fillStyle = uv_0u;
g.beginPath();
g.moveTo(poss[0].x, poss[0].y);
g.lineTo(poss[1].x, poss[1].y);
g.lineTo(poss[2].x, poss[2].y);
g.fill();
continue;
}
var vA = [ uv_1u - uv_0u , uv_1v - uv_0v ];
var vB = [ uv_2u - uv_0u , uv_2v - uv_0v ];
vA[0] *= w;
vA[1] *= h;
vB[0] *= w;
vB[1] *= h;
m._11 = vA[0];
m._12 = vA[1];
m._21 = vB[0];
m._22 = vB[1];
var im = m.getInvert();
if (!im) { continue;}
var a = im._11 * vAd[0] + im._12 * vBd[0];
var b = im._21 * vAd[0] + im._22 * vBd[0];
var c = im._11 * vAd[1] + im._12 * vBd[1];
var d = im._21 * vAd[1] + im._22 * vBd[1];
var wu = uv_0u * w;
var hv = uv_0v * h;
var du = wu * a + hv * b;
var dv = wu * c + hv * d;
g.save();
g.beginPath();
g.moveTo(poss[0].x, poss[0].y);
g.lineTo(poss[1].x, poss[1].y);
g.lineTo(poss[2].x, poss[2].y);
g.clip();
g.transform(a, c, b, d, poss[0].x - du, poss[0].y - dv);
// bounds
var bx = [wu, wu+vA[0], wu+vB[0]];
var by = [hv, hv+vA[1], hv+vB[1]];
bx.sort(P3D.num_cmp);
by.sort(P3D.num_cmp);
var bw = bx[2] - bx[0];
var bh = by[2] - by[0];
if ((bx[0]+bw) <= (w-1)) bw++;
if ((by[0]+bh) <= (h-1)) bh++;
if (bx[0] >= 1) {bx[0]--; bw++;}
if (by[0] >= 1) {by[0]--; bh++;}
g.drawImage(this.texture, bx[0], by[0], bw, bh, bx[0], by[0], bw, bh);
/*
if (shade_clr) {
g.fillStyle = shade_clr;
g.fillRect(bx[0], by[0], bw, bh);
}
*/
g.restore();
}
}
function Vec3(_x, _y, _z)
{
this.x = _x || 0;
this.y = _y || 0;
this.z = _z || 0;
}
Vec3.prototype = {
zero: function() {
this.x = this.y = this.z = 0;
},
sub: function(v) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
return this;
},
add: function(v) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
},
copyFrom: function(v) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
return this;
},
norm:function() {
return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
},
normalize: function() {
var nrm = Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
if (nrm != 0)
{
this.x /= nrm;
this.y /= nrm;
this.z /= nrm;
}
return this;
},
smul: function(k) {
this.x *= k;
this.y *= k;
this.z *= k;
return this;
},
dpWith: function(v) {
retur

