Three.js OffscreenCanvas   

OffscreenCanvas是一种相对较新的浏览器功能,目前仅在Chrome中可用,但显然也即将适用于其他浏览器。

OffscreenCanvas使web worker能够渲染canvas。这是一种办法把繁重的工作(如渲染复杂的3D场景)交给web worker,为了避免降低浏览器的响应速度。这还意味着数据是在worker中加载和解析的,因此在页面加载时可能会减少卡顿(jank)   

初步的使用非常简单,让我们移植3旋转立方体示例从the article on responsiveness。worker通常将他们的代码分离到另一个脚本文件中,而这个站点上的大多数示例都将他们的脚本嵌入到他们所在页面的HTML文件中。 在本例中,我们将创建一个名为offscreencanvas-cubes.js的文件,并将响应式example中的所有JavaScript复制到该文件中。然后,我们将进行必要的更改,使其在辅助进程中运行。

我们仍然需要写一些JavaScript代码在HTML页面中。我们需要做的第一件事是找到canvas,然后通过调用 canvas.transferControlToOffscreen 将该画布的控制权转移到屏幕外。

function main() {
const canvas = document.querySelector('#c');
const offscreen = canvas.transferControlToOffscreen(); ...

然后,我们可以用新的 worker(pathToScript,{type:'module'} 启动我们的worker。并将 offscreen 对象传递给它。

function main() {
const canvas = document.querySelector('#c');
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('offscreencanvas-cubes.js', {type: 'module'});
worker.postMessage({type: 'main', canvas: offscreen}, [offscreen]);
}
main();

需要注意的是,worker不能访问DOM。他们不能查看HTML元素,也不能接收鼠标事件或键盘事件。通常他们能做的唯一一件事就是响应发送给他们的消息,并将消息发送回页面。

要向worker发送消息,我们调用 worker.postMessage 并向其传递1或2个参数。第一个参数是一个JavaScript对象,它将被 clone 并发送给worker。第二个参数是一个可选的对象数组,它是第一个对象的一部分,第一个对象是我们想要传递给worker的对象。这些对象将不会被克隆。相反,它们将被转移,并将不再存在于主页中。“不存在”可能是错误的描述,相反,它们是中性的。只能传输某些类型的对象,而不能克隆。它们包括 OffscreenCanvas ,因此一旦将 OffscreenCanvas 传输回主页,就没有用了。

worker从他们的 onmessage 处理程序接收消息。我们传递给 postMessage 的对象在 event.data 传递给worker上的 onmessage 处理程序时到达。上面的代码在传递给worker的对象中声明了一个类型:“main”。此对象对浏览器没有意义。这完全是我们自己用的。我们将创建一个处理程序,他基于类型调用worker中不同函数。然后,我们可以根据需要添加函数,并从主页面轻松调用它们。

const handlers = {
main,
}; self.onmessage = function(e) {
const fn = handlers[e.data.type];
if (!fn) {
throw new Error('no handler for type: ' + e.data.type);
}
fn(e.data);
};

调用一个不同的函数,您可以在上面看到,我们只是根据类型查找处理程序,并将从主页发送的数据传递给它,因此,现在我们只需要开始更改我们从the article on responsiveness 粘贴到 offscreencanvas-cubes.js 中的 main 。

我们将从事件数据接收canvas,而不是从DOM中查找canvas。(canvas可以传递吗)

//function main() {
// const canvas = document.querySelector('#c');
function main(data) {
const {canvas} = data;
const renderer = new THREE.WebGLRenderer({canvas}); ...

记住worker根本看不到DOM,我们遇到的第一个问题是 ResizeRenderToDisplaySize 不能查看 canvas.clientWidth 和 canvas.ClientHight ,因为它们是DOM值。这是原始代码

function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}

相反,我们需要在 size 变化时将其发送给worker。所以,让我们添加一些全局状态,并将宽度和高度放置在那里。

const state = {
width: 300, // canvas default
height: 150, // canvas default
};

然后,让我们添加一个 “size” 处理程序来更新这些值。

function size(data) {
state.width = data.width;
state.height = data.height;
} const handlers = {
main,
size,
};

现在我们可以将 ResizeRenderToDisplaySize 更改为使用 state.width 和 state.height 。

function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
// const width = canvas.clientWidth;
// const height = canvas.clientHeight;
const width = state.width;
const height = state.height;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}

在我们计算aspect 的地方,我们需要类似的变化

function render(time) {
time *= 0.001; if (resizeRendererToDisplaySize(renderer)) {
// camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.aspect = state.width / state.height;
camera.updateProjectionMatrix();
} ...

回到主页,我们将在页面大小更改时发送大小事件。

const worker = new Worker('offscreencanvas-picking.js', {type: 'module'});
worker.postMessage({type: 'main', canvas: offscreen}, [offscreen]); function sendSize() {
worker.postMessage({
type: 'size',
width: canvas.clientWidth,
height: canvas.clientHeight,
});
} window.addEventListener('resize', sendSize);
sendSize();

我们还可以调用它一次,以发送初始大小。

仅做了这些改动,假设您的浏览器完全支持Offscreencanvas,它应该可以正常工作。在我们运行它之前,让我们检查一下浏览器是否真的支持OffscreenCanvas,如果不支持,则显示一个错误。首先,让我们添加一些HTML来显示错误。

<body>
<canvas id="c"></canvas>
<div id="noOffscreenCanvas" style="display:none;">
<div>no OffscreenCanvas support</div>
</div>
</body>

和一些css:

#noOffscreenCanvas {
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
background: red;
color: white;
}

然后我们可以检查 transferControlToOffscreen 是否存在,以查看浏览器是否支持 OffscreenCanvas

function main() {
const canvas = document.querySelector('#c');
if (!canvas.transferControlToOffscreen) {
canvas.style.display = 'none';
document.querySelector('#noOffscreenCanvas').style.display = '';
return;
}
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('offscreencanvas-picking.js', {type: 'module});
worker.postMessage({type: 'main', canvas: offscreen}, [offscreen]); ...

如果你的浏览器支持Offscreencanv,那么这个例子就可以了(官方页面中有,我没粘过来,在博客园弄js不太方便)

click here to open in a separate window

这个例子很不错,但因为目前不是每个浏览器都支持OffscreenCanvas,所以让我们将代码更改为同时使用 OffscreenCanvas 和 canvas ,如果不支持 OffscreenCanvas ,则退回到主页中使用 canvas ,就像正常情况一样

顺便说一句,如果你需要OffscreenCanvas来让你的页面更具响应性,那么现在还不清楚回退的意义何在。可能基于您是否最终在主页面上运行或在worker中运行,您可能会调整完成的工作量,以便在worker中运行时可以比在主页面上运行时做得更多。你做什么真的取决于你自己。

我们应该做的第一件事可能是将three.js代码与特定于worker的代码分开。这样我们就可以在主页和工作页面上使用相同的代码。换句话说,我们现在将有3个文件

    1. our html file: threejs-offscreencanvas-w-fallback.html
    2. a JavaScript that contains our three.js code: shared-cubes.js
    3. our worker support code: offscreencanvas-worker-cubes.js

shared-cubes.js 和 offscreencanvas-worker-cubes.js 基本上是我们之前 offscreencanvas-cubes.js 文件的拆分。首先,我们将 offscreencanvas-cubes.js 复制到 shared-cube.js 。然后我们将 main 重命名为 init ,因为我们的HTML文件中已经有一个 main ,我们需要导出 init 和 state

import * as THREE from './resources/threejs/r132/build/three.module.js';

const state = {
export const state = {
width: 300, // canvas default
height: 150, // canvas default
}; function main(data) {
export function init(data) {
const {canvas} = data;
const renderer = new THREE.WebGLRenderer({canvas});

(课业太忙了,暂时没时间写了,未完待续。。。)

翻译《threejsfundamentals》离屏渲染+web-worker一篇的更多相关文章

  1. web worker 扫盲篇

    什么是woker 官方的解释是这样的: worker是一个对象,通过构造函数Worker创建,参数就是一个js文件的路径:文件中的js代码将运行在主线程之外的worker线程: var jsFileU ...

  2. 离屏Canvas — 使用Web Worker提高你的Canvas运行速度

    离屏Canvas — 使用Web Worker提高你的Canvas运行速度 原文链接: developers.google.com 现在因为有了离屏Canvas,你可以不用在你的主线程中绘制图像了! ...

  3. 新兴的API(fileReader、geolocation、web计时、web worker)

    requestAnimationFrame() 每次浏览器重绘之前会调用这个方法!!! 它接收一个参数,就是回调函数: 它可以保证在最佳的间隔时间调用传入的回调函数,以达到让屏幕产生最流畅的动画效果. ...

  4. Web Worker javascript多线程编程(一)

    什么是Web Worker? web worker 是运行在后台的 JavaScript,不占用浏览器自身线程,独立于其他脚本,可以提高应用的总体性能,并且提升用户体验. 一般来说Javascript ...

  5. HTML5 Web Worker的使用

    Web Workers 是 HTML5 提供的一个javascript多线程解决方案,我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面. 一:如何使用Worker Web Wo ...

  6. Web Worker 是什么鬼?

    前言 前端工程师们一定有过这样的体验,当一个页面加载了大量的 js 文件时,用户界面可能会短暂地"冻结".这很好理解,因为 js 是单线程的语言.我们再走的极端点,一段 js 中出 ...

  7. 腾讯优测优分享 | 探索react native首屏渲染最佳实践

    腾讯优测是专业的移动云测试平台,旗下的优分享不定时提供大量移动研发及测试相关的干货~ 此文主要与以下内容相关,希望对大家有帮助. react native给了我们使用javascript开发原生app ...

  8. 深入理解JS异步编程四(HTML5 Web Worker)

    >Web Workers 是 HTML5 提供的一个javascript多线程解决方案,我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面. 一:如何使用Worker We ...

  9. 探索react native首屏渲染最佳实践

    文 / 腾讯 龚麒 0.前言 react native给了我们使用javascript开发原生app的能力,在使用react native完成兴趣部落安卓端发现tab改造后,我们开始对由react n ...

  10. 通过一次实验来了解HTML5的 Web Worker

    web worker 是运行在后台的 JavaScript,不会影响页面的性能. 当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成. web worker 是运行在后台的 Ja ...

随机推荐

  1. SpringBoot 02: 初识SpringBoot

    1. SpringBoot 产生原因 spring, springmvc框架使用上的一些缺点: 需要使用的大量的配置文件 还需要配置各种对象 需要把使用的对象放入到spring容器中才能使用对象 需要 ...

  2. 【Azure API 管理】Azure APIM服务集成在内部虚拟网络后,在内部环境中打开APIM门户使用APIs中的TEST功能失败

    问题描述 使用微软API管理服务(Azure API Management),简称APIM. 因为公司策略要求只能内部网络访问,所以启用了VNET集成.集成方式见: (在内部模式下使用 Azure A ...

  3. 打不开 github 的方法与推荐基于Vue3与Element plus的后台管理系统

    一.打不开 github 的方法 1.打开本机 hosts 文件(C:\Windows\System32\drivers\etc) 2.然后在 hosts 文件里的末尾放入一下两个 IP 地址: # ...

  4. ThinkPhp5 自定义异常处理类

    在项目的开发过程中异常抛出尤为重要不仅能够做出友好提示帮助掩盖我们伟大的程序员们尴尬的瞬间,还能做到提示开发人员代码白编写的错误,下面进行自定义异常抛出类,纯属个人理解,希望大家指正 首先在框架中我们 ...

  5. 配置MSTP功能示例

    组网需求 在一个复杂的网络中,网络规划者由于冗余备份的需要,一般都倾向于在设备之间部署多条物理链路,其中一条作主用链路,其他链路作备份.这样就难免会形成环形网络,若网络中存在环路,可能会引起广播风暴和 ...

  6. php7怎么安装memcache扩展

    php7安装memcache扩展 1.下载文件,解压缩 memcache windows php7下载地址: https://github.com/nono303/PHP7-memcache-dll ...

  7. SSH(三)创建包和第一个页面

    在ssh web项目src下一次创建 com.ssh/ .action .dao .entity .service 四个包,example: 在entity包下创建class,name: produc ...

  8. 长度最小子数组-LeetCode209 滑动窗口

    力扣:https://leetcode.cn/problems/minimum-size-subarray-sum/ 题目 给定一个含有 n 个正整数的数组和一个正整数 target .找出该数组中满 ...

  9. Linux 系统环境监测

    Linux系统环境监测 Linux系统环境主要监测CPU.内存.磁盘I/O和网络流量. 1. CPU (1) 查看CPU的负载情况:uptime 可以通过uptime查看系统整体的负载情况. 如果服务 ...

  10. Windows10下python3和python2同时安装(一)安装python3和python2

    Windows10下python3和python2同时安装(一) 安装python3和python2 特别说明,本文是在Windows64位系统下进行的,32位系统请下载相应版本的安装包,安装方法类似 ...