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负担,过多的透明度会影响渲染性能。
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
优化 dangerouslySetInnerHTML 渲染的几种方法: 1. 使用合适的编码方式:在使用 dangerouslySetInnerHTML 渲染内容时,需要确保内容的编码方式正确。比如,如果内容中包含特殊字符或者标签,需要使用合适的转义方式,避免出现解析错误。 2. 验证和过滤内容:在将内容设置到 dangerouslySetInnerHTML 之前,可以先对内容进行验证和过滤,确保其安全性。可以使用 DOMParser 或者其他类似的工具对内容进行解析,过滤掉潜在的恶意代码。 3. 缓存内容:如果使用的内容是静态的,可以考虑将其缓存在组件中,避免每次渲染都重新设置内容。这样可以提高渲染性能,并减少不必要的重复操作。 4. 使用虚拟 DOM:虚拟 DOM 是一个在内存中对真实 DOM 的表示,可以用于高效地对比和更新 DOM。可以将 dangerouslySetInnerHTML 的内容渲染到虚拟 DOM 中,然后通过比较更新前后的虚拟 DOM,只修改发生变化的部分,以提高渲染效率。 5. 懒加载内容:如果内容较多,可以考虑将其异步加载,而不是在首次渲染时一次性加载所有内容。可以使用类似于 React.lazy() 的懒加载方式,按需加载并渲染内容,提高页面加载速度。 总结起来,优化 dangerouslySetInnerHTML 渲染可以通过正确编码内容、验证和过滤内容、缓存内容、使用虚拟 DOM 和懒加载内容等方式实现。这样可以提高渲染性能,保证页面的安全性。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

揽月凡尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值