Skip to content

Commit ee58852

Browse files
committed
add OffscreenCanvas
1 parent daa607b commit ee58852

File tree

3 files changed

+178
-13
lines changed

3 files changed

+178
-13
lines changed

20 Three.js优化之合并对象.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,23 @@ https://sedac.ciesin.columbia.edu/data/set/gpw-v4-admin-unit-center-points-popul
6767

6868
我们选择不使用最新的 2020 年数据,而是使用 2010 年的结果。
6969

70-
为了方便你获得到 2010 年人口统计结果,你可以直接点击下面这个地址,直接下载:
70+
为了方便你获得到 2010 年男性人口统计结果,你可以直接点击下面这个地址,直接下载:
7171

7272
https://threejsfundamentals.org/threejs/resources/data/gpw/gpw_v4_basic_demographic_characteristics_rev10_a000_014mt_2010_cntm_1_deg.asc
7373

7474
> 反正我们本文的重点是模仿效果,至于数据时效性不必纠结
7575
7676
> 该人口统计数据文件格式为 .asc,至于如何解析该文件,我们会稍后讲解
7777
78+
> 为啥是男性人口统计?女性人口呢?为什么不是全部人口统计呢?
79+
> 因为在下一篇文章中,就会有女性人口统计,然后做出同一个地区 男女人口数量比较 的动画
80+
> 为了简化,本文下面文字中,将忽略 “男性人口数量” 这个概念,统一称呼为 “人口数据”
81+
7882

7983

8084
**第2问:人口数据和地区的对应关系,如何表现在地球上?**
8185

82-
我们把刚才下载得到的人口统计数据文件,重命名为 gpw_v4_2010.asc,然后将该文件移动到:src/assets/data/ 目录中。
86+
我们把刚才下载得到的人口统计数据文件,重命名为 gpw_v4_014mt_2010.asc,然后将该文件移动到:src/assets/data/ 目录中。
8387

8488
点击该文件,用记事本查看该文件内容,你会发现里面大致为以下内容:
8589

@@ -150,9 +154,9 @@ NODATA_value -9999
150154

151155

152156

153-
#### 第1步:加载人口数据文件(gpw_v4_2010.asc)
157+
#### 第1步:加载人口数据文件(gpw_v4_014mt_2010.asc)
154158

155-
1. **数据文件路径为 ./src/assets/data/gpw_v4_2010.asc**
159+
1. **数据文件路径为 ./src/assets/data/gpw_v4_014mt_2010.asc**
156160

157161
2. **由于我们使用 alias 来得到 .asc 文件编译后的路径,所以请记得:**
158162

@@ -182,7 +186,7 @@ const loadDataFile = async (url: string) => {
182186
}
183187
}
184188
185-
const ascURL = require('@/assets/data/gpw_v4_2010.asc').default
189+
const ascURL = require('@/assets/data/gpw_v4_014mt_2010.asc').default
186190
loadDataFile(ascURL)
187191
```
188192

@@ -454,7 +458,7 @@ const HelloEarth = () => {
454458

455459
useEffect(() => {
456460
if (canvasRef.current === null) { return }
457-
const ascURL = require('@/assets/data/gpw_v4_2010.asc').default
461+
const ascURL = require('@/assets/data/gpw_v4_014mt_2010.asc').default
458462
const doSomthing = async () => {
459463
try {
460464
const text = await loadDataFile(ascURL)
@@ -740,7 +744,7 @@ const HelloEarth = () => {
740744
handleResize()
741745
window.addEventListener('resize', handleResize)
742746

743-
const ascURL = require('@/assets/data/gpw_v4_2010.asc').default
747+
const ascURL = require('@/assets/data/gpw_v4_014mt_2010.asc').default
744748
const doSomthing = async () => {
745749
try {
746750
const text = await loadDataFile(ascURL)
@@ -852,12 +856,6 @@ export default HelloEarth
852856
853857
854858
855-
**通过谷歌调试工具,查看当前页面GPU渲染使用情况:**
856-
857-
1.
858-
859-
860-
861859
862860
**如何解决卡顿?减少需要渲染对象的数量!**
863861
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# 21 Three.js优化之合并对象的动画
2+
3+
在上一篇中,我们将 19000 个柱状对象合并为 1 个整体,这样优化过后渲染速度性能大幅提高。
4+
5+
但是,我们所加载的是 2010 年 全球男性人口数量统计。
6+
7+
**假设现在我们添加新的需求:**
8+
9+
1. 加载并显示全球女性人口数量
10+
2. 此时,我们程序中 男性与女性 各有 1 份数据
11+
3. 我们需要做的动画就是:当切换 不同性别数据时,柱状物也会随着人口数量不同而发生 高低 变化的动画
12+
13+
14+
15+
**不同性别的人口数据 .asc 文件下载:**
16+
17+
1. 男性:https://threejsfundamentals.org/threejs/resources/data/gpw/gpw_v4_basic_demographic_characteristics_rev10_a000_014mt_2010_cntm_1_deg.asc
18+
2. 女性:https://threejsfundamentals.org/threejs/resources/data/gpw/gpw_v4_basic_demographic_characteristics_rev10_a000_014ft_2010_cntm_1_deg.asc
19+
20+
21+
22+
很显然,之前把所有柱状物都合并成 1 个整体之后,是没有办法单独操作某一个柱状物的。
23+
24+
想实现每一个柱状物高低变化的动画,又该如何实现呢?
25+
26+
27+
28+
#### 实现方式:
29+
30+
1. 通过 设置物体材质的 morphtargets(变形目标) 属性为 true 来改变柱状物形状
31+
32+
```
33+
const material = new THREE.MeshBasicMaterial({
34+
vertexColors: true,
35+
morphTargets: true,
36+
})
37+
```
38+
39+
40+
41+
2. 通过 Tween.js 来创建改变过程中的动画
42+
43+
```
44+
import { TWEEN } from 'three/examples/jsm/libs/tween.module.min.js'
45+
46+
或者自己去安装 tween.js 的模块
47+
48+
yarn add @tweenjs/tween.js
49+
//npm i @tweenjs/tween.js --save
50+
import TWEEN from '@tweenjs/tween.js'
51+
```
52+
53+
> Tween.js 的用法,请参考官网:https://github.com/tweenjs/tween.js
54+
55+
56+
57+
3. 通过材质的 Material.onBeforeCompile() 函数来产生改变过程中柱状物颜色的变化
58+
59+
> Material.onBeforeCompile() 的用法,请参考文档:https://threejs.org/docs/index.html#api/zh/materials/Material.onBeforeCompile
60+
61+
62+
63+
#### 具体代码
64+
65+
...
66+
67+
上面仅仅是提供了解决思路,而实际具体的代码复杂程度,超出了我目前的认知。
68+
69+
所以我们暂且搁置,所有能力的同学,可自行查看本文对应的原版教程:
70+
71+
https://threejsfundamentals.org/threejs/lessons/threejs-optimize-lots-of-objects-animated.html,
72+
73+
74+
75+
将来有一天 Three.js 能力提高了,再来弥补上。
76+
77+
下一节,我们学习另外一个可以提升计算性能的方式:使用 WebWorker。
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# 22 Three.js优化之OffscreenCanvas
2+
3+
我们知道 JS 是单线程,可以通过 WebWorker 将一些复杂计算执行命令从主线程中分离出来。
4+
5+
关于 WebWorker 的使用方法,请参考:
6+
7+
https://developer.mozilla.org/zh-cn/docs/web/api/web_workers_api/using_web_workers
8+
9+
10+
11+
一些比较新的浏览器(例如谷歌浏览器) 还有另外一个和 WebWorker 类似作用,但是只针对画布的 API 接口:OffscreenCanvas。
12+
13+
14+
15+
## OffscreenCanvas的概念和用法
16+
17+
#### OffscreenCanvas的基本概念
18+
19+
你可以把 WebWorker 做为各种复杂类型的后台运算线程,作用范围比较广泛。
20+
21+
而 OffscreenCanvas 则专门针对 Canvas 做离屏渲染。
22+
23+
> 注意,这里提到的 离屏渲染 和 我们使用 WebGLRendererTarget 来做的离屏渲染,从概念上是类似的
24+
25+
> OffscreenCanvas 的 “离屏” 是指浏览器 DOM 而言
26+
>
27+
> WebGLRenderTarget 的 “离屏” 只指 Three.js 的主场景(Scene) 而言
28+
29+
你可以把 OffscreenCanvas 看作是针对 Canvas 的特殊 WebWorker 应用场景。
30+
31+
但是请记得:目前绝大多数浏览器均已支持 WebWorker,但是对 OffscreenCanvas 的支持度并不高。
32+
33+
34+
35+
**如何创建 OffscreenCanvas ?**
36+
37+
不可以使用 new OffscreenWorker() 的方式来创建 OffscreenCanvas,而是使用 canvas.transferControlToOffscreen() 来获得 canvas 对应的 OffscreenCanvas。
38+
39+
40+
41+
**如何检测当前浏览器是否支持 OffscreenCanvas?**
42+
43+
我们只需检查 canvas 是否存在 transferControlToOffscreen 方法:
44+
45+
```
46+
if(canvas.transferControlToOffscreen !== null){
47+
console.log('当前浏览器支持 OffscreenCanvas')
48+
}else{
49+
console.log('当前浏览器不支持 OffscreenCanvas')
50+
}
51+
```
52+
53+
54+
55+
#### OffscreenCanvas的用法
56+
57+
通常情况下 OffscreenCanvas 必须搭配 Web Worker 一起使用。
58+
59+
我们单独创建一个 JS 文件,将 canvas 绘制的一些 JS 代码写在这个文件中。
60+
61+
**大体步骤:**
62+
63+
1. 创建一个单独的 JS 文件,用来编写 Three.js 场景内容和渲染代码
64+
65+
> 会以这个 JS 文件来作为 web worker 的调用文件对象
66+
67+
2. 在主场景中,获得 DOM 中的 canvas
68+
69+
3. 获取 canvas 对应的 OffscreenCanvas
70+
71+
```
72+
const offscreen = canvas.transferCountrolToOffscreen()
73+
```
74+
75+
4. 创建一个 worker 对象,并且设置一些消息参数
76+
77+
```
78+
const worker = new Window.Worker('xx/xxxx.js',{type:'module'})
79+
worker.postMessage({type:'main',canvas:offscreen},[offscreen])
80+
```
81+
82+
5. 由于 web worker 不允许访问 DOM 事件,例如浏览器窗口尺寸改变事件、鼠标事件等,所以当这些事件发生后,我们需要通知 worker,将事件对应的一些参数和变动发送给 worker,以便 worker 中的 canvas 渲染逻辑作出对应的响应。
83+
84+
85+
86+
接下来,我们将通过一个实际的例子,来演示一遍。
87+
88+
89+
90+
## 离屏画布渲染示例:HelloOffscreenCanvas

0 commit comments

Comments
 (0)