Рендеринг "жестких" краев с помощью собственного шейдера

Я хотел бы воспроизвести эффект, созданный с помощью THREE.EdgesHelper (рисование границы на "жестких" краях объекта), но с использованием собственного шейдера вместо добавления отдельного THREE.Line объект. По сути, я хотел бы сделать то, что сделано в этой демонстрации, но только для "жестких" границ; например, границы, которые не находятся между двумя копланарными гранями

Подход: применить аналогичную процедуру к EdgesHelper, но пометьте вершины, которые имеют твердые края, с помощью специального атрибута (например, isEdge); наверное нужно использовать BufferGeometry, поскольку регулярный Geometry позволяет повторно использовать вершины в нескольких гранях, но BufferGeometry дублирует вершины так, что каждая вершина является частью только одного лица (по крайней мере, это мое понимание; документация не является явной).

Прогресс на данный момент:

  1. Воспроизведенный эффект в примере материалов каркаса, но с использованием BufferGeometry: http://jsfiddle.net/ogav6o77/
  2. Портировать логику EdgesHelper к "BufferEdgesHelper"функция, которая работает с BufferGeometry (но по-прежнему использовать его для создания THREE.Line): http://jsfiddle.net/L2aertya/
  3. Попытка адаптировать 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 действительно дублирует вершины, но нормали должны быть пересчитаны, если объект, с которым вы работаете, имеет общие вершины.

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