Туман

Эта статья является частью серии статей о three.js. Первая статья - основы Three.js. Если вы еще не читали их, и вы новичок в three.js, возможно, вы захотите начать с них. Если вы еще не читали о камерах, вы можете начать с этой статьи.

Туман в 3D-движке - это, как правило, способ затухания до определенного цвета в зависимости от расстояния до камеры. В three.js вы добавляете туман, создавая объект Fog или FogExp2 и устанавливая его в свойстве сцены 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 используется чаще, поскольку он позволяет вам выбрать место для нанесения тумана, чтобы вы могли решить показать чистую сцену на определенном расстоянии, а затем исчезновение до некоторого цвета за этим расстоянием.

THREE.Fog
THREE.FogExp2

Важно отметить, что туман применяется к вещам, которые отображаются. Это часть расчета каждого пикселя цвета объекта. Это означает, что если вы хотите, чтобы ваша сцена стала блеклой, вам нужно установить туман и цвет фона на один и тот же цвет. Цвет фона устанавливается с помощью свойства scene.background. Чтобы выбрать цвет фона, вы прикрепляете к нему THREE.Color. Например

scene.background = new THREE.Color('#F00');  // red
fog blue, background red
fog blue, background blue

Вот один из наших предыдущих примеров с добавленным туманом. Единственное добавление - сразу после настройки сцены мы добавляем туман и устанавливаем цвет фона сцены

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. Кубики имеют размер 1 и имеют значение z = 0. Это означает, что при настройке тумана near = 1 и far = 2 кубики исчезнут прямо вокруг их центра.

Давайте добавим интерфейс, чтобы мы могли настроить туман. Мы снова будем использовать lil-gui. lil-gui принимает объект и свойство и автоматически создает интерфейс для этого типа свойства. Мы могли бы просто позволить ему манипулировать свойствами near и far тумана, но недопустимо иметь near больше, чем far, поэтому давайте создадим помощник, чтобы lil-gui мог манипулировать свойством 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 () в конце последних 2 строк указывает lil-gui прослушивать изменения. Таким образом, когда мы меняем near на far или мы меняем far на near lil-gui обновит интерфейс другого свойства для нас.

Также было бы неплохо иметь возможность изменить цвет тумана, но, как было упомянуто выше, нам нужно синхронизировать цвет тумана и цвет фона. Итак, давайте добавим еще одно виртуальное свойство в наш помощник, который будет устанавливать оба цвета, когда lil-gui манипулирует им.

lil-gui может манипулировать цветами 4 способами, как шестнадцатеричная строка из 6 цифр CSS (например: # 112233). Как тон, насыщенность, яркость объекта (например: {h: 60, s: 1, v:}). Как массив RGB (например: [255, 128, 64]). Или как массив RGBA (например: [127, 200, 75, 0.3]).

Для нашей цели проще всего использовать шестнадцатеричную версию, поскольку таким образом lil-gui манипулирует только одним значением. К счастью, THREE.Color как метод getHexString который мы используем, чтобы легко получить такую cтроку - нам просто нужно добавить «#» вперед.

// 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 метров, поэтому вам необходимо установить материалы для внутренней части дома, чтобы не было тумана, в противном случае, если вы будете стоять внутри дома, глядя на стену в дальнем конце комнаты, она будет в тумане.

fog: true, all

Обратите внимание, что на стены и потолок в дальнем конце комнаты распространяется туман. Отключив туман для материалов дома, мы можем решить эту проблему.

fog: true, only outside materials