PixiJS 渲染优化

最近做在线CAD可视化与编辑,对前端的可视化渲染技术进行了选型,对于二维CAD来说一般用canvas就够了,但是canvas每一次平移,缩放,更新数据都需要重新计算渲染所有的图形数据,数据一多就显得非常卡。如果使用三维webgl,在没有任何第三方的开源封装技术下,通过webgl去实现二维也是会遇到很多问题。基于此,找到了PixiJS这个支持canvas和webgl渲染的引擎,关键是非常快(之前在github看到过一个在线的程序测试,有十几种渲染引擎的测试,我对比过确实是最强的,这个网站忘记在哪里了)

常规的优化策略

1. 使用BatchGeomery

BatchGeomery是一种优化渲染性能的技术,它可以将多个Geomery对象合并成一个渲染批次,从而减少渲染调用次数,是一种实例化技术,要求对象的图形和属性都是一样,其他的Graphics对象都是基于这个基准对象去优化.

const app = new PIXI.Application();

document.body.appendChild(app.view);

const geometry = new PIXI.Geometry()
    .addAttribute('aVPos', [-100, 0, 100, 0, 0, -150]);

geometry.instanced = true;
geometry.instanceCount = 5;

const positionSize = 2;
const colorSize = 3;
const buffer = new PIXI.Buffer(new Float32Array(geometry.instanceCount * (positionSize + colorSize)));

geometry.addAttribute('aIPos', buffer, positionSize, false, PIXI.TYPES.FLOAT, 4 * (positionSize + colorSize), 0, true);
geometry.addAttribute('aICol', buffer, colorSize, false, PIXI.TYPES.FLOAT, 4 * (positionSize + colorSize), 4 * positionSize, true);

for (let i = 0; i < geometry.instanceCount; i++) {
    
    
    const instanceOffset = i * (positionSize + colorSize);

    buffer.data[instanceOffset + 0] = i * 80;
    buffer.data[instanceOffset + 2] = Math.random();
    buffer.data[instanceOffset + 3] = Math.random();
    buffer.data[instanceOffset + 4] = Math.random();
}

const shader = PIXI.Shader.from(`
    precision mediump float;
    attribute vec2 aVPos;
    attribute vec2 aIPos;
    attribute vec3 aICol;

    uniform mat3 translationMatrix;
    uniform mat3 projectionMatrix;

    varying vec3 vCol;

    void main() {
        vCol = aICol;

        gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVPos + aIPos, 1.0)).xy, 0.0, 1.0);
    }`,

`precision mediump float;

    varying vec3 vCol;

    void main() {
        gl_FragColor = vec4(vCol, 1.0);
    }

`);

const triangles = new PIXI.Mesh(geometry, shader);

triangles.position.set(400, 300);

app.stage.addChild(triangles);

app.ticker.add((delta) => {
    
    
    triangles.rotation += 0.01;
});

2. 使用WebGL渲染器:WebGL渲染器可以利用GPU加速渲染,从而提高渲染性能

PixiJS默认使用WebGL渲染,但可以通过以下方式强制使用Canvas渲染

// 创建一个使用Canvas渲染的Pixi应用程序
const app = new PIXI.Application({
    
    
    width: 800,
    height: 600,
    forceCanvas: true // 强制使用Canvas渲染
});

如果要在运行时切换渲染器,可以使用以下代码

// 获取当前渲染器
const renderer = app.renderer;

// 切换渲染器
if (renderer instanceof PIXI.WebGLRenderer) {
    
    
    app.renderer = new PIXI.CanvasRenderer();
} else if (renderer instanceof PIXI.CanvasRenderer) {
    
    
    app.renderer = new PIXI.WebGLRenderer();
}

3. 减少渲染对象数量

减少渲染对象数量可以减少渲染调用次数,从而提高渲染性能。可以通过合并对象、使用图集等方式来实现。

对于CAD数据,如果每个矢量都使用一个Grpahics对象,不仅内存消耗比较大,而且性能下降很厉害。如果整个CAD图面的数据都不做修改,完全可以将所有的图形绘制到一个Graphics对象中,大概方法如下:

var g1=new PIXI.Graphics();
//绘制第一个对象;
g1.beginFill(0xFF0000);
g1.drawCircle(10,10,20);
gl.endFill();
//绘制第二个对象;
g1.beginFill(0x00FF);
g1.drawRect(0,0,10,10);
gl.endFill();
//绘制后面的对象
...
//添加到舞台;
app.stage.addChild(g1);

以下是近10M的原始CAD数据(对象大概是100万左右)使用一个对象一个Graphics的对象的渲染情况,内存消耗11G,帧率基本为0,处于半假死状态
1681627662787-2b42eca6-f6ec-47fa-ba35-83eb7bba125e.png
而如果使用将所有的对象使用放在一个Graphics中,可以发现帧率可以达到近40帧,内存消耗在4500M(但是这种方式不太适合对单个对象进行操作,对于纯浏览是没有什么问题的)
![1681627285950-e8e26fbc-018d-4363-9373-106507d0fadc.png])

4.共享几何对象

我们不是单个图形对象,而是创建多个图形,这些图形都共享相同的几何图形。图形的唯一可选构造函数是对另一个图形几何实例的引用。这种方法更新

var g1=new PIXI.Graphics();
g1.beginFill(0xFF0000);
g1.drawRect(0,0,100,100);
g1.endFill();
app.stage.addChild(g1);

var g2=new PIXI.Graphics(g1.geometry); //如果和第一个对象只是位置不同,可以这样使用.
g2.x=g2.x+10;
g2.y=g2.y+10;
app.stage.addChild(g2);

5. 使用位图文本

位图文本可以也可以大幅的减少渲染器的内存使用量,具体用法可以参考 《PixiJs文字模糊处理

6. 渲染纹理

此方法不使用共享的图形几何体,而是使用 RenderTexture 渲染单个图形对象。然后像使用任何纹理一样使用它,并在精灵之间共享。从本质上讲,这是相同的效果,但没有图形开销和更好的抗锯齿。如果需要缩放圆圈,只需以较大的初始大小渲染渲染纹理即可(在极限缩放情况下,显示还是会比较模糊)
image.png

7. 设置为可剔除的

在处理数千个元素时,仅在屏幕上显示基本元素至关重要,当可视区域数据较少时,性能可以大幅提升(可能是由于pixijs外包计算的问题,效率的效率提升并不是非常的明显)
image.png

8. 避免使用过多的滤镜:滤镜可以增强渲染效果,但是过多的滤镜会影响渲染性能。

9. 使用低分辨率纹理:使用低分辨率纹理可以减少GPU负担,从而提高渲染性能。

10. 避免使用过多的透明度:透明度会增加GPU负担,过多的透明度会影响渲染性能。

猜你喜欢

转载自blog.csdn.net/qq_33377547/article/details/130184896