Обобщённое рисование фигур

Надеюсь, все любят оптимизацию графики и процедурную генерацию, потому что тут мы соберём всё это вместе для построения универсальных шейдеров.

Процедурная текстура. Ромбы, шум.

Обобщённое рисование 2D фигур

На эту идею меня навела статья nabbla1 об ускоренной оценке длины вектора на плоскости. Евклидова длина вычисляется как корень из суммы квадратов координат. Школьники узнают это из формулы гипотенузы прямоугольного треугольника. Если прилежащий катет пустить из начала координат, получится как раз формула длины.

Если считать длину по Евклиду, то равноудалённые точки будут описывать окружность. Так и работает функция расстояния для круга: через длину и радиус. Но если мы изменим формулу длины, то изменится и положение равноудалённых точек:

Обобщённое рисование фигур

Здесь чебышевская длина описывает квадрат, манхэттэнская ромб, а их сочетание через коэффициенты создаёт восьмиугольник. Особая прелесть в том, что вычислительная сложность у них совсем маленькая. От себя я добавил чуть более сложные шестиугольную и треугольную, которые, впрочем, тоже изящно сократились под случай симметрии.

Итого, 6 фигур из заголовка описываются через такой вот код:

Обобщённое рисование фигур

Для сравнения, один только равносторонний треугольник описывается так:

Обобщённое рисование фигур

Но тут самый внимательный читатель мог заметить одну интересную вещь: вокруг моих фигур полосы ломаные, а вокруг этого треугольника закруглённые. Это так называемые изолинии, которые и описывают фигуры из равноудалённых точек. В "точных" формулах, которые работают в евклидовом пространстве, изолинии при удалении от фигуры вырождаются в идеальную окружность. Этим, к слову, пользуются для операции скругления.

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

Обобщённое рисование 3D фигур

С трёхмерными фигурами обобщать особенно важно. Произвольные наборы фигур требуют вложенных циклов, которые с большими полотнами кода просто перестают работать. Даже директива [unroll(x)] порой пасует перед трудностями.

И здесь особенно важно сохранить плавность фигур. Потому что смысл процедурной геометрии не раскрывается на слабо детализированных острых объектах.

Если на этом моменте непонятно вообще, что за процедурная геометрия такая, можно зайти почитать базовый ликбез

Прямой способ описать фигуры - придумать для каждой уникальную функцию. Из плюсов: вычисление может быть очень компактным. Как, например, у куба или эллипсоида. Буквальные две строчки.

Из минусов, уже 4 фигуры занимают вот столько места:

Обобщённое рисование фигур

Поэтому я решил пойти от двумерных фигур. Во-первых, мне попалась замечательная формула произвольного многоугольника. От треугольника до круга за одну функцию.

Изолинии, кстати говоря, плавные

А вот чтобы из двумерной фигуры сделать трёхмерную, есть несколько интересных классов: фигуры вращения и выдавливания.

Фигуры вращения получаются, когда плоскость вращается вокруг оси. Необязательно своей. Например, круг, который вращается вокруг своей оси, создаёт сферу. Но если раскрутить его по кругу большего радиуса, получится тор, он же бублик. Помимо сферы и тора полезными в моделировании являются конус (вращение треугольника) и цилиндр (квадрата). Из условно неполезных можно увидеть фигуры вращения в левом верхнем углу.

Фигура вращения наглядно
Фигура вращения наглядно

Понятное дело, что так мы потенциал многоугольников толком не раскрываем. А это не шутки, это мы целый арктангенс считаем. Поэтому докидываем до кучи фигуры выдавливания. Как можно понять, это вытягивание плоскости по третьей оси. Из треугольника получается треугольная призма, из круга цилиндр (функции избыточно перекрывают друг друга, да), а из шестиугольника... Шестиугольник. Ладно, шучу, все объёмные многоугольники называются призмами. Хитроумно можно сделать даже сферу, но об этом чуть дальше. Все продукты экструзии можно рассмотреть в нижнем ряду верхнего видосика.

Соответственно, если мы объединим эти три функции вместе, то получится около десятка стандартных фигур. И бесконечное число нестандартных, конечно же. И всё это в данном куске кода:

Обобщённое рисование фигур

Совсем обобщённое рисование 3д фигур жесть

Слабым местом предыдущего метода является формула произвольного многоугольника. Хотя она позволяет создавать на своей основе огромное количество фигур, вычисления довольно объёмные. И вероятно, все эти бесконечные вариации поверхностей могут вообще не понадобиться в моделировании. Плюс операции выдавливания и вращения перекрывают друг друга, что дополнительно намекает на возможности оптимизации.

От подхода через двумерные фигуры я решил не отказываться. Осталось выбрать, какая станет основой.

Это размышление не было слишком долгим, потому что все мы знаем главный примитив трёхмерной графики. Он встречает нас своей улыбкой в каждом стартовом проекте блендера:

Косит лиловым глазом
Косит лиловым глазом

Двумерный прямоугольник чертовски быстро вычисляется и масштабируется в обе стороны без нарушения пространства. Ну и вдобавок, ему достаточно одной операции выдавливания в пару, чтобы сделать ещё пару базовых примитивов.

Так как эта формула прямоугольника точная, она вычисляется строго в евклидовом пространстве. А как я уже говорил, в этом случае, работает операция скругления.

И если выдавленный квадрат - это куб, то выдавленный круг уже цилиндр, успех. Но скруглять можно не только на уровне 2д. Если сначала мы получим куб, а затем скруглим его, то получится сфера. А из цилиндра можно сделать капсулу, как видно на фигуре слева.

С эллипсоидом не всё так просто. Корректную сферу можно сделать исключительно из куба, растягивать его перед скруглением нельзя. Следовательно, всё-таки придётся искажать пространство. На практике это не сказать, что слишком страшно, но неприятно.

Ну и это все возможные фигуры. Конечно, куб тоже не так прост. Правильно располагая его и применяя булевы операции, можно получить пирамиду и треугольную призму, например. Но это уже эквилибристика. Зато вот столько кода на всё про всё:

Обобщённое рисование фигур

А как нарисовать всё в одну инструкцию, я пока не придумал.

2
1
1
25 комментариев