Можно ли позволить туману взаимодействовать с непрозрачностью материала? - PullRequest
0 голосов
/ 20 сентября 2018

Я работаю над проектом, который отображает здания. Требуется, чтобы здание постепенно исчезало (прозрачно) в зависимости от расстояния между камерой и зданиями. Кроме того, этот эффект должен следовать за движением камеры.

Я думаю использоватьTHREE.Fog(), но туман, похоже, может только изменить цвет материала.Buildings with White Fog enabled Выше приведено изображение здания с белым туманом.

  • Здания выложены плиткой, каждая плитка - это одна геометрия (я объединил все здания в одно)используя var bigGeometry = new THREE.Geometry(); bigGeometry.merge(smallGeometry);
  • Фиолетовый / синий цвет - это земля, а ground.material.fog = false;.Таким образом, земля не будет взаимодействовать с туманом.

Мой вопрос:

  • Можно ли позволить туману взаимодействовать с непрозрачностью материала здания вместо цвета?(более белый переводит в более прозрачный)
  • Или я должен использовать шейдер, чтобы контролировать непрозрачность материала в зависимости от расстояния до камеры?Но я понятия не имею, как это сделать.
  • Я также рассмотрел добавление alphaMap.Если это так, каждая плитка здания должна отображать альфа-карту, и все эти альфа-карты должны взаимодействовать с движением камеры.Это будет тонна работы.

Так что есть предложения?

С наилучшими пожеланиями, Артур

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

Я ОП.Потратив некоторое время на чтение, как использовать материал шейдеров Three.js.У меня есть код, который работает так, как нужно.

Вот код: https://jsfiddle.net/yingcai/4dxnysvq/

Основная идея:

  1. Создание униформы, содержащей элементы управления.target (Vector3 position).
  2. Передача атрибутов положения вершины для изменения в вершинном шейдере.Так что шейдер фрагмента может получить к нему доступ.
  3. Получите расстояние между каждой позицией вершины и контролем. Цель.Рассчитайте альфа-значение на основе расстояния.
  4. Присвойте альфа-значение цвету вершины.

Еще одна важная вещь: поскольку маска затухания должна следовать за движением камеры, поэтому не забудьте обновить элемент управления вуниформа каждый кадр.

// Create uniforms that contains control position value.
uniforms = {
    texture: {
      value: new THREE.TextureLoader().load("https://threejs.org/examples/textures/water.jpg")
    },
    control: {
      value: controls.target
    }
  };

// In the render() method.
// Update the uniforms value every frame.
uniforms.control.value = controls.target;

enter image description here

0 голосов
/ 21 сентября 2018

ПРИМЕЧАНИЕ. Я подозреваю, что, возможно, есть более простые / более красивые способы решения этой проблемы, чем непрозрачность.В частности, обратите внимание, что частично непрозрачные здания будут показывать другие здания позади них.Чтобы решить эту проблему, рассмотрите возможность использования градиента или другого фона сцены и выбора цвета тумана, чтобы соответствовать этому, вместо использования непрозрачности.Но ради того, чтобы попробовать это ...

Вот как можно изменить непрозрачность объекта в зависимости от его расстояния.На самом деле это не требует THREE.Fog, я не уверен, как вы будете использовать данные тумана напрямую.Вместо этого я буду использовать THREE.NodeMaterial, что (по состоянию на three.js r96) довольно экспериментально.В качестве альтернативы можно написать собственный шейдер с THREE.ShaderMaterial, что тоже хорошо.

const material = new THREE.StandardNodeMaterial();
material.transparent = true;
material.color = new THREE.ColorNode( 0xeeeeee );

// Calculate alpha of each fragment roughly as:
// alpha = 1.0 - saturate( distance / cutoff )
//
// Technically this is distance from the origin, for the demo, but
// distance from a custom THREE.Vector3Node would work just as well.
const distance = new THREE.Math2Node(
  new THREE.PositionNode( THREE.PositionNode.WORLD ),
  new THREE.PositionNode( THREE.PositionNode.WORLD ),
  THREE.Math2Node.DOT
);
const normalizedDistance = new THREE.Math1Node(
  new THREE.OperatorNode(
    distance,
    new THREE.FloatNode( 50 * 50 ),
    THREE.OperatorNode.DIV
  ),
  THREE.Math1Node.SAT
);
material.alpha = new THREE.OperatorNode(
  new THREE.FloatNode( 1.0 ),
  normalizedDistance,
  THREE.OperatorNode.SUB
);

Демонстрация: https://jsfiddle.net/donmccurdy/1L4s9e0c/

Снимок экрана: screenshot of solution

...