3D Сцена
3D Сцена — это концепция, названная в честь театральных сцен, на которых проходят спектакли. Она позволяет размещать объекты (displayables) в трёх измерениях. Ren'Py затем отображает эти объекты с правильной перспективой и предоставляет доступ к оси Z, что делает возможным создание эффектов освещения и глубины.
Координаты
Наверное, самое важное, что нужно понять про 3D Сцену — это система координат, которую Ren'Py использует для 3D состояния. Вот система координат, которая применяется для размещения объектов (displayables) в 2D:

В 2D прямоугольник имеет размер экрана, а ширина и высота видимой области задаются с помощью функции gui.init()
(обычно это происходит при создании новой игры).

3D сцена расширяет эту систему координат за счёт новой оси, направленной к зрителю. Значения больше 0 приближают изображение (делая его больше), а значения меньше 0 отдаляют изображение от зрителя (делая его меньше).

И наконец, когда происходит вращение в 3D, оно происходит в направлениях, указанных здесь:
При вращении вокруг оси Z, ось X движется в сторону оси Y.
При вращении вокруг оси X, ось Y движется в сторону оси Z.
При вращении вокруг оси Y, ось Z движется в сторону оси X.
Эти системы координат основаны на тех, что используются в Ren'Py, что облегчает переход от 2D к 3D сцене. При импорте 3D моделей могут применяться преобразования координат, чтобы обеспечить корректное расположение модели.
Камера
Начальное положение камеры управляется параметрами функции gui.init()
. Сначала Ren'Py использует значения width и fov для вычисления стандартного расстояния по оси z. При стандартном значении fov, равном 75:
Когда ширина = 1280, z примерно 834
Когда ширина = 1920, z примерно 1251
Когда ширина = 3840, z примерно 2502
Фактическое значение z чуть меньше (менее чем на 1) тех значений, что указаны здесь. Значение по умолчанию для z можно изменить с помощью свойства стиля perspective
или переменной config.perspective
.
Ren'Py автоматически смещает камеру на (ширина / 2, высота / 2, z) и направляет её вдоль отрицательной оси Z.
Расстояние z — это также расстояние от камеры до плоскости, на которой пиксели на экране отображаются в том же размере, что и в исходных изображениях (без учёта масштабирования окна). Увеличение значения z камеры делает всё меньше, а уменьшение — наоборот, всё больше.
Наконец, perspective
и config.perspective
задают ближнюю и дальнюю плоскости, по умолчанию равные 100 и 100000 соответственно. Это означает, что изображение исчезает, если оно находится ближе 100 единиц по оси z к камере, или дальше 100000 единиц.
- define config.perspective = (100, z, 100000)
Значение по умолчанию используется, когда
perspective
не задан как кортеж из трёх элементов. Значениеz
зависит от размера игры, как было описано выше.
Использование 3D Сцены
Первое, что нужно сделать для использования 3D сцены — это включить её для слоя с помощью оператора camera
. Если имя слоя не указано, по умолчанию используется слой master
. Обычно это делается так:
# Включение 3D сцены для слоя master.
camera:
perspective True
хотя, возможно, вы захотите задать позицию камеры по умолчанию, как описано ниже.
Кроме того, вы можете указать конкретное имя слоя, чтобы включить 3D сцену только для этого слоя.
# Включение 3D сцены для слоя background.
camera background:
perspective True
Отображение изображений (фонов и спрайтов) происходит так же, как и при использовании 2D координат.
scene bg washington
show lucy mad at right
show eileen happy
Однако можно использовать трансформы (transform), чтобы перемещать эти объекты (displayables) в трёхмерном пространстве:
scene bg washington:
xalign 0.5 yalign 1.0 zpos -1000
show lucy mad:
xalign 1.0 yalign 1.0 zpos 100
show eileen happy:
xalign 0.5 yalign 1.0 zpos 200
Если задан ATL-трансформ, то трансформ по умолчанию не используется, и необходимо указать xalign
и yalign
для позиционирования объекта по осям x и y. Конечно, также можно использовать трансформы.
transform zbg:
zpos -100
transform z100:
zpos 100
transform z200:
zpos 200
scene bg washington at center, zbg
show lucy mad at right, z100
show eileen happy at center, z200
Если попробовать это сделать, вы увидите пустое пространство вокруг фона. Это происходит потому, что при отодвигании назад изображение становится меньше и не заполняет экран. В Ren'Py есть простой способ решить эту проблему — свойство zzoom
. Установка zzoom
в True масштабирует изображение пропорционально тому, насколько оно уменьшилось из-за отрицательного значения zpos. Это удобно для фонов.
transform zbg:
zpos -100 zzoom True
Также можно использовать ATL для изменения значения zpos, так же, как и для xpos и ypos.
show eileen happy at center:
zpos 0
linear 4.0 zpos 200
Обратите внимание, что zpos может вести себя странно в сочетании с позициями вроде left
и right
, а также с xalign
и yalign
. Это происходит потому, что Ren'Py размещает изображения внутри трёхмерного прямоугольного объёма (как куб, но не все стороны одинаковой длины), а затем применяет перспективу, из-за чего части изображения могут выйти за пределы экрана.
Также можно перемещать камеру с помощью оператора camera
. Например,
camera:
perspective True
xpos 0
linear 3.0 xpos 500
В таком случае имеет смысл использовать фоновые изображения, которые больше окна.
Если вы применяете zpos к спрайту, а он не срабатывает, скорее всего, причина в том, что вы пропустили параметр perspective
в трансформе camera
.
Камеру можно вращать с помощью:
camera:
perspective True
rotate 45
Поскольку вращается камера, вращение происходит в противоположном направлении по сравнению с вращением объекта (displayable).
Глубина
По умолчанию Ren'Py отображает изображения в обычном порядке, при котором последнее показанное изображение находится поверх остальных. Это может приводить к странным эффектам, например, когда более близкое изображение (с точки зрения перспективы) оказывается позади более удалённого.
Если в вашей игре изображения отображаются в неправильном порядке, вы можете указать GPU сортировать их по глубине с помощью свойства gl_depth
:
camera:
perspective True
gl_depth True
Небольшие ошибки округления могут привести к тому, что изображения, находящиеся на одинаковой глубине, будут отображаться одно над другим или наоборот. Объединение таких изображений (флеттенинг) и их совместное отображение может решить эту проблему.
Matrix Transforms
Ren'Py использует свойство трансформации matrixtransform
для применения матрицы к объектам (displayables), что позволяет масштабировать, смещать и вращать изображение в трёхмерном пространстве. Это свойство принимает либо объект Matrix()
, либо TransformMatrix (описанный ниже), и применяется к вершинам углов отображаемого изображения.
Для удобства применения матрицы Ren'Py использует свойство трансформации matrixanchor
. Оно по умолчанию равно (0.5, 0.5) и переводится в смещение в пикселях внутри изображения, используя стандартные правила якоря Ren'Py. (Если значение целое или абсолютное, оно считается числом пикселей, иначе — долей от размера изображения.)
Ren'Py сначала смещает изображение так, чтобы якорь оказался в точке (0, 0, 0), затем применяет трансформацию, а потом смещает обратно на ту же величину. При значениях по умолчанию это означает, что матрица применяется к центру изображения.
Например:
show eileen happy at center:
matrixtransform RotateMatrix(45, 0, 0)
Изображение будет вращаться вокруг линии, проходящей горизонтально через его центр. Верхняя часть изображения отодвинется назад, а нижняя — приблизится вперёд.
Матрицы можно соединять между собой умножением. Проще всего представлять, что они применяются справа налево. В этом примере:
show eileen happy at center:
matrixtransform RotateMatrix(45, 0, 0) * OffsetMatrix(0, -300, 0)
Изображение будет сдвинуто вверх на 300 пикселей, а затем повернуто вокруг оси X.
Структурное сходство
В ATL интерполяция свойства matrixtransform
требует использования TransformMatrix с одинаковой структурой. Это означает, что должны применяться одинаковые типы TransformMatrix в одном и том же порядке.
Например, следующий код сначала поворачивает и смещает изображение, а затем возвращает обратно:
show eileen happy at center:
matrixtransform RotateMatrix(0, 0, 0) * OffsetMatrix(0, 0, 0)
linear 2.0 matrixtransform RotateMatrix(45, 0, 0) * OffsetMatrix(0, -300, 0)
linear 2.0 matrixtransform RotateMatrix(0, 0, 0) * OffsetMatrix(0, 0, 0)
Хотя первое задание matrixtransform может показаться лишним, оно необходимо для установки базового значения для первой линейной интерполяции. Если его не будет, эта интерполяция будет пропущена.
TransformMatrix
Хотя объекты Matrix подходят для статических трансформаций, они не годятся для анимации изменяющихся трансформаций. Также полезно иметь способ создания часто используемых матриц с параметрами.
TransformMatrix — это базовый класс, который расширяется рядом классов для создания матриц. Экземпляры TransformMatrix вызываются Ren'Py и возвращают объекты Matrix. TransformMatrix хорошо интегрирован с ATL, что позволяет создавать анимации с помощью matrixtransform.
transform xrotate:
matrixtransform RotateMatrix(0.0, 0.0, 0.0)
linear 4.0 matrixtransform RotateMatrix(360.0, 0.0, 0.0)
repeat
От подклассов TransformMatrix ожидается реализация метода __call__
. Этот метод принимает:
Старый объект, от которого производится интерполяция. Этот объект может быть любого класса или None, если старого объекта нет.
Значение от 0.0 до 1.0, обозначающее точку интерполяции. 0.0 — полностью старый объект, 1.0 — полностью новый объект.
Встроенные подклассы TransformMatrix
См. также
SplineMatrix
, который работает с подклассами TransformMatrix.
Ниже приведён список подклассов TransformMatrix, встроенных в Ren'Py.
- class OffsetMatrix(x, y, z)
TransformMatrix, возвращающая матрицу, которая смещает вершину на фиксированную величину.
- class RotateMatrix(x, y, z)
TransformMatrix, возвращающая матрицу, которая поворачивает отображаемый объект вокруг начала координат.
- x, y, z
Величина поворота вокруг начала координат, в градусах.
Повороты применяются в следующем порядке:
Поворот по часовой стрелке на x градусов в плоскости Y/Z.
Поворот по часовой стрелке на y градусов в плоскости Z/X.
Поворот по часовой стрелке на z градусов в плоскости X/Y.
- class ScaleMatrix(x, y, z)
TransformMatrix, который возвращает матрицу масштабирования объекта.
x, y, z
Факторы масштабирования по каждой оси.
Свойства трансформации
Ниже перечислены свойства трансформации, используемые на 3D сцене.
- matrixanchor
- Type:
(позиция, позиция)
- Default:
(0.5, 0.5)
Определяет позицию якоря матрицы относительно изображения. Если значения — числа с плавающей точкой, позиция задаётся относительно размера дочернего объекта, иначе — в абсолютных пикселях.
Устанавливает точку (0, 0, 0), относительно которой применяются трансформации point_to, orientation, xrotate, yrotate, zrotate и matrixtransform.
- point_to
- Type:
(float, float, float), Camera или None
- Default:
None
Задаёт точку, на которую будет направлен объект. Камера или отображаемый объект будут повёрнуты лицом к этой точке, даже если их позиции изменятся.
Если значение None, поворот на точку интереса не применяется.
Если значение не None, это либо 3-элементный кортеж (x, y, z) с координатами точки интереса, либо экземпляр
Camera()
. В случае камеры объект будет смотреть в её сторону.Учтите, что point_to не обновляется автоматически, поэтому, если хотите, чтобы оно обновлялось, используйте следующий код:
# Eileen всегда смотрит на камеру. show eileen happy at center: point_to Camera() 0 repeat
- class Camera(layer='master')
Экземпляры этого класса могут использоваться с point_to, чтобы направлять взгляд на положение камеры для конкретного слоя.
- layer
Имя слоя.
- orientation
- Type:
(float, float, float) или None
- Default:
None
Выполняет поворот камеры или отображаемого объекта. Три значения — это углы поворота вокруг осей x, y и z в градусах. Повороты применяются в порядке x, y, z для объектов и в порядке z, y, x для камеры.
При интерполяции значения orientation выбирается кратчайший путь между старой и новой ориентацией.
Если значение None, поворот не применяется.
- xrotate
- Type:
float или None
- Default:
None
Выполняет поворот камеры или отображаемого объекта вокруг оси x. Значение — угол поворота в градусах. Для объектов повороты применяются в порядке x, y, z. Для камеры — в порядке z, y, x.
Если значение None, поворот вокруг оси x не применяется.
- yrotate
- Type:
float или None
- Default:
None
Выполняет поворот камеры или отображаемого объекта вокруг оси y. Значение — угол поворота в градусах. Для объектов повороты применяются в порядке x, y, z. Для камеры — в порядке z, y, x.
Если значение None, поворот вокруг оси y не применяется.
- zrotate
- Type:
float или None
- Default:
None
Выполняет поворот камеры или отображаемого объекта вокруг оси z. Значение — угол поворота в градусах. Для объектов повороты применяются в порядке x, y, z. Для камеры — в порядке z, y, x.
Если значение None, поворот вокруг оси z не применяется.
- matrixtransform
- Type:
None, Matrix или TransformMatrix
- Default:
None
Если не None, задаёт матрицу, используемую для преобразования вершин дочернего объекта трансформации. Преобразование идёт из координат экрана в координаты дочернего объекта.
Интерполяция с этой свойством поддерживается только при использовании TransformMatrix и при структурном сходстве TransformMatrix, как описано выше.
- perspective
- Type:
True, False, Float или (Float, Float, Float)
- Default:
None
При применении к трансформации включает перспективную отрисовку. Принимает тройку значений: ближняя плоскость, расстояние по оси z до плоскости 1:1 и дальняя плоскость.
Если задано одно число (float), расстояния до ближней и дальней плоскостей берутся из переменной
config.perspective
. Если True — все три значения берутся из неё.Если perspective не false, значения
xpos
,ypos
,zpos
иrotate
инвертируются, создавая эффект позиционирования камеры, а не дочернего объекта.Поскольку перспективное преобразование предполагает выравнивание по окну, не имеет смысла менять позицию с помощью
xanchor
,yanchor
или их производных, таких какanchor
,align
,center
и т.п.
- zpos
- Type:
float
- Default:
0
Смещает дочерний объект вдоль оси z. Если perspective выключена, значение используется напрямую, иначе умножается на -1.
Если при установке исчезает объект, вероятно, трансформация применяется не к отображаемому объекту, где zpos включён.
- zzoom
- Type:
bool
- Default:
False
Если True, определяется расстояние до плоскости 1:1 (zone) и берётся zpos объекта. Затем дочерний объект масштабируется по осям x и y на величину (zone - zpos) / zone.
Это удобно для фоновых изображений с отрицательным zpos, которые обычно уменьшаются. Установка True позволяет отображать фон в масштабе 1:1.