Javascript HTML5画布滞后

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

我最近在我的页面中添加了一个画布元素,即球体上的随机点。它在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, 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];
返回