Unity 3D 게임제작 실습에서는 유니티의 소개, 에디터를 통한 컨텐츠 제작, 스크립트를 통한 게임오브젝트 제어, 카메라, 라이트, 쉐이더를 통한 렌더링과 퍼포먼스, 빌드까지 진행해보았습니다. 디자인 요소들은 전문가가 제작한 소스들이 제공, 실습이 진행됐습니다.
1.Unity 소개 및 Editor를 통한 컨텐츠 저작
Unity
2005년 6월 8일 출시된 3D 및 2D 비디오 게임의 개발 환경을 제공하는 게임 엔진 (라이브러리의 집합) 으로
Multi-Platform의 Mono Framework (Xamarin) 입니다.
많은 Device 업체의 Testbed로 사용 중이며 C# 기반의 AR, VR에 대한 강력한 기능 제공하며
Asset Store 로 유 무료의 스토어 개념으로 퀄리티가 좋은 소스들을 활용 가능합니다.
(경우에 따라 Asset Store를 통한 수익이 사업모델이 될 수 있음)
유니티는 Component Based Engine으로 GameObject와 Component의 형태로 기능이 정의되는데 모든 기능은 Component의 형태로 개발되며, GameObject는 Component를 담는 Container의 역할과 Object의 공통 Data만 포함하는 기능이 있습니다.
에디터를 이용해 컨텐츠를 제작하게 되는데 각 패널은 하이어락키(Hiarachy), View(Scene View, Game View), Inspector, Project/Console 영역으로 나뉘어집니다.
Hierachy에서 3d object -> plane, sphere를 설치해보며 Scene View에서 마우스 우클릭, wasd를 통해 SceneView의 카메라를 움직여도 보고, .Inpector의 Transform을 통해 Position, Rotation, Scale를 조정해보고 Gizmo를 통해 Transform을 제어해봅니다. 이게 기본적인 기능입니다 alt를 누르고 마우스 왼쪽 버튼을 드래그하면 시야 조정이, 마우스 우버튼을 누르고 asdeq는 시야 조정 및 게임 내부에서처럼 앞뒤좌우 이동이 가능합니다.
유니티의 좌표계는 왼손좌표계 (left handed)를 사용합니다. 다른 3D 프로그램의 좌표계는 각각 다음과 같습니다.
Rendering Coordinate System
Transform을 공유하는 Component들
1) Transfrom (1.Local Spalce->Model Matrix)
- Local To World
- Position, Rotation, Scale
- 계층구조의 Child에 있다면 부모로부터의 Local 좌표계로 표시
- 실제 렌더링 될 때는 자신의 Matrix에 부모의 Matrix를 곱해서 적용됨
2) Camera - ViewMatrix (2.World Space->View Matrix)
- World To View
- Camera의 Forward, Up Vector를 기준으로 생성
- 이전 Transform Component에서 구해진 World Matrix에 Camera의 ViewMatrix를 곱함
- 연산이 완료되면 카메라를 기준으로 모든 오브젝트가 정렬됨
3) Camera - Projection Matrix (3.View Space->Projection Matrix)
- View To Projection
- Ortho(직교), Perspective(원근) 투영
- 2D기법으로 Ortho를 사용
- left, right, up, bottom, near, far
- 단위 : M단위 - 3D 기법으로 Perspective를 사용
- fov, aspect Ratio, near, far
- 단위 : fov(각도), aspect ratio(화면의 가로세로 비율), near, far(M단위)
4) Camera - Projection Matrix (4.Clip Space->Screen Space)
- Projection To Screen Space
- Projection까지 진행되면 좌표계는 x(-1, 1), y(-1, 1), z(0, 1)의 좌표를 지님
- 위의 좌표계를 화면상의 pixel 좌표계로 투영시키는 과정
Mesh Rendering
Mesh Filter
- 렌더링할 Mesh를 지정 ( 렌더링할 데이터 )
Mesh Renderer
- Mesh를 렌더링 할 때 사용할 Material 지정 ( 렌더링할 속성 )
- 실제 렌더링을 진행
- Light probes, Reflection Probes, Shader등의 속성 지정
Mesh Component간의 사용관계
- Position(Vertex), Triangle(Index)
- UV(1~8), Color
- Normal, Tangent
- Bounds
- etc(BlendShape, BoneWeight, SubMesh)
Material Component간의 사용관계
- Shader
- Color, Texture
- Uniform : Shader 변수
- Render Queue
Physics
Collider
- 물리적 형태
- Box, Capsule, Sphere, Mesh, Wheel, Terrain
RigidBody
- 물리적 속성
- 무게, 저항, 중력작용 여부
- etc
Resource
Model Import
- FBX등의 Model File : Mesh, Material, Animation clip, Avatar
- Wav등의 Audio File : audio clip
- Avi, Mp4등의 Video File : Video clip
만약 Unity의 script에서 raw data를 바꾸려하더라도 실제 File은 변경되지 않고
Unity에 복사되어 생성된 unity의 data가 바뀐다.
2. Script를 통해 GameObject 제어
Script란?
- Unity에서 제공하는 Component의 사용자 정의형태
- Unity로 개발한다는 것은 결국 Script를 개발하는 것
- Component -> MonoBehaviour -> Script
- Script는 Component의 다른형태
- 이미 정의되어진 Script의 life cycle에 맞춰 사용자의 필요한 기능을 구현
Script의 Lifecycle
주로 사용되는 함수
- Awake : 처음 Component가 Add되는 시점에 한번 호출
- OnEnable : Component나 GameObject가 Enable(Active:true)되는 시점에 호출
- Start : Component나 GameObject가 Enable(Active:true)되는 시점에 한번 호출
- FixedUpdate : Edit->Project Setting->Time 에서 Fixed Timestep에 맞춰 호출(주의)
- Update : 매 프레임 한번 호출
- LateUpdate : 매 프레임 한번 호출
- OnDisable : Component나 GameObject가 Disable(Active:false)되는 시점에 호출
- OnDestroy : Component가 Destroy되는 시점에 한번 호출
FixedUpdate의 경우 한 프레임이 Fixed Timestep보다 짧으면 해당 프레임에서 무시될 수 있고, Fixed Timestep보다 길면 해당 프레임에서 여러번 호출될 수 있다. FixedUpdate에서는 deltaTime이 아니라 fixedDeltaTime를 사용
Script Excution Order
- Unity의 Script는 Message Driven의 방식으로 호출되어짐
- 각각의 Script에는 어떠한 우선순위도 정의되지 않음
- Script에서 다른 Script를 참조하여 사용할 때 Script의 실행 우선순위에 따라 오류가 발생할 수 있음
- 위 오류를 해결하는 방법이 Script Excution Order
- Edit -> Project Setting -> Script Excution Order
- Inspector창의 우측하단 ‘+’버튼을 통해 Script의 Excution Order를 제어할 수 있음
GameObject
Component에 대한 관리
- AddComponent<>()
- GetComponent<>()
- Name, Layer, Active
생성 / 삭제 방법
- new GameObject();
- new GameObject(name)
- GameObject.CreatePrimitive(PrimitiveType type);
- Destroy(gameObject);
Transform
- GameObject에는 무조건 Transform이 하나 생성된다.
- UI요소에는 Rect Transform이 생성된다.
- Position, Rotation, Scale
- 계층구조 관리
- Shader에서의 WorldMatrix를 담당함
주요 메소드
- position, rotation, lossyScale, eulerAngles
- localPosition, localRotation, localScale, localEulerAngles
- parent, getChild, childCount
- Translate, Rotate
- TransformDirection, TransformPoint, TransformVector
- InverseTransformDirection, InverseTransformPoint, InverseTransformVector
Debugging
Debug.log를 이용한 디버깅
Script에서 아래의 메소드를 사용한다.
- Debug.Log
- Debug.LogAssertion
- Debug.LogWarning
- Debug.LogError
- Debug.Assert
- Debug.DrawLine
- Debug.DrawRay
Visual Studio를 이용한 C# Debuging
- Unity Editor의 Project View에서 마우스 우클릭을 하여 “Open C# Project”를 클릭하여 Visual Studio를 실행한다.
- Visual Studio의 상단부 중앙에 있는 [Unity에 연결] 버튼을 클릭한다.
- 디버깅 할 위치에 중단점을 설정한 후 Unity Editor에서 Scene을 실행한다.
- 중단점 위치부터 Debuing을 진행한다
Input
Script에서 아래의 메소드 사용(주요)
- Input.GetButton
- Input.GetAxis
- Input.GetKey
- Input.GetKeyDown
- Input.GetKeyUp
- Input.GetMouseButton
- Input.GetMouseButtonDown
- Input.GetMouseButtonUp
- Input.MousePosition
- Input.MouseScrollDelta
Input Manager
- Unity Editor -> Edit -> Project Setting -> Input
Raycast
- Raycast는 Mesh Data에 대한 기능이 아닌 Collider에 대한 기능이다.
- 예외로 UI요소에 대하여는 Graphics Raycaster를 사용한다.
- Ray의 구성은 Position, Direction이다
// Raycast를 참고하여 mouseInput을 이용한 Raycast를 구현하여보자
Vector3 fwd = transform.TransformDirection(Vector3.forward);
if (Physics.Raycast(transform.position, fwd, 10))
print("There is something in front of the object!");
Coroutine
- Update함수는 매 초마다 fps만큼 호출된다.
- 1초에 한번 혹은 5초에 한번 실행될 기능을 Update에서 처리하는 것은 불합리 - > Coroutine을 제공
- Coroutine은 비동기 작업처럼 보이지만 결국 비동기가 아니다.
- Coroutine은 Unity Thread에서 호출된다.
- 물론 Update에서 처리하는 것 보다 미약하나마 성능에 이점이 있다.
- 약 10초에 한번 실행될 스크립트라면 꽤나 큰 이점일수도 있다.
- 그러나 Coroutine은 성능의 이점보다는 유저의 편의성에 의의가 있다.
사용법
- Unity Thread에서 호출되는 메소드에서 StartCoroutine(함수 이름());
StartCoroutine에서 사용할 수 있는 함수의 원형
// StartCoroutine은 해당하는 함수를 Coroutine에 등록시키는 것
public IEnumerator Function()
// 실제 Coroutine을 Update와 분리시키는 코드
yield return new WaitForFixedUpdate()
// 이 코드는 IEnumerator를 반환하는 함수에서만 활용할 수 있다.
// yield return의 특징은 다시 해당 메소드가 호출될 때 yield코드로 돌아온다는 것
yield return의 다양한 예
- yield return null => 다음 프레임까지 대기
- yield return new WaitForSeconds(float) => 지정된 초 만큼 대기
- yield return new WaitForFixedUpdate() => 다음 물리 프레임까지 대기
- yield return new WaitForEndOfFrame() => 모든 렌더링작업이 끝날 때까지 대기
- yield return StartCoRoutine(string) => 다른 코루틴이 끝날 때까지 대기
- yield return new WWW(string) => 웹 통신 작업이 끝날 때까지 대기
- yield return new AsynOperation => 비동기 작업이 끝날 떄까지 대기
3. Camera, Light, Shader를 통한 Rendering
Camera란?
- 한 화면의 렌더링을 담당하는 Component
주요 항목
- Clear
- Culling Mask
- Projection
- Ortho
- Perspective
- Near, Far
- Viewport
- Rendering Path
- Forward, Deferred
- Target Display
- Target Texture
예시 : 거울 구현
- 거울로 사용할 plane의 뒤에 카메라를 위치시킨다
- 해당 카메라에 Target Texture를 설정하여 Texture에 해당 카메라로 렌더링한다.
- Target Texture를 거울 오브젝트의 Material에 MainTexture로 입력한다.
Forward Rendering과 Deferred Rendering의 차이점
Lighting
-Type
- Spot : Color, Range, Spot Angle
- Point : Color, Range
- Directional : Color
-Mode
- Mixed : Lighting Setting에서 선택가능
- Realtime : 광원의 부하가 가장 심함
- Baked : Lighting이 실시간으로 변경될 때는 바람직하지 않음.
-Shadow
-Cookie
-Culling Mask
Lighting Setting & Light Explorer
-Lighting Setting
- Scene의 Lighting global setting
- Unity Editor -> Window -> Lighting -> settings
- Light만으로 설명이 안되는 이펙트가 발생한다면 가장 먼저 확인 필요
-Light Explorer
- 현재 Scene에 올라온 모든 Light에 대해 관리
- 큰 Scene을 여러 디자이너와 제작하다보면 아무도 모르게 Light가 많이 들어가는 경우가 발생
- 성능이 떨어지거나 전체적인 톤이 고르지 못한 상태라면 확인 필요
Shader
- vertex 정보들을 화면에 보여질 수 있도록 변환하는 작업을 하는 프로그램(명령어 집합)
- 스크린 위에 낱개의 픽셀마다 실행되며 이 실행들이 한번에 일어남.(병렬)
- 이러한 작업은 GPU에서 일어납니다.
- ComputeShader는 렌더링Shader와는 별개로 실행
Shader 예시
- -Color Shader
- -Texture Shader
- -UV Animation Shader
- -texture를 왼쪽으로
- -sin 파형을 이용하여 Texture mapping
- -unity에서 제공해주는 lighting 모델
https://velog.io/@godori/2018-12-09-2312-%EC%9E%91%EC%84%B1%EB%90%A8-zvjph00nd7
https://www.khronos.org/files/opengl46-quick-reference-card.pdf
https://docs.unity3d.com/kr/current/Manual/SL-VertexFragmentShaderExamples.html
After
Shader와 Camera의 복합적 모델
https://interplayoflight.wordpress.com/2017/10/25/how-unreal-renders-a-frame/
Realtime Raytracing
- Nvidia사의 RTX 그래픽카드가 이끌어가는 시장
- 추후 AMD Radeon에서도 지원할거라 발표
- Unity에서는 HDRP(High Definition Render Pipeline, 고해상도 렌더 파이프라인)으로 지원
Unity의 Rendering Pipeline
- Unity에서는 유저가 전체적인 Rendering Pipeline을 커스터마이징 하도록 Scriptable Render Pipeline을 지원
- Lightweight Render Pipeline(LWRP)
- High Definition Render Pipeline(HDRP)
4. Performance, Build
단위기능 MultiThread
-만약 NetworkEngine을 구현하거나, 동영상의 Encoding, Deconding 시스템을 구현한다면 Update에서 모든 것을 처리하기보다는 다른 Thread를 실행하여 병렬로 작업을 처리할 수 있다.
-이 경우 다른 Thread에서 처리된 Data를 Unity에 적용하기 위해서는 Thread간의 Data처리를 위해 ConcurrentQueue나 Interlocked등을 활용하여 Thread safe작업을 source단에서 처리해주어야 한다.
-CPU 코어보다 Thread 수가 많아지면 CPU리소스를 놓고 Thread간에 경쟁이 벌어지고, 이로 인해 컨텍스트 스위칭이 빈번하게 발생하게됨.
Thread State