Возникла у меня необходимость нарисовать некоторую произвольную фигуру и залить ее определенным цветом.
Обратившись к документации kivy нашел несколько способов рисования:
- Применение классов Rectangle, Ellipse, Triangle – при создании экземпляров которых в контексте canvas происходит рисование указанной фигуры по заданным координатам и с заданным размером. Например Rectangle(pos=pos, size=size). При этом фигура закрашивается или заранее определенным цветом (создание экземпляра Color) или для нее определяется атрибут texture. Однако стоит заметить, что создание более сложных фигур при этом становится задачей комбинирования этих фигур
- Применение класса Line, который позволяет рисовать произвольные фигуры линиями, или создать сразу готовую фигуру треугольник, прямоугольник, эллипс. Цвет линий определяется по заданной для контекста canvas. Можно задать толщину линии, но нет способа выполнить заливку. Например: Line(points=<список точек>)
- Применение класса Mesh. При создании экземпляра этого класса в контексте canvas происходит рисование указанной по точке фигуры. Фигура заливается либо цветом определенным в контексте canvas, либо атрибутом texture. И вот тут в зависимости от значения атрибута mode будет произведено рисования в разных режимах, а именно:
1 2 3 4 5 6 |
'points' будут нарисованы только единичные пиксели, точки 'line_strip' - точки будут соединены линиями, при этом линии имеют заданную заливку, 'line_loop' - тоже, что и предыдущие но фигура замыкается, 'lines', 'triangle_strip' - фигура со сплошной заливкой, 'triangle_fan - тоже что и предыдущие но с замыканием фигуры' |
Но самое интересное в применение Mesh заключается в том, что кроме координат вершин фигуры, задаются также и текстурные координаты, которые указывают на каким цветом из текстуры должна быть закрашено вершина. Значение текстурных координат – это числа с плавающей запятой в диапазоне от 0 до 1. При этом 0 – первый пиксель из текстуры, 1 – это последний. Так как текстура имеет два измерения, то текстурные координаты это пара значений. При этом стоит отметить, что при выполнении заливки происходит интерполяция цветов.
Например нарисуем прямоугольник и зальем его одним цветом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
from kivy.graphics.texture import Texture from kivy.uix.button import Button from kivy.uix.widget import Widget from kivy.uix.boxlayout import BoxLayout from kivy.app import App from kivy.graphics import Mesh from functools import partial from math import cos, sin, pi from gaudges.utils.kivy_utils import restriction class MeshTestApp(App): def build_mesh(self): vertices = [0,0,0,0, 200, 0, 0, 0, 200, 300, 0, 0, 0, 300, 0, 0] indices = [0, 1, 2, 3] colors = (255, 0, 0, 255) tex = Texture.create(size=(1, 1)) buf = [int(restriction(c, 0, 255)) for c in colors] tex.blit_buffer(bytes(buf), colorfmt='rgba', bufferfmt='ubyte') return Mesh(vertices=vertices, indices=indices, texture = tex, mode='triangle_fan') def build(self): wid = Widget() with wid.canvas: self.mesh = self.build_mesh() return wid if __name__ == '__main__': MeshTestApp().run() |
В этом случае на экране отобразится окно:

Однако если код немного изменить:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
from kivy.graphics.texture import Texture from kivy.uix.button import Button from kivy.uix.widget import Widget from kivy.uix.boxlayout import BoxLayout from kivy.app import App from kivy.graphics import Mesh from functools import partial from math import cos, sin, pi from gaudges.utils.kivy_utils import restriction class MeshTestApp(App): def build_mesh(self): vertices = [0,0,0,0, 200, 0, 0, 0.5, 200, 300, 0, 1, 0, 300, 0, 0.5] indices = [0, 1, 2, 3] colors = (255, 0, 0, 255, 255, 255, 0, 255, 255, 0, 0, 255) tex = Texture.create(size=(1, 3)) buf = [int(restriction(c, 0, 255)) for c in colors] tex.blit_buffer(bytes(buf), colorfmt='rgba', bufferfmt='ubyte') return Mesh(vertices=vertices, indices=indices, texture = tex, mode='triangle_fan') def build(self): wid = Widget() with wid.canvas: self.mesh = self.build_mesh() return wid if __name__ == '__main__': MeshTestApp().run() |
То отобразится прямоугольник залитый градиентом:

Вся суть в том, что мы создали текстуру из трех цветов красного, желтого и снова красного, а для прямоугольника задали для нижнего левого текстурную координату (0, 0), для верхнего правого (0, 1), а для двух других значение текстурной координаты (0, 0.5). Таким образом вы видим по диагонали ровно середину текстуры, которая соответствует желтому цвету.