티스토리 뷰
이번에는 Unreal4를 이용해서 Camera를 제어하는 방법에 대해 알아보겠습니다.
그동안 Unreal을 배워야지라고 늘 생각만 해오다가 최근 본격적으로 시작했습니다.
필자는 Unity를 사용해본 경험이 있고 C++, 자료구조, 알고리즘 등 컴퓨터 공학에 대한 기본적인 지식이 있습니다.
Unreal을 어떻게 공부할까 고민하다가 처음 Unity를 배웠던 때가 떠올라서 그때처럼 시작해보기로 결정했습니다.
처음 Unity를 배울 때 책을 보거나 튜토리얼을 따라하지 않았습니다.
대신 구현할 기능을 먼저 생각한 후 이러한 기능을 Unity에서 제공하는 방식을 찾아보고 직접 구현하며 익혔습니다.
찾아보다가 새로운 시스템을 발견하면 그 시스템에 대해서 공부하는 식이었습니다.
인터넷을 검색하며 공부하면 지식이 파편화되어 있다는 문제가 있지만 처음부터 책을 보면서 공부하는 것보다 재미도 있고 기억에도 오래 남았습니다.
어쨌든 이 포스팅에서는 무작정 기능을 구현하는 방식으로 설명할 예정입니다.
따라서 Unreal 시스템에 대한 정제된 설명을 하지는 못할 것입니다.
이 점 참고하여 읽어주시면 감사하겠습니다.
먼저 결과 영상을 보여드리겠습니다. 매우 간단한 프로그램입니다.
구현 목표
플레이어가 할 수 있는 키 입력은 1, 2, 그리고 r입니다.
1 혹은 2를 눌러서 원하는 카메라 뷰를 선택하고 r을 눌러서 큐브들을 처음 시작할 때의 위치로 둘 수 있습니다.
두 카메라는 각각 2D 뷰(Orthogonal)와 3D 뷰(Perspective)입니다.
1. 카메라 관리자 만들기
가장 먼저 이런 기능을 만들기 위해 코드를 담고 런타임에 실행되도록 만들 무언가가 필요하다고 생각했습니다.
유니티에서 씬에 게임 오브젝트를 만들고 스크립트 컴포넌트를 붙이면 게임을 플레이할 때 실행되듯이 언리얼에도 비슷한 기능이 있을거라고 생각했습니다.
그래서 찾아보니 있었습니다. 단 유니티와는 조금 다르게 느껴졌습니다.
언리얼에서는 먼저 C++ Class를 만들고 만들어진 C++ Class를 이용해 씬에 객체를 Instantiate하는 느낌이었습니다.
또 씬에 Instantiate 할 수 있는 클래스는 몇 개 정해져 있는듯 했습니다.
처음 C++ Class를 만들 때 Base Class를 정할 수 있는데 Base Class에 따라 씬에 Instantiate할 수 있는지 없는 지가 결정되는 것 같습니다.
그 외에도 언리얼에서는 Blueprint Class라는 것을 제공합니다.
여러 곳의 설명을 들어보면 대체로 기획자가 다루기 편한 블록으로 코딩하는 느낌의 시스템이라고 합니다.
가장 이상적인 개발 방향은 성능에 영향을 끼치는 함수 등은 C++ Class에서 정의하고 Blueprint Class에서는 이펙트 출력이나 기본적인 로직을 처리하는 것이 좋다고 합니다.
또 Blueprint에서 C++ 에서 구현한 함수를 호출하는 것이 가능하다고 합니다.
C++ Class이든 Blueprint Class이든 주로 Unreal에서 제공하는 기본 Class들을 상속 받아 구현하는듯 했습니다.
그래서 Unreal에서 제공한는 Base Class들을 한 번 살펴봤습니다.
상속 구조는 대체로 이런 모양인듯했습니다.
최상위에는 UObject라는 Class가 있습니다. 그 밑으로 AActor와 UActorComponent가 있는데 이 포스팅에서는 AActor만 알면 됩니다. 나머지 Class들은 참고만 하시기 바랍니다.
어찌됐든 Unreal 엔진을 이용하면 이런 기반 클래스들을 자유자재로 확장하여 자신만의 게임을 만들 수 있습니다.
대체로 위와 같은 방식을 이용해서 게임에서 쓰일 Object를 생성합니다.
또한 C++을 이용해 확장하는 과정을 생략하고 Unreal 제공 기반 클래스를 바로 Blueprint로 확장하는 것도 가능합니다.
과연 어떻게 Blueprint라는 시스템이 돌아가는걸까 고민해봤는데 Blueprint Class를 만들면 엔진에서 내부적으로 Class 코드를 만들어 주는 듯합니다.
다시 원래의 목표로 돌아와서 카메라 관리자를 만들어보겠습니다.
카메라 관리자를 하나의 Actor로 생성하기로 결정했고, 이 Actor에 Input을 받고 현재 사용중인 카메라를 바꾸는 코드, 모든 큐브를 원래의 위치로 돌려 놓는 코드를 넣기로 결정했습니다.
먼저 C++을 이용해 Actor Class를 확장했습니다.
이 Actor의 이름은 Camera Director입니다.
확장하는 방법은 "콘텐츠 브라우저"의 "C++ 클래스" 하위의 폴더에서 마우스 오른쪽 버튼을 누르고 "새 C++ 클래스"를 누르면 Base Class를 선택할 수 있습니다.
Base Class를 선택하면 아래와 같이 컨텐츠가 생성되고 자동적으로 CameraDirector.h와 CameraDirector.cpp 파일이 생성됩니다. 만들어진 컨텐츠를 더블클릭하면 C++ 파일이 켜지고 뷰포트로 끌어놓으면 Actor가 Instantiate됩니다.
이 Actor가 관리할 Actor들은 3D 뷰를 보일 Camera, 2D 뷰를 보일 Camera 그리고 cube들입니다.
코드를 이용해서 Actor들의 포인터를 가져오는게 가능할거라 생각했지만 일단 빠르게 구현하기 위해 Editor에서 셋팅할 수 있도록 빼놓고 직접 셋팅하는 방식으로 포인터를 가져왔습니다.
Editor에서 셋팅할 수 있도록 하려면 헤더에 멤버 변수로 아래와 같이 선언합니다.
매크로 UPROPERTY(EditAnywhere)를 사용해 변수를 정의하면 해당 Class를 이용해 만든 Actor 에디터에 "디테일"탭에 변수가 나타납니다.
다음으로는 행동을 하는 함수들을 정의합시다.
함수를 정의할 때는 인풋이 있을 때 이 함수들이 단 한 번 호출된다고 생각하고 정의하면 됩니다.
총 3개의 인풋이 있기 때문에 3개의 함수를 정의해야 합니다.
첫 번째는 화면을 첫 번째 카메라(2D)로 옮기는 함수고, 두 번째는 두 번째 카메라(3D)로 옮기는 함수고 세 번째는 모든 큐브들을 원래 위치로 되돌리는 함수입니다.
각각의 함수 이름은 Set2DView, Set3DView 그리고 ResetIceCubeTransforms입니다.
먼저 Set3DView와 Set2DView 함수에 대해서 설명드리겠습니다.
각각의 함수는 멤버 변수인 playerController의 SetViewTarget() 함수를 camerObj를 인자로 주어 호출하므로써 구현했습니다.
player controller에 view target을 설정하는 함수가 있는게 조금 이상하지만 아무튼 이런 식으로 구현이 가능합니다.
SetViewTarget의 인자로 넘겨지는 Actor의 Camera Component가 보는 공간이 화면에 그려지게 됩니다.
2D 뷰와 3D 뷰는 Camera Component의 "디테일"탭에서 Projection Mode를 바꿈으로써 설정할 수 있습니다.
큐브들의 위치를 되돌리는 ResetIceCubeTransforms 함수에 대해서는 마지막에 설명드리겠습니다.
2. 인풋 처리하기
Input 처리는 Blueprint를 이용해 구현하였습니다.
Blueprint를 이용하니 매우 쉽게 구현할 수 있었습니다.
먼저 Blueprint를 사용하려면 방금 만든 CameraDirector라는 C++ Class를 Blueprint로 확장하여야 합니다.
"디테일"탭에 있는 "블루프린트/스크립트 추가" 버튼을 누르면 Blueprint Class를 저장할 공간을 선택하는 창이 나오고 위치를 지정하면 Blueprint Class로 확장이 됩니다.
만들어진 Blueprint를 더블 클릭하여 Blueprint 에디터를 열고 탭에서 "이벤트 그래프" 탭을 선택하면 처음에 노드가 3개 나옵니다. 새로운 노드들을 생성하거나 삭제하거나 연결해서 로직을 구현할 수 있습니다.
다시 돌아와서 Input을 처리하려면 총 2가지 작업이 필요한데
첫 번째는 해당 actor가 input을 처리할 수 있도록 하는 것이고
두 번째 작업은 특정 input이 있을 때 특정 코드가 실행되도록 하는 것입니다.
첫 번째 작업은 Blueprint를 이용해서 할 수도 있고 C++을 이용해서 할 수도 있습니다.
C++을 이용하면 CameraDirector Class의 BeginPlay() 함수 안에 아래와 같은 코드를 입력하면 됩니다.
또는 Blueprint를 이용해 아래와 같이 만들면 됩니다.
두 번째 작업은 Blueprint를 이용해 구현하였습니다.
Blueprint를 이용하면 Event를 사용하여 특정 키가 입력되었을 때 실행되도록 할 수 있습니다.
Blueprint를 이용하여 키 입력이 있을 때 아까 정의해 두었던 함수를 호출하도록 연결하면 간단하게 구현할 수 있습니다.
3. 위치와 속도 되돌리기
마지막으로는 ResetIcecubes 함수의 구현에 대해 설명드리겠습니다.
Unreal에서 3D 씬에 배치하는 Actor는 Transform 정보를 가지고 있습니다.
AActor 클래스의 함수인 GetActorTransform() 함수를 이용하면 Object의 Transform 정보를 가져올 수 있습니다.
또한 SetActorTransform()을 이용해 Object의 Transform을 설정할 수도 있습니다.
그래서 BeginPlay에서 큐브 Actor들의 Transform을 Get 해와 저장하고 ResetIcecubes 함수에서 Set 하도록 구현하였습니다.
단, 이렇게 할 경우 실제로 플레이해보니 Transform만 설정되고 Velocity는 그대로 남아있어서 위치와 회전 정보를 되돌렸을 때 매우 빠른 속도로 밑으로 떨어지는 문제가 있었습니다.
이 문제를 해결하기 위해 찾아보니 StaticMeshComponent라는 것이 있었습니다.
StaticMeshComponent는 Geometry와 Rigidbody 정보 등이 담긴 Component였습니다.
따라서 아래와 같이 ResetIcecubes 함수가 호출되었을 때 각 Actor의 StaticMeshComponent를 불러오고 linear velocity와 angular velocity를 zero vector로 초기화되도록 구현하였습니다.
지금까지 Unreal을 이용해 Camera를 제어하고 Actor들의 위치와 속도를 Reset하는 것을 알아보았습니다.
작성한 코드와 작업이 많이 적었지만 익숙하지 않은 프로그램이라 작업하는데 꽤 오랜 시간이 걸렸습니다.
비록 개발 속도는 매우 느리지만 이런 식으로 꾸준히 해나가면 언젠가는 Unreal 프로그램에 익숙해져서 자유자재로 다룰 수 있을거라고 생각합니다.
'프로그래밍' 카테고리의 다른 글
Unreal을 이용한 CelShading (0) | 2020.10.02 |
---|---|
Unreal Blueprint를 이용해 직접 만든 DLL 사용하기 (0) | 2019.12.25 |
언리얼 HLSL을 이용한 Custom Shader 제작 (1/2) (1) | 2019.11.29 |
OpenGL 및 Assimp를 활용한 스켈레톤 애니메이션 프로그래밍 (3/3) (0) | 2019.08.31 |
OpenGL 및 Assimp를 활용한 스켈레톤 애니메이션 프로그래밍 (1/3) (0) | 2019.08.29 |
- Total
- Today
- Yesterday
- AABB
- 유니티
- normalized device coordinate
- Unreal
- perspective projection
- RL
- dynamic batching
- Scriptable Render Pipeline
- batching
- Unity
- transform
- 값 형식
- CollisionDetection
- collision detection
- 참조 형식
- 강화학습
- Mesh Processing
- NDC
- reference type
- C#
- value type
- SRP
- opengl
- Mesh
- Transformation
- 루빅스큐브
- VTK
- static batching
- RubiksCube
- MeshProcessing
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |