Точки ThreeJS (облако точек) с освещением с использованием настраиваемого материала шейдера

Закодировано с использованием:

  • Использование ThreeJS v0.130.1
  • Framework: Angular 12, но это не имеет отношения к проблеме.
  • Тестирование в браузере Chrome.

Я создаю приложение, которое набирает более 100 тысяч баллов. Я использую эти точки для визуализации объекта THREE.Points на экране.

Я обнаружил, что по умолчанию THREE.PointsMaterial не поддерживает освещение (точки видны с добавлением света в сцену или без него).

Поэтому я попытался реализовать собственный ShaderMaterial . Но я не мог найти способ добавить освещение к визуализированному объекту.

Вот пример того, что делает мой код:Пример приложения на StackBlitz, показывающий мою текущую попытку. В этом коде я использую образцы значений для данных облака точек, нормалей и цвета, но все остальное похоже на мое реальное приложение. Я могу видеть трехмерный объект, но мне нужно более подходящее освещение с использованием нормалей.

Мне нужна помощь или руководство, чтобы реализовать следующее:

  1. Добавьте освещение к пользовательскому материалу шейдера. Я погуглил и пробовал много вещей, пока безуспешно.

  2. Используя нормали, покажите эффекты освещения (в этом примере кода нормали зафиксированы в направлении оси Y, но я вычисляю их на основе некоторой векторной логики в реальном приложении). Итак, вычисление нормалей уже выполнено, но я хочу использовать их, чтобы показать световой эффект сияния / затенения в пользовательском материале шейдера.

В этом примере для атрибута цвета установлен фиксированный красный цвет, но в реальном приложении я могу применять цвета, используя УФ-диапазон от текстуры до атрибута цвета.

Посоветуйте, пожалуйста, как / можно ли получить освещение на основе нормалей для Point Cloud. Спасибо.

Примечание: я рассмотрел этот вопрос Stackoveflow, но он касается только изменения альфа / прозрачности точек, а не освещения.

1 ответ

Добавление освещения к индивидуальному материалу - очень сложный процесс. Тем более, что вы можете использовать методы Фонга, Ламберта или Физического освещения, и есть много вычислений, которые необходимо передать от вершины к шейдеру фрагмента. Например, этот сегмент кода шейдера - лишь малая часть того, что вам нужно .

Вместо того, чтобы пытаться воссоздать освещение с нуля, я рекомендую вам создать PlaneGeometry с нужным материалом (Фонг, Ламберт, Физический и т. д.) и используйте InstancedMeshдля создания тысяч экземпляров, как в этом примере .

Исходя из этого примера, псевдокод того, как можно добиться аналогичного эффекта, выглядит примерно так:

      const count = 100000;
const geometry = new PlaneGeometry();
const material = new THREE.MeshPhongMaterial();

mesh = new THREE.InstancedMesh( geometry, material, count );
mesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
scene.add( mesh );

const dummy = new THREE.Object3D();
update() {
    // Sets the rotation so it's always perpendicular to camera
    dummy.lookAt(camera);

    // Updates positions of each plane
    for (let i = 0; i < count; i++){
        dummy.position.set( x, y, z );

        dummy.updateMatrix();

        mesh.setMatrixAt( i ++, dummy.matrix );
    }
}

В for() Цикл будет самой дорогой частью каждого кадра, поэтому, если вам нужно обновлять его в каждом кадре, вы можете рассчитать его в вершинном шейдере, но это совсем другой вопрос.

Другие вопросы по тегам