Подтвердить что ты не робот

Как объединить фрагменты конвейера рисования холста Android (2D)?

Я хотел бы лучше понять, как компоненты конвейера рисования Canvas в Android (2D) сочетаются друг с другом.

Например, как взаимодействуют XferMode, Shader, MaskFilter и ColorFilter? Справочные документы для этих классов довольно редки, и документы для Canvas и Paint на самом деле не добавляют никакого полезного объяснения.

Мне также не совсем понятно, как операции рисования, которые имеют внутренние цвета (например, drawBitmap, а не "векторные" примитивы, такие как drawRect), вписываются во все это - всегда ли они игнорируют цвет Paint и используют вместо этого свой собственный цвет?

Я также был удивлен тем, что можно сделать что-то вроде этого:

Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);

Это стирает овал. До того, как я это заметил, моей ментальной моделью было то, что рисование на холсте (концептуально) рисует в отдельный "слой", а затем этот слой состоит из растрового изображения холста с использованием режима переноса Paint. Если бы это было так просто, то вышеприведенный код стер бы всю битовую карту (в пределах области отсечения), так как CLEAR всегда устанавливает цвет (и альфа) в 0 независимо от исходного альфа. Таким образом, это подразумевает, что существует дополнительная разновидность маскирования, чтобы ограничить стирание овалом.

Я нашел демоверсии API, но каждая демоверсия работает "в вакууме" и не показывает, как то, на чем она фокусируется (например, XferModes), взаимодействует с другими вещами (например, ColorFilters).

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

Этот вопрос был вдохновлен, увидев код в этом ответе на другой вопрос SO.

Обновить

Когда я искал какую-то документацию, мне пришло в голову, что, поскольку многие вещи, которые меня интересуют здесь, кажутся довольно тонким шпоном поверх skia, возможно, есть некоторая документация skia, которая будет полезна. Лучшее, что я могу найти, - это документация для SkPaint которой говорится:

Существует 6 типов эффектов, которые можно назначить краске:

  • SkPathEffect - изменение геометрии (пути) до того, как она сгенерирует альфа-маску (например, штрих)
  • SkRasterizer - создание пользовательских слоев маски (например, теней)
  • SkMaskFilter - изменение альфа-маски до ее раскрашивания и рисования (например, размытие, тиснение)
  • SkShader - например, градиенты (линейный, радиальный, развертка), растровые шаблоны (зажим, повтор, зеркальное отображение)
  • SkColorFilter - изменить исходные цвета перед применением xfermode (например, цветовой матрицы)
  • SkXfermode - например, режимы переноса портера, режимы наложения

Это не указано явно, но я предполагаю, что порядок эффектов здесь - это порядок, в котором они появляются в конвейере.

4b9b3361

Ответ 1

Как сказал Ромен Гай: "На этот вопрос сложно ответить на StackOverflow". На самом деле не было никакой полной документации, и полная документация была бы довольно большой, чтобы включить ее здесь.

В итоге я прочитал источник и провел кучу экспериментов. По пути я делал заметки и в итоге превратил их в документ, который вы можете увидеть здесь:

а также эта схема:

enter image description here

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

Исходя из вышеизложенного, здесь приведены ответы на некоторые из "подвопросов":

Мне также не совсем понятно, как операции рисования, которые имеют внутренние цвета (например, drawBitmap, а не "векторные" примитивы, такие как drawRect), вписываются во все это - всегда ли они игнорируют цвет Paint и используют вместо этого свой собственный цвет?

"Исходные цвета" происходят из Shader. В drawBitmap Shader временно заменен BitmapShader, если non- ALPHA_8 Bitmap используется. В других случаях, если ни один Shader не указан Shader, который просто генерирует твердый цвет, Paint цвета, используются.

Я также был удивлен тем, что можно сделать что-то вроде этого:

Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);

Это стирает овал. До того, как я это заметил, моей ментальной моделью было то, что рисование на холсте (концептуально) рисует в отдельный "слой", а затем этот слой состоит из растрового изображения холста с использованием режима переноса Paint. Если бы это было так просто, то вышеприведенный код стер бы всю битовую карту (в пределах области отсечения), так как CLEAR всегда устанавливает цвет (и альфа) в 0 независимо от исходного альфа. Таким образом, это подразумевает, что существует дополнительная разновидность маскирования, чтобы ограничить стирание овалом.

XferMode применяется к "исходным цветам" (из Shader) и "цветам назначения" (из Bitmap Canvas). Затем результат смешивается с пунктом назначения, используя маску, вычисленную в растеризации. Посмотрите фазу Передачи в вышеупомянутом документе для получения дополнительной информации.

Ответ 2

Этот вопрос трудно ответить на StackOverflow. Прежде чем начать, обратите внимание, что формы (drawRect()) не имеют собственного цвета. Информация о цвете всегда поступает из объекта Paint.

Это стирает овал. Прежде чем я заметил эта моя ментальная модель заключалась в том, что рисование к холсту (концептуально) обращается к отдельный "слой", а затем этот слой составлен с помощью растрового изображения Canvas используя режим переноса краски. Если оно были такими же простыми, как и выше код удалит весь битмап (в пределах области отсечения) как CLEAR всегда устанавливает цвет (и альфа) в 0 независимо от исходного альфа. Так это означает, что существует дополнительный вид маскировки, идущий к сдерживать стирание до овала.

Ваша модель немного выключена. Овал не втягивается в отдельный слой (если вы не вызываете Canvas.saveLayer()), он нарисован непосредственно на растровом изображении Canvas. Режим переноса краски применяется к каждому пикселю, нарисованному примитивом. В этом случае только результат растеризации овала влияет на битмап. Никакой специальной маскировки не происходит, сам овал - это маска.

Во всяком случае, здесь приведен упрощенный вид трубопровода:

  • Примитив (прямой, овальный, путь и т.д.)
  • PathEffect
  • растеризации
  • MaskFilter
  • Цвет /Shader/ColorFilter
  • Xfermode

(Я только что видел ваше обновление и да, то, что вы нашли, описывает этапы конвейера по порядку.)

Конвейер становится немного более сложным при использовании слоев (Canvas.saveLayer()), поскольку трубопровод удваивается. Сначала вы проходите по конвейеру, чтобы отобразить примитив внутри растрового изображения вне экрана (слой), а затемненное растровое изображение затем применяется к холсту, проходя через конвейер.

Ответ 3

SkPathEffect - изменения геометрии (пути) до того, как он генерирует альфа-маску (например, лихой) SkRasterizer - создание пользовательских слоев маски (например, теней) SkMaskFilter - модификации альфа-маски перед ее раскрашиванием и рисованием (например, размытие) SkShader - например. градиенты (линейные, радиальные, развертки), растровые рисунки (зажим, повтор, зеркало) SkColorFilter - изменить исходный цвет перед применением xfermode (например, цветовой матрицы) SkXfermode - например. портер-дафф-передачи, режимы смешивания

http://imgur.com/0X5Yqod