本文是three.js系列文章的一部分。第一篇文章是three.js 基础。如果你是个新手,还没读过,请从那里开始。如果你还没读过有关摄像机的章节,请从这篇文章开始。
在3D引擎里,雾通常是基于离摄像机的距离褪色至某种特定颜色的方式。在three.js中添加雾是通过创建 Fog
或者 FogExp2
实例并设定scene的fog
属性。
Fog
让你设定 near
和 far
属性,代表距离摄像机的距离。任何物体比 near
近不会受到影响,任何物体比 far
远则完全是雾的颜色。在 near
和 far
中间的物体,会从它们自身材料的颜色褪色到雾的颜色。
FogExp2
会根据离摄像机的距离呈指数增长。
选择其中一个类型,创建雾并设定到场景中如下:
const scene = new THREE.Scene(); { const color = 0xFFFFFF; // white const near = 10; const far = 100; scene.fog = new THREE.Fog(color, near, far); }
或者对于 FogExp2
会是:
const scene = new THREE.Scene(); { const color = 0xFFFFFF; const density = 0.1; scene.fog = new THREE.FogExp2(color, density); }
FogExp2
比较接近现实效果,但是 Fog
使用的更加普遍,因为它支持设定影响区域,所以你可以设定一定距离内显示清晰的场景,过了这段距离再褪色到某种颜色。
需要注意的是雾是作用在 渲染的物体 上的,是物体颜色中每个像素计算的一部分。这意味着如果你想让你的场景褪色到某种颜色,你需要设定雾 和 场景的背景颜色为同一种颜色。背景颜色通过scene.background
属性设置。你可以通过 THREE.Color
选择背景颜色设置。例如:
scene.background = new THREE.Color('#F00'); // red
这是我们之前添加雾的例子。唯一的改动是在添加雾之后,我们设置了场景的背景颜色。
const scene = new THREE.Scene(); +{ + const near = 1; + const far = 2; + const color = 'lightblue'; + scene.fog = new THREE.Fog(color, near, far); + scene.background = new THREE.Color(color); +}
在下面的例子,摄像机的 near
是0.1, far
是5,位于 z = 2
的位置。方块为单位大小,位于Z=0的位置。这意味着将雾设置为 near = 1
和 far = 2
,方块会在它的中间位置淡出。
让我们添加界面来调整雾。我们将再次使用lil-gui。lil-gui接收对象和属性参数,并自动为其创建界面。我们能够简单地操纵雾的 near
和 far
属性,但是 near
数值大于 far
是无效的,所以我们创建助手(helper)来确保 near
和 far
属性,让 near
小于或等于 far
, far
大于或等于 near
。
// We use this class to pass to lil-gui // so when it manipulates near or far // near is never > far and far is never < near class FogGUIHelper { constructor(fog) { this.fog = fog; } get near() { return this.fog.near; } set near(v) { this.fog.near = v; this.fog.far = Math.max(this.fog.far, v); } get far() { return this.fog.far; } set far(v) { this.fog.far = v; this.fog.near = Math.min(this.fog.near, v); } }
之后我们可以像这样添加
{ const near = 1; const far = 2; const color = 'lightblue'; scene.fog = new THREE.Fog(color, near, far); scene.background = new THREE.Color(color); + + const fogGUIHelper = new FogGUIHelper(scene.fog); + gui.add(fogGUIHelper, 'near', near, far).listen(); + gui.add(fogGUIHelper, 'far', near, far).listen(); }
当我们设置摄像机的时候,设置(助手的 near
和 far
以调节雾的最小值和最大值。
最后两行调用 .listen()
告诉lil-gui 监听 变化。当我们编辑 far
改变了 near
或者编辑 near
改变了 far
,lil-gui将会为我们更新其他属性的UI。
或许能够改变雾的颜色是个不错的主意,但是如上面提到的,我们需要保持雾的颜色和背景颜色一致。所以,让我们在助手上添加另一个 虚拟 属性,当lil-gui改变它时会设置这两个颜色。
lil-gui能够通过4种方式设置颜色。分别是6位hex字符串 (如: #112233
),色相、饱和度、明度的对象 (如: {h: 60, s: 1, v: }
),RGB数组 (如: [255, 128, 64]
),或者RGBA数组 (如: [127, 200, 75, 0.3]
)。
对于我们的目的而言,最简单的是用hex字符串的方式,因为lil-gui只修改单个数值。幸运的是通过 THREE.Color
的 getHexString
方法我们能轻松地获得这个字符串,只需要在其前面添加 '#' 。
// We use this class to pass to lil-gui // so when it manipulates near or far // near is never > far and far is never < near +// Also when lil-gui manipulates color we'll +// update both the fog and background colors. class FogGUIHelper { * constructor(fog, backgroundColor) { this.fog = fog; + this.backgroundColor = backgroundColor; } get near() { return this.fog.near; } set near(v) { this.fog.near = v; this.fog.far = Math.max(this.fog.far, v); } get far() { return this.fog.far; } set far(v) { this.fog.far = v; this.fog.near = Math.min(this.fog.near, v); } + get color() { + return `#${this.fog.color.getHexString()}`; + } + set color(hexString) { + this.fog.color.set(hexString); + this.backgroundColor.set(hexString); + } }
然后我们调用 gui.addColor
来为我们的助手虚拟属性添加颜色界面。
{ const near = 1; const far = 2; const color = 'lightblue'; scene.fog = new THREE.Fog(color, near, far); scene.background = new THREE.Color(color); * const fogGUIHelper = new FogGUIHelper(scene.fog, scene.background); gui.add(fogGUIHelper, 'near', near, far).listen(); gui.add(fogGUIHelper, 'far', near, far).listen(); + gui.addColor(fogGUIHelper, 'color'); }
你可以观察到,设置 near
如1.9, far
为2.0能在未雾化和完全雾化之间获得锐利的变化效果,而设置 near
= 1.1, far
= 2.9 会让我们旋转的方块在距离摄像机2个单位距离的位置获得最平滑的变化效果。
最后, fog
在材料上有个布尔属性,用来设置渲染物体的材料是否会受到雾的影响。对于大多数材料而言默认设置为 true
,作为你可能想关掉雾生效的例子,设想下你正在制作一个3D车辆模拟器并处于驾驶员座位或座舱的视角,你很可能为了看清车内的物体将它们的是否受雾影响属性关闭。
一个更好的例子会是一个外面弥漫浓雾的房子。让我们假设将雾设置在2米外 (near = 2) 并且在4米的地方完全进入雾中 (far = 4)。房间大于2米并且很可能大于4米,那么你需要将房子内的材质设置为不受雾的影响,否则当站在房子内尽头往墙壁外看会觉得房子是在雾里。
注意房间尽头的墙壁和天花板正受到雾的影响,当我们把房子材料上的是否受雾影响属性关闭可以解决这个问题。