Author Topic: Быдлокожу bezier-кривые в OpenGL  (Read 2581 times)

0 Members and 1 Guest are viewing this topic.

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

  • Blogger
  • *
  • Posts: 24129
  • Gender: Male
« on: February 9, 2014, 01:45 »
В старых версиях OpenGL была встроенная поддержка bezier, но сейчас оно deprecated. Более того, многие видеокарты вообще плохо реализуют поддержку линий. Даже если включено сглаживание, линии всё равно почему-то жутко aliased и вообще уродливые (моя видеокарта выдаёт кучу посторонних/отсутствующих пикселей), ибо всем давно пофиг на линии и весь труд идёт в сторону полигонов. Поэтому безье рисуются с помощью обычных полигонов.

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

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



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

Картинка:


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

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


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

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

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

Online Тайльнемер

  • Posts: 12573
  • Σοι υν βυρρο. Ix bin æn ézl
Классно.

Offline Hellerick

  • Posts: 25343
  • Gender: Male
Малопонятно, но очень интересно.

Online Тайльнемер

  • Posts: 12573
  • Σοι υν βυρρο. Ix bin æn ézl
Тот же GDI+ сильно глючит там, где поворот стремится к 180 градусам (зацените острый кол в самом верху)
Вы имеете в виду негладкое соединение двух сегментов?
А такой тип соединений вы использовали в  GDI?


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

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

  • Blogger
  • *
  • Posts: 24129
  • Gender: Male
Вы имеете в виду негладкое соединение двух сегментов?
Нет, это не соединение двух сегментов, это внутри самого сегмента. Если угол искривления внутри сегмента достаточно резкий, алгоритм GDI+'а становится нестабильным и в точке поворота начинают появляться гигантские дёргающиеся острые углы, как на картинке выше. Это простительно при статических безье, когда знаешь, что будет. Но если, например, юзер может сам создавать кривую, да ещё и анимированную — это непростительный визуальный глюк. В программе Foundry Nuke в анимированных масках такое же можно заметить

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

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

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

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

 

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Note: this post will not display until it's been approved by a moderator.
Name: Email:
Verification:
Type the letters shown in the picture
Listen to the letters / Request another image
Type the letters shown in the picture:
√49 Напишите ответ строчными буквами:
«Сто одёжек, все без застёжек» — что это?: