3D 스테이지
연극 무대에서 이름을 따온 3D 스테이지는 디스플레이어블을 3차원 공간에 배치할 수 있게 하는 개념입니다. Ren'Py는 올바른 원근법으로 디스플레이어블을 렌더링하며, 조명이나 깊이 렌더링 같은 기능을 구현할 수 있도록 z 차원도 제공합니다.
좌표
3D 스테이지에서 가장 먼저 이해해야 할 것은 Ren'Py가 사용하는 3차원 좌표계입니다. 다음은 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일 때는 다음과 같습니다.
width = 1280이면 z는 약 834입니다.
width = 1920이면 z는 약 1251입니다.
width = 3840이면 z는 약 2502입니다.
실제 z 값은 위 값들보다 크며 차이는 1 미만입니다. 기본 z 위치는 perspective 스타일 속성이나 config.perspective 변수로 덮어쓸 수 있습니다.
Ren'Py는 카메라에 (width / 2, height / 2, z) 오프셋을 자동으로 적용하며 카메라는 -Z축 방향을 바라봅니다.
z 거리는 창 크기 조절을 무시했을 때 화면의 픽셀이 원본 이미지의 픽셀과 같은 크기를 갖는 평면까지의 거리이기도 합니다. 카메라의 z 위치를 늘리면 모든 것이 작아지고 줄이면 커집니다.
마지막으로 perspective와 config.perspective는 근거리 및 원거리 평면도 정의하며 기본값은 각각 100과 100000입니다. 따라서 이미지가 카메라에서 100 z단위보다 가까우면 사라지고, 100,000 z단위보다 멀어도 사라집니다.
- define config.perspective = (100, z, 100000)
perspective에 3요소 튜플을 지정하지 않았을 때 사용하는 기본값입니다.z는 위에서 설명한 게임 크기에 따라 달라집니다.
3D 스테이지 사용
3D 스테이지를 사용하려면 먼저 camera 문으로 특정 레이어에서 켜야 합니다. 레이어 이름을 지정하지 않으면 master가 기본값입니다. 보통 다음과 같이 작성합니다.
# Enabling the 3D stage for the master layer.
camera:
perspective True
다만 아래에서 설명하는 기본 카메라 위치도 함께 지정하고 싶을 수 있습니다.
특정 레이어 이름을 지정하여 해당 레이어에서만 3D 스테이지를 켤 수도 있습니다.
# Enabling the 3D stage for the background layer.
camera background:
perspective True
배경과 스프라이트를 포함한 이미지 표시는 2D 좌표를 사용할 때와 같습니다.
scene bg washington
show lucy mad at right
show eileen happy
다만 트랜스폼으로 디스플레이어블을 3차원 공간에서 이동할 수 있습니다.
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 트랜스폼을 지정했으므로 기본 트랜스폼이 적용되지 않습니다. 따라서 x축과 y축 위치를 지정하려면 xalign과 yalign을 설정해야 합니다. 물론 트랜스폼을 사용할 수도 있습니다.
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로 xpos와 ypos를 바꾸는 것처럼 zpos도 바꿀 수 있습니다.
show eileen happy at center:
zpos 0
linear 4.0 zpos 200
zpos는 left, right 같은 위치나 xalign, yalign과 함께 사용할 때 예상과 다르게 동작할 수 있습니다. Ren'Py가 이미지를 3차원 직육면체 공간에 배치한 뒤 원근법을 적용하기 때문에 이미지 일부가 화면 밖으로 나갈 수 있습니다.
camera로 카메라도 이동할 수 있습니다. 예를 들어:
camera:
perspective True
xpos 0
linear 3.0 xpos 500
이 경우 창보다 큰 배경 이미지를 사용하는 것이 좋습니다.
스프라이트에 zpos를 적용했는데 효과가 없다면 camera 트랜스폼의 perspective 절을 빠뜨렸을 가능성이 큽니다.
다음과 같이 카메라를 회전할 수 있습니다.
camera:
perspective True
rotate 45
카메라가 회전하므로 디스플레이어블을 회전할 때와 반대 방향입니다.
깊이
Ren'Py는 기본적으로 일반적인 표시 순서를 사용하여 마지막으로 표시한 이미지를 다른 이미지 위에 놓습니다. 이 때문에 원근법상 가까운 이미지가 먼 이미지 뒤에 표시되는 이상한 결과가 생길 수 있습니다.
이처럼 순서가 맞지 않으면 gl_depth로 GPU에 깊이순 정렬을 지시할 수 있습니다.
camera:
perspective True
gl_depth True
작은 반올림 오차 때문에 깊이가 같은 이미지들이 서로의 위나 아래에 나타날 수 있습니다. 이미지들을 하나로 합쳐 함께 표시하면 해결될 수 있습니다.
행렬 트랜스폼
Ren'Py는 matrixtransform 트랜스폼 속성으로 디스플레이어블에 행렬을 적용하여 3차원 공간에서 이미지 크기를 조절하고 이동하거나 회전할 수 있습니다. Matrix() 또는 아래에서 정의하는 TransformMatrix를 받아 표시할 이미지의 모서리 꼭짓점에 적용합니다.
Ren'Py는 행렬을 쉽게 적용하도록 matrixanchor 트랜스폼 속성을 제공합니다. 기본값은 (0.5, 0.5)이며 일반적인 Ren'Py 앵커 규칙에 따라 변형할 이미지 내부의 픽셀 오프셋으로 변환합니다. 정수나 absolute이면 픽셀 수이고, 그 밖의 경우 이미지 크기에 대한 비율입니다.
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는 행렬을 생성하는 여러 클래스가 확장하는 기반 클래스입니다. Ren'Py가 TransformMatrix 인스턴스를 호출하면 Matrix를 반환합니다. 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 하위 클래스
관련 항목
TransformMatrix 하위 클래스와 함께 사용할 수 있는 SplineMatrix.
다음은 Ren'Py에 내장된 TransformMatrix 하위 클래스 목록입니다.
- class OffsetMatrix(x, y, z)
꼭짓점을 고정된 양만큼 이동하는 행렬을 반환하는 TransformMatrix입니다.
- class RotateMatrix(x, y, z)
디스플레이어블을 원점 주위로 회전하는 행렬을 반환하는 TransformMatrix입니다.
- x, y, z
원점 주위로 회전할 각도이며 도 단위입니다.
회전은 다음 순서로 적용합니다.
Y/Z 평면에서 x도만큼 시계 방향 회전.
Z/X 평면에서 y도만큼 시계 방향 회전.
X/Y 평면에서 z도만큼 시계 방향 회전.
- class ScaleMatrix(x, y, z)
디스플레이어블의 크기를 조절하는 행렬을 반환하는 TransformMatrix입니다.
- x, y, z
각 축의 크기를 조절할 배율입니다.
트랜스폼 속성
3D 스테이지는 다음 트랜스폼 속성을 사용합니다.
- matrixanchor
- 유형:
(position, position)
- 기본값:
(0.5, 0.5)
이미지를 기준으로 한 행렬 앵커의 위치입니다. float이면 자식 크기에 대한 비율이고 그 밖에는 절대 픽셀 수입니다.
point_to, orientation, xrotate, yrotate, zrotate, matrixtransform이 변형의 기준으로 삼는 (0, 0, 0) 점의 위치를 설정합니다.
- point_to
- 유형:
(float, float, float), Camera 또는 None
- 기본값:
None
바라볼 위치를 지정합니다. 카메라나 디스플레이어블의 위치가 바뀌어도 해당 점을 향하도록 회전합니다.
None이면 관심 지점을 향하는 회전을 적용하지 않습니다.
None이 아니면 3요소 튜플 또는
Camera()인스턴스입니다. (x, y, z) 튜플은 바라볼 점의 위치를 나타냅니다. Camera 인스턴스이면 카메라를 바라봅니다.point_to는 자동으로 갱신되지 않습니다. 갱신하려면 다음과 같이 작성해야 합니다.
# eileen always faces to the camera. show eileen happy at center: point_to Camera() 0 repeat
- class Camera(layer='master')
이 클래스의 인스턴스를 point_to에 지정하면 특정 레이어의 카메라 위치를 바라보도록 할 수 있습니다.
- layer
레이어의 이름입니다.
- orientation
- 유형:
(float, float, float) 또는 None
- 기본값:
None
카메라나 디스플레이어블을 회전합니다. 세 값은 도 단위의 x, y, z 회전입니다. 디스플레이어블은 x, y, z 순서로, 카메라는 z, y, x 순서로 적용합니다.
orientation을 보간할 때는 이전 방향과 새 방향 사이의 최단 경로를 따릅니다.
None이면 방향을 적용하지 않습니다.
- xrotate
- 유형:
float 또는 None
- 기본값:
None
카메라나 디스플레이어블을 x축 주위로 회전합니다. 값은 도 단위의 회전각입니다. 디스플레이어블에는 x, y, z 순서로, 카메라에는 z, y, x 순서로 적용합니다.
None이면 x축 회전을 적용하지 않습니다.
- yrotate
- 유형:
float 또는 None
- 기본값:
None
카메라나 디스플레이어블을 y축 주위로 회전합니다. 값은 도 단위의 회전각입니다. 디스플레이어블에는 x, y, z 순서로, 카메라에는 z, y, x 순서로 적용합니다.
None이면 y축 회전을 적용하지 않습니다.
- zrotate
- 유형:
float 또는 None
- 기본값:
None
카메라나 디스플레이어블을 z축 주위로 회전합니다. 값은 도 단위의 회전각입니다. 디스플레이어블에는 x, y, z 순서로, 카메라에는 z, y, x 순서로 적용합니다.
None이면 z축 회전을 적용하지 않습니다.
- matrixtransform
- 유형:
None 또는 Matrix 또는 TransformMatrix
- 기본값:
None
None이 아니면 트랜스폼 자식의 꼭짓점을 변환할 행렬입니다. 화면에서 사용하는 좌표를 트랜스폼의 자식이 사용하는 좌표로 변환합니다.
이 속성의 보간은 위에서 설명한 것처럼 구조적으로 유사한 TransformMatrix 값들을 사용하는 경우에만 지원합니다.
- perspective
- 유형:
True 또는 False 또는 Float 또는 (Float, Float, Float)
- 기본값:
None
트랜스폼에 적용하면 원근 렌더링을 켭니다. 근거리 평면, 1:1 평면까지의 z 거리, 원거리 평면을 나타내는 3요소 튜플을 받습니다.
float 하나이면 근거리 및 원거리 평면까지의 거리는
config.perspective에서 가져옵니다. True이면 세 값 모두 해당 변수에서 가져옵니다.perspective가 거짓이 아니면
xpos,ypos,zpos,rotate의 의미가 반대로 바뀌어 자식 대신 카메라의 위치를 지정하는 효과를 냅니다.원근 변환은 창에 정렬되어 있다고 가정하므로
xanchor,yanchor나 이를 설정하는anchor,align,center등으로 위치를 다시 지정하는 것은 적절하지 않습니다.
- zpos
- 유형:
float
- 기본값:
0
자식을 z축 방향으로 이동합니다. perspective가 거짓이면 값을 그대로 사용하고 그 밖에는 -1을 곱하여 사용합니다.
이를 설정했을 때 자식이 사라지면 zpos가 False인 디스플레이어블과 함께 트랜스폼을 사용하지 않았을 가능성이 큽니다.
- zzoom
- 유형:
bool
- 기본값:
False
참이면 1:1 평면까지의 z 거리(zone)와 이 디스플레이어블의 zpos를 구합니다. 이어 자식을 x축과 y축으로 (zone - zpos) / zone배 조절합니다.
음수 zpos로 인해 보통 작아지는 배경을 표시할 때 사용하도록 설계되었습니다. 참으로 설정하면 배경을 1:1 크기로 표시합니다.