Unity 엔진 종합 정리

REIN·2025년 10월 21일

Unity 관련 정보들

목록 보기
1/3

Unity의 핵심 시스템을 물리/수학적 원리와 함께 정리한 종합 복습 자료입니다. GameObject-Component 아키텍처부터 최적화까지, 실무에 필요한 개념을 심도있게 다룹니다. New Input System, TextMeshPro 등 최신 시스템 중심으로 작성되었습니다.


들어가며

Unity는 게임 엔진이지만, 그 내부는 물리 시뮬레이션, 선형대수, 컴퓨터 그래픽스 등 다양한 학문적 기반 위에 구축되어 있습니다. 이와 같은 시스템의 동작 원리를 수학적으로 이해하고 실무에 적용할 수 있도록 구성했습니다.

예를 들어 물리 엔진의 뉴턴 역학 방정식, Transform의 4×4 변환 행렬, 쿼터니언의 수학적 정의, 조명 모델의 Phong Reflection 등 핵심 수식을 포함하여, 왜 그렇게 동작하는지를 이해할 수 있도록 했습니다.

대상 독자: Unity 중급 개발자, 게임 프로그래머 지망생
필요 배경: C# 기초, 물리학/수학 기본 개념


목차

  1. Unity 아키텍처와 게임 루프
  2. GameObject와 Component 시스템
  3. Transform과 좌표계
  4. 물리 엔진 (Physics System)
  5. C# 스크립팅과 생명주기
  6. Coroutine과 비동기 처리
  7. 렌더링 파이프라인
  8. Animation 시스템
  9. UI 시스템 (uGUI)
  10. 최적화 기법

1. Unity 아키텍처와 게임 루프

1.1 엔진 아키텍처

Unity는 Entity-Component-System (ECS) 패턴의 변형인 GameObject-Component 아키텍처를 기반으로 합니다. 전통적인 객체지향 상속 구조 대신 조합(Composition)을 통한 설계를 지향합니다.

핵심 원리:

  • GameObject: 빈 컨테이너 역할
  • Component: 실제 기능을 구현하는 모듈
  • Scene: GameObject들의 계층 구조

1.2 게임 루프 (Game Loop)

Unity의 게임 루프는 전형적인 실시간 시뮬레이션 루프를 따릅니다:

게임 루프 (Game Loop) 구조

단계구분설명
Initialization초기화게임 엔진, 리소스, 시스템 초기화
Frame Start프레임 시작새 프레임 시작, 타이머 설정
Input입력 처리키보드, 마우스, 컨트롤러 입력 수집 및 처리
Physics Update물리 업데이트고정 시간 간격(Fixed timestep)으로 물리 시뮬레이션
Game Logic게임 로직AI, 충돌 검사, 상태 머신, 게임 규칙 처리
Animation애니메이션스프라이트, 모델 애니메이션 업데이트
Rendering렌더링화면에 그래픽 요소들을 그리기
Frame End프레임 종료프레임 완료, V-Sync 대기
↻ Repeat반복다음 프레임으로 루프 재시작

주요 업데이트 함수 실행 순서:
1. FixedUpdate() - 물리 시뮬레이션 (고정 시간 간격)
2. Update() - 매 프레임 로직
3. LateUpdate() - Update 이후 처리 (카메라 추적 등)

시간 관리:

  • Time.deltaTime: 이전 프레임과 현재 프레임 사이의 시간 (Δt\Delta t)
  • Time.fixedDeltaTime: 물리 업데이트 시간 간격 (기본값 0.02s, 50Hz)

Reference:

  • Unity Documentation: "Order of Execution for Event Functions" (Unity Technologies, 2024)
  • Game Engine Architecture, 3rd Edition, Jason Gregory (CRC Press, 2018)

2. GameObject와 Component 시스템

2.1 GameObject

GameObject는 Unity의 기본 엔티티입니다. 자체적으론 기능이 없으며, Component들의 컨테이너 역할만 수행합니다.

필수 Component:

  • Transform: 모든 GameObject가 반드시 가지는 Component (위치, 회전, 스케일)

2.2 Component 패턴

주요 내장 Component:

  • Renderer: 시각적 표현 (MeshRenderer, SpriteRenderer)
  • Collider: 충돌 감지 영역
  • Rigidbody: 물리적 속성
  • Script: 사용자 정의 로직

Component 접근 방법:

// 방법 1: GetComponent (런타임 탐색)
Rigidbody rb = GetComponent<Rigidbody>();

// 방법 2: SerializeField (인스펙터에서 할당)
[SerializeField] private Rigidbody rb;

// 방법 3: RequireComponent (의존성 명시)
[RequireComponent(typeof(Rigidbody))]
public class MyScript : MonoBehaviour { }

성능 고려사항:

  • GetComponent<T>()는 비용이 높은 연산 (리플렉션 사용)
  • 캐싱 권장: Awake()나 Start()에서 한 번만 호출

2.3 Tag와 Layer

Tag:

  • GameObject 식별을 위한 문자열 레이블
  • 충돌 감지, 오브젝트 탐색에 사용
  • 하나의 GameObject는 하나의 Tag만 가능

Layer:

  • 렌더링, 물리 연산, 레이캐스팅 필터링
  • 비트마스크 기반: 32개 레이어 (0-31)
  • LayerMask를 통한 비트 연산
// Layer 비트마스크 연산
LayerMask mask = LayerMask.GetMask("Player", "Enemy");
// 내부적으로: (1 << layerIndex1) | (1 << layerIndex2)

Reference:

  • Unity Documentation: "GameObjects" (Unity Technologies, 2024)
  • Design Patterns: Elements of Reusable Object-Oriented Software, Gamma et al. (Addison-Wesley, 1994)

3. Transform과 좌표계

3.1 좌표계

Unity는 왼손 좌표계(Left-Handed Coordinate System)를 사용합니다:

  • X축: 오른쪽 (Red)
  • Y축: 위쪽 (Green)
  • Z축: 앞쪽 (Blue)

좌표 공간의 계층:
1. Local Space: 부모 기준 상대 좌표
2. World Space: 전역 절대 좌표
3. View Space: 카메라 기준 좌표
4. Clip Space: 투영 후 정규화된 좌표

3.2 Transform Component

Transform은 3가지 속성으로 구성됩니다:

Position (p\mathbf{p}):

  • Local: transform.localPosition
  • World: transform.position

Rotation (R\mathbf{R}):
Unity는 회전을 표현하기 위해 쿼터니언(Quaternion)을 사용합니다:

q=w+xi+yj+zk\mathbf{q} = w + x\mathbf{i} + y\mathbf{j} + z\mathbf{k}

여기서 q=w2+x2+y2+z2=1|\mathbf{q}| = \sqrt{w^2 + x^2 + y^2 + z^2} = 1 (단위 쿼터니언)

쿼터니언의 장점:

  • Gimbal Lock 문제 해결
  • 보간(Interpolation)이 용이
  • 메모리 효율적 (4개 float vs 9개 float for matrix)

오일러 각과의 변환:

// Euler → Quaternion
Quaternion q = Quaternion.Euler(x, y, z);

// Quaternion → Euler
Vector3 euler = transform.rotation.eulerAngles;

회전 연산:

// 회전 합성 (순서 중요: 비가환 연산)
Quaternion combined = q2 * q1; // q1 먼저, q2 나중

// 벡터 회전
Vector3 rotated = q * vector;

// 보간
Quaternion interpolated = Quaternion.Slerp(q1, q2, t);

Scale (s\mathbf{s}):

  • Local: transform.localScale
  • World: transform.lossyScale (읽기 전용)

3.3 변환 행렬 (Transformation Matrix)

Transform은 내부적으로 4×4 동차 변환 행렬로 표현됩니다:

M=[Rt0T1]\mathbf{M} = \begin{bmatrix} \mathbf{R} & \mathbf{t} \\ \mathbf{0}^T & 1 \end{bmatrix}

여기서:

  • R\mathbf{R}: 3×3 회전-스케일 행렬
  • t\mathbf{t}: 3×1 이동 벡터

계층 구조에서의 변환:

Mworld=MparentMlocal\mathbf{M}_{world} = \mathbf{M}_{parent} \cdot \mathbf{M}_{local}

// 수동 계층 변환
Matrix4x4 localToWorld = transform.localToWorldMatrix;
Matrix4x4 worldToLocal = transform.worldToLocalMatrix;

Vector3 worldPos = localToWorld.MultiplyPoint3x4(localPos);

3.4 방향 벡터

Transform은 기본 방향 벡터를 제공합니다:

Vector3 forward = transform.forward;  // (0, 0, 1) in local
Vector3 right = transform.right;      // (1, 0, 0) in local
Vector3 up = transform.up;            // (0, 1, 0) in local

Reference:

  • 3D Math Primer for Graphics and Game Development, 2nd Edition, Dunn & Parberry (CRC Press, 2011)
  • Unity Documentation: "Transform" (Unity Technologies, 2024)

4. 물리 엔진 (Physics System)

4.1 Physics Engine 기초

Unity는 NVIDIA PhysX 엔진을 사용하며, 뉴턴 역학 기반의 강체 동역학(Rigid Body Dynamics)을 시뮬레이션합니다.

기본 운동 방정식:

F=ma=mdvdt\mathbf{F} = m\mathbf{a} = m\frac{d\mathbf{v}}{dt}

τ=Iα=Idωdt\boldsymbol{\tau} = \mathbf{I}\boldsymbol{\alpha} = \mathbf{I}\frac{d\boldsymbol{\omega}}{dt}

여기서:

  • F\mathbf{F}: 힘 벡터
  • mm: 질량
  • v\mathbf{v}: 선속도
  • τ\boldsymbol{\tau}: 토크
  • I\mathbf{I}: 관성 텐서
  • ω\boldsymbol{\omega}: 각속도

4.2 Rigidbody Component

주요 속성:

  • mass: 질량 (kg)
  • drag: 선형 감쇠 (air resistance)
  • angularDrag: 각 감쇠
  • useGravity: 중력 적용 여부
  • isKinematic: 운동학적 모드 (물리 엔진의 힘을 무시)

물리 모드:

  1. Dynamic: 완전한 물리 시뮬레이션
  2. Kinematic: 스크립트로만 제어, 다른 물체에 영향
  3. Static: 움직이지 않는 물체 (Collider만)

힘 적용 방법:

Rigidbody rb;

// 1. 순간 힘 (충격)
rb.AddForce(force, ForceMode.Impulse);
// Δv = F/m

// 2. 지속적 힘
rb.AddForce(force, ForceMode.Force);
// 매 FixedUpdate마다 적용

// 3. 속도 직접 변경
rb.velocity = new Vector3(x, y, z);

// 4. 토크 (회전력)
rb.AddTorque(torque);

ForceMode 비교:

ForceMode수식질량 영향사용 예
ForceFΔt/m\mathbf{F} \cdot \Delta t / mO지속적 힘
ImpulseF/m\mathbf{F} / mO순간 충격
AccelerationFΔt\mathbf{F} \cdot \Delta tX가속도
VelocityChangeF\mathbf{F}X직접 속도 변경

4.3 Collider

Collider 종류:

  • Primitive: Box, Sphere, Capsule (빠른 연산)
  • Mesh: 복잡한 형상 (연산 비용 높음)
  • Compound: 여러 Collider 조합

Trigger vs Collider:

  • isTrigger = false: 물리적 충돌 (밀림)
  • isTrigger = true: 이벤트만 발생 (통과 가능)
// Collision (물리 충돌)
void OnCollisionEnter(Collision collision) { }
void OnCollisionStay(Collision collision) { }
void OnCollisionExit(Collision collision) { }

// Trigger (영역 감지)
void OnTriggerEnter(Collider other) { }
void OnTriggerStay(Collider other) { }
void OnTriggerExit(Collider other) { }

4.4 충돌 감지 알고리즘

Unity는 2단계 충돌 감지를 사용합니다:

1. Broad Phase (넓은 검색):

  • AABB (Axis-Aligned Bounding Box) 기반
  • 잠재적 충돌 쌍 찾기
  • 시간 복잡도: O(nlogn)O(n \log n)

2. Narrow Phase (정밀 검색):

  • GJK (Gilbert-Johnson-Keerthi) 알고리즘
  • EPA (Expanding Polytope Algorithm)
  • 실제 충돌 지점 계산

4.5 Raycast

광선을 쏴서 충돌을 감지하는 기법:

// 기본 Raycast
Ray ray = new Ray(origin, direction);
RaycastHit hit;

if (Physics.Raycast(ray, out hit, maxDistance, layerMask))
{
    Debug.Log($"Hit: {hit.collider.name}");
    Debug.Log($"Distance: {hit.distance}");
    Debug.Log($"Point: {hit.point}");
    Debug.Log($"Normal: {hit.normal}");
}

// 모든 충돌 감지
RaycastHit[] hits = Physics.RaycastAll(ray, maxDistance);

// Sphere Cast (두께 있는 광선)
Physics.SphereCast(origin, radius, direction, out hit, maxDistance);

최적화 팁:

  • LayerMask 사용으로 필터링
  • QueryTriggerInteraction로 Trigger 포함 여부 제어
  • RaycastNonAlloc 사용으로 GC 방지

4.6 물리 재질 (Physics Material)

마찰과 반발 계수 정의:

PhysicMaterial material = new PhysicMaterial();
material.dynamicFriction = 0.6f;  // 운동 마찰 계수 (μ_k)
material.staticFriction = 0.8f;   // 정지 마찰 계수 (μ_s)
material.bounciness = 0.5f;       // 반발 계수 (e)

마찰력:

Ffriction=μN\mathbf{F}_{friction} = \mu \cdot \mathbf{N}

반발 계수:

e=vseparationvapproache = \frac{v_{separation}}{v_{approach}}

완전 탄성 충돌: e=1e = 1
완전 비탄성 충돌: e=0e = 0

Reference:

  • Classical Mechanics, 3rd Edition, Goldstein, Poole & Safko (Addison-Wesley, 2001)
  • Real-Time Collision Detection, Christer Ericson (Morgan Kaufmann, 2004)
  • Unity Documentation: "Physics" (Unity Technologies, 2024)

5. C# 스크립팅과 생명주기

5.1 MonoBehaviour 생명주기

Unity의 모든 스크립트는 MonoBehaviour를 상속받아야 하며, 특정 생명주기 메서드를 통해 동작합니다.

실행 순서 (Initialization):

Awake()
    ↓
OnEnable()
    ↓
Start()

프레임 업데이트 순서:

FixedUpdate() (물리 업데이트, 고정 시간)
    ↓
Update() (매 프레임)
    ↓
LateUpdate() (Update 이후)

종료 순서:

OnDisable()
    ↓
OnDestroy()

주요 메서드 비교:

메서드호출 시점용도
Awake()스크립트 인스턴스 로드 시 (1회)초기화, 참조 설정
Start()첫 Update 전 (1회)게임 시작 로직
OnEnable()GameObject 활성화 시이벤트 구독
Update()매 프레임일반 게임 로직
FixedUpdate()고정 시간 간격물리 연산
LateUpdate()Update 이후카메라 추적
OnDisable()GameObject 비활성화 시이벤트 구독 해제
OnDestroy()GameObject 파괴 시리소스 정리

5.2 Instantiate와 Destroy

객체 생성:

// Prefab에서 생성
GameObject instance = Instantiate(prefab, position, rotation);

// 부모 지정
GameObject child = Instantiate(prefab, parent.transform);

// 제네릭 버전 (Component 직접 반환)
Enemy enemy = Instantiate(enemyPrefab, position, rotation);

객체 파괴:

// 즉시 파괴
Destroy(gameObject);

// 지연 파괴
Destroy(gameObject, 3.0f);

// 컴포넌트만 파괴
Destroy(GetComponent<Rigidbody>());

DestroyImmediate vs Destroy:

  • Destroy(): 현재 프레임 끝에 파괴 (권장)
  • DestroyImmediate(): 즉시 파괴 (Editor 전용, 런타임 사용 금지)

5.3 입력 시스템 (Input System)

Unity는 두 가지 입력 시스템을 제공합니다:

1. Legacy Input Manager (구 Input System):
간단하지만 기능이 제한적입니다.

void Update()
{
    // 키 입력
    if (Input.GetKeyDown(KeyCode.Space)) { }
    if (Input.GetKey(KeyCode.W)) { }
    if (Input.GetKeyUp(KeyCode.Space)) { }
    
    // 마우스 입력
    if (Input.GetMouseButtonDown(0)) { } // 좌클릭
    
    // 축 입력 (부드러운 입력)
    float horizontal = Input.GetAxis("Horizontal"); // -1 ~ 1
    float vertical = Input.GetAxis("Vertical");
}

2. New Input System (권장):

더 강력하고 유연한 입력 처리를 제공합니다.

설치:

  • Package Manager에서 "Input System" 설치
  • Project Settings > Player > Active Input Handling을 "Input System Package (New)" 또는 "Both"로 설정

Input Actions 방식:

using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
    private PlayerInput playerInput;
    private InputAction moveAction;
    private InputAction jumpAction;
    
    void Awake()
    {
        playerInput = GetComponent<PlayerInput>();
        
        // Input Action 참조
        moveAction = playerInput.actions["Move"];
        jumpAction = playerInput.actions["Jump"];
    }
    
    void Update()
    {
        // 연속 입력 (Vector2)
        Vector2 moveInput = moveAction.ReadValue<Vector2>();
        
        // 버튼 입력
        if (jumpAction.triggered) // 한 번만 트리거
        {
            Jump();
        }
        
        if (jumpAction.IsPressed()) // 계속 누르고 있음
        {
            ChargeJump();
        }
    }
    
    // 또는 C# 이벤트 방식
    void OnEnable()
    {
        jumpAction.performed += OnJump;
        jumpAction.canceled += OnJumpCanceled;
    }
    
    void OnDisable()
    {
        jumpAction.performed -= OnJump;
        jumpAction.canceled -= OnJumpCanceled;
    }
    
    void OnJump(InputAction.CallbackContext context)
    {
        Jump();
    }
    
    void OnJumpCanceled(InputAction.CallbackContext context)
    {
        // 점프 버튼 떼었을 때
    }
}

Player Input Component 방식:

// Unity Events를 사용한 더 간단한 방식
public class PlayerController : MonoBehaviour
{
    public void OnMove(InputValue value)
    {
        Vector2 moveInput = value.Get<Vector2>();
        // 이동 처리
    }
    
    public void OnJump(InputValue value)
    {
        if (value.isPressed)
        {
            Jump();
        }
    }
}

New Input System의 장점:

  • 멀티플랫폼: PC, 콘솔, 모바일 통합 관리
  • 리바인딩: 런타임에 키 재설정 가능
  • 멀티플레이어: 여러 입력 장치 쉽게 관리
  • Action 기반: 물리적 입력이 아닌 논리적 행동으로 관리
  • Processor & Interaction: 입력 후처리 및 복잡한 제스처 지원

Input Action Asset:

  • Create > Input Actions로 생성
  • 시각적 에디터로 입력 바인딩 설정
  • Action Maps로 컨텍스트별 입력 그룹화 (Gameplay, UI, Menu 등)
ActionMap: Gameplay
├─ Move (Vector2): WASD, Left Stick
├─ Jump (Button): Space, South Button (A/Cross)
├─ Fire (Button): Left Mouse, Right Trigger
└─ Aim (Vector2): Mouse Delta, Right Stick

ActionMap: UI
├─ Navigate (Vector2): WASD, D-pad
└─ Submit (Button): Enter, South Button

5.4 충돌 및 트리거 이벤트

충돌 이벤트:

void OnCollisionEnter(Collision collision)
{
    // 충돌 정보
    ContactPoint contact = collision.contacts[0];
    Vector3 normal = contact.normal;
    float impulse = collision.impulse.magnitude;
}

void OnTriggerEnter(Collider other)
{
    // Trigger 충돌 (더 가벼움)
    if (other.CompareTag("Player"))
    {
        // Player와 충돌
    }
}

5.4 프로퍼티와 SerializeField

직렬화 (Serialization):

Unity는 Inspector에 표시하고 저장할 데이터를 직렬화합니다.

// 자동 직렬화 (public)
public float speed = 5.0f;

// 수동 직렬화 (private)
[SerializeField] private int health = 100;

// 직렬화 제외
[System.NonSerialized] public float tempValue;

// 숨김 처리
[HideInInspector] public bool debugFlag;

프로퍼티 패턴:

// C# 프로퍼티 (직렬화 안됨)
public float Speed { get; set; }

// Backing field 패턴 (직렬화 됨)
[SerializeField] private float speed;
public float Speed => speed; // 읽기 전용

// 유효성 검사
private float speed;
public float Speed
{
    get => speed;
    set => speed = Mathf.Max(0, value); // 음수 방지
}

5.5 메모리 관리와 가비지 컬렉션

Unity는 C#의 GC(Garbage Collector)를 사용하지만, 실시간 게임에서는 GC로 인한 프레임 드롭이 문제가 됩니다.

GC 유발 패턴:

// BAD: 매 프레임 allocation
void Update()
{
    Vector3 temp = new Vector3(x, y, z); // 힙 할당
    string text = "Score: " + score; // 문자열 연결
}

// GOOD: 재사용
private Vector3 temp;
private StringBuilder sb = new StringBuilder();

void Update()
{
    temp.Set(x, y, z); // 기존 객체 재사용
    sb.Clear();
    sb.Append("Score: ").Append(score);
}

Object Pooling:

public class ObjectPool
{
    private Queue<GameObject> pool = new Queue<GameObject>();
    private GameObject prefab;
    
    public GameObject Get()
    {
        if (pool.Count > 0)
        {
            GameObject obj = pool.Dequeue();
            obj.SetActive(true);
            return obj;
        }
        return Instantiate(prefab);
    }
    
    public void Return(GameObject obj)
    {
        obj.SetActive(false);
        pool.Enqueue(obj);
    }
}

Reference:

  • C# in Depth, 4th Edition, Jon Skeet (Manning, 2019)
  • Unity Documentation: "Script Lifecycle" (Unity Technologies, 2024)
  • Unity Documentation: "Input System" (Unity Technologies, 2024)
  • Garbage Collection Handbook, Jones, Hosking & Moss (CRC Press, 2011)

6. Coroutine과 비동기 처리

6.1 Coroutine 개념

Coroutine은 실행을 일시 중지하고 나중에 재개할 수 있는 함수입니다. Unity에서는 IEnumerator를 반환하는 메서드로 구현됩니다.

기본 구조:

IEnumerator MyCoroutine()
{
    Debug.Log("Start");
    
    yield return null; // 다음 프레임까지 대기
    
    Debug.Log("Next frame");
    
    yield return new WaitForSeconds(2.0f); // 2초 대기
    
    Debug.Log("After 2 seconds");
}

// 실행
StartCoroutine(MyCoroutine());

6.2 Yield 명령어

Yield 명령설명재개 시점
yield return null한 프레임 대기다음 Update
yield return new WaitForSeconds(t)t초 대기t초 후
yield return new WaitForFixedUpdate()물리 업데이트 대기다음 FixedUpdate
yield return new WaitForEndOfFrame()프레임 끝 대기렌더링 후
yield return StartCoroutine(other)다른 Coroutine 완료 대기other 종료 후
yield return new WaitUntil(() => condition)조건 만족 대기condition이 true
yield return new WaitWhile(() => condition)조건 false 대기condition이 false

6.3 Coroutine 제어

// Coroutine 참조 저장
private Coroutine activeCoroutine;

void Start()
{
    // 시작
    activeCoroutine = StartCoroutine(MyCoroutine());
}

void Stop()
{
    // 중지
    if (activeCoroutine != null)
    {
        StopCoroutine(activeCoroutine);
        activeCoroutine = null;
    }
    
    // 모든 Coroutine 중지
    StopAllCoroutines();
}

6.4 실무 활용 예제

1. 페이드 효과:

IEnumerator FadeOut(CanvasGroup canvasGroup, float duration)
{
    float elapsed = 0f;
    float startAlpha = canvasGroup.alpha;
    
    while (elapsed < duration)
    {
        elapsed += Time.deltaTime;
        float t = elapsed / duration;
        canvasGroup.alpha = Mathf.Lerp(startAlpha, 0f, t);
        yield return null;
    }
    
    canvasGroup.alpha = 0f;
}

2. 순차 실행:

IEnumerator Sequence()
{
    yield return StartCoroutine(Action1());
    yield return StartCoroutine(Action2());
    yield return StartCoroutine(Action3());
    
    Debug.Log("All actions completed");
}

3. 타임아웃 패턴:

IEnumerator LoadWithTimeout(float timeout)
{
    float elapsed = 0f;
    bool loaded = false;
    
    StartCoroutine(LoadData(() => loaded = true));
    
    while (!loaded && elapsed < timeout)
    {
        elapsed += Time.deltaTime;
        yield return null;
    }
    
    if (!loaded)
    {
        Debug.LogError("Timeout!");
    }
}

6.5 Coroutine vs Async/Await

Coroutine 특징:

  • Unity의 프레임 기반 시스템과 통합
  • Update loop에서 실행
  • yield를 통한 명시적 제어

Async/Await (C# Task):

async Task LoadDataAsync()
{
    await Task.Delay(1000); // 1초 대기
    
    // 주의: Unity API는 메인 스레드에서만 호출 가능
    // 다시 메인 스레드로 돌아와야 함
}

주의사항:

  • Async/Await은 별도 스레드에서 실행 가능
  • Unity API는 메인 스레드에서만 안전
  • Coroutine이 Unity에서 더 안전하고 직관적

6.6 성능 고려사항

GC 발생:

// BAD: 매번 새로운 객체 생성
IEnumerator Bad()
{
    while (true)
    {
        yield return new WaitForSeconds(1.0f); // GC!
    }
}

// GOOD: 캐싱
private WaitForSeconds oneSecond = new WaitForSeconds(1.0f);

IEnumerator Good()
{
    while (true)
    {
        yield return oneSecond; // 재사용
    }
}

Reference:

  • Unity Documentation: "Coroutines" (Unity Technologies, 2024)
  • C# in Depth, 4th Edition, Jon Skeet (Manning, 2019)

7. 렌더링 파이프라인

7.1 렌더링 프로세스

Unity의 렌더링 파이프라인은 다음 단계를 거칩니다:

Application Stage (CPU)
    ↓
Culling (Scene 가시성 판별)
    ↓
Geometry Stage (GPU)
    ↓
Rasterization (픽셀 생성)
    ↓
Fragment/Pixel Shader (색상 계산)
    ↓
Output Merger (최종 이미지)

7.2 카메라 시스템

투영 변환:

Unity는 두 가지 투영 방식을 지원합니다:

1. Perspective (원근) 투영:

Pperspective=[1tan(FOV2)aspect00001tan(FOV2)0000f+nfn2fnfn0010]\mathbf{P}_{perspective} = \begin{bmatrix} \frac{1}{\tan(\frac{FOV}{2}) \cdot aspect} & 0 & 0 & 0 \\ 0 & \frac{1}{\tan(\frac{FOV}{2})} & 0 & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{bmatrix}

여기서:

  • FOVFOV: Field of View (시야각)
  • aspectaspect: 종횡비 (width/height)
  • nn: Near plane (가까운 클리핑 평면)
  • ff: Far plane (먼 클리핑 평면)

2. Orthographic (정사영) 투영:

Portho=[2rl00r+lrl02tb0t+btb002fnf+nfn0001]\mathbf{P}_{ortho} = \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \\ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{t-b} \\ 0 & 0 & -\frac{2}{f-n} & -\frac{f+n}{f-n} \\ 0 & 0 & 0 & 1 \end{bmatrix}

카메라 설정:

Camera cam = Camera.main;

// 투영 설정
cam.orthographic = false; // Perspective
cam.fieldOfView = 60f; // FOV in degrees
cam.nearClipPlane = 0.3f;
cam.farClipPlane = 1000f;

// 렌더링 설정
cam.clearFlags = CameraClearFlags.Skybox;
cam.cullingMask = LayerMask.GetMask("Default", "UI");

7.3 Material과 Shader

Material 구조:

  • Shader: 렌더링 알고리즘
  • Properties: Shader에 전달되는 파라미터 (색상, 텍스처 등)
Material material = renderer.material; // 복사본 생성
Material sharedMaterial = renderer.sharedMaterial; // 원본 참조

// 속성 설정
material.SetColor("_Color", Color.red);
material.SetFloat("_Metallic", 0.5f);
material.SetTexture("_MainTex", texture);

주의:

  • material: 인스턴스별 복사본 (GC 발생)
  • sharedMaterial: 공유 Material (모든 인스턴스에 영향)

7.4 Lighting

조명 종류:

  1. Directional Light: 태양광 (평행 광선)
  2. Point Light: 전구 (구형 방출)
  3. Spot Light: 손전등 (원뿔 형태)
  4. Area Light: 면광원 (Baked만 가능)

조명 계산 모델 (Phong Reflection):

I=Iaka+Idkd(NL)+Isks(RV)αI = I_a \cdot k_a + I_d \cdot k_d \cdot (\mathbf{N} \cdot \mathbf{L}) + I_s \cdot k_s \cdot (\mathbf{R} \cdot \mathbf{V})^{\alpha}

여기서:

  • IaI_a: Ambient (환경광)
  • IdI_d: Diffuse (확산광)
  • IsI_s: Specular (반사광)
  • N\mathbf{N}: 표면 법선 벡터
  • L\mathbf{L}: 광원 방향 벡터
  • R\mathbf{R}: 반사 벡터
  • V\mathbf{V}: 시선 벡터
  • α\alpha: Shininess (광택도)

PBR (Physically Based Rendering):

Unity의 Standard Shader는 PBR 기반:

  • Albedo: 기본 색상
  • Metallic: 금속성 (0: 비금속, 1: 금속)
  • Smoothness: 표면 매끄러움
  • Normal Map: 표면 디테일
  • Emission: 자체 발광

7.5 Culling과 Occlusion

Frustum Culling:

  • 카메라 시야 밖 객체 제거
  • 자동으로 수행됨

Occlusion Culling:

  • 다른 객체에 가려진 객체 제거
  • 수동으로 Bake 필요
// Occlusion Culling 영역 설정
OcclusionArea area = gameObject.AddComponent<OcclusionArea>();
area.size = new Vector3(50, 10, 50);

Distance Culling:

// Camera의 최대 렌더링 거리 설정
Camera.main.farClipPlane = 500f;

// Layer별 거리 설정
float[] distances = new float[32];
distances[LayerMask.NameToLayer("Details")] = 50f;
Camera.main.layerCullDistances = distances;

7.6 Render Pipeline

Unity는 여러 렌더 파이프라인을 지원합니다:

1. Built-in Render Pipeline:

  • 전통적인 방식
  • 범용적이나 최적화 제한적

2. URP (Universal Render Pipeline):

  • 모바일 최적화
  • 단일 패스 forward rendering
  • Shader Graph 지원

3. HDRP (High Definition Render Pipeline):

  • 고품질 그래픽
  • PC/콘솔 타겟
  • Deferred rendering

Rendering Path 비교:

특성ForwardDeferred
조명 수제한적 (픽셀당)무제한 (씬당)
성능조명↑ 시 저하안정적
투명지원제한적
MSAA지원비지원

Reference:

  • Real-Time Rendering, 4th Edition, Akenine-Möller et al. (CRC Press, 2018)
  • Unity Documentation: "Graphics" (Unity Technologies, 2024)
  • Physically Based Rendering, 3rd Edition, Pharr, Jakob & Humphreys (Morgan Kaufmann, 2016)

8. Animation 시스템

8.1 Animator Component

Unity는 Mecanim이라는 상태 기반 애니메이션 시스템을 사용합니다.

핵심 구성 요소:

  • Animation Clip: 실제 애니메이션 데이터
  • Animator Controller: 상태 머신 그래프
  • Avatar: 휴머노이드 리깅 정보

8.2 Animator Controller

상태 머신 (State Machine):

      Entry
        ↓
      Idle ←→ Run
        ↓
      Jump
        ↓
     Falling
        ↓
       Land → Idle

Transition 조건:

  • Parameters: Bool, Float, Int, Trigger
  • Conditions: 조건식 설정
  • Exit Time: 애니메이션 종료 시 전환
Animator animator;

// Parameter 설정
animator.SetBool("isRunning", true);
animator.SetFloat("speed", 5.0f);
animator.SetInteger("weaponType", 2);
animator.SetTrigger("jump"); // 한 번만 트리거

// 상태 확인
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
bool isJumping = stateInfo.IsName("Jump");
float normalizedTime = stateInfo.normalizedTime; // 0~1

8.3 Blend Tree

여러 애니메이션을 부드럽게 혼합:

1D Blend:

  • 속도에 따라 Idle → Walk → Run

2D Blend:

  • X축: 좌우 이동
  • Y축: 전후 이동
  • 8방향 이동 애니메이션
// Blend parameter 설정
animator.SetFloat("velocityX", Input.GetAxis("Horizontal"));
animator.SetFloat("velocityZ", Input.GetAxis("Vertical"));

8.4 Animation Layering

여러 레이어로 애니메이션 합성:

Base Layer (전신)
    ↓
Upper Body Layer (상체만)
    ↓
IK Layer (손/발 위치 조정)

Layer 설정:

  • Weight: 레이어 영향력 (0~1)
  • Blending: Override vs Additive
  • Mask: 특정 뼈만 영향
// Layer weight 조정
animator.SetLayerWeight(1, 0.7f); // Upper body layer 70%

8.5 Inverse Kinematics (IK)

Forward Kinematics (FK):

  • 관절 각도 → 끝점 위치
  • 애니메이션 기본 방식

Inverse Kinematics (IK):

  • 끝점 위치 → 관절 각도
  • 손으로 물체 잡기, 발을 지면에 고정
void OnAnimatorIK(int layerIndex)
{
    if (animator)
    {
        // 손 IK
        animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1.0f);
        animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1.0f);
        animator.SetIKPosition(AvatarIKGoal.RightHand, targetPosition);
        animator.SetIKRotation(AvatarIKGoal.RightHand, targetRotation);
        
        // Look At (시선 처리)
        animator.SetLookAtWeight(1.0f);
        animator.SetLookAtPosition(lookTarget.position);
    }
}

8.6 Animation Events

애니메이션 타임라인에 이벤트 삽입:

// Animation Clip의 특정 시점에 설정
// 자동으로 호출되는 함수
void OnFootstep()
{
    // 발소리 재생
    AudioSource.PlayClipAtPoint(footstepSound, transform.position);
}

void OnAttackHit()
{
    // 공격 판정
    Collider[] hits = Physics.OverlapSphere(attackPoint.position, attackRadius);
    foreach (var hit in hits)
    {
        if (hit.CompareTag("Enemy"))
        {
            hit.GetComponent<Health>().TakeDamage(attackDamage);
        }
    }
}

8.7 Root Motion

애니메이션의 이동을 GameObject에 적용:

// Animator에서 Root Motion 활성화
animator.applyRootMotion = true;

// Root Motion 콜백
void OnAnimatorMove()
{
    // 애니메이션의 이동량 가져오기
    Vector3 deltaPosition = animator.deltaPosition;
    
    // 커스텀 처리 (예: 중력 추가)
    deltaPosition += Physics.gravity * Time.deltaTime;
    
    // 적용
    transform.position += deltaPosition;
}

Reference:

  • Unity Documentation: "Animation System" (Unity Technologies, 2024)
  • Game Engine Architecture, 3rd Edition, Jason Gregory (CRC Press, 2018)

9. UI 시스템 (uGUI)

9.1 Canvas

모든 UI는 Canvas 내부에 존재해야 합니다.

Render Mode:

  1. Screen Space - Overlay:

    • 화면에 직접 렌더링
    • 모든 3D 객체 위에 표시
    • 가장 빠름
  2. Screen Space - Camera:

    • 특정 카메라 기준으로 렌더링
    • UI와 3D 객체 간 깊이 조절 가능
  3. World Space:

    • 3D 공간의 객체로 취급
    • 게임 내 UI (HP바 등)

Canvas Scaler:

화면 해상도에 따른 UI 크기 조정:

CanvasScaler scaler = canvas.GetComponent<CanvasScaler>();

// Constant Pixel Size: 픽셀 기준 (고정 크기)
scaler.uiScaleMode = CanvasScaler.ScaleMode.ConstantPixelSize;

// Scale With Screen Size: 참조 해상도 기준 (비율 유지)
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920, 1080);
scaler.matchWidthOrHeight = 0.5f; // 0: width, 1: height

9.2 RectTransform

UI 요소의 Transform은 RectTransform을 사용합니다.

Anchor (앵커):

  • UI 요소의 기준점
  • 부모 크기 변경 시 상대적 위치 유지
RectTransform rect = GetComponent<RectTransform>();

// Anchored Position
rect.anchoredPosition = new Vector2(0, 0);

// Size
rect.sizeDelta = new Vector2(200, 100);

// Pivot (회전/스케일 중심)
rect.pivot = new Vector2(0.5f, 0.5f); // 중앙

// Anchor Preset
rect.anchorMin = new Vector2(0, 1); // 좌상단
rect.anchorMax = new Vector2(0, 1);

Stretching:
앵커를 펼쳐 부모 크기에 따라 늘어나게 설정:

// 전체 화면 stretch
rect.anchorMin = new Vector2(0, 0);
rect.anchorMax = new Vector2(1, 1);
rect.offsetMin = Vector2.zero;
rect.offsetMax = Vector2.zero;

9.3 주요 UI 컴포넌트

Image:

Image image = GetComponent<Image>();
image.sprite = mySprite;
image.color = Color.red;
image.fillAmount = 0.5f; // HP 바 등에 사용
image.type = Image.Type.Filled;

TextMeshPro (TMP) - 권장:

TextMeshPro는 Unity의 최신 텍스트 렌더링 시스템으로, 레거시 Text보다 훨씬 우수한 품질과 성능을 제공합니다.

설치:

  • Package Manager에서 "TextMeshPro" 설치 (Unity 2018.1 이후 기본 포함)
  • 첫 사용 시 Essential Resources 임포트

TMP의 장점:

  • 고품질 렌더링: SDF (Signed Distance Field) 기반
  • 스케일 독립적: 해상도와 무관하게 선명
  • 풍부한 텍스트 효과: Outline, Shadow, Glow 등
  • 성능 우수: 더 적은 드로우콜
  • 리치 텍스트: HTML 스타일 태그 지원
using TMPro;

// TextMeshProUGUI (UI용)
TextMeshProUGUI tmpText = GetComponent<TextMeshProUGUI>();
tmpText.text = "Score: 100";
tmpText.fontSize = 24;
tmpText.alignment = TextAlignmentOptions.Center;
tmpText.fontStyle = FontStyles.Bold;

// 리치 텍스트
tmpText.text = "<color=red>HP:</color> <b>100</b>";
tmpText.text = "<size=150%>Big Text</size>";
tmpText.text = "<link=\"url\">Clickable Link</link>";

// 그라디언트
tmpText.enableVertexGradient = true;
tmpText.colorGradient = new VertexGradient(
    Color.white,  // Top Left
    Color.white,  // Top Right
    Color.blue,   // Bottom Left
    Color.blue    // Bottom Right
);

// Outline
tmpText.outlineWidth = 0.2f;
tmpText.outlineColor = Color.black;

// TextMeshPro (3D 공간용)
TextMeshPro tmp3D = GetComponent<TextMeshPro>();
tmp3D.text = "World Space Text";

Legacy UI.Text (사용 비권장):

using UnityEngine.UI;

Text text = GetComponent<Text>();
text.text = "Score: 100";
text.fontSize = 24;
text.alignment = TextAnchor.MiddleCenter;
// 스케일 시 픽셀화, 성능 저하

마이그레이션:

  • GameObject 선택 > Context Menu > "Convert to TextMeshPro"
  • 또는 새로 생성: UI > Text - TextMeshPro

Button:

Button button = GetComponent<Button>();
button.onClick.AddListener(OnButtonClicked);

void OnButtonClicked()
{
    Debug.Log("Button clicked!");
}

Slider:

Slider slider = GetComponent<Slider>();
slider.minValue = 0f;
slider.maxValue = 100f;
slider.value = 50f;
slider.onValueChanged.AddListener(OnSliderValueChanged);

void OnSliderValueChanged(float value)
{
    Debug.Log($"Slider value: {value}");
}

9.4 Layout System

자동으로 UI 배치를 관리:

Layout Group:

  • Horizontal Layout Group: 가로 배치
  • Vertical Layout Group: 세로 배치
  • Grid Layout Group: 격자 배치

Layout Element:

LayoutElement element = GetComponent<LayoutElement>();
element.preferredWidth = 200f;
element.preferredHeight = 100f;
element.flexibleWidth = 1f; // 남은 공간 분배 비율

Content Size Fitter:
내용물 크기에 맞춰 자동 조정:

ContentSizeFitter fitter = GetComponent<ContentSizeFitter>();
fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;

9.5 Event System

UI 상호작용을 처리:

Raycast:
UI는 Graphic Raycaster를 통해 클릭 감지:

using UnityEngine.InputSystem; // New Input System용

// UI 요소 클릭 여부 확인
bool isPointerOverUI = EventSystem.current.IsPointerOverGameObject();

// Raycast 결과 가져오기
PointerEventData eventData = new PointerEventData(EventSystem.current);

// Legacy Input
eventData.position = Input.mousePosition;

// New Input System
eventData.position = Mouse.current.position.ReadValue();

List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, results);

이벤트 인터페이스:

public class MyButton : MonoBehaviour, 
    IPointerEnterHandler, 
    IPointerExitHandler,
    IPointerClickHandler
{
    public void OnPointerEnter(PointerEventData eventData)
    {
        // 마우스 오버
    }
    
    public void OnPointerExit(PointerEventData eventData)
    {
        // 마우스 아웃
    }
    
    public void OnPointerClick(PointerEventData eventData)
    {
        // 클릭
    }
}

9.6 ScrollView

스크롤 가능한 컨텐츠:

ScrollRect scrollRect = GetComponent<ScrollRect>();
scrollRect.content = contentTransform;
scrollRect.vertical = true;
scrollRect.horizontal = false;
scrollRect.scrollSensitivity = 20f;

// 스크롤 위치 제어
scrollRect.normalizedPosition = new Vector2(0, 1); // 최상단

동적 컨텐츠 추가:

void AddItem(GameObject itemPrefab)
{
    GameObject item = Instantiate(itemPrefab, content);
    // Layout Group이 자동으로 배치
}

Reference:

  • Unity Documentation: "UI System" (Unity Technologies, 2024)
  • Unity Documentation: "TextMesh Pro" (Unity Technologies, 2024)

10. 최적화 기법

10.1 프로파일링

최적화의 시작은 측정입니다:

Unity Profiler:

  • CPU Usage: 각 시스템별 시간 소모
  • GPU Usage: 렌더링 비용
  • Memory: 할당 및 GC
  • Rendering: Draw Call, Batch 등
// 커스텀 프로파일링
using Unity.Profiling;

ProfilerMarker myMarker = new ProfilerMarker("MySystem.Update");

void Update()
{
    myMarker.Begin();
    // 측정할 코드
    myMarker.End();
}

10.2 렌더링 최적화

Draw Call 감소:

Draw Call은 CPU가 GPU에게 내리는 렌더링 명령입니다. 많을수록 성능 저하.

Batching:

  1. Static Batching:
    • 움직이지 않는 객체들을 하나의 메시로 결합
    • 메모리 증가, Draw Call 감소
// Static으로 마킹
gameObject.isStatic = true;
  1. Dynamic Batching:

    • 작은 동적 객체들을 자동 결합
    • 조건: 같은 Material, 300 vertices 이하
  2. GPU Instancing:

    • 같은 메시를 여러 번 그릴 때
    • Material에서 "Enable GPU Instancing" 체크
// Material Property Block으로 인스턴스별 속성
MaterialPropertyBlock props = new MaterialPropertyBlock();
props.SetColor("_Color", color);
renderer.SetPropertyBlock(props);

Occlusion Culling:
앞서 설명한 대로, 보이지 않는 객체를 렌더링하지 않음.

Level of Detail (LOD):
거리에 따라 메시 복잡도 변경:

LODGroup lodGroup = gameObject.AddComponent<LODGroup>();
LOD[] lods = new LOD[3];

lods[0] = new LOD(0.5f, highDetailRenderers); // 50% 이상
lods[1] = new LOD(0.2f, midDetailRenderers);  // 20~50%
lods[2] = new LOD(0.0f, lowDetailRenderers);  // 20% 이하

lodGroup.SetLODs(lods);

10.3 물리 최적화

Layer Collision Matrix:
불필요한 충돌 검사 제거:

// Edit > Project Settings > Physics
// Layer Collision Matrix에서 체크 해제
Physics.IgnoreLayerCollision(playerLayer, playerLayer);

Fixed Timestep 조정:

// Edit > Project Settings > Time
Time.fixedDeltaTime = 0.02f; // 기본값 50Hz
// 더 높은 값 = 더 빠르지만 덜 정확

Collider 최적화:

  • Primitive Collider 사용 (Box, Sphere, Capsule)
  • Mesh Collider는 최소화
  • Convex Mesh Collider 사용 (동적 객체)

10.4 스크립팅 최적화

1. 캐싱:

// BAD
void Update()
{
    GetComponent<Rigidbody>().AddForce(force); // 매 프레임 탐색
}

// GOOD
private Rigidbody rb;

void Awake()
{
    rb = GetComponent<Rigidbody>(); // 한 번만
}

void Update()
{
    rb.AddForce(force);
}

2. 불필요한 Update 방지:

// Update가 필요 없는 경우
public class StaticObject : MonoBehaviour
{
    void Awake()
    {
        // 초기화만
        enabled = false; // Update 호출 안됨
    }
}

3. 태그 비교 최적화:

// BAD
if (other.tag == "Player") { }

// GOOD
if (other.CompareTag("Player")) { } // 문자열 비교 최적화됨

4. 벡터 연산 최적화:

// BAD
float distance = Vector3.Distance(a, b);
if (distance < threshold) { }

// GOOD (제곱근 연산 생략)
float sqrDistance = (a - b).sqrMagnitude;
if (sqrDistance < threshold * threshold) { }

10.5 메모리 최적화

Object Pooling:
앞서 설명한 패턴 사용.

Texture 압축:

  • Android: ETC2
  • iOS: PVRTC, ASTC
  • PC: DXT

Texture Atlas:
여러 텍스처를 하나로 결합하여 Draw Call 감소.

Mesh 최적화:

// Mesh 최적화
mesh.Optimize();

// Read/Write 비활성화 (메모리 절약)
// Import Settings > Read/Write Enabled 체크 해제

10.6 모바일 최적화

해상도 조정:

// 동적 해상도
Screen.SetResolution(1280, 720, true);

// 렌더 스케일 (더 효율적)
QualitySettings.renderScale = 0.8f; // 80% 해상도

FPS 제한:

Application.targetFrameRate = 60; // 모바일에서 배터리 절약

MultiThreaded Rendering:

// Player Settings > Other Settings
// Graphics Jobs (Experimental) 활성화

10.7 최적화 체크리스트

렌더링:

  • Static Batching 활성화
  • GPU Instancing 사용
  • Occlusion Culling 설정
  • LOD 그룹 설정
  • Texture 압축
  • 적절한 셰이더 사용

물리:

  • Layer Collision Matrix 최적화
  • Fixed Timestep 조정
  • Primitive Collider 사용
  • Rigidbody 개수 최소화

스크립팅:

  • Component 캐싱
  • Update 최소화
  • Object Pooling
  • sqrMagnitude 사용
  • CompareTag 사용

메모리:

  • Texture 압축
  • Audio 압축
  • Mesh 최적화
  • Resources.UnloadUnusedAssets() 호출

Reference:

  • Unity Documentation: "Optimization" (Unity Technologies, 2024)
  • Unity Performance Optimization, Chris Dickinson (Packt, 2015)

마치며

본 가이드는 Unity의 핵심 개념과 실무 활용을 물리/수학적 원리와 함께 정리한 것입니다. 각 섹션의 내용을 숙지하고 실제로 구현해보는 것이 중요합니다.

학습 권장 순서:
1. GameObject-Component 시스템 이해
2. Transform과 좌표계 마스터
3. 물리 엔진 실습
4. Coroutine으로 비동기 처리
5. UI 시스템 구축
6. 최적화 기법 적용

추가 학습 자료:


작성 일자: 2025년 10월 20일
대상: Unity 개발자 (중급)
필요 배경: C#, 물리학, 수학 기초

References:
1. Unity Technologies. (2024). Unity Documentation. https://docs.unity3d.com
2. Gregory, J. (2018). Game Engine Architecture (3rd ed.). CRC Press.
3. Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley.
4. Dunn, F., & Parberry, I. (2011). 3D Math Primer for Graphics and Game Development (2nd ed.). CRC Press.
5. Goldstein, H., Poole, C., & Safko, J. (2001). Classical Mechanics (3rd ed.). Addison-Wesley.
6. Ericson, C. (2004). Real-Time Collision Detection. Morgan Kaufmann.
7. Skeet, J. (2019). C# in Depth (4th ed.). Manning.
8. Akenine-Möller, T., Haines, E., Hoffman, N., et al. (2018). Real-Time Rendering (4th ed.). CRC Press.
9. Pharr, M., Jakob, W., & Humphreys, G. (2016). Physically Based Rendering (3rd ed.). Morgan Kaufmann.
10. Dickinson, C. (2015). Unity 5 Game Optimization. Packt.

profile
RL Researcher, Video Game Developer

0개의 댓글