내일배움캠프 72일차 TIL : 저장기능 완료, 모의면접 문법 45-51

woollim·2일 전
0

내일배움캠프TIL

목록 보기
65/66
post-thumbnail

■ 개요

○ 오늘 계획

  • UGS 커스텀 이벤트 추가하기
  • stove에 빌드 올리고 검수요청(테스트먼저)
  • 저장 기능 버그 찾기
    • 인벤토리 첫 무기 자동지급 코드 위치 물어보고 if문 처리하기
    • 장착 관리 위치 묻기
  • 테스트 질문 항목 만들기
  • 테스트 홍보 문구 작성


■ 인벤토리 저장기능

  • 직렬화를 위해 기존 프로퍼티였던 변수들을 필드로 변경
  • 직렬화를 위해 클래스위에 [System.Serializable] 추가했음

○ 인벤토리 모델 구조

  • 딕셔너리가 있기 때문에 직렬화를 위해 리스트로 변경할 필요가 있음
public class InventoryModel
{
    // weapon정보들 키(int)는 슬롯의 index와 같다.
    public Dictionary<int, WeaponInfo> weaponDatas { get; private set; } = new ();

    // 장비가 아닌 아이템 인벤토리. 키(int)는 슬롯의 index와 같습니다.
    public Dictionary<int, GenericItemInfo> itemDatas { get; private set; } = new ();
    // 아이템 인벤토리의 아이템 개수입니다. 키(int)는 아이템 슬롯의 index와 같습니다.
    public Dictionary<int, int> itemCounts { get; private set; } = new ();

    //인벤토리 업데이트 콜백
    public Action OnInventoryUpdated;

    //현재 생성된 슬롯의 개수
    public int curSlotCounts;
}

○ 리스트로 변환된 데이터를 담을 그릇 클래스

using System.Collections.Generic;
[System.Serializable]
public class SerializableInventoryModel
{
    public List<WeaponData> weaponDatas = new List<WeaponData>();
    public List<ItemData> itemDatas = new List<ItemData>();
    public int curSlotCounts;

    [System.Serializable]
    public class WeaponData
    {
        public int slotIndex;
        public WeaponInfo weaponInfo;
    }

    [System.Serializable]
    public class ItemData
    {
        public int slotIndex;
        public GenericItemInfo itemInfo;
        public int itemCount;
    }
}

○ 세이브로드 매니저

    public void LoadPlayerDataBase()
    {
        if (FileExists() == false)
        {
            Logger.Log("저장된 파일 없음");
            LoadGameDatas<PlayerDataBase, PlayerData>();
            LoadGameDatas<PlayerDataBase, PlayerStatData>();

            existFile = false;
        }
        else
        {
            Logger.Log("저장된 파일 로드");
            Logger.Log(PlayerDataFilePath);
            string json = File.ReadAllText(PlayerDataFilePath);
            Managers.Data.PlayerDataBase = JsonUtility.FromJson<PlayerDataBase>(json);

            existFile = true;
        }
    }
    /// <summary>
    /// InventoryModel -> SerializableInventoryModel 변환해주는 함수 입니다.
    /// </summary>
    /// <param name="inventoryModel">직렬화 되기전 인벤정보</param>
    /// <returns>직렬화된 인벤정보</returns>
    private SerializableInventoryModel ConvertToSerializable(InventoryModel inventoryModel)
    {
        var serializableModel = new SerializableInventoryModel();
        serializableModel.curSlotCounts = inventoryModel.curSlotCounts;

        foreach (var invenWeapon in inventoryModel.weaponDatas)
        {
            serializableModel.weaponDatas.Add(new SerializableInventoryModel.WeaponData
            {
                slotIndex = invenWeapon.Key,
                weaponInfo = invenWeapon.Value
            });
        }

        foreach (var invenItem in inventoryModel.itemDatas)
        {
            serializableModel.itemDatas.Add(new SerializableInventoryModel.ItemData
            {
                slotIndex = invenItem.Key,
                itemInfo = invenItem.Value,
                itemCount = inventoryModel.itemCounts[invenItem.Key]
            });
        }

        return serializableModel;
    }

    /// <summary>
    /// InventoryModel 저장하는 함수입니다.
    /// </summary>
    /// <param name="inventoryModel">인벤 저장 정보</param>
    public void SaveInventoryModel(InventoryModel inventoryModel)
    {
        var serializableModel = ConvertToSerializable(inventoryModel);
        string json = JsonUtility.ToJson(serializableModel, true);
        System.IO.File.WriteAllText(InvenDataFilePath, json);
        Debug.Log($"InventoryModel 저장 완료: {InvenDataFilePath}");
    }

    /// <summary>
    /// SerializableInventoryModel -> InventoryModel 변환 해주는 함수입니다.
    /// </summary>
    /// <param name="serializableModel">직렬화된 인벤 정보</param>
    /// <returns>변환된 인벤토리 정보</returns>
    private InventoryModel ConvertToInventoryModel(SerializableInventoryModel serializableModel)
    {
        var inventoryModel = new InventoryModel();
        inventoryModel.InitDic(serializableModel.curSlotCounts);

        foreach (var weaponData in serializableModel.weaponDatas)
        {
            if (weaponData.weaponInfo.ID == 0)
                continue;
            if (weaponData.weaponInfo.isEquip)
                weaponData.weaponInfo.isEquip = false;
            inventoryModel.weaponDatas[weaponData.slotIndex] = weaponData.weaponInfo;
        }

        foreach (var itemData in serializableModel.itemDatas)
        {
            if(itemData.itemCount == 0)
                continue;
            inventoryModel.itemDatas[itemData.slotIndex] = itemData.itemInfo;
            inventoryModel.itemCounts[itemData.slotIndex] = itemData.itemCount;
        }

        return inventoryModel;
    }

    /// <summary>
    /// 저장된 InventoryModel를 불러오는 함수입니다.
    /// </summary>
    /// <returns>변환된 인벤토리 정보</returns>
    public InventoryModel LoadInventoryModel()
    {
        if (!System.IO.File.Exists(InvenDataFilePath))
        {
            Debug.LogWarning("저장된 인벤토리가 없습니다.");
            return null;
        }

        string json = System.IO.File.ReadAllText(InvenDataFilePath);
        var serializableModel = JsonUtility.FromJson<SerializableInventoryModel>(json);
        Debug.Log("InventoryModel 불러오기 완료");
        return ConvertToInventoryModel(serializableModel);
    }

○ 인벤토리 초기화 할때 저장데이터 검사

public class InventoryPresenter : MonoBehaviour
{
    #region 변수
    // 뷰어
    [SerializeField] private UIInventory inventoryViewer;

    // 슬롯의 우클릭할 시 나오는 작은 메뉴창
    [SerializeField] private UIItemActionPopup actionPopup;

    // 판매 팝업
    [SerializeField] private PurchasePopup sellPopup;

    //모델
    private InventoryModel inventoryModel;

    //드래그했을때 나오는 무기의 아이콘
    private Image followImage;

    //현재 인벤토리에서 보이고 있는 창
    public InventoryView curView = InventoryView.Equip;

    //툴팁패널
    private UITooltipPanel tooltipPanel;

    #endregion

    #region Unity함수
    /// <summary>
    /// 초기화 및 이벤트 연결
    /// </summary>
    private void Awake()
    {
        inventoryModel = new InventoryModel();
        
        //인벤저장&로드 관련 이벤트 연결
        Managers.SaveLoad.saveFileInvenData += SaveInvenData;

        if (Managers.SaveLoad.FileExists())
        {
            Logger.Log("인벤저장 불러오기");
            inventoryModel = Managers.SaveLoad.LoadInventoryModel();
        }
        else
        {
            inventoryModel.InitDic(inventoryViewer.totalSlotCount);
        }

        // 모델 업데이트 시 뷰를 갱신
        inventoryModel.OnInventoryUpdated += UpdateView;
}



■ 모의면접 문법 45-53

○ 45. Unity에서 멀티스레딩을 구현하기 위한 방법에 대해 설명해주세요.

  • Unity는 기본적으로 메인 스레드에서 동작하도록 설계되어 있음
  • Unity의 C# 스레드 사용 :
    • Unity는 표준 C# 스레드를 지원하므로 System.Threading 네임스페이스를 사용하여 일반적인 스레드를 구현할 수 있음
    • 스레드를 생성하고 작업을 배분한 뒤, Unity 오브젝트를 직접 수정하지 않도록 주의해야함.
      Unity의 게임 오브젝트 및 API 호출은 반드시 메인 스레드에서 이루어져야 함
using System.Threading;

void Start()
{
    Thread thread = new Thread(HeavyTask);
    thread.Start();
}

void HeavyTask()
{
    // 시간이 오래 걸리는 작업 수행
    Debug.Log("Heavy task running on a separate thread.");
}
  • Task 및 async/await 활용 :
    • C#의 Task 및 비동기 프로그래밍 기능을 활용하면 멀티스레딩을 간단히 구현할 수 있습니다.
    • 작업이 완료된 후 Unity의 메인 스레드로 돌아오기 위해 UnityMainThreadDispatcher와 같은 라이브러리를 사용할 수도 있습니다.
      csharp
      코드 복사
async void Start()
{
    await PerformHeavyTaskAsync();
    Debug.Log("Task completed on the main thread.");
}

async Task PerformHeavyTaskAsync()
{
    await Task.Run(() => {
        // 오래 걸리는 작업
        Thread.Sleep(2000);
    });
}
  • Unity의 Job System
    • Unity의 Job System은 데이터 지향 설계와 멀티스레딩을 쉽게 구현할 수 있도록 지원합니다.
    • NativeArray 및 Burst Compiler와 함께 사용하면 성능 최적화를 극대화할 수 있습니다.
using Unity.Jobs;
using Unity.Collections;
using UnityEngine;

public class JobSystemExample : MonoBehaviour
{
    void Start()
    {
        NativeArray<int> numbers = new NativeArray<int>(10, Allocator.TempJob);
        MyJob job = new MyJob { Numbers = numbers };

        JobHandle handle = job.Schedule();
        handle.Complete();

        for (int i = 0; i < numbers.Length; i++)
        {
            Debug.Log(numbers[i]);
        }

        numbers.Dispose();
    }

    struct MyJob : IJob
    {
        public NativeArray<int> Numbers;

        public void Execute()
        {
            for (int i = 0; i < Numbers.Length; i++)
            {
                Numbers[i] = i * i;
            }
        }
    }
}
  • Unity ECS (Entity Component System)와 결합 :

    • ECS는 Unity Job System과 통합되어 성능 최적화를 더욱 쉽게 달성할 수 있습니다.
    • 데이터를 순수하게 관리하고 대규모 멀티스레딩 작업을 처리하는 데 적합합니다.
  • 주의 사항

    • 멀티스레딩은 항상 동기화 문제(데드락, 레이스 컨디션 등)를 발생시킬 수 있으므로 이를 방지하기 위한 메커니즘(락, 세마포어 등)을 적절히 사용해야 합니다.
    • Unity API를 메인 스레드에서만 호출할 수 있으므로 멀티스레드 작업은 데이터 처리 등 독립적인 작업에만 활용해야 합니다.

○ 46. CPU와 GPU의 작동 방법은 어떤 차이가 있는지 설명해주세요.

  • 요약 : CPU는 복잡한 단일 작업을 처리하는 데 적합하며, GPU는 많은 단순 작업을 동시에 처리하는 데 특화되어 있습니다. 현대 컴퓨팅 환경에서는 CPU와 GPU가 서로 보완적인 역할을 수행 합니다.

  • CPU (Central Processing Unit)

    • CPU는 컴퓨터의 "중앙 처리 장치"로, 다양한 작업을 처리할 수 있는 범용 프로세서입니다.

    • 코어 구조:

      • CPU는 적은 수의 고성능 코어(예: 4~16개)를 가지고 있으며, 복잡한 작업을 효율적으로 처리할 수 있도록 설계되었습니다.
      • 최신 CPU는 멀티스레드 기능을 지원하며, 각 코어가 여러 작업을 동시에 처리할 수 있습니다.
    • 처리 능력:

      • CPU는 직렬 작업(순차적으로 처리해야 하는 작업)에 특화되어 있습니다.
      • 명령어 세트가 다양하며, 복잡한 논리적 연산과 제어 작업에 강합니다.
    • 속도와 캐시:

      • CPU는 고속 클럭 속도로 작동하며, L1, L2, L3 캐시를 통해 데이터를 빠르게 액세스합니다.
      • 상대적으로 높은 지연 시간에도 복잡한 계산을 빠르게 수행합니다.
    • 유형별 작업:
      - 운영 체제 관리, 애플리케이션 로직 실행, 일반 계산 처리 등 범용적인 역할.

  • GPU (Graphics Processing Unit)

    • GPU는 대량의 간단한 연산을 동시에 수행할 수 있도록 설계된 병렬 처리 장치입니다. 주로 그래픽 렌더링 및 대규모 병렬 계산에 사용됩니다.
    • 코어 구조:
      • GPU는 수천 개의 작은 코어를 가지고 있어 병렬 작업을 대량으로 처리할 수 있습니다.
      • 각 코어는 상대적으로 간단하며, 단일 작업을 반복적으로 수행하는 데 적합합니다.
    • 처리 능력:
      • GPU는 병렬 작업(동시에 수행할 수 있는 작업)에 특화되어 있습니다.
      • 단순한 연산(벡터 연산, 행렬 연산 등)에 효율적입니다.
    • 속도와 메모리:
      • GPU는 전용 고속 메모리(GDDR)를 사용하여 대량의 데이터를 빠르게 처리합니다.
      • 그래픽 작업 외에도 머신러닝, 데이터 분석, 과학 계산 등에 활용됩니다.
    • 유형별 작업:
      - 3D 그래픽 렌더링, 비디오 처리, 딥러닝 및 AI 훈련 등.

  • CPU와 GPU의 비교

  • 실제 사용 사례


○ 47. 월드 스페이스 (World Space) 와 로컬 스페이스 (Local Space)의 차이에 대해 설명해주세요.

  • Unity에서 월드 스페이스와 로컬 스페이스는 게임 오브젝트의 위치, 회전, 스케일을 표현할 때 사용하는 두 가지 좌표 체계입니다. 두 스페이스의 차이는 주로 참조 기준에 따라 달라집니다.

  • 월드 스페이스 (World Space)

    • 월드 스페이스는 전체 게임 월드를 기준으로 좌표와 변환을 정의합니다.
    • 기준: 월드 좌표계는 고정된 전역 기준점을 가지고 있습니다. (예: 씬의 (0, 0, 0) 위치)
    • 사용 목적:
      • 오브젝트가 씬 전체에서의 절대적인 위치와 방향을 나타냅니다.
      • 서로 다른 오브젝트 간의 절대적인 관계를 설정할 때 사용됩니다.
    • 예제:
      • (5, 10, 3)이라는 위치는 월드 스페이스에서 씬의 기준점 (0, 0, 0)에서 X축으로 5, Y축으로 10, Z축으로 3만큼 떨어진 위치를 나타냅니다.
    • 응용:
      • 카메라를 기준으로 특정 위치에 오브젝트를 배치하거나, 특정 좌표로 오브젝트를 이동시키고 싶을 때 사용합니다.
    • 코드
// 월드 스페이스에서 오브젝트 이동
transform.position = new Vector3(5, 10, 3);

  • 로컬 스페이스 (Local Space)

    • 로컬 스페이스는 오브젝트 자신 또는 부모 오브젝트를 기준으로 좌표와 변환을 정의합니다.
    • 기준: 로컬 좌표계는 해당 오브젝트 또는 부모 오브젝트를 기준점으로 합니다.
    • 사용 목적:
      • 부모-자식 관계에서 오브젝트가 부모 오브젝트에 상대적인 위치, 회전, 스케일을 나타냅니다.
      • 계층 구조에서 오브젝트의 상대적인 변환을 쉽게 조정할 수 있습니다.
    • 예제:
      • (1, 0, 0)이라는 로컬 좌표는 부모 오브젝트의 기준점에서 X축으로 1만큼 떨어져 있는 위치를 나타냅니다.
      • 부모 오브젝트가 회전하면, 자식의 로컬 스페이스 좌표는 그 부모의 방향을 따라 변경됩니다.
    • 응용:
      • 캐릭터의 손에 무기를 들거나, 특정 오브젝트가 부모 오브젝트를 중심으로 회전하거나 움직이도록 할 때 유용합니다.
    • 코드
// 로컬 스페이스에서 오브젝트 이동
transform.localPosition = new Vector3(1, 0, 0);

  • 차이점 비교




○ 48. 벡터의 내적과 외적을 어느 상황에 사용할 수 있는지 설명해주세요.

  • Unity에서 벡터의 내적(Dot Product)외적(Cross Product)은 게임 개발에서 방향 계산, 충돌 감지, 회전, 정렬 등의 작업에 자주 사용됩니다.

  • 내적(Dot Product)

    • 정의:
      • 두 벡터의 내적은 두 벡터 간의 각도 관계를 나타냅니다.
      • 값의 범위는 -1에서 1 사이이며, 두 벡터가 직교하면 0입니다.
    • 공식:
      • A ⋅ B = ∣A∣ ⋅ ∣B∣ ⋅ cosθ
      • 여기서 θ는 두 벡터 사이의 각도입니다.
    • 특징:
      • cosθ 값에 따라 결과
        - 1: 두 벡터가 같은 방향.
        - 0: 두 벡터가 직교.
        - -1: 두 벡터가 반대 방향.
    • 사용 상황:
      • 광원 조명 계산 (라이트 닿는 정도) : 광원이 표면에 얼마나 직각으로 닿는지 계산.
      • 시야각(FOV) 검사 : AI가 플레이어를 감지할 때, 시야각 안에 있는지를 판단.
      • 두 벡터의 방향 비교:
        • 예를 들어, 플레이어가 특정 방향을 바라보는지 확인할 때.
Vector3 forward = transform.forward;  // 오브젝트의 전방 벡터
Vector3 toTarget = (target.position - transform.position).normalized;
float dot = Vector3.Dot(forward, toTarget);

if (dot > 0.9f) // 0.9 이상이면 거의 같은 방향
{
    Debug.Log("Target is in front of the object.");
}

  • 외적(Cross Product)
    • 정의:
      • 두 벡터의 외적은 벡터의 수직 방향을 나타내는 새로운 벡터를 생성합니다.
      • 결과는 두 벡터가 이루는 평면에 수직인 벡터입니다.
      • 공식
        - A × B = ∣A∣ ⋅ ∣B∣ ⋅ sinθ ⋅ n
        • 여기서 n은 단위 수직 벡터.
    • 특징
      • 결과 벡터의 방향은 오른손 법칙에 따릅니다.
      • 외적의 크기는 두 벡터가 이루는 평행사변형의 넓이를 나타냅니다.
    • 사용 상황:
      • 법선 벡터(Normal Vector) 계산 : 두 벡터로 이루어진 평면의 법선을 계산할 때.
      • Vector3 normal = Vector3.Cross(vectorA, vectorB).normalized;
    • 회전 방향 결정 : 두 벡터의 상대적 회전 방향(시계/반시계)을 결정할 때.
    • 3D 모델링 및 그래픽스 : 평면의 표면 방향을 구하거나, 삼각형의 면의 방향을 계산할 때.
    • 좌우 또는 위아래 방향 판단 : 특정 방향에서 오브젝트가 왼쪽에 있는지, 오른쪽에 있는지를 확인.
Vector3 cross = Vector3.Cross(forward, toTarget);
if (cross.y > 0)
{
    Debug.Log("Target is on the left.");
}
else
{
    Debug.Log("Target is on the right.");
}

  • 내적과 외적의 차이 요약

  • 실제 게임 개발에서의 응용

    • 내적:
      • AI의 시야각(FOV) 구현.
      • 조명 효과를 계산하여 그림자나 밝기 표현.
    • 외적:
      • 캐릭터의 발판 기울기 계산.
      • 3D 공간에서 오브젝트의 정렬 및 물리적 회전 적용.


○ 49. 쿼터니언을 사용하는 이유에 대해 설명해주세요.

  • Unity에서 쿼터니언을 사용하는 이유는 안정성, 효율성, 정확성 때문입니다. 특히 짐벌 락 문제를 해결하고, 매끄러운 회전 및 효율적인 연산을 제공하므로 게임 개발에서 필수적인 도구로 자리 잡았습니다. Unity는 쿼터니언과 오일러 각도를 모두 제공하지만, 복잡한 회전 계산에서는 쿼터니언이 기본적으로 사용됩니다.

  • 쿼터니안

    • 쿼터니언은 복소수의 확장된 형태로, 3D 회전을 표현하기 위해 4개의 스칼라 값(w, x, y, z)으로 구성된 데이터 구조입니다.

  • (상세)유니티에서 쿼터니언을 사용하는 이유

    • 짐벌 락(Gimbal Lock) 방지

      • 문제: 오일러 각도(Euler Angles)는 회전을 세 축(X, Y, Z)의 연속된 회전으로 표현합니다. 하지만 특정 각도에서 축이 겹치는 짐벌 락(Gimbal Lock) 현상이 발생할 수 있습니다.
      • 해결: 쿼터니언은 축의 겹침 없이 회전을 표현하므로 짐벌 락 문제를 방지할 수 있습니다.
    • 매끄러운 회전(Smooth Interpolation)

      • 쿼터니언은 두 회전 간의 보간(SLERP, Spherical Linear Interpolation)이 가능하여 자연스럽고 매끄러운 회전 애니메이션을 제공합니다.
      • Unity에서는 Quaternion.Slerp()를 사용하여 두 회전 간의 부드러운 전환을 구현할 수 있습니다.
    • 효율적인 연산

      • 쿼터니언은 회전 행렬에 비해 연산이 더 효율적이고 메모리 사용량이 적습니다.
      • 특히 연속적인 회전 연산(예: 오브젝트의 지속적인 회전)에서 성능 상의 이점을 제공합니다.
    • 축과 각도로 회전 표현 가능

      • 쿼터니언은 회전을 하나의 축과 각도로 표현할 수 있어 직관적인 사용이 가능합니다.
      • Unity에서는 Quaternion.AngleAxis()를 사용하여 축과 각도로 회전을 생성할 수 있습니다.
    • 회전의 누적 오류 감소

      • 쿼터니언은 부동소수점 연산에서 발생하는 누적 오류를 최소화합니다.
      • 회전 행렬과 달리 정규화를 통해 항상 단위 쿼터니언(Unit Quaternion)을 유지하므로, 정확도가 높은 회전을 제공합니다.

  • Unity에서 쿼터니언 사용 예제

    • 기본 회전 설정
      // 특정 각도로 회전 설정
      transform.rotation = Quaternion.Euler(45, 30, 60);
    • 축과 각도를 이용한 회전
      // Y축을 기준으로 90도 회전
      Quaternion rotation = Quaternion.AngleAxis(90, Vector3.up);
      transform.rotation = rotation;
    • 두 회전 간 보간
      // A와 B 사이를 부드럽게 보간
      transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime);

  • 쿼터니언과 오일러 각도의 비교


○ 50. 네트워크 프로토콜 (IP, TCP, UDP)에 대해 설명해주세요.

  • 네트워크 프로토콜
    • 컴퓨터 간 데이터 통신을 원활히 하기 위해 정의된 규칙과 표준의 집합
    • IP, TCP, UDP는 인터넷에서 데이터를 송수신하기 위해 사용되는 대표적인 프로토콜

  • IP (Internet Protocol)

    • 정의:
      • IP는 데이터를 송신지에서 목적지까지 전달하는 데 사용되는 기본 프로토콜입니다.
      • 네트워크 계층(Layer 3)에서 작동하며, 데이터 패킷을 분할하고 전송합니다.
    • 특징:
      • 패킷 기반 전송
        • 데이터를 작은 패킷 단위로 나누어 전송하고,
        • 각 패킷에는 송신지와 목적지의 IP 주소가 포함됩니다.
      • 비연결형
        • 데이터 전송 전에 연결을 설정하지 않습니다.
        • 각 패킷은 독립적으로 전송되며, 목적지에 도달하는 경로가 다를 수 있습니다.
      • 최선형 전달 (Best Effort Delivery)
        • 패킷이 손실되거나 순서가 바뀔 수 있습니다.
        • 신뢰성은 상위 계층(TCP 등)에서 보장합니다
    • 역할:
      - IP 주소를 기반으로 데이터의 출발지와 목적지를 식별.
      - 라우팅을 통해 최적 경로를 선택하여 데이터 전송.

  • TCP (Transmission Control Protocol)

    • 정의:
      • TCP는 신뢰성 있는 데이터 전송을 보장하는 프로토콜로, 전송 계층(Layer 4)에서 작동합니다.
      • 연결형 프로토콜로, 데이터 전송 전에 송신자와 수신자 간 연결을 설정합니다.
    • 특징:
      • 연결 지향(Connection-Oriented)
        • 데이터를 전송하기 전에 3-way handshake 과정을 통해 연결을 설정.
        • 연결 종료 시 4-way handshake로 연결을 해제.
      • 신뢰성
        • 데이터 패킷이 손실되면 재전송.
        • 전송 순서를 보장하며, 데이터가 올바르게 재조립되도록 합니다.
      • 흐름 및 혼잡 제어
        • 네트워크 상태에 따라 데이터 전송 속도를 조정하여 혼잡을 방지.
    • 사용사례
      - 웹 브라우징(HTTP, HTTPS), 이메일(SMTP, IMAP), 파일 전송(FTP) 등 신뢰성이 중요한 애플리케이션.

  • UDP (User Datagram Protocol)

    • 정의:
      • UDP는 최소한의 오버헤드로 데이터를 빠르게 전송하는 프로토콜로, 전송 계층(Layer 4)에서 작동합니다.
      • 비연결형 프로토콜로, 데이터 전송 전에 연결을 설정하지 않습니다.
    • 특징:
      • 비연결형(Connectionless)
        • 데이터 전송 전에 연결을 설정하지 않으며, 패킷이 독립적으로 전송됩니다.
      • 속도 우선
        • 신뢰성보다는 빠른 전송이 우선.
        • 데이터 손실이나 순서가 바뀔 수 있지만, 속도가 중요한 경우 적합.
      • 오버헤드 감소
        • TCP보다 헤더가 간단하여 처리 속도가 빠릅니다.
    • 사용사례
      - 실시간 애플리케이션(온라인 게임, 스트리밍, VoIP) 등 속도가 중요한 애플리케이션.

  • 종합적으로 본 네트워크 프로토콜의 역할

    • IP: 데이터를 목적지로 전달하는 기본 경로 제공.
    • TCP: 데이터 전송의 신뢰성을 보장하며, 순서와 재전송을 관리.
    • UDP: 간단하고 빠른 데이터 전송을 제공, 신뢰성보다는 속도가 중요한 경우 적합.



○ 50-1. TCP와 UDP의 차이를 설명해주세요.

TCP와 UDP는 전송 계층에서 데이터를 송수신하는 데 사용되는 두 가지 주요 프로토콜입니다. 이 두 프로토콜은 데이터 전송 방식과 특성이 다르며, 용도에 따라 선택적으로 사용됩니다.

  • 선택기준
    • TCP: 신뢰성과 데이터 무결성이 중요한 경우 사용.
      • 예: 파일 다운로드, 금융 거래, 웹사이트 접속.
    • UDP: 속도가 중요하고 데이터 손실이 허용되는 경우 사용.
      • 예: 실시간 비디오, 온라인 게임, 음성 통화.


○ 51. 렌더링 파이프라인에 대해 설명해주세요.

  • 개념

    • 렌더링 파이프라인(Rendering Pipeline)은 3D 그래픽스에서 화면에 이미지를 그리기 위해 수행되는 일련의 단계 말합니다.
    • 주로 GPU에서 실행되며, 3D 데이터를 2D 화면에 렌더링하는 과정을 체계적으로 처리합니다.

  • 주요 단계

    1. 애플리케이션 단계 (Application Stage)
      • 렌더링에 필요한 데이터를 준비하고 GPU로 전달합니다.
      • 주로 CPU에서 실행되며, 게임 엔진이나 애플리케이션의 논리적 처리와 연관이 있습니다.
      • 작업내용
        • 카메라, 조명, 오브젝트의 위치와 상태 계산.
        • 애니메이션, 물리 연산 및 씬 관리.
        • Draw Call: 그려야 할 객체 정보를 GPU에 전달.
    2. 지오메트리 처리 단계 (Geometry Processing Stage)
      • 3D 모델의 정점 데이터를 처리하고 화면 좌표로 변환합니다.
      • GPU의 Vertex Shader에서 실행됩니다.
      • 작업내용
        • 월드 좌표 변환 : 모델 공간의 정점 데이터를 월드, 뷰, 클립 공간으로 변환.
        • 조명 계산 : 각 정점에 대한 조명 효과 적용.
    3. 래스터화 단계 (Rasterization Stage)
      • 3D 데이터를 2D 화면 픽셀로 변환하는 과정입니다.
      • 작업내용
        • 프리미티브(Primitive) 분할 : 정점 데이터를 삼각형으로 구성.
        • 스크린 좌표로 투영 : 삼각형을 화면 픽셀에 매핑.
        • 백 페이스 컬링(Back-face Culling) : 카메라에서 보이지 않는 면 제거.
    4. 프래그먼트 처리 단계 (Fragment Processing Stage)
      • 픽셀 단위의 색상과 텍스처를 계산하는 단계로, GPU의 Fragment Shader에서 실행됩니다.
      • 작업 내용
        • 텍스처 맵핑 : 오브젝트의 텍스처를 적용.
        • 조명 및 셰이딩 : 픽셀별 조명 계산 및 셰이딩 적용(Phong, Blinn-Phong 등).
        • 픽셀 투명도 : 반투명 및 알파 블렌딩 처리.
    5. 출력 병합 단계 (Output Merging Stage)
      - 최종적으로 렌더 타겟에 결과를 저장하고 화면에 출력합니다.
      - 작업 내용
      - Z-버퍼 처리 : 깊이 테스트를 통해 픽셀의 가시성을 결정.
      - 블렌딩 : 여러 렌더 타겟이나 투명한 오브젝트를 결합.
      - 화면 출력 : 최종 이미지를 프레임 버퍼에 저장.

  • Unity의 렌더링 파이프라인

    • Unity에서는 커스터마이징 가능한 렌더링 파이프라인을 제공합니다.
    1. 내장 렌더링 파이프라인 (Built-in Render Pipeline):
      • Unity의 기본 렌더링 방식으로, 단순한 설정으로 다양한 플랫폼에서 렌더링 가능.
    2. 스크립터블 렌더 파이프라인 (Scriptable Render Pipeline, SRP):
      - 렌더링 과정을 커스터마이징할 수 있는 기능.
      - 대표적으로 URP(Universal Render Pipeline)와 HDRP(High Definition Render Pipeline)가 있음.

  • 렌더링 파이프라인의 최적화

    1. Batching:
      • 동일한 메쉬와 재질을 사용하는 오브젝트를 그룹화하여 드로우 콜(Draw Call)을 줄임.
    2. LOD (Level of Detail):
      • 화면에서 멀리 있는 오브젝트는 저해상도 메쉬를 사용.
    3. Occlusion Culling:
      • 카메라에 보이지 않는 오브젝트를 렌더링하지 않음.
    4. 쉐이더 최적화:
      - 복잡한 셰이더 연산을 줄이고 간단한 수식을 사용.

0개의 댓글