Главное меню
Мы солидарны с Украиной. Узнайте здесь, как можно поддержать Украину.

Быдлокожу bezier-кривые в OpenGL

Автор Алексей Гринь, февраля 8, 2014, 23:45

0 Пользователи и 1 гость просматривают эту тему.

Алексей Гринь

В старых версиях OpenGL была встроенная поддержка bezier, но сейчас оно deprecated. Более того, многие видеокарты вообще плохо реализуют поддержку линий. Даже если включено сглаживание, линии всё равно почему-то жутко aliased и вообще уродливые (моя видеокарта выдаёт кучу посторонних/отсутствующих пикселей), ибо всем давно пофиг на линии и весь труд идёт в сторону полигонов. Поэтому безье рисуются с помощью обычных полигонов.

Во-первых, наша кубическая безье-кривая должна быть из математической функции, выдающей непрерывную линию, преобразована в аппроксимацию отдельными точками, чтобы видеокарте было полехше. Наивные алгоритмы (типа через постоянные промежутки) показывают плохие результаты (особенно там, где угол искривления велик): при движении кривая дёргается и бесится; поэтому я позаимствовал отличный алгоритм у Максима Шеманарева (который, оказывается, внезапно умер! :( ), оный правильно вычисляет плотность точек в нужных моментах (больше искривления – больше точек) с динамической корректностью (LOD меняется плавно без дёрганий/изменения сглаженности кривой), ссылка тут: http://antigrain.com/research/adaptive_bezier/.

После того, как набор точек готов, следующим этапом у нас тесселяция этих точек, т. е. нарощение полигонов вокруг них. Это довольно простая векторная математика, тут быдлокодер Гринь с образованием три класса сельско-приходской школы смог реализовать алгоритм, не прибегая к копипасту. Вот результат прототипирования c помощью GDI+:



Даже при включённом мультисемплинге, особо сложные безье могут выглядить довольно jagged/aliased. Поэтому использован трюк: может быть, OpenGL и плохо сглаживает границы полигонов, однако цвет внутри полигона он интерполирует просто замечательно! Поэтому безье раскрашивается хитрым, но простым шейдером, который интерполирует цвет безье-линии с густого цвета в самой середине линии к alpha=0% к краям полигонов (внешним сторонам кривой). Т. е. мы рисуем края линии в шейдере. И вуаля, у нас есть сглаженная безье-кривая.

Картинка:


(результат с шейдером выглядит тоньше, потому что мы рисуем край линии внутри полигона, из-за чего часть обрезается)

Безье в действии:


Есть некоторые недочёты (безье в GDI+ выглядит всё равно сглаженнее), но этот результат куда лучше других готовых вариантов, которые я опробовал. Тот же GDI+ сильно глючит там, где поворот стремится к 180 градусам (зацените острый кол в самом верху):

Такой же баг замечен в одной программе, которую я использую. Это непростительно!

У нас глюки менее выраженные, хотя при очень большой толщине на сильных поворотах кривая перестаёт быть сглаженной и можно увидеть углы полигонов, плюс может происходить наложение текстуры одного полигона на другой из-за чего получается каша. Но для обычных тонких кривых линий (основной use case) багов практически нет.
肏! Τίς πέπορδε;

Тайльнемер


Hellerick


Тайльнемер

Цитата: Алексей Гринь от февраля  8, 2014, 23:45
Тот же GDI+ сильно глючит там, где поворот стремится к 180 градусам (зацените острый кол в самом верху)
Вы имеете в виду негладкое соединение двух сегментов?
А такой тип соединений вы использовали в  GDI?


Ваш алгоритм позволяет задавать типы соединений и концов?

Алексей Гринь

Цитата: Тайльнемер от февраля  9, 2014, 08:48
Вы имеете в виду негладкое соединение двух сегментов?
Нет, это не соединение двух сегментов, это внутри самого сегмента. Если угол искривления внутри сегмента достаточно резкий, алгоритм GDI+'а становится нестабильным и в точке поворота начинают появляться гигантские дёргающиеся острые углы, как на картинке выше. Это простительно при статических безье, когда знаешь, что будет. Но если, например, юзер может сам создавать кривую, да ещё и анимированную — это непростительный визуальный глюк. В программе Foundry Nuke в анимированных масках такое же можно заметить

Алгоритм по ссылке более стабилен в этом отношении; нестабильность тоже присутствует, но она менее заметная, огромные рандомные штыри не вылазят и слава богу. Там по ссылке есть демо алгоритма: //antigrain.com/demo/bezier_div.zip Вроде как тесселируют они собственным алгоритмом, поэтому он более совершенный

Цитата: Тайльнемер от февраля  9, 2014, 08:48
Ваш алгоритм позволяет задавать типы соединений и концов?
Два сегмента могут или «накладываться» друг на друга, создавая иллюзию большой непрырывной кривой (и control handles делятся между соседними сегментами), или не накладываться вообще (острые углы). Да, cusps можно соединять по-разному, я вроде как не сделал этого ещё. Давно делал, не помню, надо потестить.

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

Где-то на codeproject были примеры...
肏! Τίς πέπορδε;

Быстрый ответ

Обратите внимание: данное сообщение не будет отображаться, пока модератор не одобрит его.

Имя:
Имейл:
Проверка:
Оставьте это поле пустым:
Наберите символы, которые изображены на картинке
Прослушать / Запросить другое изображение

Наберите символы, которые изображены на картинке:

√36:
ALT+S — отправить
ALT+P — предварительный просмотр