ITPub博客

首页 > IT职业 > IT职场 > HTML5 3D衣服摇摆动画特效

HTML5 3D衣服摇摆动画特效

IT职场 作者:doudourabbit 时间:2021-09-09 09:17:18 0 删除 编辑

这又是一款基于HTML5 Canvas的3D动画杰作,它是一个可以随风飘动的3D衣服摇摆动画特效,非常逼真。当我们将鼠标滑过衣服时,衣服将会出现摇摆的动画,点击鼠标时,衣服将会更加剧烈地摆动。

在线演示源码下载

HTML代码

"3D on 2D Canvas" demo

move cursor to pan / click to swing

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) = 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/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 进程与线程
请登录后发表评论 登录
全部评论

注册时间:2019-04-25

  • 博文量
    193
  • 访问量
    1436