Game Engine

김명석·2023년 9월 11일
0

Game

목록 보기
1/4

교재
게임 엔진에 대한 내용을 가지고 있는 jason Gregory 의 Game Engine Architecture

Engine Architecture

오늘날 Unity 와 unreal angine 이렇게 두 가지로 크게 양분된다.
언리얼의 경우 엔진으로 시작하기 보다는 게임을 만드는 과정에서 파생된 소프트웨어이다.
유니티의 경우 늦게 등장했지만 사용이 용이하게 만들어졌다.
최적화적인 부분 등에서는 언리얼에 비해 떨어진다.

언리얼은 open source 이다.

유니티 에셋스토어.

게임 엔진이라고 하는 것은 결국 비디오 게임을 만들기 위함인데, 이에 필요한 기술들은 아래와 같다.

Architecture Overview


가상 세계에서 그려지는 게임월드라는 것이 추상적으로 존재.
data만으로는 충분히 보일 수 없다. 따라서 사운드,입력 등에 대한것이 UI를 통해 Game world와 소통하게 된다. Data와 입출력 디바이스 사이에 연결점이 game Wolrd 라고 볼 수 있다.
이러한 Game World 에 동적인 움직임을 보여주기 위한것이 아래에 있는 여러 게임 엔진이다.

Platform Independce layer

각 플랫폼(리눅스, 윈도우 등)에 대해서 일괄적으로 작용하기 위해 서로 다른 플랫폼의 API를 mapping 하여 동일 기능으로 작동하게 하는 Layer.

Core System

Platform Independce layer 위의 Core System 이있다.
아래의 기능들을 모아 놓는다.

  • 메모리 관리
  • 수학 라이브러리
  • 알고리즘, 데이터 구조

Resource Layer

앞서 말한 에셋을 어떻게 넣어 사용할 것인가와 runtime part 두 가지로 나뉜다.

the chain of off-line tools -> 게임 만들기 전의 단계

기본적인 게임에 들어가기 전의 파일이 가공이 필요하다

the resources at runtime - 기존의 파일이 사용될때 잘 불러오는 관리

Rendering Layer

vertex 들로 점을 찍고 폴리곤 -> 매쉬 -> 이를 통해 여러 픽셀들의 집합으로 만든다.
색칠하는 과정 shading

이러한 데이터들은 pixel 단계로 비춰져야 우리가 볼 수 있게된다. 이렇게 시각적으로 표현하는 Layer 가 Rendering Layer 이다.

원근법을 사용하는 Perspective 투영과 같은 크기로 바라보는 Orthographic 투영이 있다.



색깔을 칠하는 shading 추후 다시 소개 예정


Polygon 의 집합으로 표현하면 질감이 들어나지 않으니 이미지를 해당 Polygon 위에 mapping 을 통해 색감과 질감을 줄 수 있다.

Scene Graph/ Culling Optimization

눈에 보이지 않는 것을 미리 자르는 것을 Culling이라고 한다.

  • Culling
    공간적인 자료구조를 미리 만들어 놓고 공간을 분리해두면 culling을 가속화 할 수 있다.

visual Effect

이미지 생성시 추후 처리를 거쳐 rendering 과정에 특색을 추가하는 방법.
많은 fillter , wrighting 기법들이 들어간다

Collision and Physics

각 물체간의 충돌을 효율적으로 감지할 필요가 있다. 이러한 충돌에 대한 처리가 물리 시뮬레이션에 가장 중요한 부분이다.

Animation

물리적인 법칙에 따른 방식의 애니메이션이 아니라 미리 구현해놓은 방식에 따르는 Animation을 의미한다.
inverse kinematics 인체 구학, 관절의 회전 정도를 통해 모션을 역으로 구해낼 수 있다. 이를 줄여 IK라고 한다.

HID(Human Interface Devices)

사용자에게 입력 받는 여러 디바이스들

GamePlay Foundation

게임의 끝단 부분, 실질적으로 우리가 코딩하고 만드는 부분

특정 이벤트에 따른 반응을 코딩할 수 있도록 만드는 것.
화면에 보이는 것은 블루프린트 -> 언리얼 엔진에 사용되는 코딩 툴
unity - c#
unreal -블루프린트 , c++

Resources Management

리소스 관리를 중점으로 좀 더 살펴보자

리소스라는 것에 들어갈 만한 내용들은

Mesh - 3차원 다각형의 집합, 3차원의 표면
Meterails - 색깔의 변화 등
Texture - 이미지
Shader program - 색칠하는 것을 코딩을 통해서 한다했잖아 그런거
Animation - 에니메이션에 관련된 것들
Collisison Primitive - 충돌 감지에 사용되는 감지 범위
Physics Parameter - 물리적인 요소의 사용되는 매개변수들

Resource Database

resouce를 잘 정리된 방법으로 사용하려고 한다.
이를 위해선 메타데이터가 필요하다.
메타라고 하는 것은 좀 더 상위에 들어가는 개념이라고 보면된다.
예를 들어 texture 다 -> 압축을 얼마나했느냐

이런 메타데이터의 유연한 관리를 하기 방법

  • text file
    가장 기초적인 방법
  • XML파일 형식으로 사용
    주로 사용되는 방법
  • 관계형 DB
    가장 무거운 방법

일반적으로는 같은 형태 끼리 같은 폴더에 저장된다.

Basic Funtionalities


필요한 기능

  • 여러 resource를 다룰 수 있어야한다
  • resource의 생성 및 삭제
  • resource를 확인하고 볼 수 있어야한다.
  • resource의 물리적인 위치(DB상의 위치) 가 중요하지 않아야함
  • 상호 참조가능
    결합되어 복잡한 형태를 가질 수 있다.(서로간의 reference)
  • Revision history
    리소스의 변경사항 파악
  • Searching and querying
    원하는 리소스를 찾고 확인 가능 해야함

The Asset Condioning

  • Exporter
    mash 등 여러가지를 자료 구조를 다 따로 가지고 있다. 유니티에서 지원하는 파일 포멧은 몇가지 제한이 되어있다. A라는 툴로 부터 unity에 적합한 파일 포멧 형태로 converting 하는 기능을 export 한다고 한다. 이러한 기능 필요
  • Resource compilers
    게임에 사용될 최적화 형태로 전처리 과정, 예를 들어 bitmap의 경우 압축하여
  • Resource Linker
    여러 리소스를 결합하여 사용할 수 있게 해주는 기능

프리펩 -> 미리 만들어 져있다는 뜻 pre-frabricate

이러한 것들을 통해 최종적인 Scene 에 보이게 한다.

각종 외부 editor 들이 있다. 이러한 것 들로 각종 convert 과정을 통해 최종적으로 유니티에서 사용할 수 있게 변화한다.


각각의 모델 파일이 여러개의 Mutiple asset으로 import된다.
fbx 파일을 import시키면 아래와 같이 나온다.
이와 같이 여러 tap 의 형태로 등장

  • 어떤 리소스 간에 특정 순간에는 한 copy 만 올라오도록 보장
  • 각 리소스의 lifetime
    메모리에 올라왔다가 사용되고 다시 하드디스크로 내려가는
  • composite resource
    링크가 되어있는 resource가 서로 연결이 잘된 상태로 메모리에 올라와야한다.
  • referential integrity
    서로간의 참조가 무결성을 지켜야한다
  • Memory usage
    메모리를 효율적으로 다뤄 성능을 높일 수 있게해야한다. 캐시 등 방법 사용

로딩 정책

모든 resource 가 동시에 올라올 필요는 없다. 그렇기에 특정 순간을 기점으로 로딩하는 것이 다를 것이다.
1.게임 전체에 사용되는 정보
2.레벨 단위 로딩
3. 드물게 나오는 이펙트
비동기적으로 한다. -> 로딩때 시간이 걸리면 싫으니까 백그라운드에서 필요한 순간에 미리

LSR 항상 로딩
Level-wise 각 레벨별 로딩
Temporary필요할때 잠깐
Streamed 스트리밍 ->

여기에 나오는 숫자는 Reference count 몇번 참조되는가

필요한 resource
level 1 -> ABC
level 2 -> BCDE
level 2 필요한 애들 1씩증가
level 1은 이제 안쓰니까 자기에게 필요했던애들 -1 씩
로딩단계에서 현재 0인 애들 (1)이렇게 로딩해주는것.


유니티는 레벨위에 올려놓으면 동시에 올라감
내가 runtime 에 필요의 경우에 따라서 로딩하는 경우는
AssetBundles.loadAsset()
ㄴ 유니티 플레이어 밖에 존재하는 외부 리소스
Resource.load()
ㄴ 플레이어안에 있는 리소스 폴더를 의미

동적으로 웹서버에 들어가 가져오는 것, 실행파일 안에 있는것 정도의 차이

Unity의 Memory 관리

GC가 존재해서 메모리를 관리해준다.
아까 말한 reference count를 써서 GC가 잡아서 메모리 공간에서 해제한다.

GC를 직접 동작시키고 싶다. System.GC.Collect()를 쓰면 된다.
ㄴ 실제론 잘 안씀- 교수님도 안씀

Game Loop

모든 게임이 가지고 있다.

게임 - 매 프레임 마다 새로운 상태로 변화시키고 그려주고 입력을 받는 것
어딘가에는 이러한 루프가 존재해야한다. 종료 전까지 계속해서.

보통 하는 일은

  • 카메라를 업데이트
  • 장면에 존재하는 element update
  • 변화된 상태 보여주기위해 render scene
  • swapBuffer
    실제 보이는 버퍼와 background buffer(다음 화면)를 바꿔줌

예시 pong

이런 식의 게임 로직
랜더링과 큰 줄기는 비슷하나 사용자에게 입력 받은 상태 변화를 반영한다는 것이 가장 큰 차이이다.
이러한 차이를 구현하는데 2가지 방식이 있는데
1.메세지 pump
2.Callback
대게 위와 같은 두가지 방식으로 구현한다.


메세지 pump의 방식


Callback 함수 방식

callback 함수의 경우는 등록을 해놓으면 특정 이벤트 발생시 자동으로 넘어간다. framelistener 프레임에 관련된 이벤트 발생시 이를 처리하는 callback 함수를 처리해줌

메시지를 받아 처리하느냐 , callback 함수를 사용하느냐의 차이

이런 프레임 리스너는 상위의 클래스에서 함수를 불러온다. 원하는 이벤트에 맞는 함수를 오버라이딩하여 사용하게 된다. 프레임 마다 관심있는 객체들을 늘릴 수 있다.

예시
Playable Charater 뿐만 아니라 NPC도 등록을 하고 상호작용

Unity의 callback 함수

유니티의 게임 오브젝트들은 MonoBehaviour 에 등록이 되어있다.
Update와 Start 등의 코드를 작성하게 된다.

위에 보이는 내용들은 유니티의 익숙해지면 그 차이에 익숙해지게된다.
Update - 매 프레임마다(1초에 60프레임)
FixedUpdate - 정규 시간마다
LateUpdate - Update가 끝난후

우선 이러한 것들이 있다는 것을 알면되고 필요시에 찾아서 사용할 줄 알면 된다.

Frame Rate

내 프레임이 얼마나 빠르게 바껴나가느냐를 이야기하는 프레임의 비율

Frame Per Second
영화나 TV의 경우 24 FPS
게임의 경우 60 FPS


Δt

매프레임 마다 동일한 간격으로 Update 되면 좋겠지만 실제론 그렇게 되지 않을 수 있다. 그렇기에 현실세계의 시간이 필요하다
이러한 프레임과 프레임간의 시간을 Δt로 이야기한다

예시


얼마 만큼 이동했는지 Δt후 속도 = 속도 +가속도* Δt로 표현
Δt가 똑같은 Δt라도 좀 더 좋은 접근법이 있을 수 있다 이는 예시로 오일러 접근법을 사용했다.
우선 Δt가 크기 때문에 근사에 대한 오류가 있다.
Δt 가 일정하지 않으면 오류의 부정확도가 높아져서 더욱 문제가 발생할 수 있다.
Δt 를 고정 수치로 했을 때 컴퓨터의 성능에 따라 시뮬레이션의 속도가 결정 될 수 있다. (고성능 -> 빠른 시뮬 , 저성능->느린 시뮬)

속도에 따른 차이


컴퓨터의 속도에 따라 서로 다른 게임
ex) 테트리스의 터보 버튼 - 누르면 게임 속도가 빨라짐

해결방안


모든 사람이 동일한 경험을 하게하려면 Δt를 고려해서 할 필요가 있다 그래서 현재 대부분의 컴퓨터에서 High-resolution timer를 제공한다.
펜티엄이라는 옛날 컴퓨터에도 엄청 작동을 잘한다.

위와 같은 함수들을 제공한다는 점만 인지하면된다. 이렇게 High-resolution timer 접근할 수 있다. 유니티는 High-resolution timer가 자동으로 적용되어 있고 Update()에서 해당 정보를 불러오는 API도 존재한다.

Unity에서 time불러오기

Time.time을 사용하여 시간의 대한 정보를 불러올 수 있다. 아래 코드는 연속적인 발사가 아닌 최소한의 대기시간을 넣어주는 역할을 한다.

0개의 댓글