Skip to content

Commit 3486a64

Browse files
committed
update 25 scene background
1 parent bf4f34d commit 3486a64

File tree

1 file changed

+130
-27
lines changed

1 file changed

+130
-27
lines changed

25 Three.js解决方案之添加背景和天空盒.md

Lines changed: 130 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ const canvasStyle = {
297297
298298
## 天空盒(Skybox)
299299
300-
假设我们身处一个盒子内部,我们可以观察到盒子内部 6 个面的背景贴图。
300+
假设我们身处一个立方体内部,我们可以观察到立方体内部 6 个面的背景贴图。
301301
302302
> 这不就是我们身处某个房间内吗?
303303
@@ -309,31 +309,40 @@ const canvasStyle = {
309309
310310
<br>
311311
312-
#### 第1种实现天空盒的方法
312+
**天空盒一共有 2 种形式的贴图资源:**
313+
314+
1. 全景图(hdri),又名 天空图
315+
2. 立方体贴图(cubemap)
316+
317+
318+
319+
<br>
320+
321+
#### 第1种实现天空盒的方法:全景图(hdri)
313322
314323
很明显,我们最容易想到的实现方式为:
315324
316-
1. 我们把整个 Three.Screen 当做立方体,也就是将整个场景当做盒子
325+
1. 我们把整个 Three.Screen 当做立方体,也就是将整个场景当做立方体
317326
318-
> 再次重复一遍:我们并不是在场景中创建一个立方体,而是直接将整个场景当做盒子
327+
> 再次重复一遍:我们并不是在场景中创建一个立方体,而是直接将整个场景当做立方体
319328
>
320-
> 假设你要给场景中某个盒子设置类似的效果,那么你要做的事情是:
329+
> 假设你要给场景中某个立方体设置类似的效果,那么你要做的事情是:
321330
>
322-
> 1. 创建纹理,使用盒子纹理加载器(Three.CubeTextureLoader)加载图片资源
331+
> 1. 创建纹理,使用立方体纹理加载器(Three.CubeTextureLoader)加载图片资源
323332
>
324333
> 2. 创建材质,除了设置材质的纹理之外,还要设置 .side 属性,将值为 Three.BackSide,例如
325334
>
326335
> ```
327336
> new MeshPhongMaterial({ map:xxxx, side: Three.BackSide })
328337
> ```
329338
>
330-
> 3. 最终创建盒子网格(Three.Mesh)
339+
> 3. 最终创建立方体网格(Three.Mesh)
331340
332-
> 请注意:绝大多数 VR 看房,都是将场景当做盒子即可
341+
> 请注意:绝大多数 VR 看房,都是将场景当做立方体即可
333342
334343
2. 按照指定顺序,获取(加载) 6 个面的纹理贴图,得到纹理
335344
336-
> 请注意,这次加载我们并不使用 Three.TextureLoader,而是采用盒子专有的纹理加载器 Three.CubeTextureLoader
345+
> 请注意,这次加载我们并不使用 Three.TextureLoader,而是采用立方体专有的纹理加载器 Three.CubeTextureLoader
337346
338347
3. 将得到的纹理作为场景背景
339348
@@ -388,7 +397,7 @@ cubeTextureLoader.load([
388397
389398
**针对贴图资源顺序的补充说明:**
390399
391-
在上面示例代码中,我们可以看到加载盒子 6 面图片贴图资源的顺序是固定的,依次为:
400+
在上面示例代码中,我们可以看到加载立方体 6 面图片贴图资源的顺序是固定的,依次为:
392401
393402
pos-x.jpg、neg-x.jpg、pos-y.jpg、neg-y.jpg、pos-z.jpg、neg-z.jpg
394403
@@ -426,24 +435,24 @@ pos-x.jpg、neg-x.jpg、pos-y.jpg、neg-y.jpg、pos-z.jpg、neg-z.jpg
426435
427436
<br>
428437
429-
**对于盒子贴图,使用的是左手系统!**
438+
**对于立方体贴图,使用的是左手系统!**
430439
431440
因此上面图片名称的含义为:
432441
433-
| 名称 | 含义 | 对应盒子内部的面来说 | 对于站在盒子内部中间的人来说 |
434-
| ----- | ---------- | -------------------- | ---------------------------- |
435-
| pos-x | X 轴正方向 | 左面 | 视觉左方 |
436-
| neg-x | X 轴负方向 | 右面 | 视觉右方 |
437-
| pos-y | Y 轴正方向 | 上面 | 视觉上方 |
438-
| neg-y | Y 轴负方向 | 下面 | 视觉下方 |
439-
| pos-z | Z 轴正方向 | 后面 | 视觉后方 |
440-
| neg-z | Z 轴负方向 | 前面 | 视觉前方 |
442+
| 名称 | 含义 | 对应立方体内部的面来说 | 对于站在立方体内部中间的人来说 |
443+
| ----- | ---------- | ---------------------- | ------------------------------ |
444+
| pos-x | X 轴正方向 | 左面 | 视觉左方 |
445+
| neg-x | X 轴负方向 | 右面 | 视觉右方 |
446+
| pos-y | Y 轴正方向 | 上面 | 视觉上方 |
447+
| neg-y | Y 轴负方向 | 下面 | 视觉下方 |
448+
| pos-z | Z 轴正方向 | 后面 | 视觉后方 |
449+
| neg-z | Z 轴负方向 | 前面 | 视觉前方 |
441450
442-
> 请注意,盒子的前面或后面完全是由观察者所处的位置来决定的
451+
> 请注意,立方体的前面或后面完全是由观察者所处的位置来决定的
443452
>
444-
> 如果你在盒子外面去看盒子,那么正面看到的是盒子的正面,看不到的是盒子的背面
453+
> 如果你在立方体外面去看立方体,那么正面看到的是立方体的正面,看不到的是立方体的背面
445454
>
446-
> 但是我们现在做的是站在盒子内部去观察盒子,所以此刻 “盒子的正面” 实际上对于我们观察者而言是在我们身后,也就是我们的视觉后方。
455+
> 但是我们现在做的是站在立方体内部去观察立方体,所以此刻 “立方体的正面” 实际上对于我们观察者而言是在我们身后,也就是我们的视觉后方。
447456
448457
449458
@@ -455,9 +464,9 @@ pos-x.jpg、neg-x.jpg、pos-y.jpg、neg-y.jpg、pos-z.jpg、neg-z.jpg
455464
456465
> 重复一遍:
457466
>
458-
> 1. 一般盒子模型贴图使用左手坐标系统
467+
> 1. 一般立方体模型贴图使用左手坐标系统
459468
> 2. Three.js 整体使用右手坐标系统
460-
> 3. 但在渲染盒子内部贴图时,Three.js 会自动帮我们做好左右兑换
469+
> 3. 但在渲染立方体内部贴图时,Three.js 会自动帮我们做好左右兑换
461470
> 4. 因此我们在传递纹理贴图时,贴图顺序使用的是左手坐标系统
462471
463472
@@ -470,12 +479,106 @@ pos-x.jpg、neg-x.jpg、pos-y.jpg、neg-y.jpg、pos-z.jpg、neg-z.jpg
470479
471480
<br>
472481
473-
#### 第2种实现天空盒的方法
482+
#### 第2种实现天空盒的方法:立方体贴图(cubemap)
474483
475484
我们第1种实现天空盒,实际上使用的是 6 个面的图片资源组合成了一个 3D 空间。
476485
477-
接下来我们学习使用一张 360° 球形相机拍摄的照片,来实现 3D 空间盒子。
486+
接下来我们学习使用一张 360° 球形相机拍摄的照片,来实现 3D 空间立方体。
487+
488+
489+
490+
<br>
491+
492+
首先你从网上找到一张 360° 的场景图片资源:
493+
494+
https://threejsfundamentals.org/threejs/resources/images/equirectangularmaps/tears_of_steel_bridge_2k.jpg
495+
496+
> 请注意,这类图片尺寸宽高比例为 2:1,经常称呼这类图片为 “全景图”
497+
498+
499+
500+
<br>
501+
502+
**实现思路:**
503+
504+
1. 使用纹理加载器加载该图片资源
505+
506+
> 这种 2:1 的图片,被称为 “等矩形图像”
507+
508+
2. 实例化一个 Three.WebGLCubeRenderTarget,构造函数中的 size 属性为图片资源的高
509+
510+
> WebGLCubeRenderTarget 继承于 WebGLRenderTarget,属于离屏渲染的一种特例(专门针对立方体模型)
511+
512+
> 在 WebGLRenderTarget 的源码中可以看到这句代码:super( size, size, options );
513+
>
514+
> WebGLRenderTarget 构造函数需要传递 width 和 height,但是 WebGLCubeRenderTarget 构造函数只需传入 1 个 size,因为正方体,所以宽高一样。
515+
516+
3. 调用该实例化对象的 fromEquirectangularTexture() 函数
517+
518+
> 将等距图像 转化为 立方体模型贴图
519+
>
520+
> > 可以简单理解成:就是将 1 整张图片转化为 6个面的立方体模型贴图,并进行渲染
521+
522+
4. 将场景背景设置为该实例对象
523+
524+
> 这样相当于将场景背景图的值设置为 WebGLCubeRenderTarget 的渲染结果
525+
526+
527+
528+
<br>
529+
530+
**具体代码:**
531+
532+
```
533+
const textureLoader = new Three.TextureLoader()
534+
textureLoader.load(require('@/assets/imgs/tears_of_steel_bridge.jpg').default,
535+
(texture) => {
536+
const crt = new Three.WebGLCubeRenderTarget(texture.image.height)
537+
crt.fromEquirectangularTexture(renderer,texture)
538+
scene.background = crt.texture
539+
}
540+
)
541+
```
542+
543+
> 补充说明:scene.background 的类型为 WebGLBackground
544+
>
545+
> 请留意上述代码中 `scene.background = crt.texture`,事实上在以前的一些教程中可以写成 `scene.background = crt`,WebGLBackground 会在内部进行判断,如果 background 类型为 WebGLRenderTarget,则使用该实例的 .texture 属性值。
546+
>
547+
> 但是在最新版 r127 中已经删除了该判断代码,所以现在必须写成 `scene.background = crt.texture`。
548+
>
549+
> 就这个问题,我已向官网教程进行了修改提交:https://github.com/gfxfundamentals/threejsfundamentals/pull/205
550+
551+
552+
553+
<br>
554+
555+
### 补充说明:全景图(hdri) 与 立方体贴图(cubemap) 互转
556+
557+
网上有人提供了 全景图与立方体模型图 之间的转化工具包:
558+
559+
在线地址:https://matheowis.github.io/HDRI-to-CubeMap/
478560
561+
项目源码:https://github.com/aunyks/hdri-to-cubemap
562+
563+
564+
565+
<br>
566+
567+
你以为本文结束了?没有!
568+
569+
我们上面示例讲的都是加载纹理,然后通过设置 场景背景(scene.background) 来实现的,除了这种方式,还有没有别的途径来实现?
570+
571+
572+
573+
<br>
574+
575+
接下来我们就要讲解第 3 种方式:创建球体,然后让我们身处球体之内。
576+
577+
> 为什么是球体,而不是 立方体?
578+
579+
580+
581+
<br>
479582
583+
## 场景背景的第3种添加方式
480584
481-
<br>

0 commit comments

Comments
 (0)