Рендеринг "жестких" краев с помощью собственного шейдера
Я хотел бы воспроизвести эффект, созданный с помощью THREE.EdgesHelper
(рисование границы на "жестких" краях объекта), но с использованием собственного шейдера вместо добавления отдельного THREE.Line
объект. По сути, я хотел бы сделать то, что сделано в этой демонстрации, но только для "жестких" границ; например, границы, которые не находятся между двумя копланарными гранями
Подход: применить аналогичную процедуру к EdgesHelper
, но пометьте вершины, которые имеют твердые края, с помощью специального атрибута (например, isEdge
); наверное нужно использовать BufferGeometry
, поскольку регулярный Geometry
позволяет повторно использовать вершины в нескольких гранях, но BufferGeometry
дублирует вершины так, что каждая вершина является частью только одного лица (по крайней мере, это мое понимание; документация не является явной).
Прогресс на данный момент:
- Воспроизведенный эффект в примере материалов каркаса, но с использованием
BufferGeometry
: http://jsfiddle.net/ogav6o77/ - Портировать логику
EdgesHelper
к "BufferEdgesHelper
"функция, которая работает сBufferGeometry
(но по-прежнему использовать его для созданияTHREE.Line
): http://jsfiddle.net/L2aertya/ - Попытка адаптировать
BufferEdgesHelper
сохранить результаты в пользовательском атрибуте (isEdge
), затем прочитайте этот атрибут в пользовательском шейдере, когда решаете, рендерить или нет ребро: http://jsfiddle.net/4tf4c6sf/
Первые две скрипки работают, как и ожидалось, показывая (1) белый каркасный край, представленный шейдером, затем (2) белые края из шейдера плюс красные "жесткие" края из Line
, Однако (3) дает те же результаты, что и (2), вместо использования isEdge
атрибут, чтобы решить, следует ли рисовать линию или нет; Я не могу понять, почему это так.
Любая идея, как это исправить, чтобы шейдер отображал только жесткие края (например, красные и белые линии перекрываются)?
Спасибо!
1 ответ
Прежде всего, алгоритм обрезки края должен быть немного настроен. Вам нужно сохранить вершины для обеих граней, а не только для первой грани, потому что вам нужно изменить оба треугольника, связанные с ребром, чтобы они правильно отображались с использованием барицентрических координат.
Во-вторых, я думаю, что это можно сделать без нового isEdge
переменная, но просто изменяя centers
,
Нормальная установка для барицентрических координат имеет три вершины (1,0,0)
, (0,1,0)
, (0,0,1)
, Однако, если мы не хотим рисовать ребро между вершинами 0 и 1, мы можем изменить это на (1,0,1)
, (0,1,1)
, (0,0,1)
, так что независимо от того, как далеко от вершины 2 мы получим, vCenter.z
всегда 1. Тогда мы можем начать с centers
заполнить единицами (все ребра отключены) и включить ребра по одному, так как мы видим, какие ребра должны остаться.
Имея это в виду, я немного переработал ваш код. Я удалил краевой объект и просто оставил барицентрический материал: http://jsfiddle.net/v72rn4bk/4/
Я обнаружил, что вызов для вычисления нормалей должен быть сделан после преобразования в BufferGeometry
, призвание .fromGeometry
действительно дублирует вершины, но нормали должны быть пересчитаны, если объект, с которым вы работаете, имеет общие вершины.