Javascript HTML5画布滞后
我最近在我的页面中添加了一个画布元素,即球体上的随机点。它在PC上非常有效,但在手机和平板电脑上渲染速度非常慢。 如何加速球体并减少滞后?Javascript HTML5画布滞后,javascript,html5-canvas,Javascript,Html5 Canvas,我最近在我的页面中添加了一个画布元素,即球体上的随机点。它在PC上非常有效,但在手机和平板电脑上渲染速度非常慢。 如何加速球体并减少滞后? 任何帮助都将不胜感激。还有很大的改进空间 在渲染循环中 for (var p of points) { p = rotation.multiplyVector(p); ctx.beginPath(); ctx.arc(p.x + c.width / 2, p.y + c.height / 2, 2, 0
任何帮助都将不胜感激。还有很大的改进空间 在渲染循环中
for (var p of points) {
p = rotation.multiplyVector(p);
ctx.beginPath();
ctx.arc(p.x + c.width / 2, p.y + c.height / 2, 2, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
}
如果反复渲染相同的样式,则不需要beginPath
ctx.beginPath();
for (var p of points) {
p = rotation.multiplyVector(p);
const x = p.x + c.width / 2;
const y = p.y + c.height / 2;
ctx.moveTo(x + 2, y)
ctx.arc(x, y, 2, 0, 2 * Math.PI);
}
ctx.fill();
然后矩阵向量乘法具有不必要的检查、不必要的内存分配和对象实例化
你有
Matrix3.prototype.multiplyVector = function (vec) {
if (vec instanceof Vector3) {
var x = this.data[0 + 0 * 3] * vec.x + this.data[0 + 1 * 3] * vec.y + this.data[0 + 2 * 3] * vec.z;
var y = this.data[1 + 0 * 3] * vec.x + this.data[1 + 1 * 3] * vec.y + this.data[1 + 2 * 3] * vec.z;
var z = this.data[2 + 0 * 3] * vec.x + this.data[2 + 1 * 3] * vec.y + this.data[2 + 2 * 3] * vec.z;
return new Vector3(x, y, z);
}
}
如果(vec instanceof Vector3){?,这种情况不会发生吗?不在代码中,那么为什么要浪费CPU时间呢
然后this.data[2+0*3]
乐观主义者可能会帮你得到这个,但手机的优化效果不如台式机,我不确定这是否会被采用。另外,一些浏览器在使用间接引用this.data[?]
时速度比data[?]
慢
为每个圆创建一个新的向量以立即丢弃它对内存来说一点也不友好。您只需要一个对象,因此将其传递给函数进行设置
改进
Matrix3.prototype.multiplyVector = function (vec, retVec = new Vector3(0,0,0)) {
const d = this.data;
retVec.x = d[0] * vec.x + d[3] * vec.y + d[6] * vec.z;
retVec.y = d[1] * vec.x + d[4] * vec.y + d[7] * vec.z;
retVec.z = d[2] * vec.x + d[5] * vec.y + d[8] * vec.z;
return retVec;
};
然后在循环中
const rp = new Vector3(0,0,0);
ctx.beginPath();
for (var p of points) {
rotation.multiplyVector(p,rp);
const x = rp.x + c.width / 2;
const y = rp.y + c.height / 2;
ctx.moveTo(x + 2, y)
ctx.arc(x, y, 2, 0, 2 * Math.PI);
}
ctx.fill();
Vector3
和Matrix3
对象都是非常浪费内存的对象,这意味着您无法控制CPU周期,只能在应该重用内存时分配和删除,如上所示
您可以使用矩阵旋转函数来构建旋转,该旋转会创建一个新矩阵来创建一个旋转矩阵,然后需要一个新矩阵来进行乘法。您可以创建6个完整的矩阵对象来获得一个矩阵
调用rotate函数时,x,y,z中的2为0,这意味着许多乘法和加法都只是得到0,或者最终加上等于1的omc+cos,或者乘以1不做任何更改
你有
Matrix3.rotate = function (angle, x, y, z) {
var result = new Matrix3();
result.setIdentity();
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var omc = 1 - cos;
result.data[0 + 0 * 3] = x * omc + cos;
result.data[1 + 0 * 3] = y * x * omc + z * sin;
result.data[2 + 0 * 3] = x * z * omc - y * sin;
result.data[0 + 1 * 3] = x * y * omc - z * sin;
result.data[1 + 1 * 3] = y * omc + cos;
result.data[2 + 1 * 3] = y * z * omc + x * sin;
result.data[0 + 2 * 3] = x * z * omc + y * sin;
result.data[1 + 2 * 3] = y * z * omc - x * sin;
result.data[2 + 2 * 3] = z * omc + cos;
return result;
}
通过直接乘以矩阵创建旋转矩阵,每个轴需要一个旋转矩阵
Matrix3.prototype.rotateX = function(angle, result = new Matrix3()) {
const r = result.data;
const d = this.data;
const c = Math.cos(angle);
const s = Math.sin(angle));
const ns = -s;
r[0] = d[0]
r[1] = d[1] * c + d[2] * ns;
r[2] = d[1] * s + d[2] * c;
r[3] = d[3];
r[4] = d[4] * c + d[5] * ns;
r[5] = d[4] * s + d[5] * c;
r[6] = d[6];
r[7] = d[7] * c + d[8] * ns;
r[8] = d[7] * s + d[8] * c;
return result;
},
对rotateY和rotateZ执行相同的操作(每个操作与上述操作不同)
实例矩阵直接设置标识,而不需要第二次调用
function Matrix3() { this.data = [1,0,0,0,1,0,0,0,1] }
认同
Matrix3.prototype.setIdentity = function () {
const d = this.data;
d.fill(0);
d[8] = d[4] = d[0] = 1;
}
然后在循环函数中访问两个矩阵对象
const mat1 = new Matrix3();
const mat2 = new Matrix3();
const rp = new Vector3(0,0,0);
const MPI2 = 2 * Math.PI;
function loop(){
mat1.setIdentity();
mat1.rotateX(angle.x,mat2);
mat2.rotateY(angle.y,mat1);
mat1.rotateZ(angle.z,mat2);
// your text rendering in here
const cw = c.width / 2;
const ch = c.height / 2;
ctx.beginPath();
for (var p of points) {
mat2.multiplyVector(p,rp);
const x = rp.x + cw;
const y = rp.y + ch;
ctx.moveTo(x + 2, y)
ctx.arc(x, y, 2, 0, MPI2);
}
ctx.fill();
}
这将给你一点额外的速度。任何其他的改进都将是特定于浏览器/设备的
更新根据注释中的要求,以下代码段包含缩短的旋转矩阵乘以X、Y和Z轴的旋转
//如何通过
//删除a[?]*0=0
//减少a[?]*1=a[?]
//
//以下是X、Y、Z作为矩阵的旋转
//-------------------
//旋转X
// 1 0 0
//0 cos(r)sin(r)
//0-正弦(r)余弦(r)
//-------------------
//旋转Y
//cos(r)0 sin(r)
// 0 1 0
//-sin(r)0 cos(r)
//-------------------
//旋转Z
//cos(r)sin(r)0
//-sin(r)cos(r)0
// 0 0 1
//矩阵索引
// [0][1][2]
// [3][4][5]
// [6][7][8]
//使用索引和乘法是c=a*b
//c[0]=a[0]*b[0]+a[1]*b[3]+a[2]*b[6]
//c[1]=a[0]*b[1]+a[1]*b[4]+a[2]*b[7]
//c[2]=a[0]*b[2]+a[1]*b[5]+a[2]*b[8]
//c[3]=a[3]*b[0]+a[4]*b[3]+a[5]*b[6]
//c[4]=a[3]*b[1]+a[4]*b[4]+a[5]*b[7]
//c[5]=a[3]*b[2]+a[4]*b[5]+a[5]*b[8]
//c[6]=a[6]*b[0]+a[7]*b[3]+a[8]*b[6]
//c[7]=a[6]*b[1]+a[7]*b[4]+a[8]*b[7]
//c[8]=a[6]*b[2]+a[7]*b[5]+a[8]*b[8]
//然后使用旋转矩阵找到零和一
//例如旋转X b[1],b[2],b[3],b[6]为零,b[0]为一
//c[0]=a[0]*1+a[1]*0+a[2]*0
//c[1]=a[0]*0+a[1]*b[4]+a[2]*b[7]
//c[2]=a[0]*0+a[1]*b[5]+a[2]*b[8]
//c[3]=a[3]*1+a[4]*0+a[5]*0
//c[4]=a[3]*0+a[4]*b[4]+a[5]*b[7]
//c[5]=a[3]*0+a[4]*b[5]+a[5]*b[8]
//c[6]=a[6]*1+a[7]*0+a[8]*0
//c[7]=a[6]*0+a[7]*b[4]+a[8]*b[7]
//c[8]=a[6]*0+a[7]*b[5]+a[8]*b[8]
//然后消除所有零项a[?]*0==0,然后
//从1*a[?]=a[?]
//c[0]=a[0]
//c[1]=a[1]*b[4]+a[2]*b[7]
//c[2]=a[1]*b[5]+a[2]*b[8]
//c[3]=a[3]
//c[4]=a[4]*b[4]+a[5]*b[7]
//c[5]=a[4]*b[5]+a[5]*b[8]
//c[6]=a[6]
//c[7]=a[7]*b[4]+a[8]*b[7]
//c[8]=a[7]*b[5]+a[8]*b[8]
//您只需进行应用特定旋转或任何其他变换所需的最小计算。
Matrix3.prototype.rotateX=函数(角度,结果=新Matrix3()){
常数r=结果数据;
const d=这个数据;
常数c=数学cos(角度);
常数s=数学sin(角度);
常数ns=-s;
r[0]=d[0];
r[1]=d[1]*c+d[2]*ns;
r[2]=d[1]*s+d[2]*c;
r[3]=d[3];
r[4]=d[4]*c+d[5]*ns;
r[5]=d[4]*s+d[5]*c;
r[6]=d[6];
r[7]=d[7]*c+d[8]*ns;
r[8]=d[7]*s+d[8]*c;
返回结果;
}
Matrix3.prototype.rotateY=函数(角度,结果=新Matrix3()){
常数r=结果数据;
const d=这个数据;
常数c=数学cos(角度);
常数s=数学sin(角度);
常数ns=-s;
r[0]=d[0]*c+d[2]*ns;
r[1]=d[1];
r[2]=d[0]*s+d[2]*c;
r[3]=d[3]*c+d[5]*ns;
r[4]=d[4];
r[5]=d[3]*s+d[5]*c;
r[6]=d[6]*c+d[8]*ns;
r[7]=d[7];
r[8]=d[6]*s+d[8]*c;
返回结果;
}
Matrix3.prototype.rotateZ=函数(角度,结果=新Matrix3()){
常数r=结果数据;
const d=这个数据;
常数c=数学cos(角度);
常数s=数学sin(角度);
常数ns=-s;
r[0]=d[0]*c+d[1]*ns;
r[1]=d[0]*s+d[1]*c;
r[2]=d[2];
r[3]=d[3]*c+d[4]*ns;
r[4]=d[3]*s+d[4]*c;
r[5]=d[5];
r[6]=d[6]*c+d[7]*ns;
r[7]=d[6]*s+d[7]*c;
r[8]=d[8];
返回