# Туман

Эта статья является частью серии статей о 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