NURBS моделирование в Rhino 3D и T-Spline
Существует, как минимум, два подхода к созданию 3D моделей. В одном из них, наиболее популярном, объекты состоят из множества полигонов. В другом (freeform surface modelling) — из NURBS поверхностей, которые задаются кривыми (сплайнами).
Каждый из подходов имеет свои преимущества и недостатки, во многом схожие с различиями между растровой и векторной 2D графикой. Особенностям работы с ПО для полигонального моделирования посвящено довольно много статей но, что касается средств NURBS моделирования, тут, на мой взгляд, ситуация сложнее. Большинство таких статей либо являются туториалами по созданию конкретных объектов, либо предназначены скорее для создателей ПО, нежели для его пользователей и полны терминов вида «веса, T-точки, кривые n-го порядка,», и т п. Я же попробую пройти посередине.
Создание объектов из NURBS поверхностей используется в тех областях, где важную роль играет точность — как сама по себе, так и её сохранение при редактировании объекта. Это особенно важно при изготовлении деталей на станках с ЧПУ, из-за чего такой подход находит широкое применение в САПР.
Однако точность — не единственная причина отказа от полигонов. Весьма широко NURBS моделирование используется в промышленном дизайне, архитектуре и ювелирке. Если взглянуть на известные современные здания — можно заметить, что они представляют собой сочетание переходящих друг в друга форм — либо узнаваемых геометрических примитивов, либо сложных, явно математически определённых, поверхностей. Тоже самое касается корпусов автомобилей, бытовой техники, а также различных колец, ожерелий (особенно «органического» вида) и т.п.
Часто эти формы довольно узнаваемы и обусловлены типовыми возможностями ПО для NURBS моделирования. Другими словами, нередко дизайн определяется больше спецификой используемого ПО, чем идеями дизайнера.В этой статье я хочу, на примере пакета Rhino 3D, акцентировать внимание на некоторых особенностях и проблемах, характерных для данного подхода.
Здесь необходимо сразу сделать отступление. Дело в том, что работать с NURBS поверхностями тоже можно сильно по-разному.
Мы рассмотрим два способа — стандартный функционал Rhino и функционал T-Spline, представляющий собой популярный плагин для Rhino и, по сути, являющийся редактором внутри редактора — со своим представлением поверхностей/тел и своими способами их редактирования.
Для начала посмотрим на несколько примитивов, созданных с помощью трёх разных подходов. Далее я буду называть их «mesh» (полигональный), «rhino» (Rhino NURBS) и «tspline» (T-Spline NURBS). Да, полигональное моделирование в Rhino тоже возможно, хотя и в очень урезанном виде.
Здесь изображены по три цилиндра, сферы, куба, криволинейных поверхности.
Конечно, напрямую сравнивать одно с другим не вполне корректно — в частности потому, что вершины полигонов и точки задающие сплайн — далеко не одно и то же. Однако, кое-какие полезные моменты здесь можно наглядно наблюдать.
Например, в Rhino варианте сфера — это одна свёрнутая поверхность (там, где линия жирнее — место её соединения).
Цилиндр — три поверхности: скрученная стенка и две круглые «крышки».
Rhino куб в чём-то похож на mesh — состоит из шести плоских поверхностей (просто здесь тот факт, что они плоские — лишь частный случай — они могли бы быть и вогнутыми).
В T-Spline варианте явно что-то странное — цилиндр выглядит как бочка, а куб как сфера. Да и поверхность, если присмотреться, имеет закруглённые уголки. По сути такое впечатление, что надутый шарик пытаются стянуть обручами. И, чтобы приблизиться к требуемой чёткой форме, «обручей» понадобится больше. Но к этому мы ещё вернёмся. Так же можно заметить, что швов у T-Spline объектов нет.
C Mesh понятно — видно, что криволинейные поверхности, при небольшом числе полигонов, не сильно плавные. Что не новость, конечно. Но зато с кубом всё замечательно.
Теперь попробуем исказить все объекты похожим, по возможности, образом, потянув за уголок:
Реакция явно отличается. Mesh объекты среагировали острее всех, Rhino оказались более ленивы и пластичны, ну, а T-Spline вообще — образцы мягкотелости.
Общее представление получили, теперь перейдём к конкретике.
В Rhino можно нарисовать кривую и одной из команд PlanarSrf, ExtrudeCrv, EdgeSrf (есть и другие варианты) получить плоскость, ограниченную некоей кривой:
Кажется, что результат (за исключением формы) везде аналогичен. Но это не так — в первом случае команда PlanarSrf в действительности просто взяла прямоугольник и скрыла у него всё, что выходит за пределы кривой. Этот процесс называется trimming. Ниже можно видеть результат команды Untrim, удаляющей обрезку:
Это отличие существенно, поскольку часто объекты (и отверстия в них) состоят из обрезанных поверхностей большего размера и ведут себя соответственно:
Нередко при выполнении операций над такими объектами возникают проблемы в местах стыковки поверхностей. Например, вот довольно типичная ситуация с образованием дыр при операции снятия фаски (так называемые «naked edges», выделены цветом):
И ещё пример:
Для устранения такого рода проблем приходится делать untrim и вручную создавать новые кривые для обрезки, с последующей подгонкой их для стыковки поскольку, если они будут стыковаться неточно, сплошное тело (соединением при помощи Join) мы не получим.
Чтобы избежать лишней работы, необходимо заранее тщательно продумывать, что как и на каком этапе будет делаться ибо, когда проблема вдруг возникает, оказывается, что заложена она была много шагов назад и вернуться к тому этапу уже проблематично.
Говоря проще, в Rhino не существует простого способа редактировать сложные поверхности и состоящие из них тела. Это существенный недостаток в работе с Rhino, который отчасти устранён в T-Spline.
Теперь попробуем изобразить плоскую поверхность в T-Spline. Сразу скажу, что получить плоскость ограниченную конкретной кривой так же просто, как в Rhino — нельзя. Точнее можно, но её топология будет такой (ужасной), что использовать вы её сможете лишь в каких-то частных случаях.
В первом случае t-spline объект образуется экструзией кривой. Обратите внимание, что рёбра образуются там, где на кривой были точки (другими словами — не все похожие на вид кривые будут одинаково полезны для конкретной задачи).
Также, здесь существует проблема дырки в центре, о которой ниже. Здесь дырка просто замаскирована — она имеет нулевой размер (координаты всех точек, определяющих её края — совпадают), но на практике это очень нехорошая ситуация. Кстати говоря, упомянутая на одной из предыдущих картинок штатная tspline сфера сделана также — по факту, она не является сплошным телом и имеет дырки на полюсах. А вот quadball, хотя топологически и ближе к кубу, но выглядит как сфера и, к тому же, сплошной. Так вот всё сложно и загадочно.
Во втором случае за основу берётся каркас из линий. Этот способ позволяет получить хорошее приближение к нужной форме и при этом, что очень важно, даёт вменяемую топологию (собственно, вы полностью задаёте её сами). Однако, взаимосвязь линий и результирующей поверхности — очень неочевидна даже в простых случаях.
Третий случай — это аналог Loft из Rhino.
В четвёртом случае плоскость создаётся сразу — командой tsPlane. Можно задать количество граней по горизонтали и вертикали. Взяв за основу такую плоскость, удалив затем лишнее и подвигав оставшееся — можно получить довольно сложную фигуру с хорошей топологией:
Возвращаясь к вопросу дырок
Существует команда _tsFillHole, которая автоматически их заделывает. Однако, результат её работы плохо предсказуем и удовлетворительным бывает лишь в каких-то совсем простых случаях (типа дырки на рисунке выше).
В большинстве случаев дырки приходится заделывать вдумчиво и вручную — либо сваривая между собой близлежащие вершины командой tsWeld, либо создавая грани между существующими вершинами командой _tsAppend:
Как можно видеть, если подходить «в лоб», во всех случаях результат получается ужасным. Мало того, что топология такая, что практического применения это не имеет, так ещё и форма внешних границ исказилась. И, хотя всё это можно выправить, ошибка тут в самом способе, которым была создана поверхность — исправлять здесь будет сложнее, чем сделать заново. Для данной ситуации куда лучше подошёл бы tsFromLines (кстати, напомнило известную картинку с паутиной обкуренного паука и трезвого):
Чем отличается сплошное тело (solid или closed polysurface) от поверхности (surface) или нескольких соединённых поверхностей (open polysurface)? Как ни странно, сплошные тела от просто поверхностей внешне могут и не отличаться. Настоящее различие — в отсутствии дыр. Все образующие сплошное тело поверхности должны быть плотно соединены (Join) без всяких щелей. В этом случае объект будет считаться closed (а не open) polysurface. Конечно, есть понятие точности (tolerance) и её можно изменить настройками настолько, что отчётливо видимая щель будет считаться отсутствием щели. Но это уже нештатная ситуация и не стоит идти по этому пути.
Изогнутую поверхность можно получить так же, как и плоскую — экструзией кривой, а также ещё несколькими способами:
Возьмём простой пример — колпачок клавиши. Это та ситуация, когда Rhino отлично подходит. Для удобства вставим при помощи PictureFrame картинку, чтобы сразу видеть, что, где и какого размера примерно должно быть:
Здесь всё, что бралось за основу — стандартно. Параллелепипед из примитива, сверху экструдированный прямоугольник со скруглёнными краями. В результате корректно сработало и вычитание сферы (для получения углубления) и все последующие скругления рёбер.
Теперь возьмём вариант посложнее — телефонную трубку и попытаемся изобразить её особо не раздумывая (обычно поначалу делают именно так, после чего разочаровываются в инструменте).
Вариант первый, через CreateSolid:
Т.е. обводим контуры кривыми, экструзией превращаем их в поверхности, затем командой CreateSolid создаём тело, ограниченное пересечением этих поверхностей.
Вроде, поначалу всё идёт хорошо, а главное просто. Проблемы начинаются, когда мы хотим сделать трубке закруглённые края.
Для этого существует команда Fillet. Во-первых, довольно сложно сделать именно такие закругления, как нужно, но в это даже не будет углубляться. Делаем примитивно — выбираем края и радиус. Сработало, но с одной стороны виден явный артефакт (по факту их там больше, просто другие менее заметны). При ближайшем (укрупнённом) рассмотрении оказывается, что в этом месте поверхности далеко не идеальны, а были как бы смяты. Соответственно и Fillet сработал неадекватно. Странно, ведь исходные кривые были вполне гладкие и аккуратные на вид. Оказывается, этого далеко недостаточно!
Причины проблем бывают разные. Может оказаться, что кривая, по которой обрезан край поверхности, имеет мелкие петли, перегибы (kinks) и другие прелести.
В результате, тут мы будем вынуждены откатиться назад, сделать этим кривым Rebuild/Refit, а то и пересоздать тело заново. Бывают проблемы вызванные самими операциями, в результате которых образуются новые кривые и поверхности.
Может быть, можно сделать закругления сразу? Ну, можно. Например, при помощи Loft и NetworkSurf:
Здесь используется другой подход — несколько кривых, отражающих формы сечений в нескольких местах тела. Команда Loft по этим кривым сразу строит тело. Всё бы ничего (только кривых конечно надо побольше, чтобы поверхность была точнее), но есть проблема с дырками по концам, которые корректно заделать очень сложно (в данном случае использовалась Path).
Более сложный вариант — команда NetworkSurf.
В этом случае берутся кривые не в одном направлении, а в двух или трёх. В теории, всё должно получаться замечательно. На практике же, все кривые должны быть расположены друг относительно друга строго определённым образом — где-то пересекаться, где-то нет. Эти правила очень неочевидны (и формально не описаны). Поэтому с небольшим количеством кривых, как в этом примере, команда проходит, а чуть побольше — уже нет. Причём, содержательная диагностика отсутствует — просто команда не может выполниться. Что именно не так — выяснить очень сложно.
Любой подход, конечно, не исключает объединения нескольких тел в одно, отрезания каких-то частей, трансформаций и пр. Но проблемы заложенные изначально, на более поздних этапах редко удаётся хорошо исправить.
Общая мораль такова: в Rhino можно создать сложное аккуратное тело. Но 90% успеха определяется в самом начале работы — на этапе выбора удачного для данного конкретного тела подхода и при создании основных кривых. Нежелание заниматься подобным — одна из причин, по которым появились средства типа T-Spline…
В T-Spline разнообразия будет поменьше. Причина в том, что в нём проще, по сравнению с Rhino, исправлять что-то уже сделанное. По этой причине бывает удобно взять какой-то примитив и просто подредактировать до нужной формы.
Аналогично ситуации с плоскостью, можно использовать tsFromLines, задав сетку линий не на плоскости, а в 3d. Хотя, это ещё сложнее, чем в 2D случае.
В некоторых ситуациях удобно сначала сделать какую-то Rhino поверхность или даже импортировать Mesh, затем преобразовать это в T-Spline, а дальше уже редактировать его. Но это возможно лишь в довольно простых случаях. Кроме того, в такой ситуации вы не можете влиять на итоговую топологию, а от этого напрямую зависят перспективы дальнейшего редактирования.
Для примера, рассмотрим создание той же самой телефонной трубки в T-Spline. Возьмём примитив Box и будем его редактировать:
Сначала изогнём при помощи Bend. Следующей логичной идеей было бы деформировать его среднюю часть (как на перечёркнутой картинке), но сразу скажу — это плохая идея. В данном конкретном случае не получится таким способом сделать аккуратные плавные изгибы. Так что поступим иначе — сначала удалим часть граней, а затем закроем дыры с помощью tsAppend.
Можно заметить, что данная конкретная трубка — симметричный объект. Мы можем сильно упростить себе работу, указав на это T-Spline’у командой tsSymmetry. При этом есть два подхода — либо обозначить ось симметрии, если мы уже имеем симметричный объект (не наш случай, потому что трубка лишь кажется симметричной — для T-Spline половинки окажутся всё же чуть разными). Либо создать симметричный объект. Для этого удалим половину трубки и укажем, что плоскость симметрии проходит по линии удаления. С этого момента все действия на одной половинке будут отражаться и на другой (см. третью картинку):
Кстати, обратите внимание, что в ходе процесса в некоторых местах были удалены лишние рёбра. Чем их меньше, тем проще сделать гладкую ровную поверхность. С другой стороны, чем рёбер больше, тем более детальные изменения можно вносить. В процессе работы ребра в нужных местах то удаляют, то добавляют — взависимости от ситуации.
В отличии от Rhino, в T-Spline сложно сделать резкие границы или углы. Есть два принципиально различных подхода к решению этого вопроса. Один — создание так называемых creases (сгибы). При этом T-Spline’у явным образом дают понять, что конкретное ребро должно быть резким
На практике этот подход имеет массу недостатков. В частности, этой резкостью никак нельзя управлять, а значит в итоге вам всё равно потом после преобразования поверхности в Rhino придётся делать скругление (fillet). С очень большой вероятностью в процессе возникнут проблемы, которые будет сложно устранить.
Другой подход — управление кривизной при помощи дополнительных рёбер и изменения расстояния между ними. Тут тоже есть свои сложности — например, на угле где сходятся три ребра будет сложно получить требуемый радиус закругления. Кроме того, совсем резкий перегиб (чтобы потом, при преобразовании в Rhino получилось одно «ребро») получить и вовсе не удастся. А значит и что-то сделать с ним, например скруглить, вы потом уже вряд ли сможете.
Rhino имеет достаточно богатый набор команд, позволяющих наклонить, изогнуть, скрутить и даже сложным образом исказить поверхность. Единственное, что тут следует учитывать, это плохую обратимость таких трансформаций. Если вы изогнёте поверхность в одну сторону, а потом изогнёте обратно — скорее всего получится уже другая, более сложная поверхность. При многократных и/или сложных трансформациях тел состоящих из нескольких поверхностей, возникнут проблемы в местах стыковки этих поверхностей.
В T-Spline всё гораздо проще. Чаще всего применять какие-то специальные команды даже не нужно — простой выбор и перемещение/поворот/масштабирование точек, рёбер или граней, в том числе в сочетании с радиальной симметрией, даёт почти всё, что нужно.
Тут нет проблемы необратимости — точки всегда можно вручную вернуть назад, пусть даже это и потребует кропотливой ручной работы.
Что касается применения упомянутых выше стандартных для Rhino команд (_Twist, _Bend и пр.), то здесь есть важный ньюанс — эффект зависит от режима редактирования. Если tspline объект выбран как объект, то применение к нему команд трансформации приведёт к преждевременному преобразованию объекта из tspline в rhino, что совершенно неприемлемо. А вот если выбран режим контрольных точек, рёбер или граней, то трансформации, по сути, будут подвергаться точки:
При этом можно выбирать для трансформации лишь часть объекта:
Хотя Rhino не позволяет детально редактировать геометрию готовых поверхностей, у него есть режим history, с момента включения которого запоминаются производимые операции. К примеру, если вы создали поверхность на основе одной или нескольких кривых при включённой history, последующее перемещение точек этих кривых приведёт к изменению этой поверхности. Этот режим, впрочем, имеет ряд ограничений — даже простое перемещение поверхности его отключает, пересчёт сложных поверхностей при каждом сдвиге точек требует много вычислительных ресурсов и пр.
Хотя команда Extrude есть и в Rhino, в T-Spline она работает по-другому. Здесь объекты состоят из множества граней, к которым экструзию можно применять выборочно.
В левой части объекта четыре грани подняты вверх без экструзии. В правой — с экструзией. Обратите внимание, что при экструзии возникают особые точки, где сходятся пять рёбер — звезды (star). Аналогичные точки (из трёх рёбер) можно видеть и на углах объекта.
Управлять кривизной в таких местах сложно — там легко могут появляться складки, морщины и т.п., поэтому звезд следует, по возможности, избегать (а если это не удалось — хотя бы минимизировать число сходящихся рёбер). Звёзды могут появляться сами — при удалении граней, затыкании дырок, экструзии граней и т.п.
В общем случае подход следующий:
Rhino:
— Если моделируемый объект имеет острые или резкие края/грани (к примеру, драгоценный камень после огранки)
— Если имеет сложную конфигурацию, которая должна быть точно повторена (к примеру, должен соответствовать чертежу)
— Если объект имеет мелкие (относительно самого объекта) детали, особенно отверстия или цилиндры правильной формы и особенно, если их много.
— Если объект состоит из нескольких плотного прилегающих друг к другу частей
T-Spline:
— Если моделируемый объект имеет плавные, в том числе плавно переходящие друг в друга формы без резких граней и переходов. Обычно подобные формы называют «органическими»
— Если нужно имитировать неидеальности (неровности, неточности) граней и поверхностей. В Rhino это сделать очень сложно — даже с дополнительными мерами при рендеринге объект может казаться слишком правильным (а значит — недостаточно реалистичным).
— Если форму объекта в будущем предполагается менять
Впрочем, как уже было упомянуто, нередко заготовку делают в T-Spline, преобразуют в Rhino поверхность и дорабатывают уже в Rhino.
Достаточно типовая схема работы, если речь идёт о создании модели по образцу, следующая (при условии, что T-Spline применим — т.е. формы плавные):
1.Если есть лишь изображение объекта с непонятного ракурса, то либо сразу начинаете, поглядывая на изображение, создавать поверхность в T-Spline (из примитива или экструзией кривых) либо, если это удобно, сначала создаёте общую форму в Rhino, а затем преобразуете поверхность в T-Spline и там продолжаете редактировать.
Если есть хотя бы одно изображение строго сверху, снизу, сбоку, то вставляете его при помощи pictureFrame и по его контурам делаете всё вышеперечисленное.
Если уже есть полигональная mesh модель (например, с 3d сканера), то сначала пробуете преобразовать её сразу в rhino или t-spline модель. Скорее всего, не выйдет. Тогда вы можете в T-Spline создать модель руководствуясь вершинами полигональной модели — как бы натягивая создаваемую tspline поверхность на контуры mesh.
Вплоть до того, что прямо tsAppend’ом создаёте грани на поверхности полигональной модели и потом подравниваете точки получившейся T-Spline поверхности по полигональной.
2.Готовую T-Spline поверхность преобразуете в Rhino поверхность. Это надо делать когда вы абсолютно уверены, что она полностью готова и в T-Spline её уже более не улучшить (обратного пути не будет).
3.Задумчиво смотрите на полученную Rhino поверхность и обращаете внимание, что на самом деле она состоит из нескольких поверхностей. Швы — это будущая ваша боль. Постарайтесь не производить вплотную к ним каких-либо операций типа отверстий, вырезов и т.п. Высока вероятность, что последующие скругления и фаски на краях расположенных там вырезов будут проблемными. Вплоть до того, что придётся модифицировать исходную T-Spline поверхность (которую вы предусмотрительно сохранили)
4.Делаете всё, что позволяет Rhino, но не позволяет T-Spline. Всякие резкие выемки, отверстия, торчащие элементы и пр. Если брать пример с телефонной трубкой, то после преобразования в Rhino её надо разрезать на две части (поскольку она в жизни состоит из двух половинок), скруглить у каждой части края, прорезать отверстия над динамиком и микрофоном, а также под шнур и винт.
5.Итак, вы получили готовую модель в Rhino. Что можно с ней сделать?
Рендер. Это отдельная длинная история, со своими нюансами. В Rhino есть встроенный рендерер, но он позволяет разве что получить общее представление — о реалистичности говорить не приходится. Для получения реалистичного изображения используют внешние пакеты — Keyshot, V-Ray и подобные. Причём, некоторые умеют работать непосредственно с NURBS и, соответственно, кривые поверхности там будут гладкими при любом разрешении…
Некоторые рендереры, в большей или меньшей степени, интегрируются с Rhino. Т.е. нажатием одной кнопки можно передавать изменённую модель прямо в рендерер, либо он будет работать непосредственно в окне Rhino…
Что касается анимации, то в Rhino такой функционал не предусмотрено совсем. Некие минимальные возможности бывают в пакетах рендеринга, но они довольно примитивны и предназначены для создания чего-то типа презентации объекта (покрутить, приблизить, поиграться цветами, светом, текстурой), но никак не для сложных сценариев.
Разумеется, из Rhino есть экспорт в различные форматы — от CAD-овских, типа STEP или IGES, до полигональных (при этом, соответственно, поверхности преобразуются в полигоны).
На момент написания статьи, текущей является Rhino версии 6. Проблема в том, что T-Spline с ней не работает и работать не будет. Более того, новых версий T-Spline (выше 4.x) тоже не будет, поскольку Autodesk решил включить его в состав своего, конкурирующего с Rhino, продукта.
Есть другой плагин со схожей функциональностью — Clayoo. Кроме того, автор Rhino заявлял, что планирует аналогичную функциональность в самом Rhino. Но будет это в любом случае нескоро.
С другой стороны, совершенно спокойно можно не переживать относительно новых версий и работать в Rhino 5 + T-Spline (как многие и делают). Связка вполне стабильна и функциональна.