首页 > IT职业 > IT职场 > HTML5 3D衣服摇摆动画特效
这又是一款基于HTML5 Canvas的3D动画杰作,它是一个可以随风飘动的3D衣服摇摆动画特效,非常逼真。当我们将鼠标滑过衣服时,衣服将会出现摇摆的动画,点击鼠标时,衣服将会更加剧烈地摆动。
"3D on 2D Canvas" demo
move cursor to pan / click to swing
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) = 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 1)) {ibase += 2; continue;}
tbase = ix_buf[ibase++] 1)) {++ibase; continue;}
tbase = ix_buf[ibase++] 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 = 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) { return this.x*v.x + this.y*v.y + this.z*v.z;
},
cp: function(v, w) { this.x = (w.y * v.z) - (w.z * v.y); this.y = (w.z * v.x) - (w.x * v.z); this.z = (w.x * v.y) - (w.y * v.x); return this;
},
toString: function() { return this.x + ", " + this.y + "," + this.z;
}
}function M44(cpy){ if (cpy) this.copyFrom(cpy); else { this.ident();
}
}
M44.prototype = {
ident: function() { this._12 = this._13 = this._14 = 0; this._21 = this._23 = this._24 = 0; this._31 = this._32 = this._34 = 0; this._41 = this._42 = this._43 = 0; this._11 = this._22 = this._33 = this._44 = 1; return this;
},
copyFrom: function(m) { this._11 = m._11; this._12 = m._12; this._13 = m._13; this._14 = m._14; this._21 = m._21; this._22 = m._22; this._23 = m._23; this._24 = m._24; this._31 = m._31; this._32 = m._32; this._33 = m._33; this._34 = m._34; this._41 = m._41; this._42 = m._42; this._43 = m._43; this._44 = m._44; return this;
},
transVec3: function(out, x, y, z) {
out[0] = x * this._11 + y * this._21 + z * this._31 + this._41;
out[1] = x * this._12 + y * this._22 + z * this._32 + this._42;
out[2] = x * this._13 + y * this._23 + z * this._33 + this._43;
out[3] = x * this._14 + y * this._24 + z * this._34 + this._44;
},
transVec3Rot: function(out, x, y, z) {
out[0] = x * this._11 + y * this._21 + z * this._31;
out[1] = x * this._12 + y * this._22 + z * this._32;
out[2] = x * this._13 + y * this._23 + z * this._33;
},
perspectiveLH: function(vw, vh, z_near, z_far) { this._11 = 2.0*z_near/vw; this._12 = 0; this._13 = 0; this._14 = 0; this._21 = 0; this._22 = 2*z_near/vh; this._23 = 0; this._24 = 0; this._31 = 0; this._32 = 0; this._33 = z_far/(z_far-z_near); this._34 = 1; this._41 = 0; this._42 = 0; this._43 = z_near*z_far/(z_near-z_far); this._44 = 0; return this;
},
lookAtLH: function(aUp, aFrom, aAt) { var aX = new Vec3(); var aY = new Vec3(); var aZ = new Vec3(aAt.x, aAt.y, aAt.z);
aZ.sub(aFrom).normalize();
aX.cp(aUp, aZ).normalize();
aY.cp(aZ, aX); this._11 = aX.x; this._12 = aY.x; this._13 = aZ.x; this._14 = 0; this._21 = aX.y; this._22 = aY.y; this._23 = aZ.y; this._24 = 0; this._31 = aX.z; this._32 = aY.z; this._33 = aZ.z; this._34 = 0; this._41 = -aFrom.dpWith(aX); this._42 = -aFrom.dpWith(aY); this._43 = -aFrom.dpWith(aZ); this._44 = 1; return this;
},
mul: function(A, B) { this._11 = A._11*B._11 + A._12*B._21 + A._13*B._31 + A._14*B._41; this._12 = A._11*B._12 + A._12*B._22 + A._13*B._32 + A._14*B._42; this._13 = A._11*B._13 + A._12*B._23 + A._13*B._33 + A._14*B._43; this._14 = A._11*B._14 + A._12*B._24 + A._13*B._34 + A._14*B._44; this._21 = A._21*B._11 + A._22*B._21 + A._23*B._31 + A._24*B._41; this._22 = A._21*B._12 + A._22*B._22 + A._23*B._32 + A._24*B._42; this._23 = A._21*B._13 + A._22*B._23 + A._23*B._33 + A._24*B._43; this._24 = A._21*B._14 + A._22*B._24 + A._23*B._34 + A._24*B._44; this._31 = A._31*B._11 + A._32*B._21 + A._33*B._31 + A._34*B._41; this._32 = A._31*B._12 + A._32*B._22 + A._33*B._32 + A._34*B._42; this._33 = A._31*B._13 + A._32*B._23 + A._33*B._33 + A._34*B._43; this._34 = A._31*B._14 + A._32*B._24 + A._33*B._34 + A._34*B._44; this._41 = A._41*B._11 + A._42*B._21 + A._43*B._31 + A._44*B._41; this._42 = A._41*B._12 + A._42*B._22 + A._43*B._32 + A._44*B._42; this._43 = A._41*B._13 + A._42*B._23 + A._43*B._33 + A._44*B._43; this._44 = A._41*B._14 + A._42*B._24 + A._43*B._34 + A._44*B._44; return this;
},
translate: function(x, y, z) { this._11 = 1; this._12 = 0; this._13 = 0; this._14 = 0; this._21 = 0; this._22 = 1; this._23 = 0; this._24 = 0; this._31 = 0; this._32 = 0; this._33 = 1; this._34 = 0; this._41 = x; this._42 = y; this._43 = z; this._44 = 1; return this;
},
transpose33: function() { var t;
t = this._12; this._12 = this._21; this._21 = t;
t = this._13; this._13 = this._31; this._31 = t;
t = this._23; this._23 = this._32; this._32 = t; return this;
}, // OpenGL style rotation
glRotate: function(angle, x, y, z) { var s = Math.sin( angle ); var c = Math.cos( angle ); var xx = x * x; var yy = y * y; var zz = z * z; var xy = x * y; var yz = y * z; var zx = z * x; var xs = x * s; var ys = y * s; var zs = z * s; var one_c = 1.0 - c;/*
this._11 = (one_c * xx) + c;
this._21 = (one_c * xy) - zs;
this._31 = (one_c * zx) + ys;
this._41 = 0;
this._12 = (one_c * xy) + zs;
this._22 = (one_c * yy) + c;
this._32 = (one_c * yz) - xs;
this._42 = 0;
this._13 = (one_c * zx) - ys;
this._23 = (one_c * yz) + xs;
this._33 = (one_c * zz) + c;
this._43 = 0;
this._14 = 0;
this._24 = 0;
this._34 = 0;
this._44 = 1;
*/
this._11 = (one_c * xx) + c; this._12 = (one_c * xy) - zs; this._13 = (one_c * zx) + ys; this._14 = 0; this._21 = (one_c * xy) + zs; this._22 = (one_c * yy) + c; this._23 = (one_c * yz) - xs; this._24 = 0; this._31 = (one_c * zx) - ys; this._32 = (one_c * yz) + xs; this._33 = (one_c * zz) + c; this._34 = 0; this._41 = 0; this._42 = 0; this._43 = 0; this._44 = 1; return this;
}
}// matrix 2x2function M22(){ this._11 = 1; this._12 = 0; this._21 = 0; this._22 = 1;
}
M22.prototype.getInvert = function(){ var out = new M22(); var det = this._11 * this._22 - this._12 * this._21; if (det > -0.0001 && det 3D衣服动画JS代码
function ClothApp(){ this.canvas = document.getElementById("cv");
P3D.g = this.canvas.getContext("2d"); var tex = new Image(); this.texture1 = tex;
tex.onload = function(){ _this.start(); };
tex.src = "20090226032826.gif";
tex = new Image(); this.texture2 = tex;
tex.onload = function(){ _this.start(); };
tex.src = "20090226032825.png"; this.mLoadCount = 2; this.mTickCount = 0; this.G = 0.53; this.G1 = 0.45; this.mProjMat = null; this.mViewMat = null; this.mViewFrom = new Vec3(); this.mViewFrom.y = -150; this.mViewFrom.z = 1000; this.mViewFromA = (new Vec3()).copyFrom(this.mViewFrom); this.mViewAngle = 0; this.mNLen = 0; this.mNodes = []; this.mRenderTris = null; this.mLTNode = null; this.mRTNode = null; this.mLTNodeV = new Vec3(); this.mRTNodeV = new Vec3(); this.mWForce = new Vec3(); this.frate = 15; var _this = this;
}
ClothApp.zsortCmp = function(t1, t2) { return t2.sortKey - t1.sortKey;
}
ClothApp.prototype = {
start: function() { if (--this.mLoadCount != 0) return; this.vUP = new Vec3(0, 1, 0); this.vAT = new Vec3(0, 80, 0); this.mViewport = {}; this.mViewport.w = 480; this.mViewport.h = 300; this.mViewport.ow = 240; this.mViewport.oh = 150; this.setupTransforms(); this.generateCloth(180); this.generateRenderTriangles(); var _this = this; this.canvas.addEventListener("mousemove", function(e){_this.onMouseMove(e);}, false); this.canvas.addEventListener("mousedown", function(e){_this.onClick(e);}, false); window.setTimeout(function(){_this.onInterval();}, this.frate);
},
onInterval: function() { this.mTickCount++; // this.mLTNodeV.z = Math.cos(this.mTickCount*0.1) * 2;
this.tick(); this.updatePosition(); this.draw(); var _this = this; window.setTimeout(function(){_this.onInterval();}, this.frate);
},
onMouseMove: function(e) { if (e.clientX || e.clientX == 0) this.mViewAngle = (e.clientX - 240) * 0.004; if (e.clientY || e.clientY == 0) this.mViewFromA.y = 90 - (e.clientY - 0) * 0.8;
},
onClick: function(e) { if (e.clientX || e.clientX == 0)
{ this.mWForce.z = -4; this.mWForce.x = (e.clientX - 240) * -0.03;
}
},
tick: function() { this.updateViewTrans(this.mViewAngle); var nlen = this.mNodes.length; var i, nd; for(i = 0;i 0.01)
sh = "rgba(0,0,0,"+t.shade+")";
P3D.drawTriangle(t.tposs, t.uvs, sh);
}
},
applyTension: function() { var i, k, nd; var v = new Vec3(); var nlen = this.mNodes.length; var naturalLen = this.mNLen; for (k = 0;k 0) {
v.smul(dlen * 0.5 / len);
F.x += v.x;
F.y += v.y;
F.z += v.z;
nd.cv.add(v.smul(0.8));
}
}
}
},
setupTransforms: function() { this.mProjMat = new M44(); this.mProjMat.perspectiveLH(24, 15, 10, 9000); this.mViewMat = new M44(); this.updateViewTrans(0);
},
updateViewTrans: function(ry) { this.mViewFromA.z = Math.cos(ry) * 380; this.mViewFromA.x = Math.sin(ry) * 380; this.mViewFrom.smul(0.7); this.mViewFrom.x += this.mViewFromA.x * 0.3; this.mViewFrom.y += this.mViewFromA.y * 0.3; this.mViewFrom.z += this.mViewFromA.z * 0.3; this.mViewMat.lookAtLH(this.vUP, this.mViewFrom, this.vAT);
},
generateCloth: function(base_y) { var cols = 9; var rows = 8; var step = 22; this.mNLen = step*0.9; var w = (cols-1) * step; var i, k; for (k = 0;k 0) { var prv_nd = this.mNodes[this.mNodes.length-1];
prv_nd.links[1] = nd;
nd.links[0] = prv_nd;
} if (k > 0) { var up_nd = this.mNodes[this.mNodes.length-cols];
up_nd.links[4] = nd;
nd.links[3] = up_nd;
} if (i != 0 && i != 4 && i != (cols-1))
nd.flags |= 4; this.mNodes.push(nd);
}
} // fix left-top and right-top
this.mNodes[0 ].flags |= 1; this.mNodes[4 ].flags |= 1; this.mNodes[cols-1].flags |= 1; this.mLTNode = this.mNodes[0 ]; this.mRTNode = this.mNodes[cols-1];
},
generateRenderTriangles: function() { if (!this.mRenderTris) this.mRenderTris = []; var i; var nd; var nlen = this.mNodes.length; for(i = 0;i 0)
t.shade = 0.8
else {
t.shade = 0.1 - N.y * 0.6; if (t.shade 以上就是HTML5 3D衣服摇摆动画特效的源码介绍,需要更为深入学习的下载源代码来研究。
本文链接:http://www.codeceo.com/article/html5-3d-cloth-swing.html
本文作者:码农网 – 小峰
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4809/viewspace-2809276/ ,如需转载,请注明出处,否则将追究法律责任。