Точки ThreeJS (облако точек) с освещением с использованием настраиваемого материала шейдера
Закодировано с использованием:
- Использование ThreeJS v0.130.1
- Framework: Angular 12, но это не имеет отношения к проблеме.
- Тестирование в браузере Chrome.
Я создаю приложение, которое набирает более 100 тысяч баллов. Я использую эти точки для визуализации объекта THREE.Points на экране.
Я обнаружил, что по умолчанию THREE.PointsMaterial не поддерживает освещение (точки видны с добавлением света в сцену или без него).
Поэтому я попытался реализовать собственный ShaderMaterial . Но я не мог найти способ добавить освещение к визуализированному объекту.
Вот пример того, что делает мой код:Пример приложения на StackBlitz, показывающий мою текущую попытку. В этом коде я использую образцы значений для данных облака точек, нормалей и цвета, но все остальное похоже на мое реальное приложение. Я могу видеть трехмерный объект, но мне нужно более подходящее освещение с использованием нормалей.
Мне нужна помощь или руководство, чтобы реализовать следующее:
Добавьте освещение к пользовательскому материалу шейдера. Я погуглил и пробовал много вещей, пока безуспешно.
Используя нормали, покажите эффекты освещения (в этом примере кода нормали зафиксированы в направлении оси 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()
Цикл будет самой дорогой частью каждого кадра, поэтому, если вам нужно обновлять его в каждом кадре, вы можете рассчитать его в вершинном шейдере, но это совсем другой вопрос.