Matrixcolor
Ren'Py поддерживает перекрашивание изображений с помощью свойства трансформации matrixcolor.
Это свойство может принимать объект Matrix или ColorMatrix.
Цвет с предварительно умноженной альфой
Когда изображение загружается, Ren'Py распаковывает его, а затем копирует в GPU вашего компьютера или мобильного устройства. В процессе копирования каждый из четырех цветовых каналов (красный, зелёный, синий и альфа — где альфа представляет непрозрачность) масштабируется до числа в диапазоне от 0.0 до 1.0. В этой системе 1.0 представляет полный уровень цвета или полную непрозрачность, тогда как 0.0 представляет отсутствие цвета или полную прозрачность пикселя.
Однако Ren'Py на этом не останавливается. Как только значения были масштабированы, красный, зелёный и синий каналы умножаются на альфа-канал. Это означает, что непрозрачный белый пиксель будет иметь значение (1.0, 1.0, 1.0, 1.0), на 50% прозрачный красный пиксель — (0.5, 0.0, 0.0, 0.5), а полностью прозрачный пиксель — (0.0, 0.0, 0.0, 0.0).
Предварительно умноженная альфа позволяет Ren'Py масштабировать изображения вверх и вниз, не вызывая тёмных артефактов, которые появляются при более прямом представлении цветов. Масштабирование изображений похоже на усреднение двух пикселей. Без предварительно умноженной альфы у нас мог бы быть сплошной белый пиксель и прозрачный пиксель — (1.0, 1.0, 1.0, 1.0) и (0.0, 0.0, 0.0, 0.0) соответственно. Их усреднение даёт (0.5, 0.5, 0.5, 0.5), что в системе с прямой альфой представляет 50% непрозрачный серый цвет.
Однако, поскольку полностью прозрачный пиксель на самом деле не имеет цвета, он не должен влиять и на итоговый цвет — только на итоговую прозрачность. В системе с предварительно умноженной альфой начальные значения те же, и результат тоже — за исключением того, что теперь (0.5, 0.5, 0.5, 0.5) предопределено как 50% непрозрачный белый цвет. Сохраняя цвета таким образом, Ren'Py может корректно отрисовывать их на экране, не получая странных артефактов при масштабировании.
Использование матрицы для изменения цветов
Объекты Matrix, используемые для изменения цветов, могут состоять из 16
чисел, которые, в свою очередь, можно расположить в виде сетки 4x4. Вот способ
сделать это, присвоив букву каждому числу:
define mymatrix = Matrix([ a, b, c, d,
e, f, g, h,
i, j, k, l,
m, n, o, p, ])
Хотя здесь они представлены буквами, следует понимать, что на самом деле это числа, заданные напрямую или вычисленные.
Эти значения применяются к красному (R), зелёному (G), синему (B) и альфа (A) каналам исходного цвета для создания нового цвета (R', G', B', A'). Формулы для этого таковы:
R' = R * a + G * b + B * c + A * d
G' = R * e + G * f + B * g + A * h
B' = R * i + G * j + B * k + A * l
A' = R * m + G * n + B * o + A * p
Хотя это может показаться сложным, у этого есть довольно простая структура — первая строка создаёт новый красный канал, вторая — новый зелёный канал и так далее. Так что, если бы мы по какой-то причине захотели создать матрицу, которая меняет местами красный и зелёный каналы, мы бы написали:
transform swap_red_and green:
matrixcolor Matrix([ 0.0, 1.0, 0.0, 0.0,
1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0, ])
Хотя это простой пример, таким образом можно выразить большую часть теории цвета. Матрицы можно комбинировать, перемножая их друг с другом, и в этом случае матрицы комбинируются справа налево.
ColorMatrix
Хотя объекты Matrix подходят для статических изменений цвета, они не годятся для анимированных изменений цвета. Также полезно иметь способ брать распространённые матрицы и инкапсулировать их так, чтобы матрицу можно было параметризовать.
ColorMatrix — это базовый класс, который расширяется рядом классов, создающих Matrix. Экземпляры ColorMatrix вызываются Ren'Py и возвращают объекты Matrix. ColorMatrix хорошо интегрирован с ATL, что позволяет создавать анимации matrixcolor.
transform red_blue_tint:
matrixcolor TintMatrix("#f00")
linear 3.0 matrixcolor TintMatrix("#00f")
linear 3.0 matrixcolor TintMatrix("#f00")
repeat
Класс ColorMatrix можно наследовать, при этом подклассы переопределяют его
метод __call__. Этот метод принимает:
Старый объект для интерполяции. Этот объект может быть любого класса, и может быть None, если старого объекта нет.
Значение от 0.0 до 1.0, представляющее точку для интерполяции. 0.0 — это полностью старый объект, а 1.0 — полностью новый объект.
И должен возвращать Matrix.
В качестве примера ColorMatrix, вот реализация класса TintMatrix из Ren'Py.
class TintMatrix(ColorMatrix):
def __init__(self, color):
# Store the color given as a parameter.
self.color = Color(color)
def __call__(self, other, done):
if type(other) is not type(self):
# When not using an old color, we can take
# r, g, b, and a from self.color.
r, g, b = self.color.rgb
a = self.color.alpha
else:
# Otherwise, we have to extract from self.color
# and other.color, and interpolate the results.
oldr, oldg, oldb = other.color.rgb
olda = other.color.alpha
r, g, b = self.color.rgb
a = self.color.alpha
r = oldr + (r - oldr) * done
g = oldg + (g - oldg) * done
b = oldb + (b - oldb) * done
a = olda + (a - olda) * done
# To properly handle premultiplied alpha, the color channels
# have to be multiplied by the alpha channel.
r *= a
g *= a
b *= a
# Return a Matrix.
return Matrix([ r, 0, 0, 0,
0, g, 0, 0,
0, 0, b, 0,
0, 0, 0, a ])
Структурное сходство
В ATL интерполяция свойства matrixcolor требует использования
объектов ColorMatrix, имеющих структурное сходство. Это означает одинаковые
типы ColorMatrix, перемноженные в том же порядке.
Например, следующий код выполнит интерполяцию от нормального состояния до обесцвеченного синего оттенка, а затем вернётся к нормальному.
show eileen happy at center:
matrixcolor TintMatrix("#ffffff") * SaturationMatrix(1.0)
linear 2.0 matrixcolor TintMatrix("#ccccff") * SaturationMatrix(0.0)
linear 2.0 matrixcolor TintMatrix("#ffffff") * SaturationMatrix(1.0)
Хотя первая установка matrixcolor может показаться ненужной, она требуется для создания основы для первой линейной интерполяции. Если бы её не было, эта интерполяция была бы пропущена.
Встроенные подклассы ColorMatrix
Ниже приведён список подклассов ColorMatrix, встроенных в Ren'Py.
- class BrightnessMatrix(value=1.0)
ColorMatrix, которая может быть использована с
matrixcolorдля изменения яркости изображения, оставляя альфа-канал без изменений.- value
Величина изменения яркости изображения. Это должно быть число от -1 до 1, где -1 соответствует самому тёмному возможному изображению, а 1 – самому яркому.
- class ColorizeMatrix(black_color, white_color)
ColorMatrix, которая может быть использована с
matrixcolorдля окрашивания чёрно-белых отображаемых объектов. Она использует цвет каждого пикселя в чёрно-белом изображении для интерполяции между чёрным и белым цветами.Альфа-канал не затрагивается.
Предназначена для использования с чёрно-белым изображением (или тем, что было обесцвечено с помощью
SaturationMatrix()), и приведёт к странным результатам при использовании с изображениями, которые не являются чёрно-белыми.- black_color, white_color
Цвета, используемые в интерполяции.
- class ContrastMatrix(value=1.0)
ColorMatrix, которая может быть использована с
matrixcolorдля изменения контрастности изображения, оставляя альфа-канал без изменений.- value
Значение контрастности. Значения от 0.0 до 1.0 уменьшают контрастность, а значения выше 1.0 – увеличивают.
- class HueMatrix(value=1.0)
ColorMatrix, которая может быть использована с
matrixcolorдля поворота цветового тона на value градусов. Хотя value может быть любым числом, положительным или отрицательным, 360 градусов соответствуют полному обороту. Альфа-канал не затрагивается.
- class IdentityMatrix
ColorMatrix, которая может быть использована с
matrixcolorи не изменяет цвет или альфа-канал того, к чему она применяется.
- class InvertMatrix(value=1.0)
ColorMatrix, которая может быть использована с
matrixcolorдля инвертирования каждого из цветовых каналов. Альфа-канал не затрагивается.- value
Степень инвертирования. 0.0 – не инвертировано, 1.0 – полностью инвертировано. Используется для анимации инверсии.
- class OpacityMatrix(value=1.0)
ColorMatrix, которая может быть использована с
matrixcolorдля изменения непрозрачности изображения, оставляя цветовые каналы без изменений.- value
Значение, на которое будет умножен альфа-канал, число от 0.0 до 1.0.
- class SaturationMatrix(value, desat=(0.2126, 0.7152, 0.0722))
ColorMatrix, которая может быть использована с
matrixcolorдля изменения насыщенности изображения, оставляя альфа-канал без изменений.- value
Степень насыщенности в итоговом изображении. 1.0 – неизменённое изображение, 0.0 – оттенки серого.
- desat
Это кортеж из 3 элементов, который контролирует, какая часть красного, зелёного и синего каналов будет помещена во все три канала полностью обесцвеченного изображения. Значение по умолчанию основано на константах, используемых для канала яркости телевизионного сигнала NTSC. Поскольку человеческий глаз наиболее чувствителен к зелёному цвету, сохраняется большая часть зелёного канала, чем двух других.
- SepiaMatrix(tint='#ffeec2', desat=(0.2126, 0.7152, 0.0722))
Функция, которая возвращает ColorMatrix, которую можно использовать с
matrixcolorдля придания отображаемому объекту оттенка сепии. Это эквивалентно следующему:TintMatrix(tint) * SaturationMatrix(0.0, desat)
- class TintMatrix(color)
ColorMatrix, которая может быть использована с
matrixcolorдля тонирования изображения, оставляя альфа-канал без изменений.- color
Цвет, в который матрица будет тонировать. Этот параметр передаётся в
Color()и поэтому может быть чем угодно, что Color поддерживает в качестве своего первого аргумента.