离屏渲染(OffscreenRendering)

离屏渲染(OffscreenRendering)是性能优化策略,通过在内存中完成渲染后再显示,避免屏幕闪烁和重绘。HTML5的OffscreenCanvas允许在Web Worker线程渲染,减轻主线程负担。在OpenGL和WebGL中,离屏渲染常用于3D场景和特殊效果。虽然消耗更多资源,但能提升渲染效率。示例展示了如何在Web Worker中使用OffscreenCanvas进行离屏绘制。
  1. 介绍:

离屏渲染(OffscreenRendering)是一种常见的性能优化策略,用于减少图形渲染的时间和复杂性。在此模式下,所有的渲染操作都会在当前屏幕视图之外的内存区域进行。只有当所有的渲染操作完成后,才会将最终的图像传输到屏幕上。
这种方式的一个重要好处是可以避免屏幕闪烁或者不必要的重绘,因为所有的渲染工作都是在后台完成的,用户不会看到半成品的渲染结果。 HTML5 的
OffscreenCanvas 就是离屏渲染技术的一个实例。它允许开发者在 Web Worker
线程中执行渲染操作,然后再将结果显示到屏幕上。这样可以把渲染过程从主线程中剥离出去,避免阻塞 UI 的运行。
另外,在OpenGL或WebGL等3D渲染环境中,离屏渲染也被广泛使用。例如,开发者可能会创建一个离屏缓冲区(Framebuffer
Object, FBO),在这个缓冲区里绘制3D场景,然后再将渲染结果呈现到屏幕上。这对于实现各种效果(如反射、阴影、模糊等)非常有用。
总的来说,离屏渲染是一个强大且灵活的工具,能提供更优雅和高效的渲染解决方案。但是,它也需要更多的内存和处理能力,所以在使用时需要权衡其利弊。

  1. OffscreenCanvas 的基本使用示例如下:
  • 首先,我们需要在主线程上创建 OffscreenCanvas,并传送给 worker:
var offscreen = document.querySelector('canvas').transferControlToOffscreen();
var worker = new Worker('worker.js');
worker.postMessage({ canvas: offscreen }, [offscreen]);
  • 接下来,在 worker 内部,我们可以像通常一样操作 Canvas:
self.onmessage = function(event) {
  var offscreen = event.data.canvas;
  var ctx = offscreen.getContext('2d');

  ctx.fillStyle = 'red';
  ctx.fillRect(0, 0, offscreen.width, offscreen.height);
};
  1. 企业使用案例:
  • 初始化需要绘制的canvas实例
initCanvas() {
this.canvas = this.$refs[`canvas${this.cameraIndex}`]
this.ctx = this.canvas.getContext("2d", { alpha: false })

// to here
// Globally init once 离屏画布
this.image = new Image()

this.offscreen_img_canvas = document.createElement("canvas")
this.offscreenCtx = this.offscreen_img_canvas.getContext("2d", {
  alpha: false,
}}
  • 离屏绘制具体步骤案例
drawImages: async function (info) {
     const begin = window.performance.now(),
       image = new Image(),
       { ctx, offscreen_img_canvas, offscreenCtx } = this
     if (this.current_concurrency >= this.concurrency_threshold) {
       return
     }
     this.current_concurrency++
     const t0 = performance.now()
     let blob = new Blob([info.matData], { type: "image/jpeg" })
     const t1 = performance.now()
     this.draw_duration_counter.register("getBlob", t1 - t0)
     image.src = (window.URL || window.webkitURL).createObjectURL(blob)
     image.onload = () => {
       this.current_concurrency--
       const t2 = performance.now()
       this.draw_duration_counter.register("imgLoad", t2 - t1)

       if (!this.draw_counter) {
         this.draw_counter = new GeneralCounter("draw")
       }
       this.draw_counter.count()

       // console.info(">>> onload")

       if (image.src) {
         window.URL.revokeObjectURL(image.src)
       }
       this.clock(begin, "Image Loaded Success!")
       offscreen_img_canvas.width = info.cols
       offscreen_img_canvas.height = info.rows

       // FIXME:自适应
       offscreenCtx.drawImage(image, 0, 0, info.cols, info.rows)
       const t3 = performance.now()
       this.draw_duration_counter.register("offCanvasImgDraw", t3 - t2)

       this.changeoffscreenCtx(info)
       this.drawGazes(offscreenCtx)
       this.drawHand && this.drawHand(offscreenCtx)
       this.drawFace && this.drawFace(offscreenCtx)
       const t4 = performance.now()
       this.draw_duration_counter.register("offCanvasMetaDraw", t4 - t3)

       ctx.clearRect(0, 0, info.cols, info.rows)
       ctx.drawImage(offscreen_img_canvas, 0, 0)

       const t5 = performance.now()
       this.draw_duration_counter.register("canvasDraw", t5 - t4)

       this.clock(begin, "Draw Success!")
       this.draw_duration_counter.register("total", t5 - t0)
     }
   },
   
  • 使用来自外部信息 info 的尺寸设置离屏 canvas 的大小:
offscreen_img_canvas.width = info.cols;
offscreen_img_canvas.height = info.rows;
  • 利用 drawImage() 方法在离屏 canvas 上绘制图像:
offscreenCtx.drawImage(image, 0, 0, info.cols, info.rows);
  • 在离屏 canvas 上进行一些额外的绘制操作,如绘制注视点
(this.drawGazes(offscreenCtx))、手势 (this.drawHand && this.drawHand(offscreenCtx)) 和面部(this.drawFace && this.drawFace(offscreenCtx)):

javascript复制代码this.changeoffscreenCtx(info);
this.drawGazes(offscreenCtx);
this.drawHand && this.drawHand(offscreenCtx);
this.drawFace && this.drawFace(offscreenCtx);
  • 清除主 canvas,然后将离屏 canvas 的内容绘制到主 canvas 上:
ctx.clearRect(0, 0, info.cols, info.rows);
ctx.drawImage(offscreen_img_canvas, 0, 0);

以上这整个流程就是典型的离屏渲染。首先在内存中的 canvas (即离屏
canvas)上进行所有的绘制操作,这包括绘制图像和一些额外的元素(如注视点、手势、面部等)。然后只有当所有的绘制操作都完成后,才会把最终的图像渲染到页面上的
canvas 元素上。这种做法可以有效地减少浏览器重绘的次数,从而提高性能。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值