Пиксельный круг как основа кистей для рисования

  Большинство редакторов, в которых возможно рисование, используют метод оттисков - след кисти представляет собой ряд оттисков некой картинки. Картинка эта, правда, особенная, она не видима взгляду. Фактически, это даже не картинка, а двухмерный числовой массив (то есть массив, имеющий два индекса, соответствующих координатам X и Y), и содержит этот массив не цвет пикселей, а числа, указывающие на прозрачность. Будут числа по краям массива близки к единице – кисть будет иметь мягкие края, будет переход между единицей и числами, меньшими неё, резок – края кисти будут жёсткими.

  Так, или примерно так, устроены все графические редакторы. А теперь представьте – вы ведёте стилусом по планшету, и кисть рисует – она оставляет след. Весь этот след состоит из отдельных оттисков. Постепенно, по мере продвижения кисти, оттиски накладываются один на другой.
 
  И вы думаете, что это один и тот же оттиск?
  Да ничего подобного – перед началом работы вы же настроили динамические параметры своей кисти, позаботились о том, чтобы след кисти не был однообразен и уныл, Чтобы он слегка расширялся, а затем сужался и обрывался не так уж вдруг, а исчезал постепенно, увеличивая свою прозрачность, или распадался на красивые случайно длящиеся и более узкие следы, а по дороге, пока след ещё не исчез, по краям его появляются красивые шероховатости и прорехи, и, неправда ли, только тогда след вашей кисти можно будет назвать художественно красивым.

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

  Теперь вы понимаете, зачем Фотошопу нужно так много памяти? Почему, если размер ОЗУ вашего компьютера небольшой, фотошоп зависает, а иногда и вовсе отказывается работать? Да, Фотошоп, по части пожирания памяти, это программа монстр. Для нормальной работы ему требуется очень много памяти.

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

  Так «по быстрому» это же хорошо, скажите Вы. И будете правы – да, на заре компьютерной эры, когда компьютеры считали очень медленно, быстрые нашлёпки были единственным способом заставить программу рисовать красивыми художественными кистями. С той поры много воды утекло, технический прогресс продвинулся, и скорость счёта центрального процессора стала неимоверной, а рисование во всех без исключения редакторах делается с помощью всё тех же архаичных нашлёпок.

  СРАВНЕНИЕ СКОРОСТИ ОТТИСКА СО СКОРОСТЬЮ ПОПИКСЕЛЬНОГО РИСОВАНИЯ

  Но так ли уж быстро работает метод оттисков?
  Давайте сравним. В той среде, в которой я работаю, то есть, в Визуал Бейсике 6, метод оттиска реализуется оператором PaintPicture. Вот так выглядит строка программы, переносящая фрагмент одного рисунка (читай –слоя) на другой –

Picture1.PaintPicture Picture2, X1, Y1, W1, H1, X2, Y2, W2, H2, option

Здесь величины X2, Y2, W2, H2 указывают на поле переносимого фрагмента, в нашем случае этот фрагмент – выбранная нами кисть.
  Указываются координаты левого верхнего угла, ширина и высота фрагмента. Аналогичные величины с индексами 1 указывают поле оттиска, который ставится на рисунок_1. Варьируя величины W и H в ходе наложения оттисков легко создавать динамику кисти, менять размеры оттиска, или использовать для оттиска не всю кисть, а только центральную её часть. Отрицательные значения W1 и H1 создают зеркальные отражения оттиска справа-налево и сверху-вниз. 

  Вы хотите наложить на кисть текстуру? Это тоже легко можно сделать.
  Параметр option, который для обычного переноса можно и не указывать, задаёт побитовую логику – некие логические действия, которые можно совершить над битами переносимого фрагмента и полем того рисунка, куда этот фрагмент переносится. Например, это могут быть операции логического And или Or, или ещё ряд других операций и их комбинаций.
  Сделав промежуточный перенос фрагмента с изображением кисти на поле, изображающее текстуру с опциями And, Or или другими, можно соединить кисть с текстурой и уже затем, полученный результат перенести на нужное место рисунка.
  Хотите динамики? Пожалуйста, ведь тем же методом PaintPicture вы можете текстуру увеличивать, уменьшать, плющить и передвигать. Таким способом можно не только легко сделать из обычного следа зернистый, но можно постепенно увеличивать размер прорех в зернистом следе, создав для следа красивое художественное окончание.

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

  Какова скорость описанного процесса? Я провёл тест и выяснил, что скорость, с которой осуществляется перенос изображения методом PaintPicture, на моём компьютере составляет 286 передач в секунду.
  Это очень большая скорость, даже если мы двигаем стилус быстро, проходя 90 пикселей за одну секунду, то и тогда наша программа успевает каждый раз сделать 3 переноса, подцепив фактурный фон и создав в следе прорехи. А самое приятное это то, что скорость метода PaintPicture совершенно не зависит от размеров того поля, которое мы перемещаем, эта скорость совершенно одинакова как для маленьких кистей, так и для кистей огромного размера, или огромного текстурного фона, способного передать множество мелких подробностей.

  Поэтому понятно, почему компании, разрабатывающие графические редакторы, с таким упорством  держатся за старый и архаичный метод штамповки оттисков.
  Вы спросите, а чем же плох метод штамповки?
  А попробуйте нарисовать картину, используя не настоящую кисть, а штамп – печать, не совсем ровно измазанную краской. У Фотошопа именно это очень хорошо получается. А вот художественного вида мазков не получается ну никак. И только искусственный интеллект способен в какой-то мере управляться с невыразительными кистями Фотошопа.
  А созданные без искусственного интеллекта произведения Фотошопа Вы узнаете сразу – гладенькое контуры, однообразная текстура. Таким способом очень хорошо изображать монстров или Кикимор, что любители Фотошопа охотно и делают.
  Итак, произведения, сделанные методом штамповки, составляют особый род искусства, называемый компьютерной живописью, весьма специфический по своему стилю и содержанию.

  Однако взглянем на возможности по-пиксельного рисования. Этот метод предполагает не штамповку оттиска, а заполнение аналогичной области окрашенными пикселями, которые ставятся не сразу, а по очереди.
  На первый взгляд это очень нехороший и медленный способ. Однако посмотрим на реальные скорости такого процесса.
  Чтобы реализовать полупрозрачную кисть мы должны считать цвет каждого пикселя, находящегося в круге кисти, смешать этот цвет с красящим цветом, используя заданную для этого пропорцию, и затем вернуть полученный цвет на место, то есть, покрасить им пиксель на рисунке. Математические операции, проводимые при этом, особо на скорость не влияют, они протекают очень быстро. В сотню раз более медленно происходит чтение цвета пискселя с рисунка – 127 тысяч пикс/сек, и запись цвета пикселя на рисунок - – 169 тысяч пикс/сек. И это действительно медленно – подумайте, пикселей же много.
  Совместный процесс чтения-записи идёт со скоростью – 72500 пикс/сек.
  Ясно, что чем большее количество пикселей будет заключено в круг, изображающий отпечаток круглой кисти, тем более долгое время будет делаться такой отпечаток. А у метода штамповки, как Вы помните, подобной зависимости нет.
  Расчёт показывает, что фрагмент размером 50х50 пикселей заполняется цветом (учитывая предварительное чтение, а потом запись) с одинаковой скоростью (286 пикс/сек), будь то метод штамповки, или метод по-пиксельного рисования. Квадрат 50х50 содержит столько же пикселей, что и круг диаметра 77, и это означает следующее.

  Если кисть имеет диаметр более чем 77 пикселей, то рисование такой кистью по-пиксельно будет идти медленнее, чем рисование методом штамповки. Зависимость скорости по-пиксельного рисования от диаметра пятна обратно квадратичная, поэтому кисти для рисования большого размера будут заведомо зависать, а метод штамповки, по-прежнему, будет прекрасно работать. 
  А вот для кистей диаметром менее 77 пикселей, наоборот - по-пиксельное рисование предпочтительнее, и предпочтительнее во всех отношениях, и по скорости, и по возможностям. Всё дело в том, что возможности у штамповки убогие.

   И это естественно. Разница между процессом, идущим методом PaintPicture (и другими подобными методами), и процессом по-пиксельного рисования, состоит ещё и в том, что для рисования используются разные процессоры – первым методом управляет графический процессор, работающий с массивами быстро, но просто, а вычисления по второму методу выполняет центральный процессор, он работает с массивами примерно в 25 раз медленнее, но алгоритмы его работы могут быть куда более разнообразными.

  И в самом деле, тот PaintPicture, который тестировал я, дееспособен только в пределах тех опций, которые указаны в конце оператора, и ничего нового и своего в эти опции привнести нельзя. Даже сложить цвета, или умножить цвет на какую-нибудь постоянную этот оператор не может.
  Он не может даже учесть полупрозрачность слоя – есть способ, в котором, с помощью так называемой маски, можно сделать часть пикселей слоя совершенно прозрачными, однако другая часть пикселей будет при этом совершенно непрозрачна, и это всё, чего от этого метода можно добиться.
  А вот Фотошоп для штамповки оттисков использует, по-видимому, более совершенный метод, позволяющий учитывать и полупрозрачность пиксельных слоёв.

  ПИКСЕЛЬНЫЙ КРУГ

  При небольших размерах кисти (в моей программе диаметр кисти не превышает значения 41) преимущества по-пиксельного рисования неоспоримы, тут и перетекающая по пикселям акварель https://youtu.be/ICwFE-j-A_E и стекающая акварель https://youtu.be/RkNQEKQwXM4 и пастель с тонкой растушёвкой https://youtu.be/aKm5z3S-sF4 - всего в программе «Стереометрия и Анимация» семь разных кистей, каждая со своими многочисленными опциями и настройками.  Все эти кисти ориентированы на по-пиксельное рисование, а основой для пяти кистей является пиксельный круг.

  Если Вы сделаете запрос в интернете, то узнаете, что пиксельным кругом называется список пикселей, заключённых в круге определённого радиуса, или находящихся на окружности заданного радиуса. Список пикселей моей программы ещё и упорядочен по углу.

  Пиксельный круг создаётся в самом начале работы программы, при её загрузке, и делается он по постепенно расширяющейся спирали, начиная от центрального пикселя и продвижением по часовой стрелке. В ходе этого продвижения найденный пиксель проверяется – был ли этот пиксель уже включён в список, и если нет, то тогда его X и Y координаты заносятся в список. Всего, в кругах до внешнего радиуса 20 оказывается 1331 пиксель.
  Если круг имеет меньший радиус, то внутри него оказывается меньшее количество пикселей.
  На иллюстрации показан пиксельный круг в натуральную величину – в чёрном, цветном, и в увеличенном виде. В цветном изображении каждый слой с новым радиусом показан другим цветом.

  КАК ИСПОЛЬЗУЕТСЯ ПИКСЕЛЬНЫЙ КРУГ

  Работа кистью с использованием пиксельного круга протекает так – в момент касания стилусом планшета происходит событие Picture1_MouseDown. Этому событию мы присваиваем номер 1, и сигнал о нём направляем в подпрограмму рисования кистью. Затем мы начинаем двигать стилус по планшету. При каждом переходе на соседний пиксель возникает событие Picture1_MouseMove, координаты нового пикселя запоминаются в глобальных переменных Xm и Ym, а сигнал об этом событии в виде числа 2 снова передаётся в ту же подпрограмму. Подпрограмма организует цикл по окраске пикселей новым цветом. Первым красится центральный пиксель, затем пиксель №2, затем по кругу покраска доходит до пикселя №9, и идёт далее, вплоть до последнего пикселя с номером Im.  Упрощённо, подпрограмма, создающая след кисти, выглядит так –

If M = 1 Then 'Down
  Im = R20(R) 'находим число пикселей в кисти заданного радиуса
  A = (CV + 1) / 10 'определяем плотность кисти
  If F55a > 0 Then 'делаем зернистым начало следа
    For I = 1 To Im: Ar(I) = Int(Rnd(1) * 3 * F55a): Next I
  End If: End If

If M = 2 Then 'move
  For I = 1 To Im 'делаем цикл от центра пятна к периферии
    If F55a > 0 Then 'делаем пропуски в начале следа
      Xi = Ar(I): If Xi > 0 Then Ar(I) = Xi - 1: GoTo 5:
    End If
    X = Xm + RXY(I, 1): Y = Ym + RXY(I, 2) 'находим координаты пикселя
    C = Form1.Picture1.Point(X, Y) 'читаем цвет пикселя на рисунке
    C = ccRGB(Ca, C, A) 'добавляем красящий цвет с учётом плотности кисти
    Form1.Picture1.PSet (X, Y), C 'красим пиксель на рисуке
5 Next I: End If

  Если флаг F55a буквенной опции А поднят, то некоторые пиксели блокируются, и начинают работать только тогда, когда кисть пройдёт определённый путь. В результате, начало следа кисти становится зернистым.

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

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

__________
19.07.2023
 
ПРИЛОЖЕНИЕ
Программа, создающая пиксельный круг –

'========================== Пиксельный круг
Public Sub RXYini(K As Single)
'заполнение круга координатами пикселей X,Y при загрузке Формы
Dim I As Integer, R As Single, U As Single, dU As Single
Dim X As Single, Y As Single, N As Integer, C As Long
  RXY(0, 0) = 1: RXY(1, 0) = 0: RXY(1, 1) = 0: RXY(1, 2) = 0:
  For R = 1 To 20
    U = 0: dU = (K1 + 0.45) / R  '.5
    Do While U < 7.12: X = R * Cos(U): Y = R * Sin(U):
    Call RXY1(X, Y): U = U + dU: Loop '6.29
  Next R: R20(0) = 4: R20(20) = R20(21)
End Sub

Public Sub RXY1(A As Single, B As Single)
'включение пикселей в массив при заполнении круга
Dim X As Integer, Y As Integer, M As Integer
Dim N As Integer, I As Integer, R As Single
Static RN As Integer
  M = RXY(0, 0): N = 0: X = A: Y = B: If M = 1400 Then Exit Sub
  For I = 1 To M: If X = RXY(I, 1) And Y = RXY(I, 2) Then N = 1
  Next I:
  If N = 0 Then M = M + 1: RXY(M, 1) = X: RXY(M, 2) = Y: RXY(0, 0) = M
  If N = 0 Then R = X * X + Y * Y: RN = Sqr(R): RXY(M, 0) = RN: R20(RN) = M
End Sub


Рецензии