2D Объекты-капли в Max2DМатериал из Blitz Et CeteraЭтот тьюториал поможет тебе научиться рисовать объекты-капли, используя простые команды Max2D. Обычно, когда ты рисуешь картинку на экране, ты видишь её, как она есть, пиксель в пиксель. Если эта картинка была кругом, то, после того, как ты её нарисуешь, на экране ты увидишь круг. Форма картинки не изменилась, т.к. она зафиксирована в памяти попиксельно. Добавление картинок на экран не изменит форму других картинок. Объекты-капли от других отличаются тем, что их форма, которая обычно - круг, меняется в зависимости от того, как близко такие объекты расположены друг от друга. Два отдельных объекта могут слиться в один (на самом деле их два, но смотрится, как один). Классная это штука - объекты-капли! Как только ты нарисуешь несколько объектов-капель на достаточно близком расстоянии, они начнут влиять друг на друга. Чем ближе они друг к другу, тем сильнее они "выпучиваются" в сторону друг друга, как будто стягиваемые гравитационной силой. Когда же они совсем близко они начинают смешиваться в одну "гладкую фигуру"(похожую на знак бесконечность, если объекта два). Приемлемо называть такую фигуру "каплей". Если объекты находятся в одной точке, то образуется одна сфера побольше. Иногда объекты-капли называют "меташарами" (metaballs), поскольку это название хорошо объясняет их поведение - "это что-то большее, чем просто шар ". Можно представлять отдельный объект-каплю как ядро атома с энергетическим полем вокруг. Чем ближе подбираемся к нему - тем сильнее энергетическое поле. Сферообразная форма атома получается из-за "размытия" электронов, летящих вокруг него на огромной скорости. С приближением атомов друг к другу, такая форма меняется, т.к. на электроны одного атома влияет соседний(и наоборот). В конечном счете электроны вырываются из орбиты "своего" атома и перелетают на другой, потом, возможно, возвращаясь и т.д. Это ,в основном, и создает "каплю". Вот почему объекты-капли используются в науке для моделирования поведения атомов и молекул. Для нас вопрос в том, чтобы научиться рисовать фигуры, которые будут менять фигуру по заданному закону в зависимости от того, как близко они расположены друг к другу. Другой вопрос - это как рисовать классные "гладкие" фигуры, и как это делать быстро . Изобретено много алгоритмов по рисованию объектов капель. Самый известный из них - "движущиеся кубы"("marching cubes"). Про него можно почитать в Интернете. Алгоритм этот патентованный, так что мы не можем полностью его использовать(фигуры). Однако, получено несколько "побочных эффектов", например "движущиеся треугольники" ("marching triangles"). Основная идея такого алгоритма в том, чтобы подразделять данный набор "атомов" и их объединенные энергетические поля в кубы. Затем ты работаешь на очень маленьком уровне, когда внутри куба создается полигон, перпендикулярный поверхности энергетического поля. Тебе не нужно понимать, как это работает (в нашем случае), так как этот алгоритм мы использовать не будем. Он обычно используется для генерирования 3D полигональных мешей с определенным уровнем детализации. Чаще всего, по такому алгоритму, полигон будет создан в любой точке энергетического поля, где его интенсивность приблизительно равна половине силы. Это понимается, как порог. Т. к. алгоритму нужно знать все возможные места, где энергетический уровень на своем "пороге" в половину силы, требуется большое количество вычислений, особенно работая в 3D. Одна из областей использования объектов-капель - это моделирование органических форм в 3D, и это фича самых навороченных 3D редакторов. Главным образом тяжело это сделать в реальном времени - приходиться разрабатывать специфический системный код. Сперва нужно разобраться, как выглядит объединенное энергетическое поле нескольких объектов-капель или атомов. Представь несколько атомов, висящих в воздухе неподалеку друг от друга. Они испускают энергетические поля заданной силы, рассеивающиеся с расстоянием. В пространстве, где энергетические поля пересекаются, сила энергетического поля равна сумме энергий пересеченных "кусочков". Что хочется сделать в первую очередь - это по данным положениям атомов определить, количество энергии в каждой точке пространства. Очевидно, что в 3D таких точек очень много. В 2D всё проще, особенно с фиксированным количеством пикселей на экране. Так что нам нужно знать только что такое энергетическое поле на пиксельной основе. Традиционные алгоритмы, такие как "движущиеся кубы", используют "много математики" чтобы узнать где располагается энергетическое поле. Поскольку они обычно работают в 3D, они должны задать трехмерную систему точек заданного разрешения и построить энергетическое поле в нем. Это достигается множеством формул и, в случае алгоритма "движущихся кубов", пытается ограничить вычисления ссылкой на возможное кол-во перестановок результата. Но всё это считает процессор. Поскольку мы собираемся создавать двумерные объекты-капли, нам нужно знать как выглядит объединенное энергетическое поле нескольких объектов в 2D. Начнем с рисования картинки энергетического поля в оттенках серого. Всё что нам нужно - это нарисовать энергетическое поле каждого атома и убедится, что в области их пересечения энергия пересеченных "кусочков" складывается. Поскольку мы работаем в 2D и вычисляем положение точек "меша" за один шаг, каждый пиксель можно использовать как точка энергетического поля. Мы просто делаем кадр всех энергетических полей вокруг всех атомов. Вместо использования массива для хранения поля, или использования математики для работы в реальном времени, мы будем использовать картинку на экране. Экран - это массив данных, преобразуемых железом в цвет в зависимости от содержания данных. А фрукт в том, что используя картинку в качестве объекта-капли, мы можем спихнуть вычисления на видеокарту. Видеокарта = скорость видео. BlitzMax позволяет рисовать картинки разными способами. Установить способ рисования можно командой SetBlend. Обычно картинки рисуются непрозрачными, с использованием режима SOLIDBLEND, установленного по умолчанию. При таком режиме содержание картинки полностью заменяет содержимое экрана под собой. Но нам нужно другое - LIGHTBLEND. Это режим "прибавления". В таком режиме цвет каждого пикселя картинки складывается с соответствующем пикселем экрана. Когда цвет складываемых пикселей получается больше 255(в цвете) или 1.0(в цвете, выраженным числом с плавающей точкой), то сумма обрезается, соответственно до 255 и 1.0. Таким образом мы можем использовать режим LIGHTBLEND для определения пересекающихся частей каждого поля. Ничего, что непересекающиеся участки полей рисуются в таком режиме - позади этих областей черный экран, так что картинка нарисуется так, как она нарисуется в режиме SOLIDBLEND . Итак, мы можем использовать режим LIGHTBLEND для комбинирования энергий каждого атома. Мы будем использовать обычную DrawImage , чтобы нарисовать энергию каждого атома. Энергетическое поле будет просчитываться до использования и храниться в картинке. Пре-просчитывание картинки - это важный фактор, позволяющий нам в реальном времени, с нормальной скоростью создавать эффект капли. Если просчитывать каждое поле, комбинировать его с другими полями, причем делать всё это в реальном времени, то наша прога будет жутко тормозить. Итак, теперь вопрос в том, чтобы сгенерировать энергетическое поле атома и сохранить его как картинка в оттенках серого. Ну, как я уже говорил, чем дальше мы от атома - тем слабее сила энергетического поля. Следовательно, энергетическое поле атома представляет собой шар, с убывающей к краям плотностью. Центр шара - яркий, края шара - почти невидимы. Будем рисовать каждый уровень энергетического поля разным цветом и, поскольку мы работаем в оттенках серого, мы будем использовать 256 оттенков серого. Нарисовать энергетическое поле атома очень легко, скажешь ты. Начать нужно с установки цвета черным, затем нарисовать большой круг, по размеру равный энергетическому полю. Затем нужно повторять этот цикл, уменьшая размер круга, и добавляя 1 к его цвету(и к красному, и к зеленому, и к синему). Получиться круг, залитый градиентом от белого до черного, из центра к краям. Это выглядит так: Если положить это в картинку и нарисовать её несколько раз, получим это: Эффекта капли не получилось. Пока энергии пересеченных кусочков не складываются, нет эффекта гладкой поверхности. Это становится более очевидным, если выделить некоторые кусочки поля одного цвета контрастным, например красным: Далее можно увидеть, какая, собственно, фигура получилась. Получился почти прямой "мост" между двумя полями. Но почему? Эта прямолинейность - результат приращения цвета исходной картинки. Градиент получился полностью "линейным". Его изменение показано на графике: Так как цвет изменяется от черного к белому, существует устойчивый шаг его увеличения, пропорциональный диаметру нарисованных кругов. Из-за "линейного" градиента ничего не получается. Технически энергетические поля комбинируются, но делают они это не так, как нам надо. Нам не подходит такой способ представления объектов-капель. Нам нужно сгенерировать искривленную поверхность. Нам нужно, чтобы объекты взаимодействовали постепенно, чтобы образовалась гладкая искривленная поверхность, а не все сразу рывком. Чтобы этого достичь, нужно изменить форму градиента, чтобы он был нелинейным. Это значит, что вместо увеличения цвета на 1 с каждым шагом, нужно медленно увеличивать изменение цвета (до этого оно всегда было 1). Электрону из такого энергетического поля, на краю поля будет очень легко вылететь, когда при приближении к центру это становится почти невозможным. Рисование изогнутого градиента включено в исходник ниже. Нам нужно увеличивать интенсивность цвета квадратично. Пока число маленькое - кривая не сильно гнется, но с его увеличением, она становится очень изогнутой. Выглядит такая кривая так: Так выглядит энергетическое поле атома, заданное картинкой, залитой квадратичным градиентом: У новой картинки больше проявляется центр, где максимум яркости и прозрачность краев. Яркость быстро спадает по направлению от центра к краям. Это идеальная форма для объекта-капли. Такой градиент подходит больше всего, т.к. его кривизна также показывает, как взаимодействуют два поля друг на друга в зависимости от расстояния между ними. При рисовании нескольких таких картинок в режиме LIGHTBLEND образуются не только гладкоизогнутые формы, но и различные углы кривизны, зависящие от близости атомов. С линейным градиентом получается резкое образование "моста" между двумя атомами, когда как при изогнутом градиенте мы получаем различную степень выгнутости. Итак, вот что получается при рисовании двух энергетических полей новым способом: Теперь это совсем не похоже на то, что у нас получилось в начале. Опять же, выделив "кусочки" поля красным, видим кривые, но теперь такие, как нам надо: Получился нормальный объект-капля. Области ближе к центру ещё не "вытянулись", т.к. ещё не находятся во влиянии друг друга. Области, которые влияют друг на друга (пересекаясь) начинают выгибаться в сторону друг друга и объединяться. Только из-за квадратичного градиента у нас всё получилось. Всё, теперь у тебя есть объект-капля, нарисованный на экране! Самое классное это то, что это очень-очень простая техника по сравнению с "движущимися кубами". Особенно классно то, что мы все преобразования производим, используя данные картинки и, следовательно, используем ускорение видеокарты. Простая комбинация пре-просчитанной картинки, с использованием правильного градиента и "прибавительного" режима рисования обеспечивает нам эффект объекта-капли. Существуют и другие кривые градиента, основанные на других формулах. Формула ЧИСЛОxЧИСЛО - самая простая и производит стандартный эффект. Другие формулы дают более плоские кривые, или подчеркивают центр. Изменение кривой таким способом могут сделать объекты-капли более "липкими". Главная идея получения объектов-капель в том, что сперва генерируется объединенное поле, официально называемое "изоповерхность"("isosurface") и, затем рисуется с определенным порогом. В моем примере выше(про выделение красным) я взял программу рисования, включил потоковую заливку, шириной в 5 пикселей и тыкнул мышкой в нескольких местах. Можно определить порог цвета, который будет рисоваться. Обычно объекты-капли так и рисуются, рисуя только пиксели цветом, скажем, между 120 и 140. Получится полоска, похожая на одну из красных на картинках выше. В этом тьюториале я всего лишь показываю тебе основы генерации объектов-капель. Твоя задача в том, чтобы преобразовать сгенерированную картинку в ту, что тебе надо. В следующем, более продвинутом примере, я перевел весь код в прямой OpenGL. Это позволяет мне устанавливать режимы рисования, не имеющиеся в оригинальном Max2D. Используя дополнительные режимы, я несколько раз покрывал экран заполненным треугольником, и с каждым разом производились различные математические преобразования над цветами пикселей. В конечном результате можно получить несколько полосок цвета. В примере этого тьюториала есть встроенный порог в 255, т.е. в любой точке экрана яркость не может быть больше 255. Посредством различных манипуляций можно сделать объект-каплю полностью белым. В добавление можно нарисовать прямоугольник над экраном в режиме LIGHTBLEND с цветом $80,$80,$80 (наполовину серый), который приведет к изменению порога так, что он будет равен половине силы поля - что гораздо лучше смотрится, чем белый. Немного умных манипуляций и может получиться что-нибудь, похожее на это: Пока всё что мы сделали - это сферический объект-капля. Мы работаем с пре-просчитанной картинкой в качестве поля. Можно её сохранить в файл и, затем изменить в любом графическом редакторе. Потом нужно будет просто загрузить её в начале программы, вместо генерации. Изменяя форму, или добавляете что-либо в начальную картинку, можно достичь классных эффектов! Можно закрашивать картинки при рендеринге, используя SetColor для каждой. Так можно получить эффект, похожий на изображенный выше. Этот алгоритм поддерживает неограниченное количество объектов! Повеселись! Надеюсь всё написано чётко и понятно (я тоже - прим. всеп. пер.). Вот очень маленький исходник, просто скопируй, вставь в свой IDE и запусти! Тут реализовано создание сферических объектов-капель диаметром 512, 256 и 128 пикселей. Возможны и другие размеры, но для них нужно определить значения balldivider и lineardivider - уверен, что существует формула их вычисления, но я пока не смог её вывести. 'Объекты-капли в BlitzMax, используя только Max2D
;Blobby Objects для Blitz3D
;Портировал на Блитз: Солодовниченко Михаил ака MANIAK_dobrii Автор: AngelDaniel (worklog: http://www.blitzbasic.com/logs/userlog.php?log=436&user=8053) |











