<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>kim_j_h.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 14 Jun 2025 22:00:36 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>kim_j_h.log</title>
            <url>https://velog.velcdn.com/images/kim_j_h/profile/82e3f712-f364-44e8-8c89-62245018d0e7/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. kim_j_h.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/kim_j_h" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[인터럽트]]></title>
            <link>https://velog.io/@kim_j_h/%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8</link>
            <guid>https://velog.io/@kim_j_h/%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8</guid>
            <pubDate>Sat, 14 Jun 2025 22:00:36 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<blockquote>
<ul>
<li><strong>CPU가 하던 작업을 멈추고 중요한 내/외부 요청을 먼저 처리하게끔 하는 매커니즘</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>컴퓨터에서 발생하는 비정기적 사건(이벤트)을 처리하기 위한 시스템 레벨 기능</strong></li>
<li><strong>CPU는 보통 순차적으로 명령을 처리하지만, 인터럽트가 발생하면 순서를 잠깐 중단하고 다른 일을 먼저 하고 끝나면 원래 하던 일로 복귀함 (Return from Interrupt)</strong></li>
<li><strong>사용자의 입력 /  시스템 오류 /  하드웨어 요청처럼 예측할 수 없는 이벤트를 처리하기 위해서 필요함</strong></li>
<li><strong>인터럽트도 너무 많은게 동시에 들어오면 병목현상이 일어날수있음</strong></li>
<li><blockquote>
<p>마우스 / 키보드 / 컨트롤러 진동 / 사운드 재생 등등</p>
</blockquote>
</li>
</ul>
<h2 id="종류">종류</h2>
<blockquote>
<h3 id="1-하드웨어-인터럽트-hardware-interrupt">1) 하드웨어 인터럽트 (Hardware Interrupt)</h3>
</blockquote>
<ul>
<li><strong>외부 장치가 CPU에게 신호를 보냄(키보드 입력 /  마우스 클릭 / 네트워크 패킷 수신, 디스크 완료 등)</strong></li>
<li><blockquote>
<p>Input Action으로 하드웨어 입력이 발생하면 인터럽트 후 PlayerController에서 처리</p>
</blockquote>
</li>
<li><blockquote>
<p>오디오 장치가 인터럽트를 통해 CPU에게 요청</p>
</blockquote>
<h3 id="2-소프트웨어-인터럽트-software-interrupt">2) 소프트웨어 인터럽트 (Software Interrupt)</h3>
</li>
<li><strong>프로그램이 직접 인터럽트를 발생시킴 (예외 처리 /  시스템 콜 /  강제 종료 등)</strong></li>
<li><blockquote>
<p>check()나 ensure()가 실패할 때 발생하는 예외</p>
</blockquote>
</li>
<li><blockquote>
<p>AddOnScreenDebugMessage() 호출로 게임 중 디버그 출력</p>
</blockquote>
</li>
<li><blockquote>
<p>AI가 Invalid 상태일 때 AbortTask() 트리거</p>
</blockquote>
</li>
<li><blockquote>
<p>애니메이션 노티파이(Notify): 몽타주 재생 중 특정 프레임에 도달하면 소프트웨어 인터럽트처럼 행동하여 외부 이벤트(이펙트 / 사운드 등) 트리거</p>
</blockquote>
</li>
</ul>
<h2 id="처리-흐름">처리 흐름</h2>
<blockquote>
<p><strong>인터럽트 발생 -&gt; 현재 작업을 중단하고 상태 저장 -&gt; 인터럽트 핸들러(Interrupt Service Routine, ISR)로 분기 -&gt; 요청 처리 -&gt; 중단된 작업 복귀</strong></p>
</blockquote>
<h4 id="isr--인터럽트가-발생했을-때-실행되는-함수-또는-코드-블록으로-cpu가-어떤-인터럽트를-받으면-그-요청을-처리하기-위한-전용-코드를-실행isr">ISR? : 인터럽트가 발생했을 때 실행되는 함수 또는 코드 블록으로 <strong>CPU가 어떤 인터럽트를 받으면 그 요청을 처리하기 위한 전용 코드를 실행(ISR)</strong></h4>
<p>-&gt; IputAction / AnimNotify / 타이머 등등</p>
<h2 id="우선순위">우선순위</h2>
<blockquote>
<ul>
<li>**모든 인터럽트가 동시에 발생할 수 있기 때문에 우선순위 시스템이 있음</li>
<li><blockquote>
<p>시스템 크래시 = 최우선 /  사용자 입력 = 중간 /  마우스 위치 갱신 = 낮음**</p>
</blockquote>
</li>
<li><blockquote>
<p>OnComponentBeginOverlap()과 InputAction이 동시에 일어날 경우에 Input 우선 처리</p>
</blockquote>
</li>
<li><blockquote>
<p>게임 중 Pause 메뉴 켜졌을 때 나머지 Tick / 애니메이션 멈춤</p>
</blockquote>
</li>
</ul>
</blockquote>
<h2 id="캐시--버스와의-관계">캐시 / 버스와의 관계</h2>
<blockquote>
<h3 id="캐시">캐시</h3>
</blockquote>
<ul>
<li><strong>인터럽트가 발생하면 CPU의 현재 상태(레지스터 등)를 저장해 복귀 후 원활히 돌아가게끔 함</strong><h3 id="버스">버스</h3>
</li>
<li><strong>하드웨어 인터럽트는 보통 제어 버스를 통해 CPU에 도달함 (IRQ 요청 핀 통해 전달됨)</strong></li>
<li><blockquote>
<p>BindAction()으로 등록한 키 입력은 실제로 OS가 하드웨어 인터럽트를 통해 전달한 입력 이벤트를 언리얼이 추상화한 것</p>
</blockquote>
</li>
<li><blockquote>
<p>게임패드의 버튼 / 진동은 OS -&gt; CPU -&gt; 언리얼 Input 시스템으로 들어오는 인터럽트 기반 흐름</p>
</blockquote>
</li>
</ul>
<h2 id="인터럽트가--게임에-미치는-영향">인터럽트가  게임에 미치는 영향</h2>
<blockquote>
<h3 id="1-입력-지연">1) 입력 지연</h3>
</blockquote>
<ul>
<li><strong>인터럽트가 쌓이면 처리 대기 시간 증가 (많은 장치 입력 시)</strong><h3 id="2-gcgarbage-collection-중지">2) GC(Garbage Collection) 중지</h3>
</li>
<li><strong>인터럽트 중 메모리 접근 제한되면 GC도 잠시 대기할 수 있음</strong><h3 id="3-tick-정지">3) Tick 정지</h3>
</li>
<li><strong>강제 중단 시 Tick이 안 돌 수 있음 (디버그 중단, 오류 처리 등)</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[버스 구조]]></title>
            <link>https://velog.io/@kim_j_h/%EB%B2%84%EC%8A%A4-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@kim_j_h/%EB%B2%84%EC%8A%A4-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sat, 14 Jun 2025 21:25:34 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<blockquote>
<ul>
<li><h4 id="cpu--메모리---저장장치---gpu-등-컴퓨터-내부-부품-간-데이터를-주고받는-통로경로">CPU / 메모리 /  저장장치 /  GPU 등 컴퓨터 내부 부품 간 데이터를 주고받는 통로(경로)</h4>
</li>
</ul>
</blockquote>
<ul>
<li><h4 id="데이터를-옮기는-일종의-도로">데이터를 옮기는 일종의 도로</h4>
</li>
<li><h4 id="버스를-통해-명령--데이터--주소-등이-부품-사이를-오감">버스를 통해 명령 / 데이터 / 주소 등이 부품 사이를 오감</h4>
</li>
<li><h4 id="실체가-있음--메인보드-회로-안에-존재하는-신호선하나의-선이-아니라-전송-목적에-따라-분리된-여러-선들로-구성">실체가 있음 : 메인보드 회로 안에 존재하는 신호선(하나의 선이 아니라 전송 목적에 따라 분리된 여러 선들로 구성)</h4>
</li>
<li><h4 id="속도-단위로는-mhz-gts-giga-transfers-per-second등이-이씀">속도 단위로는 MHz, GT/s (Giga Transfers per second)등이 이씀</h4>
</li>
</ul>
<h2 id="종류">종류</h2>
<blockquote>
<h3 id="1-데이터-버스data-bus">1) 데이터 버스(Data Bus)</h3>
</blockquote>
<ul>
<li><strong>데이터를 실어 나르는 선(정수값, 문자, 메모리값)</strong></li>
<li><blockquote>
<p>실시간 물리 연산(캐릭터 RagDoll / Niagara 이펙트 계산)이 많으면 실시간으로 많은 데이터를 주고받게 되므로 데이터 버스 사용량이 증가</p>
</blockquote>
</li>
<li><blockquote>
<p>AI가 Tick마다 상태 갱신하고 접근할때도 내부적으로 연산 결과 데이터를 주고받음</p>
</blockquote>
<h3 id="2-주소-버스address-bus">2) 주소 버스(Address Bus)</h3>
</li>
<li><strong>데이터를 어디로 보낼지 지정하는 선(RAM 주소)</strong></li>
<li><blockquote>
<p>애니매이션에선 여러 바디 파츠에 대한 데이터 주소 접근 시에 활용</p>
</blockquote>
<h3 id="3-제어-버스control-bus">3) 제어 버스(Control Bus)</h3>
</li>
<li><strong>읽쓰 여부 / 인터럽트 등 제어 신호 전달(읽쓰 신호 / IRQ(Interrupt Request, 인터럽트 요청))</strong></li>
<li><blockquote>
<p>InputAction등을 CPU가 제어 버스를 통해 수신</p>
</blockquote>
</li>
<li><blockquote>
<p>오디오 재생 같은 명령도 제어 신호로 들어감</p>
</blockquote>
<h3 id="데이터-흐름">데이터 흐름</h3>
</li>
<li><em>CPU가 메모리에서 데이터를 읽어오라고 지시 -&gt; 주소 버스로 대상 메모리 주소를 전송(내비) -&gt; 제어 버스로 읽기 명령 전송(운전) -&gt; 데이터 버스로 RAM에서 CPU로 값 전달(택배)*</em></li>
<li><blockquote>
<p>게임 시작 시 Level을 로딩할때 이 3종의 버스가 동시에 사용됨</p>
</blockquote>
</li>
<li><blockquote>
<p>특히 LevelStreaming등에서 해당 흐름이 발생하며, Asset 대량 로딩 중 Hitch(멈칫)가 생기면 이 흐름이 병목된 것</p>
</blockquote>
<h4 id="이때-cpu는-명령만-내리고-실제-데이터는-디스크---ram---vram---gpu로-이동하면서-버스가-계속-사용됨">이때 CPU는 명령만 내리고, 실제 데이터는 <strong>디스크 -&gt; RAM -&gt; VRAM -&gt; GPU</strong>로 이동하면서 버스가 계속 사용됨</h4>
이 경로가 막히면 로딩이 느려지거나 화면이 멈칫하는 현상이 발생함</li>
</ul>
<h2 id="버스의-폭bit-width">버스의 폭(bit Width)</h2>
<blockquote>
<h3 id="한번에-보낼-수-있는-데이터-양을-의미">한번에 보낼 수 있는 데이터 양을 의미</h3>
<p>-&gt; VRAM이 많은 텍스처 데이터를 GPU로 옮길때 (4K 텍스쳐, LOD / HLOD 레벨 스트리밍등) 폭이 좁을 때 끊김발생 
-&gt; 렌더링 중 Lumen, Nanite 같은 기술은 초당 전송해야하는 데이터가 많아 버스 성능 중요
<img src="https://velog.velcdn.com/images/kim_j_h/post/659eb8fd-b41c-4790-ad61-46ab9a19bdcd/image.png" alt="">
<strong>Nanite, ShadowDepths, Lumen</strong> : 각각 별도의 GPU 작업은 VRAM 대역폭 소모, PCIe 버스 폭 영향
<strong>TOTAL GPU</strong> : 시간이 높고 각 작업이 1~2ms씩 분산되면 버스가 한계에 도달했을 가능성 있음</p>
</blockquote>
<h2 id="병목-현상bottleneck">병목 현상(Bottleneck)</h2>
<blockquote>
<ul>
<li><strong>버스가 너무 좁으면 RAM이 아무리 빨라고 전송 속도가 느려짐</strong></li>
</ul>
</blockquote>
<ul>
<li>*<em>CPU는 처리 가능하지만 버스에서 대기하게 되면서 성능 저하 발생 *</em></li>
<li><blockquote>
<p>텍스처 스트리밍 메모리 사용량이나 GPU 작업량이 과도할 경우 버스를 통해 RAM -&gt; VRAM 또는 CPU -&gt; GPU로 ㅗ이동하는 데이터가 급격히 몰리면서 FPS는 낮아지고 STreaming Pool이 초과되는 현상이 나타날 수 있음
<img src="https://velog.velcdn.com/images/kim_j_h/post/403dd2d8-551e-43e8-8978-f5e3b381ea3b/image.png" alt=""></p>
</blockquote>
</li>
<li><em>Streaming Pool = 800MB(100%)*</em> : VRAM에 실시간 스트리밍 데이터가 다 차서 병목이 생길 수있음</li>
<li><em>Wanted Mips와 Inflight Requests(GPU로 이동 중인 요청)도 높아져 있음*</em> : 아직 GPU가 텍스처 다 못 받았다는 뜻</li>
<li><em>IO Bandwidth(입출력 대역폭) = 0MB/s*</em> : 현재 디스크 -&gt; RAM 이동이 중단되었거나 막혀 있음</li>
</ul>
<h2 id="여기서-캐시">여기서 캐시</h2>
<blockquote>
<ul>
<li>캐시는 <strong>CPU안에 있어서</strong> 버스를 타지 않기 때문에 훨씬 빠름</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[메모리 계층 구조]]></title>
            <link>https://velog.io/@kim_j_h/%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B3%84%EC%B8%B5-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@kim_j_h/%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B3%84%EC%B8%B5-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sat, 14 Jun 2025 20:54:03 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<blockquote>
<ul>
<li><strong>CPU가 데이터를 읽는 속도와 비용에는 계층적인 차이가 존재</strong></li>
</ul>
</blockquote>
<h4 id="비교표">비교표</h4>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/62544c47-f314-4721-8666-05a5d03473e4/image.png" alt=""></p>
<ul>
<li><strong>빠르면서 큰 메모리를 만들기에는 너무 비쌈</strong></li>
<li>** 빠르고 비싼건 적게 / 느리고 싼 건 많이 (가성비중요)**</li>
</ul>
<h2 id="종류">종류</h2>
<blockquote>
<h3 id="레지스터">레지스터</h3>
</blockquote>
<ul>
<li>*<em>CPU 내부의 가장 작은 저장 공간 *</em></li>
<li>** 연산할 값을 잠깐 담는 작업 공간**</li>
<li><strong>직접 제어 불가 : 컴파일러가 자동으로 관리함</strong></li>
<li><blockquote>
<p>int 계산, FVector 연산 등 (CPU 내부 즉시 처리)</p>
</blockquote>
<h3 id="캐시">캐시</h3>
</li>
<li><strong>CPU와 RAM 사이에 있는 고속 중간 저장소</strong></li>
<li>** 자주 쓰는 데이터를 미리 저장해서 속도 향상**</li>
<li><strong>자동 저장 / 삭제됨 (수동 제어 불가)</strong></li>
<li><blockquote>
<p> Tick() 내 연속 구조체 접근, AI 상태 캐싱</p>
</blockquote>
<h3 id="ram-메인-메모리">RAM (메인 메모리)</h3>
</li>
<li><strong>CPU 외부에 있는 주 기억장치</strong></li>
<li><strong>게임에 로드한 모든 에셋과 오브젝트들이 올라감</strong></li>
<li><blockquote>
<p>UWorld에 로딩된 액터/애셋들 (Spawn된 오브젝트)</p>
</blockquote>
<h3 id="ssd--hdd-보조-저장-장치">SSD / HDD (보조 저장 장치)</h3>
</li>
<li><strong>프로그램 / 게임 파일등이 저장되어있는 디스크 저장소</strong></li>
<li><blockquote>
<p>.umap / .uasset / .pak 등의 실제 저장 데이터</p>
</blockquote>
<h3 id="네트워크-디스크--클라우드">네트워크 디스크 / 클라우드</h3>
</li>
<li><strong>인터넷을 통해 접근하는 저장소</strong></li>
<li><strong>온라인 멀티 / 원격 다운로드 등에서 사용</strong></li>
<li><blockquote>
<p>멀티 게임에서 리소스를 Stream 서버에서 다운</p>
</blockquote>
</li>
<li><blockquote>
<p>클라우드 저장소</p>
</blockquote>
</li>
</ul>
<h2 id="">?</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/f90fa04f-8145-40fc-a911-5327955d2344/image.png" alt="">(궁금해서 찾아봄)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[캐시(Cache)]]></title>
            <link>https://velog.io/@kim_j_h/%EC%BA%90%EC%8B%9CCache</link>
            <guid>https://velog.io/@kim_j_h/%EC%BA%90%EC%8B%9CCache</guid>
            <pubDate>Sat, 14 Jun 2025 20:53:48 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<blockquote>
<ul>
<li><h4 id="cpu와-메인-메모리ram-사이에-있는-고속-임시-저장-공간">CPU와 메인 메모리(RAM) 사이에 있는 <strong>고속 임시 저장 공간</strong></h4>
</li>
</ul>
</blockquote>
<ul>
<li><strong>자주 사용하는 데이터를 미리 저장해서 빠르게 뽑아올수있는곳</strong></li>
<li><strong>캐시는 물리적인 장치라기보다는 CPU 내부에서 자동으로 동작하는 추상적인 매커니즘에 가까움</strong></li>
<li><strong>물리적으로 존재하는 부분도 있음 : L1 ~ L3 캐시는 CPU 칩 안에 실제 회로 형태로 존재 하지만 직접 관리하지 않음(RAM처럼 명령할수 없고 CPU가 스스로 캐시에 넣고 안쓰면 버림)</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/f488a91c-6f11-4f7e-8f6b-f4cca4419631/image.png" alt=""></li>
</ul>
<h2 id="지역성">지역성</h2>
<blockquote>
<h3 id="1-시간-지역성">1) 시간 지역성</h3>
<p><strong>최근 사용한 데이터를 또 쓸 확률이 높음(캐릭터가 계속 뛸때 달리는 애니매이션 반복 / 체력 값을 매 프레임 확인할시)</strong></p>
</blockquote>
<h3 id="2-공간-지역성">2) 공간 지역성</h3>
<p><strong>사용한 데이터 주변도 함께 쓸 가능성이 있음(LandScape 타일 한칸 로딩 시 주변 타일도 미리 불러둠)</strong></p>
<h2 id="왜-쓰냐">왜 쓰냐</h2>
<blockquote>
<ul>
<li><strong>RAM에서 데이터를 가져오는 속도는 상대적으로 매우 느림</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>CPU는 너무 빠르고 RAM은 매우 느려서 그 사이를 메꾸기 위해 사용</strong></li>
<li><strong>때문에 자주 쓰는 데이터를 미리 CPU가까이 저장하고 또 쓸때 즉시 처리할수있게끔해줌</strong></li>
<li><blockquote>
<p>빠르게 반복되는 연산(물리 / 충돌 / 이동)은 캐시에 올라가야 프레임 드랍없이 실행됨(Character Movement / Line Trace / Lumen 등)</p>
</blockquote>
</li>
</ul>
<h2 id="어떻게-쓰냐">어떻게 쓰냐</h2>
<blockquote>
<ul>
<li><strong>우리는 캐시에 직접 뭘 넣을수가 없음(CPU가 판단)</strong></li>
<li><blockquote>
<p><strong>그렇기 때문에 캐시에 잘 들어가게 유도 하는것이 중요함</strong></p>
</blockquote>
</li>
<li><blockquote>
<p>Tick() 최적화 : 동일 구조체 필드에 순차적으로 접근해서 공간 지역성을 확보</p>
</blockquote>
</li>
<li><blockquote>
<p>다수의 Actor 반복 꼐산 : 연속된 배열(TArray)을 사용해서 캐시 히트율 증가 유도</p>
</blockquote>
</li>
<li><blockquote>
<p>AI BT : 상태 캐싱 : 매 틱마다 계산하지 않고 저장해서 재사용</p>
</blockquote>
</li>
<li><blockquote>
<p>Tarray&lt;&gt;에 적 데이터를 담고 순차 루프에서 접근하는식</p>
</blockquote>
</li>
</ul>
</blockquote>
<h2 id="캐시-내부-구조">캐시 내부 구조</h2>
<blockquote>
<h3 id="캐시-안에-어떤-용도로-나뉘어-저장됨">캐시 안에 어떤 용도로 나뉘어 저장됨?</h3>
</blockquote>
<ul>
<li><strong>Instruction Cache (I-Cache)</strong> : 실행할 명령어들을 저장함 (함수 코드, 로직 흐름) </li>
<li><strong>Data Cache (D-Cache)</strong> : 연산에 사용되는 실제 데이터를 저장함 (변수, 구조체 값 등) 
직접 지정 불가. CPU가 알아서 데이터 주소 해시값을 바탕으로 저장 위치를 찾음<h4 id="현대-대부분의-cpu에서는-l1캐시에-명령어데이터-캐시가-분리되어있음---접근이-빠르기-때문">현대 대부분의 CPU에서는 L1캐시에 명령어/데이터 캐시가 분리되어있음. -&gt; 접근이 빠르기 때문</h4>
<h4 id="l2l3-캐시는-명령어데이터를-통합해-저장하는-구조가-일반적---속도보다는-용량과-공유성에-초점을-둠">L2/L3 캐시는 명령어/데이터를 통합해 저장하는 구조가 일반적 -&gt; 속도보다는 용량과 공유성에 초점을 둠</h4>
<h4 id="직접-지정-불가-cpu가-데이터-주소의-해시값-또는-indextag-방식으로-자동으로-저장-위치를-계산함-맵핑mapping">직접 지정 불가. CPU가 데이터 주소의 해시값 또는 Index/Tag 방식으로 자동으로 저장 위치를 계산함 (맵핑(Mapping))</h4>
</li>
<li><blockquote>
<p>L1: Tick, BT Task, AnimUpdate, PhysicsUpdate 같은 짧고 반복적인 명령어들이 주로 올라감</p>
</blockquote>
</li>
<li><blockquote>
<p>L2~L3: UObject 참조, BTMemory, Actor Component 상태 값들이 이쪽에서 접근</p>
</blockquote>
</li>
<li><blockquote>
<p>구조체 기반으로 짜인 TArray&lt; FVector &gt; 같은 데이터는 D-Cache로 자주 접근됨</p>
</blockquote>
</li>
</ul>
<h2 id="캐시-구현-구조">캐시 구현 구조</h2>
<blockquote>
<h3 id="캐시가-데이터를-어떤-규칙으로-저장함">캐시가 데이터를 어떤 규칙으로 저장함?</h3>
</blockquote>
<h3 id="1-direct-mapping">1) Direct-Mapping</h3>
<p><strong>1개의 주소에 1개의 캐시라인사용(빠름 / 충돌 위험 높음)</strong></p>
<h3 id="2-fully-associative">2) <strong>Fully-Associative</strong></h3>
<p><strong>아무 캐시 라인에 저장가능(충돌 없지만 검색 느림)</strong></p>
<h3 id="3-set-associative-cache">3) <strong>Set-Associative Cache</strong></h3>
<p><strong>현대 CPU에서 가장 많이 사용하는 구조</strong></p>
<h3 id="set-associative-cache-어떻게">Set-Associative Cache 어떻게?</h3>
<p><strong>1) 전체 캐시를 여러개의 셋(Set)으로 나눔  **
*<em>2) 각 Set은 여러 개의 캐시 라인(Slot)을 가짐 (2-Way : 2개 슬롯) 
슬롯이 다 찼을 경우엔 가장 오래된 데이터 제거 (LRU, Least Recently Used)  *</em>
**3) 새 데이터가 오면 주소를 기반으로 특정 Set이 자동 결정하고 그 Set 안에서 비어있는 라인이 있으면 저장, 없으면 오래된 항목 제거 (LRU) 덕분에 충돌이 적으면서도 검색 속도도 빠름</strong>
-&gt; 여러 Actor들이 유사한 Tick, 구조체 패턴을 가지면 캐시 Set 충돌이 발생 가능
-&gt; TArray&lt;&gt;를 쓸 때, 모든 적의 구조체 크기/정렬이 같으면 특정 Set에만 몰릴 수 있음
-&gt; 이럴 땐 LRU로 덜 사용된 캐시가 제거되므로 불필요한 캐시 미스 발생 가능성 있음</p>
<h2 id="캐시-라인">캐시 라인</h2>
<blockquote>
<ul>
<li><strong>캐시의 최소 단위는 1줄(라인)</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>보통 64바이트(512비트) 정도의 고정 크기</strong></li>
<li><strong>캐시에 한번에 데이터를 가져올 때, 라인 단위로 가져옴</strong></li>
<li><em>-&gt; 캐시 라인은 한 번에 연속된 64바이트를 가져오므로,
배열처럼 인접한 메모리 구조를 사용할 경우 한번에 여러 데이터를 가져올 수 있어
캐시 히트율이 높아지고 성능이 향상됨*</em></li>
<li><blockquote>
<p>FTransform이나 FVector가 배열로 연속된 메모리에 있을때 캐시 라인 1개로 여러 데이터 읽을 수 있음</p>
</blockquote>
</li>
<li><blockquote>
<p>구조체를 TArray가 아닌 포인터 배열로 만들면 다른 위치에 있는 메모리를 불규칙하게 접근해서 캐시 라인 히트율을 저하시킴</p>
</blockquote>
<h3 id="예시">예시</h3>
<h4 id="good">Good</h4>
<img src="https://velog.velcdn.com/images/kim_j_h/post/4ea13767-5d7d-4525-97d5-397942ecf024/image.png" alt=""></li>
<li>모두 <strong>4바이트 정렬된</strong> float -&gt; 인접 메모리에 배치되어서 캐시 라인 접근 1번이면 됨<h4 id="bad">Bad</h4>
<img src="https://velog.velcdn.com/images/kim_j_h/post/590dfd30-39fc-437c-a8ba-60f540af45c3/image.png" alt=""></li>
<li>중간에 패딩이 생기고 캐시 라인 접근이 2번 이상 필요할 수 있음</li>
<li><blockquote>
<p>메모리 낭비 + 캐시 미스 발생 가능성 증가</p>
</blockquote>
</li>
</ul>
<h2 id="패딩padding">패딩(Padding)?</h2>
<blockquote>
<ul>
<li><strong>메모리 정렬을 위해 구조체 사이에 자동으로 채워지는 빈 공간</strong></li>
</ul>
</blockquote>
<ul>
<li>1<strong>파이트와 4바이트가 있는 구조체일때 중간에 3바이트 패딩이 자동으로 들어감(정렬 보정) -&gt; 패팅이 많으면 캐시 라인 낭비 -&gt; 캐시 미스 가능성 높아짐</strong></li>
<li><blockquote>
<p>구조체에 bool / FVecgtor / float / bool 처럼 섞어 쓰면 정렬 비효율적이기 때문에 FVector  / float / bool 순으로 정렬해 패딩을 최소화시키면 좋음</p>
</blockquote>
</li>
</ul>
<h2 id="캐시-미스">캐시 미스?</h2>
<blockquote>
<ul>
<li><strong>CPU가 필요한 데이터가 캐시에 없는 상황으로 RAM에서 다시 가져와야하니까 훨씬 느림 -&gt; 게임 중에는 프레임 드롭/지연으로 이어질수 있음</strong></li>
</ul>
</blockquote>
<ul>
<li>**L1에 없네? -&gt; L2 -&gt; L3 -&gt; RAM -&gt; SSD/HDD 순으로 계층적 조회함</li>
<li><blockquote>
<p>언리얼에서는 TArray &lt; Struct &gt;같은 연속 메모리 배열을 추천(불규칙한 포인터 배열 X)**</p>
</blockquote>
</li>
<li><blockquote>
<p>포인터 배열로 구성된 AI 행동 루틴이 많을 경우 매 틱마다 다양한 주소를 접근해 캐시 미스 증가시킬수있음</p>
</blockquote>
</li>
<li><blockquote>
<p>UObject* 참조가 많은 경우에도 위치가 흩어져 있어 캐시 미스 유발 가능성 있음</p>
</blockquote>
</li>
</ul>
<h3 id="언리얼-내부에서도-이미-캐시-최적화가-되어있음">언리얼 내부에서도 이미 캐시 최적화가 되어있음</h3>
<blockquote>
<ul>
<li><strong>FTransform, FVector, FRotator 구조체는 4/8 바이트 단위 정렬로 최적화되어 있음</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>UObjet도 연속 접근보단 Index 기반 / WeakRefernce로 접근 시 캐시 효율 감소</strong></li>
<li><strong>UObject는 포인터 기반이라 연속 접근엔 불리하므로 필요 시 Index 배열로 캐시 친화적 접근 유도 가능</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 19일차(범용적 기믹 클래스)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-19%EC%9D%BC%EC%B0%A8%EB%B2%94%EC%9A%A9%EC%A0%81-%EA%B8%B0%EB%AF%B9-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-19%EC%9D%BC%EC%B0%A8%EB%B2%94%EC%9A%A9%EC%A0%81-%EA%B8%B0%EB%AF%B9-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Wed, 04 Jun 2025 11:13:03 GMT</pubDate>
            <description><![CDATA[<h2 id="기획-의도">기획 의도</h2>
<blockquote>
<h3 id="목표--여러-맵에서-범용적으로-재사용-가능한-구조로-기믹-시스템-구축하기">목표 : 여러 맵에서 범용적으로 재사용 가능한 구조로 기믹 시스템 구축하기</h3>
</blockquote>
<ul>
<li>맵마다 컨셉이랑 구조가 달라 기믹의 컨셉은 달라지겠지만 결국 로직 자체는 비슷하다는 결론을 지어 이런 구조 결정</li>
</ul>
<h2 id="클래스-구조">클래스 구조</h2>
<blockquote>
<h4 id="lcbasegimmcik--공통-베이스-클래스">LCBaseGimmcik : 공통 베이스 클래스</h4>
</blockquote>
<ul>
<li>메쉬, 사운드 쿨타임 타겟 트리거링등 기본 기능 구현</li>
<li>자동 복귀 / 상태 유지 선택 가능<h4 id="lcrotationgimmcik--회전기믹-클래스">LCRotationGimmcik : 회전기믹 클래스</h4>
</li>
<li>지정하는 각도로 회전하는 기능</li>
<li>회전 보간 처리<h4 id="lclocationgimmcik--이동기믹-클래스">LCLocationGimmcik : 이동기믹 클래스</h4>
</li>
<li>지정하는 위치로 이동하는 기능</li>
<li>이동 보간 처리</li>
</ul>
<h2 id="주요-구조-설계">주요 구조 설계</h2>
<blockquote>
<h4 id="1-기능-작동은-server--기준--모든-상호작용은-서버에서-실행되고-클라이언트는-요청만-수행">1) 기능 작동은 Server  기준 : 모든 상호작용은 서버에서 실행되고 클라이언트는 요청만 수행</h4>
</blockquote>
<h4 id="2-multicast-연출--이동--회전은-모두-multicast로-클라이언트-동기화">2) Multicast 연출 : 이동 / 회전은 모두 Multicast로 클라이언트 동기화</h4>
<h4 id="3-타겟-트리거--linkedtargets을-통해-라인트레이스로-감지-후-상호-작용">3) 타겟 트리거 : LinkedTargets을 통해 라인트레이스로 감지 후 상호 작용</h4>
<h4 id="4-보간-방식--tick이-아닌-timermanager를-사용해-보간">4) 보간 방식 : Tick이 아닌 TimerManager를 사용해 보간</h4>
<h4 id="5-모든-수치값이나-사용-여부는-에디터에서-수정가능하게-작성">5) 모든 수치값이나 사용 여부는 에디터에서 수정가능하게 작성</h4>
<h2 id="트러블-슈팅">트러블 슈팅</h2>
<blockquote>
<h3 id="1-시각적-보간-미적용">1) 시각적 보간 미적용</h3>
</blockquote>
<ul>
<li>회전이나 이동 시 캐릭터나 오브젝트가 부드럽게 움직이지 않고, 방향이 순간적으로 바뀌는 느낌이 들었음.</li>
<li>특히 <strong>Listen Server 화면(=호스트)</strong>에서 보간이 아예 적용되지 않아 시각적 괴리 발생.<h3 id="원인">원인</h3>
</li>
<li>회전/이동은 Multicast 함수로 전체 클라이언트에 전파했지만,</li>
<li>내부 로직에서 <strong>HasAuthority() 조건문이 있어</strong> Listen Server에서는 보간이 실행되지 않았음.<h3 id="해결책">해결책</h3>
</li>
<li>HasAuthority() 대신 <strong>IsRunningDedicatedServer() 사용</strong>하여 Listen Server도 포함하도록 조건 수정</li>
<li><blockquote>
<p>(HasAuthority() -&gt; 서버는 항상 true / IsRunningDedicatedServer() → 전용 서버만 true, Listen Server는 false)</p>
</blockquote>
</li>
<li>회전이나 이동 시 보간을 넣어줘서 자연스러운 움직임이 나오게끔 보완<h4 id="--서버랑-클라이언트-둘다-해줘야-host쪽도-자연스러움이-나옴">- 서버랑 클라이언트 둘다 해줘야 Host쪽도 자연스러움이 나옴</h4>
<h3 id="2-클라이언트에서-상호작용이-안되는-문제">2) 클라이언트에서 상호작용이 안되는 문제</h3>
</li>
<li>가장 시간을 많이 잡아먹던 문제였음</li>
<li>서버쪽에서는 상호작용도 되고 회전하는게 클라이언트 화면에서도 잘 보였지만 막상 클라이언트 화면에서 상호작용을 하면 로직이 동작을 안함</li>
<li>로그 확인 결과 Server_InteractWithGimmick_Implementation()에는 진입하지만 내부에서 Interactor == nullptr로 판단되어 로직이 강제 종료됨<h3 id="원인-1">원인</h3>
</li>
<li><h4 id="unreal의-server-rpc-구조상-꼭-필요한-전제-조건이있음">Unreal의 Server RPC 구조상 꼭 필요한 전제 조건이있음</h4>
</li>
</ul>
<ol>
<li>서버에 해당 Target 액터가 유효할것<h4 id="2-해당-엑터의-owner가-존재할-것">2. 해당 엑터의 Owner가 존재할 것</h4>
</li>
</ol>
<p><strong>하지만 Owner를 지정할 수 없었음.. 왜냐 -&gt; Overlap 기믹은 사용하지 않았기 때문에 굳이 지정을 해주지 않아도 로직이 동작할수 있다고 생각했기 때문(이 생각때문에 하루를 날렸음...)</strong></p>
<h3 id="해결-방안">해결 방안</h3>
<h4 id="1">1)</h4>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/bf45c1f2-6066-43de-a195-94ba58b7a8d8/image.png" alt=""></p>
<ul>
<li>캐릭터 담당분께 상황을 설명드리고 <strong>컨트롤러에서 명시적으로 SetOwner(this) 호출</strong></li>
<li><blockquote>
<p>그 후 확인 결과 Interact함수는 호출되나 Cast시도 시 nullptr이 발생하고있음</p>
</blockquote>
</li>
<li><strong>에디터에 배치된 액터는 기본적으로 Owner == None</strong>이라고 함 그렇기 때문에 서버는 누가 상호작용을 했는지 알 수가 없게됨..<h4 id="2">2)</h4>
<img src="https://velog.velcdn.com/images/kim_j_h/post/b1d9f25f-ddd9-4564-a9c1-c82c84434b9a/image.png" alt=""></li>
<li>기믹 내부에서는 GetOwner()를 기반으로 안전하게 Cast해서 Owner를 지정</li>
</ul>
<h2 id="추후-도전할-기능">추후 도전할 기능</h2>
<blockquote>
<ul>
<li>** 협동/경쟁 구조 기반 퍼즐 : **두 플레이어가 동시에 다른 핸들을 돌려야 문이 열림</li>
<li><blockquote>
<p>타이머로 몇초 안에 둘다 사용되면 성공? Manager를 만들어서 관리해야할듯</p>
</blockquote>
</li>
</ul>
</blockquote>
<ul>
<li>*<em>이동의 다양화 : *</em>직선 이동이 아닌 커브나 경로 기반 이동</li>
<li><blockquote>
<pre><code>Spline을 깔아서 그걸 기반으로 움직이게끔?</code></pre></blockquote>
</li>
<li>*<em>조건부 활성화 : *</em>열쇠 획득, 특정 아이템 사용, 미션 완료 시 기믹 사용 가능</li>
<li><blockquote>
<p>열쇠를 만들고 플레이어 상태에 열쇠 유무를 저장? 기믹 시 유무를 판단할수 있게?</p>
</blockquote>
</li>
<li><strong>연속 트리거 / 체인 반응 구조 :</strong> 하나의 기믹이 다른 기믹을 자동으로 연쇄 실행 -&gt; 시간차를 둬서 자연스럽게 하는 방법이 가장 쉽긴할듯</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 18일차(빛 동상)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-18%EC%9D%BC%EC%B0%A8%EB%B9%9B-%EB%8F%99%EC%83%81</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-18%EC%9D%BC%EC%B0%A8%EB%B9%9B-%EB%8F%99%EC%83%81</guid>
            <pubDate>Sun, 01 Jun 2025 07:25:37 GMT</pubDate>
            <description><![CDATA[<h2 id="간단한-기획">간단한 기획</h2>
<blockquote>
<h3 id="빛을-이용한-기믹">빛을 이용한 기믹</h3>
</blockquote>
<ul>
<li><strong>회전하는 동상</strong> : 위치는 움직이지 않고 한번 동작 시 일정한 회전값으로 회전</li>
<li><strong>동상을 회전시키게 해주는 핸들</strong> : 동상을 회전시켜주는거 핸들로써 한번 누를때 동상도 일정한 회전값으로 한번 회전</li>
<li><strong>동상이 빛을 발사할 수 있게 해주는 장치</strong> -&gt; 이걸 핸들에 넣어야지 동상이 빛을 냄</li>
<li><strong>빛을 받는 돌?</strong> : 동상에서 발사된 빛을 이 돌에 잘 맞춰서 쏴서 활성화 시켜야함</li>
<li>빛을 받는 매개체가 조건을 만족해서 활성화가 되면 생기는 다리(다리를 생기게 할지, 뭐 문이 열리게 할지 아직 고민중)</li>
<li><strong>생성 방식</strong> :  블루프린트로 상속 시키고 에디터 레벨에 직접 배치를 할지, 스포너를 만들어서 배치를 하고 그중 하나에 랜덤하게 스폰하게 할지 고민중
값들은 에디터에서 블루프린트로 값이나 메쉬등을 수정할 수 있게 작성</li>
</ul>
<h2 id="구상중인-구조">구상중인 구조</h2>
<blockquote>
<ul>
<li><strong>RuinsGimmickBase</strong> : 모든 트리거와 타겟의 부모</li>
<li><blockquote>
<p>서버 관련 함수는 Implementation도 같이 선언</p>
</blockquote>
</li>
</ul>
</blockquote>
<ul>
<li>디버깅 로그는 만들어둔 커스텀 로그 사용</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 17일차(미로 함정)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-17%EC%9D%BC%EC%B0%A8%EB%AF%B8%EB%A1%9C-%ED%95%A8%EC%A0%95</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-17%EC%9D%BC%EC%B0%A8%EB%AF%B8%EB%A1%9C-%ED%95%A8%EC%A0%95</guid>
            <pubDate>Sun, 01 Jun 2025 03:40:02 GMT</pubDate>
            <description><![CDATA[<h2 id="함정-배치">함정 배치</h2>
<blockquote>
<ul>
<li>미로 내부에 함정을 랜덤으로 배치하기</li>
</ul>
</blockquote>
<ul>
<li>함정은 에디터에서 종류와 비율을 선택할 수 있게 작성</li>
<li>기본 함정 베이스는 UnifiedPlate클래스를 사용</li>
</ul>
<h2 id="함정-소환">함정 소환</h2>
<blockquote>
<h3 id="함정-배치-지정과-관련-수치값-조절을-위한-구조체">함정 배치 지정과 관련 수치값 조절을 위한 구조체</h3>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/f09bd29d-6a4b-49bc-8422-7289aadac214/image.png" alt=""> </p>
</blockquote>
<h4 id="maybespawngimmickatcell--셀에-함정을-생성할-수-있는-조건을-판단한-후-생성-로직-실행서버-권한--기준-조건--plate와-target의-조합의-존재-유무">MaybeSpawnGimmickAtCell() : 셀에 함정을 생성할 수 있는 조건을 판단한 후 생성 로직 실행(서버 권한 / 기준 조건 / Plate와 Target의 조합의 존재 유무)</h4>
<h4 id="tryplacegimmicks--미로-전체-셀을-순회하면서-각-셀에-기믹이-생성-가능한지-판단한-후-maybespawngimmickatcell을-호출--방문한-셀만을-대상으로-실행">TryPlaceGimmicks() : 미로 전체 셀을 순회하면서 각 셀에 기믹이 생성 가능한지 판단한 후 MaybeSpawnGimmickAtCell()을 호출 ( 방문한 셀만을 대상으로 실행)</h4>
<h3 id="beginplay---generatemaze---tryplacegimmicks---maybespawngimmickatcell-방식으로-호출">BeginPlay() -&gt; GenerateMaze() -&gt; TryPlaceGimmicks() -&gt; MaybeSpawnGimmickAtCell() 방식으로 호출</h3>
<h2 id="결과">결과</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/fef98cae-846a-4238-ae10-2186c2c31a89/image.png" alt=""> 블루프린트로 타겟 / 트리거 생성
<img src="https://velog.velcdn.com/images/kim_j_h/post/734c27e9-90ca-4e1d-be32-e2df586634c5/image.png" alt="">MazeManager에 타겟과 트리거를 추가
<img src="https://velog.velcdn.com/images/kim_j_h/post/c72c028b-5fe5-44a5-aff7-61edfe77eb65/image.png" alt=""> 정상적으로 생성</p>
</blockquote>
<h3 id="추후-블루프린트로-함정의-종류를-늘리고-어울리는-에셋을-적용시켜주기만-하면-완성">추후 블루프린트로 함정의 종류를 늘리고 어울리는 에셋을 적용시켜주기만 하면 완성</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 16일차(미로 리팩토링)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-16%EC%9D%BC%EC%B0%A8%EB%AF%B8%EB%A1%9C-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-16%EC%9D%BC%EC%B0%A8%EB%AF%B8%EB%A1%9C-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81</guid>
            <pubDate>Sat, 31 May 2025 09:01:55 GMT</pubDate>
            <description><![CDATA[<h2 id="현재-구조의-문제점">현재 구조의 문제점</h2>
<blockquote>
<ul>
<li><h4 id="메인경로-하나---그-중간중간-막힌-가지-경로-생성-방식인데-길이-하나다-보니까-기믹넣고-하다보면-길-찾는데-시간이-너무-오래-걸릴거-같아서-유효-경로를-늘리는-방안을-생각">메인경로 하나 -&gt; 그 중간중간 막힌 가지 경로 생성 방식인데 길이 하나다 보니까 기믹넣고 하다보면 길 찾는데 시간이 너무 오래 걸릴거 같아서 유효 경로를 늘리는 방안을 생각</h4>
</li>
</ul>
</blockquote>
<h2 id="리팩토링-방식">리팩토링 방식</h2>
<blockquote>
<ul>
<li><h4 id="메인-경로중간에-나오는-막힌-가지-경로들을-임의로-몇개-선택하고-길을-만들어-다시-유효-경로로-붙게끔-설계">메인 경로중간에 나오는 막힌 가지 경로들을 임의로 몇개 선택하고 길을 만들어 다시 유효 경로로 붙게끔 설계</h4>
</li>
</ul>
</blockquote>
<h4 id="generatebranchesfromdeadends-함수로-만든-가지-경로--">GenerateBranchesFromDeadEnds() 함수로 만든 가지 경로 -&gt;</h4>
<h4 id="connectloopstomainpath--막다른-셀을-인접-메인-경로-셀에-연결하여-유효-경로-생성-개수는-maxloopcount로-제한">ConnectLoopsToMainPath() : 막다른 셀을 인접 메인 경로 셀에 연결하여 유효 경로 생성 (개수는 MaxLoopCount로 제한)</h4>
<h4 id="generatemaze-함수에-최소-유효-경로를--정해주고7개로-지정---반복을-최대-30회로-제한혹시-모를-무한-루프-방지이지만-결국에는-생성을-해야하기때문에-나중에는-제한을-없애거나-제한-개수를-늘려줘야할듯">GenerateMaze() 함수에 최소 유효 경로를  정해주고(7개로 지정) -&gt; 반복을 최대 30회로 제한(혹시 모를 무한 루프 방지이지만 결국에는 생성을 해야하기때문에 나중에는 제한을 없애거나 제한 개수를 늘려줘야할듯)</h4>
<h2 id="결과">결과</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/10548fc6-fc2e-4fde-a712-cec962cd941c/image.png" alt=""> </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 15일차(미로 기믹)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-15%EC%9D%BC%EC%B0%A8%EB%AF%B8%EB%A1%9C-%EA%B8%B0%EB%AF%B9</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-15%EC%9D%BC%EC%B0%A8%EB%AF%B8%EB%A1%9C-%EA%B8%B0%EB%AF%B9</guid>
            <pubDate>Tue, 27 May 2025 14:34:43 GMT</pubDate>
            <description><![CDATA[<h2 id="초기-기획">초기 기획</h2>
<blockquote>
<ul>
<li><strong>신전 입구에 들어가기전에 랜덤으로 미로를 생성하고 미로 내부에 신전입구 열쇠를 배치</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>추후 다른기믹추가를 고려해서 Base클래스 생성</strong></li>
<li><h3 id="모든-벽을-데이터-상으로만-세우고-경로에-따라서-벽을-지우는-방식으로-길을-생성">모든 벽을 데이터 상으로만 세우고, 경로에 따라서 벽을 지우는 방식으로 길을 생성</h3>
</li>
<li><strong>서버에서 1회 생성 -&gt; 모든 클라이언트에게 Replicate</strong></li>
<li><strong>입구와 출구는 고정된 위치에 존재하며, 그 사이를 Depth-First Search (DFS) 알고리즘을 통해 연결하는 방식으로 경로를 생성</strong><h3 id="dfs-생성-방식">DFS 생성 방식</h3>
</li>
<li><h4 id="한-방향으로-쭉-가다가-더-이상-갈-곳이-없으면-이전으로-되돌아가서-다른-방향을-파는-방식">한 방향으로 쭉 가다가 더 이상 갈 곳이 없으면 이전으로 되돌아가서 다른 방향을 파는 방식</h4>
<h3 id="ruinsgimmickbaseh">RuinsGimmickBase.h</h3>
<img src="https://velog.velcdn.com/images/kim_j_h/post/6c6a2d21-37aa-4672-a4c0-5b0f57f4d8f3/image.png" alt=""></li>
<li><strong>추후 기믹추가를 고려해 Base 미리 생성</strong></li>
</ul>
<h2 id="미로-설계">미로 설계</h2>
<blockquote>
<h3 id="ruinsmazestructs">RuinsMazeStructs</h3>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/5356d191-579f-49b8-9bf2-d6233d4beeb3/image.png" alt=""></p>
</blockquote>
<ul>
<li><strong>방문 여부와 벽의 유무 여부를 확인하기 위한 구조체</strong></li>
<li><strong>DFS로 경로를 연결할때 연결한 방향의 벽만 제거하기</strong></li>
</ul>
<h3 id="ruinsmazewall">RuinsMazeWall</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/a647f246-e253-4d46-9d31-7802b90d49a2/image.png" alt=""></p>
</blockquote>
<ul>
<li><strong>bReplicates = true로 클라이언트로 복제시킴
서버에서 생성 -&gt; 클라이언트에 복제</strong></li>
<li><strong>LDMaxDrawDistance를 설정해서 최적화</strong></li>
</ul>
<h2 id="ruinsmazemanager-주요-함수">RuinsMazeManager 주요 함수</h2>
<blockquote>
<h3 id="generatemaze">GenerateMaze()</h3>
</blockquote>
<ul>
<li>MazeBounds로 미로 구역 계산</li>
<li>셀 / 벽 정보 초기화</li>
<li>DFS로 경로 생성</li>
<li>벽 스폰</li>
<li>입출구 연결 유효성 검사(디버깅용)<h3 id="generatemainpath">GenerateMainPath()</h3>
</li>
<li>현재 셀 방문 처리</li>
<li>방문하지 않은 이웃 방향을 랜덤하게 추출</li>
<li>이웃 셀로 이동 -&gt; 현재 셀과의 사이 벽 제거</li>
<li>재귀로 반복<h3 id="getshuffledunvisitedneighbors">GetShuffledUnvisitedNeighbors()</h3>
</li>
<li>현재 셀에서 방문하지 않은 방향을 랜덤하게 섞은 후 반환</li>
<li>Fisher–Yates 방식 섞기
<img src="https://velog.velcdn.com/images/kim_j_h/post/34a66020-b5bc-4e5c-ae9b-fa3977125791/image.png" alt=""><h4 id="fisher-yates-shuffle">Fisher-Yates Shuffle</h4>
</li>
<li><strong>배열을 무작위로 섞는 알고리즘</strong></li>
<li><strong>편향이 없고 각 순열이 같은 확률로 나옴</strong></li>
<li><strong>배열에 끝에서 시작 -&gt; 현재 위치(i)보다 작거나 같은 위치(j)를 무작위로 선택 -&gt; i와 j의 위치를 서로 바꿈</strong><h3 id="spawnwall">SpawnWall()</h3>
</li>
<li>각 셀의 4방향을 기준으로 ARuinsMazeWall 액터를 스폰</li>
<li>스폰 시 충돌 방지 설정 : AlwaysSpawn<h3 id="ispathtoexitvalid">IsPathToExitValid()</h3>
</li>
<li>생성된 미로가 실제 입출구를 연결하는지 검사(디버깅용)<h3 id="recursivecheckpath">RecursiveCheckPath()</h3>
</li>
<li>재귀 DFS로 실제 연결 여부를 검사하는 내부 함수</li>
<li>이미 제거된 벽 뱡향으로만 이동</li>
</ul>
<h2 id="구조체-적용-리팩토링">구조체 적용 리팩토링</h2>
<blockquote>
<ul>
<li><strong>Visited / Wall 배열을 RuinsMazeCell 구조체로 통합해서 미로 셀 데이터를 관리하기 더 용이하게 리팩토링 진행</strong></li>
</ul>
</blockquote>
<h3 id="셀-방문-여부">셀 방문 여부</h3>
<ul>
<li><h4 id="visitedxy---mazecellsxybvisited">Visited[X][Y] -&gt; MazeCells[X][Y].bVisited</h4>
<img src="https://velog.velcdn.com/images/kim_j_h/post/f2eaa1ec-c584-41e6-8369-a3d06a903e54/image.png" alt="">
<img src="https://velog.velcdn.com/images/kim_j_h/post/5cbb8369-7b8f-46cd-a99b-daa958f871e4/image.png" alt=""><h3 id="벽-상태">벽 상태</h3>
</li>
<li><h4 id="wallsxy와-같은-문자열-키---mazecellsxybwalltop-같은-명시적-멤버">Walls[X]<a href="%22Top%22">Y</a>와 같은 문자열 키 -&gt; MazeCells[X][Y].bWallTop 같은 명시적 멤버<img src="https://velog.velcdn.com/images/kim_j_h/post/89f286d4-c68b-4fa2-ad70-8d653ca5a30b/image.png" alt=""></h4>
<img src="https://velog.velcdn.com/images/kim_j_h/post/12fd95d2-1021-47d9-bc7b-948278a7f9e5/image.png" alt=""><h3 id="배열-구성">배열 구성</h3>
</li>
<li><h4 id="2개의-분리된-배열에서-통합-구조체-배열로-변경">2개의 분리된 배열에서 통합 구조체 배열로 변경</h4>
<h3 id="초기화-방식">초기화 방식</h3>
</li>
<li><h4 id="tmap-기반-반복에서-구조체-자동-초기화">TMap 기반 반복에서 구조체 자동 초기화</h4>
<img src="https://velog.velcdn.com/images/kim_j_h/post/f88fcbfa-85a3-4622-8fbe-16b05c49418d/image.png" alt="">
<img src="https://velog.velcdn.com/images/kim_j_h/post/bf48b910-da2d-4ee1-bda4-ef6cdcfe7998/image.png" alt=""></li>
</ul>
<h2 id="결과물">결과물</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/db6cda60-6ffd-45c9-ac4a-e5819caf02fa/image.png" alt=""></p>
</blockquote>
<ul>
<li><strong>입 출구 테그를 붙인 후 실험 결과 경로가 생성되고 로그도 정상적으로 뜸</strong></li>
</ul>
<h2 id="확장계획">확장계획</h2>
<blockquote>
<ul>
<li>내부에 벽에 걸치지 않고 자연스럽게 장애물이나 아이템 스폰</li>
</ul>
</blockquote>
<ul>
<li>몬스터를 피할 수 있게 구멍이 나있는 벽도 넣어 여러 벽으로 생성되게 확장</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 14일차(최적화 마무리)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-14%EC%9D%BC%EC%B0%A8%EC%B5%9C%EC%A0%81%ED%99%94-%EB%A7%88%EB%AC%B4%EB%A6%AC</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-14%EC%9D%BC%EC%B0%A8%EC%B5%9C%EC%A0%81%ED%99%94-%EB%A7%88%EB%AC%B4%EB%A6%AC</guid>
            <pubDate>Mon, 26 May 2025 08:27:49 GMT</pubDate>
            <description><![CDATA[<h2 id="나나이트-적용">나나이트 적용</h2>
<blockquote>
<ul>
<li><strong>기획 변경 전 레벨과 동일하게 나나이트 적용</strong></li>
</ul>
</blockquote>
<h2 id="그림자">그림자</h2>
<blockquote>
<ul>
<li><strong>스태틱 쉐도우를 제외하고 끄기</strong></li>
</ul>
</blockquote>
<h2 id="루멘-비활성화">루멘 비활성화</h2>
<blockquote>
<ul>
<li><strong>프로젝트 세팅 / Post Process Volume에서 해제</strong></li>
</ul>
</blockquote>
<h2 id="결과">결과</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/72e963e0-48bb-49de-b70c-f6acba59be02/image.png" alt=""> <strong>리소스도 절반 정도로 줄였음.. 나이스..</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary(13일차)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary13%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary13%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 22 May 2025 21:30:26 GMT</pubDate>
            <description><![CDATA[<h2 id="기획-변경">기획 변경</h2>
<blockquote>
<ul>
<li>기존 숲 맵의 4개의 테마를 각각의 게이트로 나눠서 하기로 기획 변경함</li>
<li><blockquote>
<p>맵이 너무 멀어 유도하기 어렵고 좀 더 가벼운 느낌의 게임으로 변화시키기 위함</p>
</blockquote>
</li>
</ul>
</blockquote>
<h2 id="ruins-맵-최적화">Ruins 맵 최적화</h2>
<blockquote>
<ul>
<li>신전 맵 에셋을 구매하여 최적화 진행</li>
</ul>
</blockquote>
<ul>
<li>GPU의 사용량을 분석해 진행</li>
</ul>
<h2 id="virtual-texture-pool">Virtual Texture Pool</h2>
<blockquote>
<ul>
<li><strong>버추얼을 사용하는 에셋이였기 때문에 프로젝트 초기 세팅</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/3c05e782-20cc-47e2-99bd-18f3643a8c32/image.png" alt=""></li>
</ul>
</blockquote>
<ul>
<li>**하지만 활성화 시키니 FPS를 비롯한 GPU 성능 부하가 더 일어났음!!!!</li>
<li><blockquote>
<p>원인을 찾아보니 다양한 포맷이 중첩 로딩되어 부하가 발생하고 나나이트랑 동시에 사용하게 되면 병목 현상이 일어난다고함..** </p>
</blockquote>
<h3 id="virtual-texture는-사용-안하기로-결정">Virtual Texture는 사용 안하기로 결정</h3>
</li>
</ul>
<h2 id="streaming-pool">Streaming Pool</h2>
<blockquote>
<ul>
<li>지금 약 700mib 정도가 오버되고있음</li>
</ul>
</blockquote>
<h3 id="텍스처-크기-분석">텍스처 크기 분석</h3>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/f2978aa3-7752-45e2-91e4-c337b63d9ca0/image.png" alt=""><strong>341MB라는 말도 안되는 크기가 있음</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/16513c31-ce43-4a64-8d4b-e7a931835312/image.png" alt=""><strong>해상도도 4096x4096이고 압축 세팅이 너무 무거운 포맷으로 되어있음 -&gt; 해상도 2048x2048 / Masks로 변경</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/f04403d3-c045-49fe-ab1a-92bd4f265930/image.png" alt=""> 
<strong>-&gt; 다른 텍스처도 변경</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/57e58557-da25-4bb0-822b-b08027d2f3fa/image.png" alt="">*<em>최소 정상 진입 -&gt; 추후 필요하면 잘 안보이는 텍스처 위주로 1024로 다시 리사이징
*</em></p>
<h2 id="루멘">루멘</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/113c3864-07d1-4abc-a5b1-22327a5a484f/image.png" alt="">Lumen작업 관련해서 병목이 가장 많이 발생함 
<strong>Lumen</strong> : 실시간으로 간접광 / 반사를 계산하는 시스템 -&gt; 멀티플레이 게임에서는 안쓰는게 좋음.. 주로 시네마틱용도
<img src="https://velog.velcdn.com/images/kim_j_h/post/0289bcb8-d0d4-47b1-a7ae-b7ae82f8c54a/image.png" alt=""><strong>Screen Space</strong>로 변경 : 화면 기반으로 동작
<img src="https://velog.velcdn.com/images/kim_j_h/post/c5642095-8b68-49c7-8bb0-2443732ce15b/image.png" alt="">추후 루멘을 완전히 끌 수도 있음</p>
</blockquote>
<h2 id="그림자">그림자</h2>
<blockquote>
<ul>
<li><strong>ShadowDepths</strong>를 낮춰서 성능 향상시키기 -&gt; 그림자 / 조명 관련</li>
</ul>
</blockquote>
<h3 id="폴리지-그림자-세팅-변경">폴리지 그림자 세팅 변경</h3>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/ddab82f4-3d8f-4ff2-9519-681d365adc99/image.png" alt="">풀의 그림자 세팅에서 스태틱 섀도를 제외하고 비활성화 시켜 성능 향상 시키기 -&gt; 티가 안나는 부분이라 디테일한 그림자가 필요없음</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 10일차(Fog)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-10%EC%9D%BC%EC%B0%A8Fog</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-10%EC%9D%BC%EC%B0%A8Fog</guid>
            <pubDate>Mon, 19 May 2025 12:13:53 GMT</pubDate>
            <description><![CDATA[<h2 id="안개-만들기">안개 만들기</h2>
<blockquote>
<ul>
<li>레벨에 맵이 여러개 있기 때문에 하이트 포그로 사용하면 분위기를 바꾸기 힘들고 성능면에서도 안좋아서 PostProcessVolume에 머티리얼을 넣어서 맵마다 안개 구현 예정</li>
<li><em>M_PostFog*</em>
<img src="https://velog.velcdn.com/images/kim_j_h/post/6f85a462-3098-4ee2-8ed7-aa5c623904c2/image.png" alt=""></li>
</ul>
</blockquote>
<ul>
<li>최적화를 같이 고려한 하늘이나 안개 조성에 관한 자료를 계속 찾아보고는 있는데 마땅한게 아직은 나오지 않아서 작업 자체는 얼마 진행하지 못하는중..</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 9일차(최적화)]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-9%EC%9D%BC%EC%B0%A8%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-9%EC%9D%BC%EC%B0%A8%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Fri, 16 May 2025 03:44:25 GMT</pubDate>
            <description><![CDATA[<h2 id="pcg-최적화">PCG 최적화</h2>
<blockquote>
<ul>
<li><strong>나무를 에셋을 적용시켜보니 프레임이 20대로 바로 떨어짐
<img src="https://velog.velcdn.com/images/kim_j_h/post/876789f2-b7d2-4ed9-a806-341cfb41bc66/image.png" alt="">가장 먼저 PCG 볼륨 디테일 창에서 파티션 여부를 체크 해줌 -&gt; 프레임이 20대에서 50대로 올라감
<img src="https://velog.velcdn.com/images/kim_j_h/post/b0adf1d1-2ce4-4163-a8e6-6468b1534531/image.png" alt="">적용된 모습</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/fffd3483-e192-4688-997c-b851e58c404e/image.png" alt=""><strong>FPS : 53정도로 여유롭지는 않음
GPU Time : 18.83ms로 평균 초과 -&gt; 병목 발생 가능
Draw Calls : 135k Prims정도로 아직 많이 높음</strong></li>
</ul>
</blockquote>
<h2 id="메쉬-수정">메쉬 수정</h2>
<blockquote>
<ul>
<li><em><strong>메쉬의 나나이트 값을 수정해 퍼포먼스를 조금 올려보기</strong></em>
<img src="https://velog.velcdn.com/images/kim_j_h/post/348d4f60-acef-40ea-93bf-8a25398f2092/image.png" alt="">
<img src="https://velog.velcdn.com/images/kim_j_h/post/09d24689-4988-4de9-9a4f-4ae0a079fb74/image.png" alt=""></li>
<li><em>초기 상태 -&gt; 트라이앵글 감소가 없는 세팅*</em>
<img src="https://velog.velcdn.com/images/kim_j_h/post/25a81993-bd5b-49f0-adb7-dd635d598431/image.png" alt=""> <strong>세팅 변경 -&gt; 나나이트 트라이앵글 수 감소</strong></li>
</ul>
</blockquote>
<h3 id="-머터리얼들을-mask로-변경">+ 머터리얼들을 Mask로 변경</h3>
<h3 id="grass-컬-수정">Grass 컬 수정</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/c3958460-2640-4a33-9f53-38498e68e6de/image.png" alt=""><strong>지금 세팅에서는 컬 디스턴스의 시작과 끝이 동일 -&gt; 가깝거나 멀어도 동일하게 보임
<img src="https://velog.velcdn.com/images/kim_j_h/post/ae3ab53e-6a20-4322-8eac-b4976c737a07/image.png" alt="">변경 후
컬 디스턴스 시작 / 끝 수치 변경
다이내믹 새도 끄기 -&gt; 안개맵, 풀은 중요하지 않을 것 같아서 제거
<img src="https://velog.velcdn.com/images/kim_j_h/post/46db84de-9bd2-41c1-b722-f7fc1c5e6ad9/image.png" alt=""> Lumen Scene Lighting은 좋아지고 했지만
다른 부분은 안좋아지거나 비슷함
GPU Time -&gt; 증가
Distance Filed -&gt; 증가
Draw Calls -&gt; 증가(이건 감소할줄알았는데;)
Prims -&gt; 소폭 감소</strong></p>
</blockquote>
<ul>
<li><strong>가장 큰 문제가 나무 인 것 같음 -&gt; 임시로 쓰고 있는 나무기 때문에 쓸 나무를 정하고 그의 값을 조절해야할듯.</strong></li>
</ul>
<h2 id="메쉬-교체-후-최적화-작업">메쉬 교체 후 최적화 작업</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/19e82c08-3d0d-47c4-b603-ff1750b5f5e3/image.png" alt=""></p>
</blockquote>
<ul>
<li><strong>나나이트 활성화 / 수치 조정</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/b216a439-09ac-4c7d-9933-3dbbd4430d8f/image.png" alt=""></li>
<li><strong>인스턴스 컬 디스턴스 활성화 / 수치 조정</strong><h3 id="추후-추가로-들어가는-에셋도-동일하게-작업">추후 추가로 들어가는 에셋도 동일하게 작업</h3>
</li>
</ul>
<h2 id="pcg-분할">PCG 분할</h2>
<blockquote>
<ul>
<li>** 지금 테스트용으로 하나의 PCG 볼륨을 다 덮어놓음 -&gt; 과부화가 발생할 수 있기 때문에 인스턴스화해서 영역 분리해서 배치 작업하기**</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 8일차]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-8%EC%9D%BC%EC%B0%A8-z9gryysv</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-8%EC%9D%BC%EC%B0%A8-z9gryysv</guid>
            <pubDate>Thu, 15 May 2025 10:20:00 GMT</pubDate>
            <description><![CDATA[<h2 id="pcg-기본-생성">PCG 기본 생성</h2>
<blockquote>
<p><strong><img src="https://velog.velcdn.com/images/kim_j_h/post/fbb8e3a4-a221-443c-a2b6-848ed0de2585/image.png" alt=""><img src="https://velog.velcdn.com/images/kim_j_h/post/505fafba-fecd-420a-8e7b-4ad7c37d646d/image.png" alt="">PCG를 사용하고 크기를 적용해 나무를 넣어봄 -&gt; 나무가 지형각도대로 배치가 되어 너무 어색
<img src="https://velog.velcdn.com/images/kim_j_h/post/618f2252-f67b-4744-a817-572276d8e1d3/image.png" alt="">Transform Points노드에서 Rotation설정을 통해서 자연스럽게 서있는 느낌으로 구현
<img src="https://velog.velcdn.com/images/kim_j_h/post/c1123dcb-c382-495e-b41e-aebfdb4ee7c7/image.png" alt="">적용 완료</strong></p>
</blockquote>
<h3 id="랜드스케이프-최적화-설정-완료후-추가-작업-할-예정">랜드스케이프 최적화 설정 완료후 추가 작업 할 예정</h3>
<h2 id="월드-파티션-활성화">월드 파티션 활성화</h2>
<blockquote>
<ul>
<li><strong>에디터에서 오픈 월드에는 기본적으로 활성화가 되어있기 때문에 빈 오픈월드에서 생성해뒀음</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/f93ff67b-c63e-4667-87b2-c0f4b99217e4/image.png" alt=""><strong>오픈월드에서 생성하니 자동으로 나뉘는 셀</strong></li>
</ul>
</blockquote>
<h3 id="미니맵-생성">미니맵 생성</h3>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/dc27bd36-a979-494a-9185-d4087b0f4817/image.png" alt=""><strong>창 -&gt; 월드 파티션 -&gt; 월드 파티션 에디터를 활성화하니 이런 창이 뜨고 미니맵을 빌드할 수있음</strong></p>
<h3 id="월드--랜드스케이프-디테일-설정">월드 / 랜드스케이프 디테일 설정</h3>
<p><strong><img src="https://velog.velcdn.com/images/kim_j_h/post/f34f89be-e1d6-4b15-a242-eba66d9bc568/image.png" alt="">월드 세팅에 있는 파티션 인덱스 MainPartition를<img src="https://velog.velcdn.com/images/kim_j_h/post/52af49f1-25eb-4467-82f9-cea1b46d9577/image.png" alt="">랜드스케이프 세팅에 있는 런타임 그리드에 적용한후 &quot;공간적으로 로드되었는지 여부&quot;를 꼭 체크해야지 셀이 자동으로 분할 표시됨</strong></p>
<h3 id="플레이어-캐릭터-설정">플레이어 캐릭터 설정</h3>
<ul>
<li><strong>월드 파티션 스트리밍은 플레이어나 지정된 소스의 위치를 기준으로 작동하기 때문에
플레이어에 컴포넌트를 하나 부착<img src="https://velog.velcdn.com/images/kim_j_h/post/90e420ef-9a95-44ec-a4da-f2639c831c68/image.png" alt=""><img src="https://velog.velcdn.com/images/kim_j_h/post/0ace05e1-0e7b-43ff-8745-8f64ee32c2b8/image.png" alt="">스트리밍 소스 활성화 체크 확인</strong></li>
</ul>
<h2 id="hlod-설정">HLOD 설정</h2>
<blockquote>
<ul>
<li><strong>월드 파티션만 활성화 시키면 멀리 있던 산이 일정거리내의 시야로 들어오면 갑자기 생기는 방식이라 월드 파티션으로 생성 -&gt; HLOD로 그래픽 보정 방향으로 갈 생각</strong></li>
</ul>
</blockquote>
<h3 id="레이어-적용">레이어 적용</h3>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/a1ef71e6-9edb-45cb-b0b5-1a16201ee757/image.png" alt=""><strong>레벨 생성 시 자동으로 생성되는 HLOD 레이어를 적용 시키기 ( Merged는 lnstanced의 부모)</strong></p>
<ul>
<li><strong>lnstanced : PCG로 뿌린 나무 등 반복 오브젝트 최적화용</strong></li>
<li>**Merged : 추후 구조물, 스태틱 메쉬 그룹화용</li>
<li><blockquote>
<p>나중에 PCG에 사용 가능하면 적용해서 최적화 할 예정**
<img src="https://velog.velcdn.com/images/kim_j_h/post/4d85140c-f0a2-43cb-bfe5-8fbd83300c6c/image.png" alt=""> <strong>랜드스케이프는 기본적으로 LOD기능이 적용되어있어 다른 메쉬를 집어 넣어주지 않아도 적용이 됨</strong></p>
</blockquote>
<h3 id="하지만-다른-메쉬는-hlod-적용-메쉬를-넣어줘야-적용이-됨----ex-로우-폴리곤-모델링">하지만 다른 메쉬는 HLOD 적용 메쉬를 넣어줘야 적용이 됨  -&gt; Ex) 로우 폴리곤 모델링</h3>
</li>
</ul>
<h2 id="디버깅">디버깅</h2>
<blockquote>
<ul>
<li><strong>기본적으로 활성화 되어있는 월드 파티션을 디버깅을 통해 플레이 화면에서 자연스러운지 확인하고 수치를 조절하기</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/7880c257-e572-48f1-aacf-ae722a323950/image.png" alt=""></li>
</ul>
</blockquote>
<ul>
<li><strong>wp.Runtime.ToggleDrawStreamingSources : 플레이어 컨트롤러의 Streaming Source 상태를 표시한 것</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/9efab1dc-7b9a-4165-93bf-d480354b3354/image.png" alt=""></li>
<li><strong>wp.Runtime.ToggleDrawStreamingPerf : Streaming 시스템의 전체 상태 표시</strong></li>
<li><strong>현재 PIE 모드에서 단일 플레이어로 실행중</strong></li>
<li><strong>Blocking Enabled : 스트리밍 지연 방지가 설정되어있음</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/6295e368-e77e-4fd7-a4a9-14d4acfa375c/image.png" alt=""></li>
<li>**wp.Runtime.ToggleDrawRuntimeCellsDetails : 각 셀의 로딩 상태를 실시간으로 출력</li>
<li><blockquote>
<p>HLOD 셀과 MainPartition 셀이 함께 로드된 경우도 출력**
<img src="https://velog.velcdn.com/images/kim_j_h/post/e79cb1fb-3739-489a-949a-ef48c1f29c78/image.png" alt=""></p>
</blockquote>
</li>
<li><strong>wp.Runtime.ToggleDrawRuntimeHash2D : 현재 로딩 셀을 2D 그리그 셀로 시각화 함 -&gt; 언리얼 공식 문서에는 색이 활성화되는 이미지가 있었는데 나는 활성화가 안되서 찾아보니 5.3 이후에는 명령어가 바뀌었다고 함.. 아직은 잘 모르겠음</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/66458132-3ed4-46d9-9f83-3b25b645606c/image.png" alt=""></li>
<li>** HLOD 셀 시각화 : 이건 정상적으로 색이 보임..**</li>
</ul>
<h2 id="월드-파티션--hlod-조합-수치-조절">월드 파티션 + HLOD 조합 수치 조절</h2>
<blockquote>
<ul>
<li><strong>플레이어의 시야각 : 90 / 안개를 배치한다는 가정하에 초기 설정</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/73d2d601-ba5c-4bf3-860d-27752bd7390f/image.png" alt=""></li>
</ul>
</blockquote>
<ul>
<li><strong>셀 크기(5120) : 약 50m x 50m 단위</strong></li>
<li><strong>로딩 범위(15360) : 카메라 주변 약 150m 반경으로 셀 로딩</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/dd80936f-0625-4d62-8e4d-15548919a671/image.png" alt=""></li>
<li><strong>셀 크기(15360) : 파티션 로딩범위와 일치 시킴</strong></li>
<li><strong>로딩 범위(76800) : 약 768m로 셀크기의 약 5배 정도로 설정(더 줄여도 무방할거같음)</strong></li>
</ul>
<h2 id="다음-할일--pcg-최적화">다음 할일 : PCG 최적화</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 7일차 ]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-7%EC%9D%BC%EC%B0%A8-1ynz0292</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-7%EC%9D%BC%EC%B0%A8-1ynz0292</guid>
            <pubDate>Wed, 14 May 2025 12:19:05 GMT</pubDate>
            <description><![CDATA[<h2 id="랜드스케이프-머터리얼-적용">랜드스케이프 머터리얼 적용</h2>
<blockquote>
<ul>
<li><strong>위치, 거리 등 조건에 맞게 자동 생성해주는 머터리얼 파일을 가져와서 임시 배치</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>활용해서 구역별 텍스처만 바꿔주면 작업 시간 빨라질 것 같음.</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/87d9c693-dfbb-4f2f-87cf-cb8ae9494989/image.png" alt="">임시 배치</li>
</ul>
<h2 id="pcg-사용">PCG 사용</h2>
<blockquote>
<ul>
<li><strong>PCG를 인스턴스화해서 메쉬만 바꾸고 컨셉에 맞게 배치하면 될듯</strong>
<img src="https://velog.velcdn.com/images/kim_j_h/post/88abac58-3597-4ce0-bd87-2550be0b8203/image.png" alt="">**초기 임시 노드</li>
<li><blockquote>
<p>LandScape의 지형 데이터를 받아와 -&gt; 지형 정보에 따라 포인터들을 랜덤하게 찍고 -&gt; Density필터를 통해 간격을 조절해 -&gt; 회전 / 크기 등을 설정해서 배치**
<img src="https://velog.velcdn.com/images/kim_j_h/post/247617a4-332e-4066-a721-b761bf201212/image.png" alt=""><strong>기본 PCG 메쉬를 이용해 임시 배치하기</strong></p>
</blockquote>
</li>
</ul>
</blockquote>
<h3 id="추가-기능과-기울기에-따른-배치-필터방식에-대해서-좀-알아보기">추가 기능과 기울기에 따른 배치 필터방식에 대해서 좀 알아보기</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 7일차]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-7%EC%9D%BC%EC%B0%A8-rf72we3t</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-7%EC%9D%BC%EC%B0%A8-rf72we3t</guid>
            <pubDate>Tue, 13 May 2025 12:14:57 GMT</pubDate>
            <description><![CDATA[<h2 id="랜드스케이프-임포트">랜드스케이프 임포트</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/82fc9917-6250-47b2-afaf-571058a0b47d/image.png" alt="">504x504 16개로 임포트 완료 -&gt; 산맥지형을 좀 더 부곽시키는 방향으로 HeightMap 재생성</p>
</blockquote>
<h2 id="기본-환경-설정">기본 환경 설정</h2>
<blockquote>
<ul>
<li><strong>라이트와 포그를 조절해 밤 느낌이 나게 조절하기</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>하나의 레벨에서 여러맵이 있으므로 ExponentialHeightFog는 약하게 설정하고 PostProcessVolume + Fog로 맵마다 설정을 할 계획</strong><h3 id="일단-숲-맵을-기준으로-설정하기">일단 숲 맵을 기준으로 설정하기</h3>
</li>
<li>**시간대 : 달빛이 은은하게 보이는 밤</li>
<li><blockquote>
<p>Directional Light 와 Sky Light로 조절**</p>
</blockquote>
</li>
<li><strong>하늘 : Sky Atmosphere + 하늘 텍스쳐를 넣어서 표현</strong></li>
<li>**안개 : 기본 ExponentialHeightFog로는 기본적인 표현만 하기</li>
<li><blockquote>
<p>숲은 시야가 어느정도 트이게 안개 조절**</p>
</blockquote>
</li>
</ul>
<h3 id="유튜브로-기본-강의-영상을-좀-보면서-공부해야할듯">유튜브로 기본 강의 영상을 좀 보면서 공부해야할듯..</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 6일차]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-6%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-6%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 12 May 2025 13:26:53 GMT</pubDate>
            <description><![CDATA[<h2 id="하이트맵-분할-작업">하이트맵 분할 작업</h2>
<blockquote>
<h3 id="추후-월드-파티션을-사용하기-위해-분할하기">추후 월드 파티션을 사용하기 위해 분할하기</h3>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/c1d3347c-bdf0-4150-ae2f-99074ac8f9e7/image.png" alt=""><strong>분할한 타일 중 하나인데 컴포넌트 수가 너무 많아서 성능에 지장을 줄 것 같음</strong></p>
</blockquote>
<ul>
<li>**언리얼에서는 기본적으로 최대 32x32로 제한해두기 때문에 분할 작업을 다시해야함</li>
<li>*</li>
<li>** 63x63 쿼드 / 1x1 섹션 / 컴포넌트수를 8x8 정도로 리사이징 후 4x4크기로 해서 2km 크기로 맞추기**<img src="https://velog.velcdn.com/images/kim_j_h/post/35eb3aad-ddd5-4969-981a-1807ae21860c/image.png" alt="">뭔가 마음에 안듬..
절벽 구성이 좀 밋밋한 느낌이 든다</li>
</ul>
<h2 id="랜드스케이프-다시-제작중">랜드스케이프 다시 제작중...</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[최대공약수와 최소공배수]]></title>
            <link>https://velog.io/@kim_j_h/%EC%B5%9C%EB%8C%80%EA%B3%B5%EC%95%BD%EC%88%98%EC%99%80-%EC%B5%9C%EC%86%8C%EA%B3%B5%EB%B0%B0%EC%88%98</link>
            <guid>https://velog.io/@kim_j_h/%EC%B5%9C%EB%8C%80%EA%B3%B5%EC%95%BD%EC%88%98%EC%99%80-%EC%B5%9C%EC%86%8C%EA%B3%B5%EB%B0%B0%EC%88%98</guid>
            <pubDate>Mon, 12 May 2025 01:02:40 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p><strong>두 수를 입력받아 두 수의 최대공약수와 최소공배수를 반환하는 함수, solution을 완성해 보세요. 배열의 맨 앞에 최대공약수, 그다음 최소공배수를 넣어 반환하면 됩니다. 예를 들어 두 수 3, 12의 최대공약수는 3, 최소공배수는 12이므로 solution(3, 12)는 [3, 12]를 반환해야 합니다.</strong></p>
</blockquote>
<h2 id="풀이">풀이</h2>
<pre><code>#include &lt;string&gt;
#include &lt;vector&gt;

using namespace std;

int max(int a, int b)
{
    while(b != 0)
    {
        int c = a % b;
        a = b;
        b = c;
    }
    return a;
}

vector&lt;int&gt; solution(int n, int m) {
    vector&lt;int&gt; answer;

    int g = max(n , m);
    int l = (n * m) / g;

    answer.push_back(g);
    answer.push_back(l);

    return answer;
}</code></pre><h2 id="풀이-방식">풀이 방식</h2>
<blockquote>
<ul>
<li>**유클리드 호제법을 사용해 최대공약수를 구하기</li>
<li><blockquote>
<p>두 정수 a, b에 대해 a를 b로 나눈 나머지 c를 구하고 b와 c로 다시 과정을 반복해서 나머지가 0이 되면 그 수가 최대공약수**</p>
</blockquote>
</li>
</ul>
</blockquote>
<ul>
<li><strong>while 문 : 유클리드 호제법은 O(logN)만큼만 반복해서 매우 빠르고 반복 횟수도 적으니 while이 효율적</strong></li>
<li><strong>조건 : 종료 조건이 나머지가 0이 될때, 즉 a가 아니라 b가 0이 될때가 최대공약수</strong></li>
<li>**a, b 의 크기는 고려를 안해도 되나?</li>
<li><blockquote>
<p>안해도 됨 어차피 b 가 이 될때까지 반복하면서 결국 최대공약수에 도달하기 때문
Ex) gcd(12, 30) : 12 % 30 = 12 -&gt; gcd(30, 12) -&gt; 30 % 12 = 6 처럼 어차피 정렬됨.**</p>
</blockquote>
</li>
<li><strong>최소 공배수 : 두 수의 고베서 최대 공약수를 나누기</strong></li>
</ul>
<h2 id="다른-풀이">다른 풀이</h2>
<blockquote>
<ul>
<li>C++17 이상에서는 gcd와 lcm라는 라이브러리 함수를 이용해서 쉽게 구할 수 있음</li>
</ul>
</blockquote>
<pre><code>#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;numeric&gt;  // std::gcd, std::lcm

using namespace std;

vector&lt;int&gt; solution(int n, int m) {
    vector&lt;int&gt; answer;

    int g = gcd(n, m);       // 최대공약수
    int l = lcm(n, m);       // 최소공배수

    answer.push_back(g);
    answer.push_back(l);

    return answer;
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 3일차]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-3%EC%9D%BC%EC%B0%A8-j4klt5xq</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-3%EC%9D%BC%EC%B0%A8-j4klt5xq</guid>
            <pubDate>Fri, 09 May 2025 11:25:51 GMT</pubDate>
            <description><![CDATA[<h2 id="ai-이미지-생성으로-height맵-작성하기">AI 이미지 생성으로 Height맵 작성하기</h2>
<blockquote>
<ul>
<li><strong>프롬프르틀 작성해 하이트맵 뽑기</strong></li>
</ul>
</blockquote>
<h2 id="지형-구성-상세">지형 구성 상세</h2>
<blockquote>
<h3 id="중앙-구역">중앙 구역</h3>
</blockquote>
<ul>
<li><strong>평평하거나 약간의 기복이 있는 지형</strong></li>
<li><strong>플레이어 스폰 지역으로 사용</strong></li>
<li><strong>사방으로 이동 가능한 구조</strong></li>
<li><strong>지형 중심이 약간 솟아 있되 전반적으로 평탄함 유지</strong><h3 id="북쪽-구역">북쪽 구역</h3>
</li>
<li><strong>점진적으로 상승하는 경사 -&gt; 삼각형 형태의 봉우리</strong></li>
<li><strong>고대 신전이 놓일 수 있는 언덕 느낌</strong></li>
<li><strong>전경 -&gt; 중경 -&gt; 배경으로 삼각형 시야 구성을 반영한 고도 분포</strong></li>
<li><strong>경사는 부드럽고 자연스러워야 함</strong><h3 id="남쪽-구역">남쪽 구역</h3>
</li>
<li><strong>부드럽게 하강하는 곡선형 협곡 또는 계곡</strong></li>
<li><strong>동굴 입구처럼 보이게 하되 급경사 없이 자연스럽게 연결</strong></li>
<li><strong>물 흐름을 연상시키는 U자형 또는 V자형 지형</strong><h3 id="동서쪽-구역">동/서쪽 구역</h3>
</li>
<li><strong>완만한 경사 또는 구릉지형</strong></li>
<li><strong>중심부와 연결되며 생태/테마 전환을 위한 기반 제공</strong></li>
<li><strong>서쪽은 낮은 늪지 느낌, 동쪽은 약간 올라간 언덕 형태</strong><h3 id="외곽-경계">외곽 경계</h3>
</li>
<li><strong>전체 맵의 가장자리는 부드러운 언덕 또는 고지대로 둘러쌈</strong></li>
<li><strong>절벽 없이 자연스러운 고도 차로 플레이어 이탈 방지</strong></li>
<li><strong>경계 고도는 주변보다 약간 높지만 급격한 상승 없음</strong></li>
</ul>
<h2 id="기술적-조건">기술적 조건</h2>
<blockquote>
<ul>
<li><strong>이미지 해상도는 정확히 2049 x 2049 픽셀이어야 함</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>16비트 그레이스케일 (R16 RAW 형식)으로 저장</strong></li>
<li><strong>깨끗한 고도 정보만 포함 (픽셀 노이즈, 계단 현상 X)</strong></li>
<li><strong>지나치게 검거나 하얀 픽셀 없음 (예: 0 또는 65535 회피)</strong></li>
<li><strong>일반적인 고도는 중간 값대(예: 30000 근처) 중심</strong></li>
<li><strong>출력물은 반드시 흑백 하이트맵 데이터만 포함해야 함 (색, 텍스트, 건물 없음)</strong></li>
<li><strong>언리얼 엔진에서 오픈월드 숲 테마 허브 지형으로 사용</strong></li>
<li><strong>이후 foliage(수풀), 구조물 배치 등을 위해 고저차가 과하지 않아야 함</strong></li>
<li><strong>AI의 내비게이션 메시가 완전 커버될 수 있도록 매끄러운 경사 유지</strong></li>
<li><strong>최종 결과물은 그레이스케일 높이 데이터만 포함된 이미지</strong></li>
<li><strong>RAW 포맷은 비손실로 저장되어야 하며, 포토샵 또는 툴을 통해 변환 가능</strong></li>
</ul>
<h2 id="생성한-height-맵">생성한 Height 맵</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/kim_j_h/post/a0aa5d72-0000-4137-b0ea-b7ba1f7fbbe2/image.png" alt=""><img src="https://velog.velcdn.com/images/kim_j_h/post/12ba6ae3-1d15-4e23-8586-7d9eaee0cdb5/image.png" alt=""><strong>3x3으로 나눠서 랜드스케이프 임포트 후 경계부분이나 디테일한 부분은 브러쉬로 작업할 예정</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Last Canary 2일차]]></title>
            <link>https://velog.io/@kim_j_h/Last-Canary-2%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@kim_j_h/Last-Canary-2%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 08 May 2025 10:52:34 GMT</pubDate>
            <description><![CDATA[<h2 id="게이트-내부-숲-맵-기획">게이트 내부 숲 맵 기획</h2>
<blockquote>
<h3 id="개요">개요</h3>
</blockquote>
<ul>
<li><strong>맵 이름 : 게이트 내부 -&gt; 숲</strong></li>
<li><strong>맵 컨셉 : 게이트를 통해 진입한뒤 탐사하고, 다른 입구를 찾는 허브 구역</strong></li>
<li><strong>크기 : LandScape 706 x 706 9개 (3x3 그리드)</strong></li>
<li><strong>구성 구역 : 5개 (중앙 초기 스폰지역 + 4개의 테마 구역입구)</strong></li>
<li><strong>목표 : 환경/정보/자원 탐색, 다른 입구를 찾아 진입</strong></li>
<li><strong>흐름 구조 : 랜덤 스폰 -&gt; 탐색 -&gt; 입구 발견 후 진입 -&gt; 나온 후 현실로 탈출</strong></li>
<li><strong>탈출 방식 : 미정 (게이트 랜덤 생성 / 시간별 생성 / 아이템 이용 생성)</strong></li>
</ul>
<h2 id="구조">구조</h2>
<blockquote>
<h3 id="중심-숲초기-스폰-지역">중심 숲(초기 스폰 지역)</h3>
</blockquote>
<ul>
<li><strong>게이트 진입 후 각 플레이어는 랜덤 위치에서 스폰</strong></li>
<li><strong>비교적 안전한 공간으로, 합류 / 파밍 / 정비가 가능한 초기 거점</strong></li>
<li>*<em>입구 방향은 구조물, 시체, 지형, 시야 연출로 자연스럽게 유도하는것이 목표 *</em><h3 id="4방향-입구-구역">4방향 입구 구역</h3>
</li>
<li><strong>동서남북(혹은 모서리) 4구역내에 특정 위치에 존재</strong></li>
<li><strong>각 입구 주변에는 컨셉에 맞는 환경으로 조성</strong></li>
<li><strong>진입 시 해당 컨셉 레벨로 Seamless Load</strong><h3 id="맵-경계-처리-방식">맵 경계 처리 방식</h3>
</li>
<li>** 각 구역 간 경계는 자연스럽게 연결되도록 구성**</li>
<li><strong>급격한 지형 변화 없이 숲-&gt; 늪지 -&gt; 바위지대 등으로 자연스럽게 연결</strong></li>
<li><strong>입구 지역으로의 접근은 시야 차단 요소 + 트라이앵글 기법으로 유도</strong></li>
<li><strong>외각 경계는 짙은 안개, 빛 차단 구조등으로 처리</strong></li>
</ul>
<h2 id="유도-방식">유도 방식</h2>
<blockquote>
<h3 id="시각적-유도">시각적 유도</h3>
</blockquote>
<ul>
<li>**프레이밍 (Framing) : 나무, 바위, 구조물 등으로 시야를 제한하거나 특정 방향을 강조</li>
<li><blockquote>
<p>숲 사이 틈새로 멀리 신전의 실루엣이 보이도록 구성**</p>
</blockquote>
</li>
<li>**삼각 구성 (Triangle Composition) : 전경 –&gt; 중경 –&gt; 배경을 삼각형처럼 배치해 시선 유도</li>
<li><blockquote>
<p>바위 ~ 쓰러진 석상 ~ 폐허 입구**</p>
</blockquote>
</li>
<li>**라이팅 , 머터리얼 : 따뜻한 색의 광원, 햇살, 랜턴 등을 통해 시각적 유도</li>
<li><blockquote>
<p>안개 속 밝은 틈새나 강한 조명 연출 **</p>
</blockquote>
<h3 id="환경적-유도">환경적 유도</h3>
</li>
<li><strong>지형 흐름 : 평지 -&gt; 완만한 경사 -&gt; 협곡 등 자연스러운 이동 경로 제공</strong></li>
<li><strong>구조물 배치 : 폐허, 기념비, 시체 등 중간중간 흥미를 끄는 오브젝트 배치</strong></li>
<li><strong>소프트 바리어 (Soft Barriers) : 덤불, 급경사 등으로 갈 수 없는 길을 우회 유도</strong><h3 id="행동-유도">행동 유도</h3>
</li>
<li><strong>AI 동선 유도 : 동물/NPC의 이동을 따라가면 입구에 도달</strong></li>
<li><strong>이벤트 트리거 : 특정 위치 진입 시 사운드, 카메라 연출 등으로 방향 피드백 제공</strong><h3 id="인지-유도">인지 유도</h3>
</li>
<li><strong>대조 강조 : 목적지는 독특한 구조/조명으로 시각적 우위 확보</strong></li>
<li><strong>파밍 오브젝트 : 시체, 무기, 흔적 등을 흐름 있게 배치하여 방향 유도</strong></li>
</ul>
<h2 id="환경-디자인-방향">환경 디자인 방향</h2>
<blockquote>
<ul>
<li>*<em>전체 지형  : 자연스러운 숲 구상 (지형으로는 컨셉의 구간 경계를 표현하지 않음) *</em></li>
</ul>
</blockquote>
<ul>
<li><strong>산 : 플레이어가 오를 수 있는 경사 지형은 하이트맵으로 조정 (15~30도 완경사 유지) /  플레이할 수 없는 영역의 높고 급격한 산, 배경용 절벽 등은 Static Mesh 오브젝트로 배치
-&gt; 이 오브젝트 산은 시야 차단, 연출, 레벨 경계 표현(바깥 맵 차단) 등의 용도로 사용 / LOD 및 Collision 여부는 거리/성능에 따라 세분화하여 설정</strong></li>
<li><strong>계곡/하천 : 맵을 관통하는 흐름에서 잔가지 흐름  / 허리 높이 이하 수심(AI와 플레이어 파트의 할 일이 많아짐)</strong></li>
<li>*<em>늪지대 : 묘비쪽 컨셉에 배치 -&gt;마찬가지로 허리 이하 *</em></li>
<li><strong>식생 : 컨셉에 맞는 수종 및 풀 종류를 PCG로 배치 / 주요 구역은 수동 조절</strong></li>
<li><strong>분위기 : 구역마다 광원 및 안개, 배경음등을 다르게 연출</strong></li>
<li><strong>경계 전환부 : 두 컨셉이 자연스럽게 이어지도록 색감, 식생, 조도 등을 점진적 변화시켜 연결</strong></li>
<li>*<em>배치툴 : PCG 활용 예정 / 이벤트 영역은 수동 배치 *</em></li>
<li><strong>내비메시 : 플레이어가 이동 가능한 지역에 커버되도록 지형 조정</strong></li>
</ul>
<h2 id="구역-컨셉">구역 컨셉</h2>
<blockquote>
<ul>
<li><strong>중앙 숲 : 나무 밀도 대체로 낮음 / 입구 방향에 시체나 구조물등을 배치해 파밍요소에 대해 간접적으로 알려주고, 방향 유도</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>동굴 입구 : 어두운 협곡 / 습기 찬 환경 / 입구까지 그늘과 암석이 점차 증가 / 계곡 쪽에서 지하동굴로 들어가는 느낌</strong></li>
<li><strong>공동 묘지 입구 : 짙은 안개 / 주변에 늪지대 / 경계선에서 나무 밀도 낮아지고 죽은 땅 분위기</strong></li>
<li><strong>폐허 테마파크 입구 : 쓰러진 놀이기구 / 접근할수록 갈라진 땅이나 철골 구조물 배치</strong></li>
<li><strong>폐허 신전입구 : 산 위에 배치 / 대칭 석상(고대 조형물) / 입구 방향에 식생 밀도 줄이고 석상 조형물이 많아짐</strong></li>
</ul>
<h2 id="지형-조정">지형 조정</h2>
<blockquote>
<h3 id="landscape-구성">LandScape 구성</h3>
</blockquote>
<ul>
<li><strong>706 x 706 LandScape 9개 (3x3 Grid)</strong></li>
<li><em>-&gt; 하나로 만들시 2049 x 2049*</em></li>
<li><strong>Level Streaming 적용</strong></li>
<li><em>-&gt; 몇번 Height맵을 만들어 실험해본 결과 경계간 연결이 부자연스럽게 적용되는 문제가 발생해 문제 해결이 안될 시 하나의 LandScape 사용 고려*</em><h3 id="스무딩-처리--고저차-처리">스무딩 처리 / 고저차 처리</h3>
</li>
<li>** Smooth 기능을 활용해 고저차 조정이 필요한 부분와 지형이 어색한 부분 직접 수정**<h3 id="컨셉-경계-전환">컨셉 경계 전환</h3>
</li>
<li><strong>지형 / 식생 / 조명 / 분위기 요소등을 점진적 전환</strong></li>
<li><strong>경계부는 혼합 식생과  중간 톤, 조명 사운드 조절등을 통해 부드럽게 연결</strong><h3 id="경계-시각-보완">경계 시각 보완</h3>
</li>
<li><strong>외각 경계는 짙은 안개, 폐목, 큰 바위등을 배치해 이동 제한 연출</strong></li>
</ul>
<h2 id="하이트-맵-생성-요구사항">하이트 맵 생성 요구사항</h2>
<blockquote>
<h3 id="몇번의-테스트-후-height맵-생성시-ai에게-요구할-사항-정리">몇번의 테스트 후 Height맵 생성시 AI에게 요구할 사항 정리</h3>
</blockquote>
<ul>
<li>**지형을 활용해 구역 간 경계를 직접 표현하지 말 것</li>
<li><blockquote>
<p>시야 차단용 오브젝트, 식생, 안개 등으로 구분 연출**</p>
</blockquote>
</li>
<li>** 하이트맵 해상도는 전체 레벨 해상도와 반드시 동일하게 설정</li>
<li><blockquote>
<p>예: 전체 맵 해상도가 2049x2049라면 하이트맵도 정확히 2049x2049**</p>
</blockquote>
</li>
<li>**16bit R16 RAW 포맷으로 저장 필수</li>
<li><blockquote>
<p>R8 또는 8bit 포맷은 디테일 손실과 뾰족한 지형 발생 우려로 사용 금지**</p>
</blockquote>
</li>
<li>**과도한 경사 디테일 표현 금지</li>
<li><blockquote>
<p>고저차나 지형 세부 표현이 과할 경우 실제 플레이 시 마인크래프트 형태처럼 각지고 비현실적인 지형이 발생할 수 있음**</p>
</blockquote>
</li>
<li>**뾰족하거나 각진 고도 표현 방지</li>
<li><blockquote>
<p>플레이어나 AI가 걸을 수 없는 급경사 또는 뾰족한 지형 금지**</p>
</blockquote>
</li>
<li>**Smooth 기능을 활용해 경사를 부드럽게 조정할 것</li>
<li><blockquote>
<p>불연속 픽셀, 톱니 현상, 이동 불가 지형을 제거하여 내비메시 커버 보장**</p>
</blockquote>
</li>
</ul>
<h3 id="지형에-대한-세부-설정--팀원과-기획-조율후-height맵-생성-요청예정">지형에 대한 세부 설정 / 팀원과 기획 조율후 Height맵 생성 요청예정</h3>
]]></description>
        </item>
    </channel>
</rss>