<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ID.log</title>
        <link>https://velog.io/</link>
        <description>이사감 -&gt; bit.ly/KunHo_Heo</description>
        <lastBuildDate>Thu, 23 Feb 2023 14:21:25 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ID.log</title>
            <url>https://velog.velcdn.com/images/hkun_ho/profile/247c27ad-7d9b-44b5-8c2c-e74ea6a3a18a/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ID.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hkun_ho" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[UE] Collision]]></title>
            <link>https://velog.io/@hkun_ho/UE-Collision-ejtuneqt</link>
            <guid>https://velog.io/@hkun_ho/UE-Collision-ejtuneqt</guid>
            <pubDate>Thu, 23 Feb 2023 14:21:25 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<ul>
<li>본 학습 자료는 경희대학교 게임 &amp; 실감형 컨텐츠 제작 동아리 <code>Ludens</code> 의 Unreal-Study 자료입니다.</li>
</ul>
<h1 id="player">Player</h1>
<ul>
<li>우리는 먼저 Player 의 무기에 Collision 을 추가해줄겁니다.</li>
</ul>
<h2 id="weapon-collision">Weapon Collision</h2>
<ul>
<li>PlayerBP 를 열어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/849bcef0-4778-4acb-b0c3-86a5f3b4528f/image.png" alt=""></p>
<ul>
<li><p>메시 컴포넌트의 하위 항목으로 &#39;Box Collision&#39; 을 추가해줍시다. 이름은 Weapon 으로 합시다.</p>
</li>
<li><p>Weapon 의 디테일 탭에서, &#39;부모 소켓&#39; 을 FX_weapon_base 로 바꿔줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/46c9e517-5c28-4ba7-a3e0-27dce896af1d/image.png" alt=""></p>
<ul>
<li>그리고, 트랜스폼의 각 요소들을 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9e2110f3-1db4-41a3-b422-1c28e6b2cedb/image.png" alt=""></p>
<ul>
<li>위와 같이 트랜스폼을 변경하면 다음과 같이 칼의 크기와 비슷한 Collision 이 생성될 것입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/478060a4-704e-4009-8240-f9cd9dbc5eb4/image.png" alt=""></p>
<ul>
<li>만약 Collision 이 이상하거나, 조금 더 잘 맞게 바꾸고 싶다면 직접 트랜스폼의 요소들을 변경하면 됩니다.</li>
</ul>
<h3 id="collision-설정">Collision 설정</h3>
<ul>
<li>디테일 탭을 조금 내리다보면, &#39;콜리전&#39; 이라는 항목이 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/28c4234a-016a-46b6-a412-19890f3c7008/image.png" alt=""></p>
<blockquote>
<ul>
<li>&#39;Can Character Step Up On&#39; 을 &#39;No&#39; 로 설정해줍시다. 말 그대로 칼 위에 다른 캐릭터가 서 있을 수 없도록 설정하는 것입니다. (크게 중요하진 않습니다.)</li>
<li>&#39;콜리전 프리셋&#39; 을 &#39;Custom...&#39; 으로 설정해주고, &#39;콜리전 활성화됨&#39; 을 &#39;No Collision&#39; 으로 설정해줍시다.<blockquote>
<p>왜 콜리전을 없애버리는 지 궁금하신 분도 계실겁니다. 곧 설명하겠지만, Player 가 공격을 할 때만 Collision 을 On 하고, 공격이 끝나면 Off 하는 방식을 사용할 것이기 때문에, 평소에는 No Collision 상태로 설정해두는 것입니다.</p>
</blockquote>
</li>
<li>마지막으로, &#39;콜리전 반응&#39; 에서 오버랩을 체크해줍시다. 무언가가 Collision 을 통과하였을 때 반응하겠다는 뜻입니다.</li>
</ul>
</blockquote>
<h3 id="overlap-event-생성">Overlap Event 생성</h3>
<ul>
<li>디테일 탭을 조금 더 내리면, &#39;이벤트&#39; 라는 항목이 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/de9591e4-7d0a-4e6f-9499-f8efa39ac865/image.png" alt=""></p>
<ul>
<li>&#39;컴포넌트 오버랩 시작 시&#39; 이벤트를 추가해줍시다. + 버튼을 누르면 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ec29b3a8-c25f-417c-b849-e3e234a85a32/image.png" alt=""></p>
<ul>
<li>바로 이벤트 노드로 넘어왔다면 잘 생성된겁니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/22b9c73e-1080-4923-a362-8a9e7828fc7a/image.png" alt=""></p>
<ul>
<li>오버랩 된 다른 액터가 &#39;Enemy&#39; 라는 Tag 를 가지고 있을 때만 &#39;Enemy&#39; 라는 문구를 출력하겠다는 이야기입니다.<blockquote>
<ul>
<li>Print String 노드는 확인용입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="ememy-tag-추가">Ememy Tag 추가</h4>
<ul>
<li>우리는 Enemy 에게 &#39;Enemy&#39; 라는 Tag 를 추가한 적이 없습니다. 따라서 추가해줍시다.<blockquote>
<ul>
<li>EnemyBP 를 열어줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/34a81ca8-24fd-4462-a16b-0cc574523b0e/image.png" alt=""></p>
<ul>
<li>EnemyBP (셀프)를 선택한 뒤, 디테일 탭에서 Tag 를 검색해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/84c987a3-5860-44aa-9263-6a35549aabd9/image.png" alt=""></p>
<ul>
<li>태그 항목 옆에 있는 &#39;+&#39; 버튼을 눌러주고, 인덱스[0] 에 Enemy 를 적어줍시다.</li>
</ul>
<h2 id="collision-onoff">Collision On/Off</h2>
<ul>
<li>우리는 AnimNotify 를 이용하여 Collision 을 켜고, 끌겁니다. AnimNotify 1주차에 이어 재등장~</li>
</ul>
<h3 id="montage-에서-notify-추가">Montage 에서 Notify 추가</h3>
<ul>
<li>PrimaryAttack_A_Slow_Montage, PrimaryAttack_B_Slow_Montage, PrimaryAttack_C_Slow_Montage, PrimaryAttack_D_Slow_Montage 에 똑같은 작업을 수행할 것임으로, PrimaryAttack_A_Slow_Montage 를 예시로 들어 설명하겠습니다.<blockquote>
<ul>
<li>PrimaryAttack_A_Slow_Montage 를 검색하여 열어줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/42393b85-e0be-4a28-9c6d-669a401ce9a4/image.png" alt=""></p>
<h4 id="primaryattack_a_slow_montage">PrimaryAttack_A_Slow_Montage</h4>
<ul>
<li>먼저, 노티파이 트랙을 하나 더 추가해줄겁니다. 다음과 같이 추가해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/041c5677-ff68-4703-8ba9-a7a7a6a32b07/image.png" alt=""></p>
<ul>
<li>노티파이 트랙 &#39;2&#39; 의 빈공간을우클릭하고, 다음과 같이 새 노티파이를 추가해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/04b7e55d-bc2a-462d-9ae1-8e853c750092/image.png" alt=""></p>
<ul>
<li>이와 같은 방법으로 노티파이를 2개 추가해줄겁니다. 이름은 각각 &#39;AttackStart&#39; 와 &#39;AttackFinish&#39; 로 해줍니다.<blockquote>
<ul>
<li>말 그대로, 공격의 시작 지점과 끝 지점에서 Notify 를 발생시켜주는 역할을 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/08295389-b3ab-41fa-81dd-c2b91751e8b8/image.png" alt=""></p>
<ul>
<li>각각의 노티파이 위치를 위와 같이 조정해줍시다.<blockquote>
<ul>
<li>본인이 생각하기에 공격의 시작이라고 생각되는 지점에 AttackStart 를 배치하고, 끝이라고 생각되는 지점에 AttackFinish 를 배치해주면 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="primaryattack_b_slow_montage">PrimaryAttack_B_Slow_Montage</h4>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/144c7fc7-f2a2-4656-8b8f-dc61b4641440/image.png" alt=""></p>
<h4 id="primaryattack_c_slow_montage">PrimaryAttack_C_Slow_Montage</h4>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d13d2826-d306-42b3-93b7-6c890bb683bd/image.png" alt=""></p>
<h4 id="primaryattack_d_slow_montage">PrimaryAttack_D_Slow_Montage</h4>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6628ade0-b5ba-4ae9-9053-8de61ed14b65/image.png" alt=""></p>
<h3 id="notify-event-추가">Notify Event 추가</h3>
<ul>
<li>Montage 에서 Notify 를 발생시켜줬으니, 이를 이벤트 그래프에서 받아주어야 합니다.<blockquote>
<ul>
<li>PlayerAnimBP 를 열고, 이벤트 그래프로 갑시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4f4c22f5-9576-43b4-96e7-b910549aa61e/image.png" alt=""></p>
<blockquote>
<ul>
<li>AttackStart Notify 가 발생하면 Collsion Enabled 상태가 되고, AttackFinish Notify 가 발생하면 No Collision 상태가 됩니다.</li>
</ul>
</blockquote>
<ul>
<li>이제 플레이하여 확인해봅시다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bcff6b8b-84e9-46a2-948c-445b969e14e9/image.gif" alt=""></p>
<ul>
<li>&#39;Enemy&#39; 가 잘 출력되네요~</li>
</ul>
<h1 id="enemy">Enemy</h1>
<ul>
<li>이제 Enemy 의 무기에 Collision 을 추가해줄겁니다.<blockquote>
<ul>
<li>Enemy 의 무기 개수가 2개라는 것을 제외하면, 큰 흐름은 Player 와 같습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="weapon-collision-1">Weapon Collision</h2>
<ul>
<li>EnemyBP 를 열어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/590d9a4a-19dc-4fe8-9c7d-d7df03f9022b/image.png" alt=""></p>
<ul>
<li><p>위와 같이 Box Collision 을 2개 추가해줍시다.</p>
<blockquote>
<ul>
<li>Enemy 는 Player 와 달리, 무기가 2개이므로 Weapon_R 과 Weapon_L 을 구분하여 생성하는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>Weapon_R 과 Weapon_L 은 일부 항목들을 제외하면 같으므로, Weapon_R 을 예시로 설명하겠습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5cb566c8-ecc3-42e7-898e-6d8fe20ab24e/image.png" alt=""></p>
<ul>
<li>트랜스폼의 각 요소들을 위와 같이 바꿔주고, 부모 소켓을 FX_WeaponBase_R 로 바꿔줍시다.<blockquote>
<ul>
<li>그리고, 무기의 두께가 얇으므로 &#39;박스 크기&#39; 도 바꿔줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4b42314b-4f3f-4e72-83eb-f31879437728/image.png" alt=""></p>
<h3 id="collision-설정-1">Collision 설정</h3>
<ul>
<li>앞서 했던 것처럼, 콜리전을 설정해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a8487734-6651-4d47-8c37-97bdebc21d84/image.png" alt=""></p>
<h3 id="overlap-event-생성-1">Overlap Event 생성</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/de9591e4-7d0a-4e6f-9499-f8efa39ac865/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0115e84b-1bb6-4f90-8bf4-8aba1c613e72/image.png" alt=""></p>
<h4 id="player-tag-추가">Player Tag 추가</h4>
<ul>
<li>PlayerBP 를 열어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4b160feb-6da0-4edd-99db-7c3a551d4d03/image.png" alt=""></p>
<ul>
<li>PlayerBP (셀프)를 선택한 뒤, 디테일 탭에서 Tag 를 검색해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/50f18897-2411-4eaf-9afd-e1b9afa09113/image.png" alt=""></p>
<ul>
<li>인덱스[0]에 Player 를 적어줍시다.</li>
</ul>
<h3 id="weapon_l">Weapon_L</h3>
<ul>
<li>이제 Weapon_R 의 Collision 설정이 끝났습니다. Weapon_L 도 해주는 것을 잊지 맙시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9502b150-c3c4-470b-808c-56065669bfd3/image.png" alt=""></p>
<ul>
<li>위와 같이 바꿔주고, 콜리전 세팅도 Weapon_R 과 똑같이 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/546b95fd-6f4e-4922-9935-ec4326b0a832/image.png" alt=""></p>
<ul>
<li>그리고 &#39;컴포넌트 오버랩 시작 시&#39; 이벤트도 만들어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/68d09cd0-bf17-4bf9-a93b-f018e820d98a/image.png" alt=""></p>
<ul>
<li>이제, Collision 에 대한 설정은 끝났습니다.</li>
</ul>
<h2 id="collision-onoff-1">Collision On/Off</h2>
<ul>
<li>마찬가지로 AnimNotify 를 이용하여 Collision 을 켜고, 끌겁니다.</li>
</ul>
<h3 id="montage-에서-notify-추가-1">Montage 에서 Notify 추가</h3>
<ul>
<li>Player 와 다른 점은, Weapon_R 과 Weapon_L 을 구분해야 한다는 것밖에 없습니다.<blockquote>
<ul>
<li>우리는 AttackStart_R / AttackStart_L 및 AttackFinish_R / AttackFinish_L 을 통해 구분해줄겁니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="primary_attack_a_normal_montage">Primary_Attack_A_Normal_Montage</h4>
<ul>
<li>Attack1 BTT 에 사용하는 Montage 입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a9ab7fb1-67b8-4ae4-9ae5-66f6ae0e876d/image.png" alt=""></p>
<h4 id="primary_attack_normal_montage">Primary_Attack_Normal_Montage</h4>
<ul>
<li>Attack2 BTT 에 사용하는 Montage 입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/04ba6504-4197-4a1e-b0ad-736eba767b25/image.png" alt=""></p>
<h4 id="primary_attack_b_normal_montage">Primary_Attack_B_Normal_Montage</h4>
<ul>
<li>Attack3 BTT 에 사용하는 Montage 입니다.<blockquote>
<ul>
<li>2개의 무기를 모두 사용하므로, 노티파이도 전부 추가해주어야 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/33a44e3b-8476-4eb3-82c2-63d7479c871d/image.png" alt=""></p>
<h4 id="ability_q_montage">Ability_Q_Montage</h4>
<ul>
<li>Dash BTT 에 사용하는 Montage 입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/62034959-63f2-4d86-9b76-237ba4487987/image.png" alt=""></p>
<h4 id="ability_ultimate_montage">Ability_Ultimate_Montage</h4>
<ul>
<li>FlyAttack BTT 에 사용하는 Montage 입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bafdfcfa-4d00-4766-bcf7-12425ca65f69/image.png" alt=""></p>
<h3 id="notify-event-추가-1">Notify Event 추가</h3>
<ul>
<li>2가지의 노티파이(R/L)를 생성하였기 때문에 Event 도 2가지 만들어 주어야 합니다.<blockquote>
<ul>
<li>EnemyAnimBP 를 열고, 이벤트 그래프로 갑시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/df257cc9-b103-4b6a-bd93-f71e200b3dd5/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/413c2677-ce3d-49d8-b0eb-ebbd0d9f2f11/image.png" alt=""></p>
<h2 id="projectile-collision">Projectile Collision</h2>
<ul>
<li>Slash BTT 가 실행되면 Projectile 이 생성되며 날아옵니다. 따라서 Projectile 또한 Collision 설정을 해주어야 합니다.<blockquote>
<ul>
<li>ProjectileBP 를 열어줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="collision1">Collision1</h3>
<ul>
<li>Blade1 의 하위 항목에 Box Collision 을 만들고 이름은 Collision1 으로 해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d43217f3-21e6-435d-a561-4b987bf2b532/image.png" alt=""></p>
<ul>
<li>디테일 탭에서 다음과 같이 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/48681384-bbb9-4122-8284-e6c162a42c05/image.png" alt=""></p>
<ul>
<li>콜리전 설정을 다음과 같이 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a149a724-d3c1-4fdb-b003-71a4fc736603/image.png" alt=""></p>
<ul>
<li>오버랩 이벤트를 생성해 줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/de9591e4-7d0a-4e6f-9499-f8efa39ac865/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4a15e0fb-578c-43f1-8c66-8c172b109723/image.png" alt=""></p>
<h3 id="collision2">Collision2</h3>
<ul>
<li>Blade2 의 하위 항목에 Box Collision 을 만들고 이름은 Collision2 로 해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/11de1f3f-030c-45c8-b0d2-bc540ff88057/image.png" alt=""></p>
<ul>
<li>디테일 탭에서 다음과 같이 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0f19f2ef-92e5-4a8b-8fc4-262621064346/image.png" alt=""></p>
<ul>
<li>콜리전 설정을 다음과 같이 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a149a724-d3c1-4fdb-b003-71a4fc736603/image.png" alt=""></p>
<ul>
<li>오버랩 이벤트를 생성해 줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/de9591e4-7d0a-4e6f-9499-f8efa39ac865/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/fbe5bc40-3a48-477c-a265-53de0d2f2384/image.png" alt=""></p>
<ul>
<li>이제 모든게 완료되었습니다! 플레이하여 확인해봅시다~</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4aea7f5a-759e-4d1b-af29-88e8289fb2d9/image.gif" alt=""></p>
<ul>
<li>&#39;Player&#39; 가 잘 출력되는 것을 확인하실 수 있습니다~</li>
</ul>
<h1 id="마치며">마치며</h1>
<ul>
<li><p>이로써 언리얼 스터디 3주 과정의 강의가 모두 끝났습니다. 제대로 된 게임이 되려면 추가해야할 요소들이 많지만, 게임 제작에 있어서 핵심이 되는 부분들은 대부분 살펴본 것 같습니다. (아닐 수도 있지만...ㅎㅎ)</p>
</li>
<li><p>나머지는 여러분들께 맡기겠습니다! 시간적 제약도 있고, 스스로 공부해보는 것도 좋으니까요~ 하지만 막막한 부분이 생긴다면 언제든 질문해주세요. 동아리 부원 분들이라면 개인적으로 연락주시고, 혹시나 외부에서 보시는 분들이 있다면 <a href="mailto:hkh7710@khu.ac.kr">hkh7710@khu.ac.kr</a> 로 연락주시면 최대한 답변해 드리겠습니다.</p>
</li>
<li><p>그럼 모두들 화이팅~</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UE] VFX]]></title>
            <link>https://velog.io/@hkun_ho/UE-VFX</link>
            <guid>https://velog.io/@hkun_ho/UE-VFX</guid>
            <pubDate>Sun, 19 Feb 2023 13:44:33 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<ul>
<li>본 학습 자료는 경희대학교 게임 &amp; 실감형 컨텐츠 제작 동아리 <code>Ludens</code> 의 Unreal-Study 자료입니다.</li>
</ul>
<h1 id="player">Player</h1>
<ul>
<li>우리는 먼저 Player 의 Attack 에 해당하는 VFX 를 넣어볼겁니다.</li>
</ul>
<h2 id="comboattack">ComboAttack</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c8d48789-cc31-4192-9cb4-ee885abc940c/image.png" alt=""></p>
<ul>
<li>PrimaryAttack_A_Slow_Montage 를 검색하여 더블 클릭해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ca4013e9-008d-4aee-b425-4b7d2f71c0ec/image.png" alt=""></p>
<ul>
<li>좌측의 &#39;노티파이&#39; 의 하위 항목인 &#39;1&#39; 에 해당하는 부분에서의 빈공간을 우클릭해줍시다.<blockquote>
<ul>
<li>노티파이 스테이트 추가 - 트레일 을 선택해줍시다. 다음과 같이 노티파이 스테이트가 생성됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d058f88a-5adb-4d2f-9daf-012335a70883/image.png" alt=""></p>
<ul>
<li>그리고 범위를 늘려줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/af552a63-156c-444a-bedf-59295b364295/image.png" alt=""></p>
<ul>
<li>Trail 을 더블 클릭해줍시다. 우측 &#39;디테일&#39; 에 다음과 같은 항목들이 보이실 겁니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/67e550c1-eb69-440a-b81f-e249463ac04a/image.png" alt=""></p>
<ul>
<li>우리는 이를 다음과 같이 채워줄겁니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e4f3b7cf-a735-4bd1-94d7-24011f4b908b/image.png" alt=""></p>
<blockquote>
<ul>
<li>PS 템플릿 : P_Kwang_Primary_Trail</li>
<li>첫번째 소켓 이름 : FX_weapon_base</li>
<li>두번째 소켓 이름 : FX_weapon_tip</li>
</ul>
</blockquote>
<ul>
<li>끝입니다! 하지만 우리는 이 작업을 PrimaryAttack_B_Slow_Montage, PrimaryAttack_C_Slow_Montage, PrimaryAttack_D_Slow_Montage 에도 반복해주어야 합니다.<blockquote>
<ul>
<li>반복 작업이니, 별다른 설명은 생략하도록 하겠습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="directionallight-설정">DirectionalLight 설정</h2>
<ul>
<li>이펙트를 더 잘보이게 하기 위해 DirectionalLight 의 설정을 조금 변경해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/14535ec0-44ef-415c-8a47-d8dec15be16f/image.png" alt=""></p>
<ul>
<li>우측 상단의 &#39;아웃라이너&#39; 에 DirectionalLight 를 검색해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/057270b9-ae1c-46ca-b28d-cc16de0ac6a3/image.png" alt=""></p>
<ul>
<li>디테일 탭의 &#39;강도&#39; 를 1.5로 변경해줍시다. 그리고 플레이해봅시다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e3151397-2299-405d-8f13-40e882b78161/image.gif" alt=""></p>
<ul>
<li>잘 나오네요~</li>
</ul>
<h1 id="enemy">Enemy</h1>
<ul>
<li>이제, Enemy 의 Attack 에 해당하는 VFX 를 넣어봅시다.</li>
</ul>
<h2 id="attack-123">Attack 1/2/3</h2>
<ul>
<li>우리는 먼저 Attack 1/2/3 에 해당하는 VFX 를 넣어볼겁니다.<blockquote>
<ul>
<li>Player 의 경우와 과정은 완벽히 일치합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="attack-1">Attack 1</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/b4fc1444-3b55-43bd-9c09-e92ef1a7a6a6/image.png" alt=""></p>
<ul>
<li>Primary_Attack_A_Normal_Montage 를 검색하여 더블 클릭해줍시다.<blockquote>
<ul>
<li>Trail 노티파이 스테이트를 만들고, 범위를 늘려줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3da53fe5-1255-45d9-a897-9e4ed6b4afe5/image.png" alt=""></p>
<ul>
<li>Trail 을 더블 클릭하여 디테일에 있는 항목들을 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3adf2a00-2a68-45de-a7fb-971f10d631a8/image.png" alt=""></p>
<blockquote>
<ul>
<li>PS 템플릿 : P_CountessMeleeTrail</li>
<li>첫번째 소켓 이름 : FX_WeaponBase_L</li>
<li>두번째 소켓 이름 : FX_WeaponTip_L</li>
</ul>
</blockquote>
<h3 id="attack-2">Attack 2</h3>
<ul>
<li>Primary_Attack_Normal_Montage 를 검색하여 더블 클릭해줍시다.<blockquote>
<ul>
<li>Trail 노티파이 스테이트를 만들고, 범위를 늘려줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2909b4db-2ce7-4fc6-81fe-6854206871fc/image.png" alt=""></p>
<ul>
<li>Trail 을 더블 클릭하여 디테일에 있는 항목들을 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e4e3b729-48ed-4c46-920f-6cb3b28cd81e/image.png" alt=""></p>
<blockquote>
<ul>
<li>PS 템플릿 : P_CountessMeleeTrail</li>
<li>첫번째 소켓 이름 : FX_WeaponBase_R</li>
<li>두번째 소켓 이름 : FX_WeaponTip_R</li>
</ul>
</blockquote>
<h3 id="attack-3">Attack 3</h3>
<ul>
<li><p>Primary_Attack_B_Normal_Montage 를 검색하여 더블 클릭해줍시다.</p>
</li>
<li><p>Attack 3에서는 노티파이 트랙을 하나 더 추가해줄겁니다.</p>
<blockquote>
<ul>
<li>좌측의 &#39;노티파이&#39; - 노티파이 트랙 추가 를 선택해줍시다. 그럼 &#39;2&#39; 라는 노티파이 트랙이 생성될겁니다. </li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8d205de1-592f-4051-8ebb-615c7fb0b456/image.png" alt=""></p>
<ul>
<li>노티파이 트랙 1, 2에 각각 Trail 노티파이 스테이트를 만들고, 범위를 늘려줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/385b9edf-e820-4850-b908-6e016588a71e/image.png" alt=""></p>
<ul>
<li>노티파이 트랙 1의 Trail 을 더블 클릭하여 디테일에 있는 항목들을 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1b3e765c-e03a-4341-afd7-9026c9221c33/image.png" alt=""></p>
<blockquote>
<ul>
<li>PS 템플릿 : P_CountessMeleeTrail</li>
<li>첫번째 소켓 이름 : FX_WeaponBase_R</li>
<li>두번째 소켓 이름 : FX_WeaponTip_R</li>
</ul>
</blockquote>
<ul>
<li>노티파이 트랙 2의 Trail 을 더블 클릭하여 디테일에 있는 항목들을 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/b1d331d8-1339-47e8-bfdc-8614cd45ac1d/image.png" alt=""></p>
<blockquote>
<ul>
<li>PS 템플릿 : P_CountessMeleeTrail</li>
<li>첫번째 소켓 이름 : FX_WeaponBase_L</li>
<li>두번째 소켓 이름 : FX_WeaponTip_L</li>
</ul>
</blockquote>
<ul>
<li>이제 플레이하여 확인해봅시다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9de4508f-b10a-4992-b125-abb1bd4f6abc/image.gif" alt=""></p>
<h2 id="dash">Dash</h2>
<ul>
<li>Ability_Q_Montage 를 검색하여 더블 클릭해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/778d2c34-101c-4824-b6b5-a97eb8ef41b5/image.png" alt=""></p>
<ul>
<li>이번에는 &#39;노티파이 추가&#39; - 파티클 이펙트 재생을 생성해줍시다.<blockquote>
<ul>
<li>노티파이의 위치를 조정해줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6e36c07f-db04-4e16-9480-3a1e03994388/image.png" alt=""></p>
<ul>
<li>PlayParticleEffect 노티파이를 더블 클릭하여 디테일에 있는 항목들을 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bef6fad9-a024-4774-9277-1e8204614dea/image.png" alt=""></p>
<blockquote>
<ul>
<li>PS 템플릿 : p_Countess_XSlash</li>
<li>위치 오프셋 : Z 값을 -50으로 변경</li>
<li>소켓 이름 : FX_SpineCenter</li>
</ul>
</blockquote>
<ul>
<li>플레이하여 확인해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c9d29abb-334a-442b-b30d-284cb2f0e740/image.gif" alt=""></p>
<h2 id="slash">Slash</h2>
<ul>
<li>이번에는 Montage 에서 노티파이를 추가하는 방식이 아닌, 이벤트 그래프에서 파티클을 추가하는 방식을 살펴보겠습니다.<blockquote>
<ul>
<li>저번 시간에 만든 BTT 인 Slash 를 열어봅시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/77a7fbac-17a4-4152-9d1f-91994805e5ae/image.png" alt=""></p>
<ul>
<li><p>Play Anim Montage 노드와 딜레이 노드 사이에 &#39;Spawn Emitter at Location&#39; 이라는 노드를 추가해줍시다.</p>
<blockquote>
<ul>
<li>Emitter Template : P_Countess_TeleportArrive</li>
<li>Location : 위 사진 참조</li>
<li>Scale : X 2.0 Y 2.0 Z 2.0</li>
</ul>
</blockquote>
</li>
<li><p>플레이해봅시다!</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/15000069-9447-4bb2-ab2a-f812932fac12/image.gif" alt=""></p>
<ul>
<li>칼날을 날리기 전에 기를 모으는 듯한 이펙트가 잘 구현되었습니다. 굳~</li>
</ul>
<h2 id="flyattack">FlyAttack</h2>
<ul>
<li>마지막으로, Montage 에서 노티파이를 추가하는 방식과 이벤트 그래프에서 파티클을 추가하는 방식을 모두 사용해보겠습니다.<blockquote>
<ul>
<li>우선, 이벤트 그래프에서 파티클을 추가하겠습니다. 저번 시간에 만든 BTT 인 FlyAttack 을 열어봅시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/90208daf-1724-4bb1-a495-4dae142e8872/image.png" alt=""></p>
<ul>
<li><p>점프 노드와 딜레이 노드 사이에 &#39;Spawn Emitter at Location&#39; 이라는 노드를 추가해줍시다.</p>
<blockquote>
<ul>
<li>Emitter Template : P_Countess_TeleportArrive</li>
<li>Location : 위 사진 참조</li>
<li>Scale : X 2.0 Y 2.0 Z 2.0</li>
</ul>
</blockquote>
</li>
<li><p>다음으로, Montage 에서 노티파이를 추가해보겠습니다.</p>
<blockquote>
<ul>
<li>Ability_Ultimate_Montage 를 검색하여 열어줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2dcd8e1d-cf4e-46e2-8086-495d20b22b73/image.png" alt=""></p>
<ul>
<li>&#39;노티파이 추가&#39; - 파티클 이펙트 재생을 생성해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e860f37c-1b6a-4ecc-8ab3-11c8773d06f9/image.png" alt=""></p>
<ul>
<li>PlayParticleEffect 노티파이를 더블 클릭하여 디테일에 있는 항목들을 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/172cc53b-1c70-4f81-9e7e-b9c356021893/image.png" alt=""></p>
<blockquote>
<ul>
<li>PS 템플릿 : p_CountessUlt_SlashFX</li>
<li>위치 오프셋 : X 값을 90으로 변경</li>
<li>회전 오프셋 : Y 값을 30으로 변경</li>
<li>소켓 이름 : FX_SiphonCenter</li>
</ul>
</blockquote>
<ul>
<li>플레이하여 확인해봅시다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/71639169-309a-4692-8c45-e3d411dc8589/image.gif" alt=""></p>
<ul>
<li>여기까지 3주차 Part.1 - VFX 였습니다. 다음 포스팅은 3주차 Part.2 - Collision 입니다~</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UE] AI Application]]></title>
            <link>https://velog.io/@hkun_ho/UE-AI-Application-2lh98xu9</link>
            <guid>https://velog.io/@hkun_ho/UE-AI-Application-2lh98xu9</guid>
            <pubDate>Thu, 09 Feb 2023 16:42:07 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<ul>
<li>본 학습 자료는 경희대학교 게임 &amp; 실감형 컨텐츠 제작 동아리 <code>Ludens</code> 의 Unreal-Study 자료입니다.</li>
</ul>
<h1 id="맵-수정하기">맵 수정하기</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a87aae02-04b7-475e-8f06-4ad9ccaa0393/image.png" alt=""></p>
<ul>
<li>Enemy 가 활약하려면 장애물들이 없는 것이 좋겠습니다. 바닥과 벽을 제외하고 모두 없애줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/81ff9d56-7ab1-426c-a6f5-2038771e3416/image.png" alt=""></p>
<ul>
<li>깔끔해졌네요~</li>
</ul>
<h1 id="btt-생성">BTT 생성</h1>
<ul>
<li>저번 시간에 이어서 AI 폴더에 BTT 를 생성해봅시다.</li>
</ul>
<h2 id="attack-1">Attack 1</h2>
<ul>
<li><p>Player 도 Combo Attack 을 할 수 있는데, Enemy 라고 못할 이유는 없겠죠? 우리의 Enemy 는 3단 Combo Attack 이 가능하게 할겁니다.</p>
<blockquote>
<ul>
<li>Attack 1 은 3단 Combo 의 1단계입니다.</li>
</ul>
</blockquote>
</li>
<li><p>우선 BTT 를 생성해줍시다. 이름은 Attack1 으로 하고, 열어줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/83f0e565-5c6d-4e3a-b1d6-d024a544346c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/248126d2-4b67-452b-acfb-2071e4bdf27d/image.png" alt=""></p>
<ul>
<li><p>Play Anim Montage 노드의 Anim Montage 에셋 이름은 &#39;Primary_Attack_A_Normal_Montage&#39; 입니다.</p>
</li>
<li><p>그리고 BTT 가 잘 작동하는지 확인해보기 위해 간단한 BT 를 짰습니다.</p>
<blockquote>
<ul>
<li>저는 주로 아래와 같은 방식으로 BTT 의 작동을 확인합니다. 참고해두시면 좋을 것 같습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bbc7f682-9ade-498a-931d-618307dcaaac/image.png" alt=""></p>
<ul>
<li>이제 플레이해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a2c2b2ee-b6d2-4192-a54c-eb3b1db24300/image.gif" alt=""></p>
<ul>
<li>애니메이션이 뭔가 이상합니다. 왜일까요?</li>
</ul>
<h3 id="default-slot-추가">Default Slot 추가</h3>
<ul>
<li>이 부분이 바로 기억나신 분들은 앞으로도 Montage 가 안나오는 순간을 마주했을 때 잘 해결할 수 있으실겁니다~<blockquote>
<ul>
<li>EnemyAnimBP 의 AnimGraph 에 Default Slot 을 추가해주어야 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2b1fe6e2-b314-4a82-8405-489555623691/image.png" alt=""></p>
<ul>
<li>추가한 뒤, 슬롯 이름을 DefaultGroup.UpperBody 로 바꿔줍시다. 그리고 플레이해봅시다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2f90a56f-b1f9-45fe-a761-3c0b95ddb38d/image.gif" alt=""></p>
<ul>
<li>깔끔하게 공격하는 모습이네요~</li>
</ul>
<h2 id="attack-2">Attack 2</h2>
<ul>
<li><p>AI 폴더에 BTT 를 생성해줍시다. 이름은 Attack2 로 합시다.</p>
</li>
<li><p>Attack 1과 Montage 를 제외한 모든 것이 똑같습니다.</p>
<blockquote>
<ul>
<li>Attack 1의 이벤트 그래프를 복사해오신 후, Montage 만 바꾸시는 것을 추천합니다.</li>
</ul>
</blockquote>
</li>
<li><p>Play Anim Montage 노드의 Anim Montage 에셋 이름은 &#39;Primary_Attack_Normal_Montage&#39; 입니다.</p>
</li>
<li><p>바꾼 뒤, 확인을 위해 BT 에 BTT 를 추가합시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f2b73917-8e04-457a-bddb-f8a4cb0ac3b6/image.png" alt=""></p>
<ul>
<li>그리고 실행해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a14896b8-87ee-4f27-b387-a1573c0dc43c/image.gif" alt=""></p>
<ul>
<li>스무스하네요~</li>
</ul>
<h2 id="attack-3">Attack 3</h2>
<ul>
<li><p>Combo Attack 의 마지막입니다. AI 폴더에 BTT 를 생성해주고 이름은 Attack3 로 합시다.</p>
</li>
<li><p>Attack 1, Attack 2와 Montage 말고도 다른 점이 하나 더 있습니다.</p>
<blockquote>
<ul>
<li>나머지는 똑같습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8313ecc2-75c3-45cc-81d2-5f42d6b206a4/image.png" alt=""></p>
<ul>
<li><p>바로 벡터의 곱셈 값입니다.</p>
<blockquote>
<ul>
<li>빨간색 박스의 곱하기 값을 X : 3500, Y : 3500 으로 바꿔줍시다.</li>
</ul>
</blockquote>
</li>
<li><p>Play Anim Montage 노드의 Anim Montage 에셋 이름은 &#39;Primary_Attack_B_Normal_Montage&#39; 입니다.</p>
</li>
<li><p>바꾼 뒤, 확인을 위해 BT 에 BTT 를 추가합시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/cc3bf20d-fa2c-43ef-b168-11d3bceeb68c/image.png" alt=""></p>
<ul>
<li>그리고 실행해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/26934008-1572-48c0-9906-791e1498bd78/image.gif" alt=""></p>
<ul>
<li>Combo Attack 완성!</li>
</ul>
<h3 id="attack-montage-speed">Attack Montage Speed</h3>
<ul>
<li>Enemy 의 공격 속도가 조금 빠른 것 같습니다. 난이도를 고려하여 Montage 의 속도 스케일을 조절해줍시다.<blockquote>
<ul>
<li>Primary_Attack_A_Normal_Montage 를 찾아서 열어봅시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4957acf3-340e-4c6b-b365-1c4a899a3ca1/image.png" alt=""></p>
<ul>
<li>여기서 속도 스케일을 0.8로 바꿔줍시다.<blockquote>
<ul>
<li>이 작업을 Primary_Attack_Normal_Montage, Primary_Attack_B_Normal_Montage 에도 해주면 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="bt-구현">BT 구현</h1>
<ul>
<li>일정 거리보다 멀 때는 Player 를 쫓아오고, 일정 거리 내에 들어왔을 경우 Attack 하는 BT 입니다.<blockquote>
<ul>
<li>일정 거리(Distance)는 400으로 하였습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/faf2ff35-98db-4ba0-b573-e7cccd9d02ed/image.png" alt=""></p>
<ul>
<li>플레이해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e62cf9b8-1159-4639-b55e-760c04254e7b/image.gif" alt=""></p>
<ul>
<li>뭔가 이상합니다. 본래는 짧은 거리를 빠르게 Dash 해야 하는데, 이상한 곳으로 미끄러지듯이 이동하는 모습입니다.</li>
</ul>
<h2 id="stop-btt">Stop BTT</h2>
<ul>
<li>위에서 발생한 문제는 &#39;MoveToPlayer&#39; BTT 에 존재하는 AI MoveTo 노드에서 파생되는 문제입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/138045ef-cce4-4b8d-9172-1820399b73d8/image.png" alt=""></p>
<ul>
<li><p>AI MoveTo 노드의 입력 값인 Destination 에 Player 의 위치가 입력되고, 입력된 값에 대한 처리가 &#39;Attack&#39; BTT 의 Launch Character 노드의 입력 값인 Launch Velocity 보다 우선 순위이기 때문에, 짧은 거리를 빠르게 Dash 하지 않고, 최대 걷기 속도로 이동하는 것입니다.</p>
<blockquote>
<ul>
<li>그러므로 우리는 Stop 이라는 BTT 를 추가하여 AI MoveTo 노드의 Desination 입력 값을 바꿔줌으로써 문제를 해결할 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>AI 폴더에 BTT 를 생성하고 이름은 Stop 으로 해줍니다.</p>
</li>
<li><p>변수를 하나 생성해줍시다.</p>
<blockquote>
<ul>
<li>EnemyLoc(벡터) : Enemy 의 위치를 담을 변수</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/919c12e9-5e21-4a99-8531-ee115e2ce247/image.png" alt=""></p>
<ul>
<li>이제 이벤트 그래프에서 코드를 구현합시다. 여기서 그림이 조금 잘못됐는데, Enemy Loc과 AI Move To 노드의 &#39;Destination&#39;을 연결해 주어야 합니다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d6022551-2d3f-499c-a1fc-9369ce30dd67/image.png" alt=""></p>
<ul>
<li>간단하죠~ 그리고 BT 에 Stop 을 추가해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/31656e7b-cde4-4751-a5c7-56cd5f9b9988/image.png" alt=""></p>
<ul>
<li>이제 플레이해볼까요?</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ddeeb1ba-d676-48af-a952-e0eb36caa05d/image.gif" alt=""></p>
<ul>
<li>일정 거리보다 멀 때는 Player 를 쫓아오고, 일정 거리 내에 들어왔을 경우 Attack 하는 BT 를 완성했습니다!</li>
</ul>
<h1 id="다시-btt-생성">다시, BTT 생성</h1>
<h2 id="dash">Dash</h2>
<ul>
<li><p>이제 조금 더 먼 거리를 빠르게 Dash 하는 BTT 를 만들어 볼겁니다. AI 폴더에 BTT 를 생성하고, 이름은 Dash 로 합시다.</p>
</li>
<li><p>변수를 하나 만들어줍시다.</p>
<blockquote>
<ul>
<li>PlayerLoc(벡터) : Player 의 위치를 담을 변수</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f0451bc2-20e6-46ba-b9e5-602635935fa2/image.png" alt=""></p>
<ul>
<li>그리고 Dash BTT 에 쓰일 Montage 를 생성해 줍시다.<blockquote>
<ul>
<li>여태까지는 생성된 Montage 를 썼지만, 이제는 생성해주어야 합니다. 간단하니 걱정마세요!</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="montage-생성">Montage 생성</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ed1b402f-488f-4584-b788-3ea3b34d67d1/image.png" alt=""></p>
<ul>
<li>콘텐츠 브라우저에서 TravelMode_Start 를 검색하고, Countess 가 맞는 지 확인해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4e26a706-c183-421f-9a2c-7bda4f851840/image.png" alt=""></p>
<ul>
<li>애니메이션을 우클릭하고, 맨 위의 &#39;생성&#39; - &#39;애님몽타주 생성&#39; 을 선택해줍니다. 이름은 그대로 사용합시다.<blockquote>
<ul>
<li>기존 애니메이션 이름에 _Montage 가 붙게됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/607b5dfb-e58d-4e26-b168-e9a57d8158d8/image.png" alt=""></p>
<ul>
<li>잘 생성된 모습입니다. 같은 방법으로, Ability_Q 라는 애니메이션도 몽타주를 만들어줍시다.<blockquote>
<ul>
<li>이제 준비는 끝났습니다. Dash BTT 를 다시 열어줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="다시-dash">다시, Dash</h2>
<ul>
<li>이벤트 그래프를 채워볼 시간입니다. 양이 조금 많아서, 우선적으로 구조부터 보여드리고 부분적으로 확대하여 보여드리겠습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8e2b58b3-1cbc-452b-af2a-6bc4680075cb/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/de3ed187-1a02-48dd-92eb-d4eb0e0a8abd/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c80064b3-8b76-4329-a577-399d4cf88fd6/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/dc0f256f-de75-41a7-8027-2eb033c3df96/image.png" alt=""></p>
<ul>
<li><p>세부적인 부분 잘 확인하며 따라와주시기 바랍니다.</p>
</li>
<li><p>Play Anim Montage 노드의 Anim Montage 에셋 이름은 왼쪽부터 각각 &#39;TravelMode_Start_Montage&#39;, &#39;Ability_Q_Montage&#39; 입니다.</p>
</li>
</ul>
<h2 id="bt-에-dash-추가">BT 에 Dash 추가</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bf9855ae-6f23-4a4b-8f82-60af09a5cafb/image.png" alt=""></p>
<ul>
<li><p>Dash 를 추가한 것 이외에 Decorator 부분의 조건도 조금씩 바뀌었으니 참고하여 수정해주시기 바랍니다.</p>
</li>
<li><p>이제 또 플레이해보면, Montage 가 정상 작동하지 않는 모습을 보실 수 있습니다.</p>
</li>
</ul>
<h3 id="default-slot-추가-1">Default Slot 추가</h3>
<ul>
<li>분명 아까 Default Slot 을 추가해주었는데, 왜 안될까요?<blockquote>
<ul>
<li>보편적인 상황은 아니지만, Default Slot 을 하나 더 추가해주어야 합니다. EnemyAnimBP 의 AnimGraph 로 갑시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/62e25a42-86a4-4af5-9336-447c3fa2993d/image.png" alt=""></p>
<ul>
<li>Default Slot 을 하나 더 추가해주고, 이번에는 슬롯 이름을 변경하지 않고 그냥 둡시다.<blockquote>
<ul>
<li>다시 플레이해봅시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d91030bd-b919-4982-b9d1-ee0201a753b9/image.gif" alt=""></p>
<ul>
<li>잘 실행되네요~</li>
</ul>
<h2 id="slash">Slash</h2>
<ul>
<li>Enemy 가 Slash 를 하여 검기를 날리는 BTT 를 만들겁니다. BTT 를 만들게 전에 할 일이 조금 있습니다. 하나하나 해봅시다.</li>
</ul>
<h3 id="paragon-에셋-임포트-하기">Paragon 에셋 임포트 하기</h3>
<ul>
<li><p>조금 뜬금없을 수도 있지만, Effect 와 Material 등을 사용하기 위해 Paragon 에셋을 하나 더 임포트해줄 겁니다.</p>
</li>
<li><p>에픽 게임즈 런처 - 상단의 &#39;마켓플레이스&#39; - &#39;Paragon&#39; 검색 - &#39;Paragon:Revenant&#39; 다운로드 및 프로젝트에 추가해줍시다.</p>
</li>
</ul>
<h3 id="blade-파일-임포트-하기">Blade 파일 임포트 하기</h3>
<ul>
<li><p>다음 링크에 Blade.fbx 파일을 업로드해두었습니다. 바탕화면에 다운로드 해주세요!</p>
<blockquote>
<ul>
<li><a href="https://drive.google.com/drive/folders/1wZ8tAuxCWGy1IeyNECHfDrzj1rUpJUGo?usp=sharing">2023_winter_unreal_study</a></li>
</ul>
</blockquote>
</li>
<li><p>바탕화면에 다운로드 받은 Blade 파일을 언리얼 내부의 Enemy 폴더로 드래그해줍시다.</p>
<blockquote>
<ul>
<li>이런 식으로 드래그하지 않고, 직접 파일 위치 경로를 옮겨줘도 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d844c68d-6134-400d-b81e-74444ab4c95a/image.png" alt=""></p>
<ul>
<li>그럼 창이 하나 뜨는데, &#39;모두 임포트&#39;를 눌러주면 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d2921723-8f4b-40c0-85b9-c7cf8d014053/image.png" alt=""></p>
<ul>
<li>임포트가 끝나면 이상한 오류같은 것들이 뜰 수도 있는데, 이는 무시하셔도 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1e563e10-c7cd-4e31-881e-8b6177fafef3/image.png" alt=""></p>
<ul>
<li>이 모습이라면 임포트가 성공적으로 완료된겁니다!</li>
</ul>
<h3 id="projectilebp">ProjectileBP</h3>
<ul>
<li>Enemy 가 날리는 검기 즉, 발사체의 BluePrint 를 생성해줄겁니다. Enemy 폴더에 블루 프린트를 생성해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/19cd49ef-c7ac-4268-9d7f-3ba79b363d8f/image.png" alt=""></p>
<ul>
<li>이번엔 Pawn 으로 선택해줍시다. BP 이름은 ProjectileBP 로 합시다.<blockquote>
<ul>
<li>생성 후 바로 열어줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/60fface3-972e-40eb-80e4-9f81efc0bc5a/image.png" alt=""></p>
<ul>
<li>컴포넌트를 4개 만들어줄겁니다. 다음 순서대로 만들어줍시다.<blockquote>
<ul>
<li>스태틱 메시 컴포넌트 (Blade1)</li>
<li>스태틱 메시 컴포넌트 (Blade2)</li>
<li>화살표 컴포넌트 (Arrow)</li>
<li>발사체 이동 컴포넌트 (ProjectileMovement)</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="blade-1">Blade 1</h4>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5547e48b-f04f-4020-b32e-f40e37d86e0a/image.png" alt=""></p>
<ul>
<li><p>위치, 회전, 스케일을 위와 같이 바꿔줍시다.</p>
</li>
<li><p>스태틱 메시는 앞서 다운 받은 Blade_Mesh 로 바꿔주고, 머터리얼은 M_Revenant_GlowEyes 로 바꿔줍시다.</p>
</li>
</ul>
<h4 id="blade-2">Blade 2</h4>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f6e3414e-7cab-482c-b1fd-8363374cf236/image.png" alt=""></p>
<ul>
<li>Blade 1과 회전 빼고는 다 똑같습니다. 위 그림과 같이 바꿔줍시다.</li>
</ul>
<h4 id="발사체-이동-컴포넌트">발사체 이동 컴포넌트</h4>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f61bd0ae-3ba9-4b7c-bacc-555cad5942ec/image.png" alt=""></p>
<ul>
<li>발사체 중력 스케일을 0으로 바꿔주고, 속도의 X, Y, Z 값을 모두 0으로 바꿔줍시다.</li>
</ul>
<h3 id="다시-projectilebp">다시, ProjectileBP</h3>
<ul>
<li><p>이벤트 그래프로 갑시다.</p>
</li>
<li><p>우선 변수를 2개 만들어 줍시다.</p>
<blockquote>
<ul>
<li>PlayerLoc(벡터) : Player 의 위치를 담을 변수</li>
<li>ProjectileLoc(벡터) : Projectile 의 위치를 담을 변수</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7e485542-6c50-4e7d-b0ad-f945ae5343fd/image.png" alt=""></p>
<ul>
<li>이제 이벤트 그래프를 채워봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/90f71437-2bb2-4bb1-a569-2c29b1a46f24/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a1f3fc45-4ed2-46af-8bfb-826161d009d5/image.png" alt=""></p>
<ul>
<li>Add World Offset 노드 같은 경우에는 처음 노드를 생성할 때, &#39;컨텍스트에 따라&#39; 항목을 체크 해제하고 검색하시면 위 그림과 일치하는 노드를 찾으실 수 있습니다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1ede8aaf-2c72-482a-8b51-12a7f4156fea/image.png" alt=""></p>
<blockquote>
<p>체크 해제하지 않으면 다음과 같이 뜨는데, 처음 하시는 분들이라면 헷갈릴 수도 있다고 생각하여 첨언하였습니다. 참고로 이 상황에선 Blade 1 혹은 Blade 2를 선택해주시면 됩니다!
<img src="https://velog.velcdn.com/images/hkun_ho/post/b9195559-67f9-4fc2-9b51-46bfa00ef084/image.png" alt=""></p>
</blockquote>
<ul>
<li>ProjectileBP 는 완성입니다! 잘 작동하는지는 Slash 기능을 만들어서 확인합시다.</li>
</ul>
<h2 id="다시-slash">다시, Slash</h2>
<ul>
<li>AI 폴더에 BTT 를 생성하고, 이름은 Slash 로 합시다.<blockquote>
<ul>
<li>바로 열어줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="montage-생성-1">Montage 생성</h3>
<ul>
<li>앞서 언급했던 것과 같은 방법으로, Ability_E 라는 애니메이션도 몽타주를 만들어줍시다.</li>
</ul>
<h2 id="다시-slash-1">다시, Slash</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c7f43dbc-6b25-4826-a56f-e955d9629dfc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3b73b847-d4c2-4b1f-81d0-f204b6e8cbe3/image.png" alt=""></p>
<ul>
<li><p>Play Anim Montage 노드의 Anim Montage 에셋 이름은 &#39;Ability_E_Montage&#39; 입니다.</p>
</li>
<li><p>SpawnActor Projectile BP 라는 노드가 보이실겁니다. 저 노드의 원래 이름은 &#39;Spawn Actor from Class&#39; 입니다.</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/113db957-89c9-4ad0-a2c4-4e800a3e3f44/image.png" alt=""></p>
<ul>
<li>입력 부분의 &#39;Class&#39;를 ProjectileBP 로 지정하면 노드의 이름이 바뀌는 구조입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="bt-에-slash-추가">BT 에 Slash 추가</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0206195e-c4b2-40ef-8455-1a4ca8f70bbd/image.png" alt=""></p>
<ul>
<li><p>Slash 를 추가하였습니다. 나머지 바뀐 점은 없습니다!</p>
</li>
<li><p>플레이해봅시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ecf09990-e918-40e7-8108-7ac3e0e76ce0/image.gif" alt=""></p>
<h2 id="flyattack">FlyAttack</h2>
<ul>
<li>Enemy 의 마지막 공격입니다! AI 폴더에 BTT 를 생성하고 이름은 FlyAttack 으로 해줍니다.</li>
</ul>
<h3 id="montage-생성-2">Montage 생성</h3>
<ul>
<li>앞서 언급했던 것과 같은 방법으로, Ability_Ultimate 라는 애니메이션도 몽타주를 만들어줍시다.</li>
</ul>
<h2 id="다시-flyattack">다시, FlyAttack</h2>
<ul>
<li>생성한 BTT 를 열고 변수를 하나 만듭시다.<blockquote>
<ul>
<li>PlayerLoc(벡터) : Player 의 위치를 담을 변수</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c853589a-7a15-45ad-914b-7039d0166d27/image.png" alt=""></p>
<ul>
<li>이제 이벤트 그래프를 채워봅시다. 마찬가지로 양이 조금 많아서, 우선적으로 구조부터 보여드리고 부분적으로 확대하여 보여드리겠습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e01857ce-fda2-490b-a6fd-e18a355835a1/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c478c33a-6b09-48c1-a8c5-a5a5cdfef0ff/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f4c13081-d6df-4301-a39b-cdd0ce4772c2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5502e3bf-b248-411d-8f87-ac25a2663b1d/image.png" alt=""></p>
<ul>
<li><p>캐릭터 무브먼트는 get character movement 로 가져올 수 있습니다.</p>
</li>
<li><p>&#39;중력 스케일&#39;을 입력 값으로 갖는 Set 노드의 이름은 &#39;set gravity scale&#39; 입니다.</p>
</li>
<li><p>Play Anim Montage 노드의 Anim Montage 에셋 이름은 &#39;Ability_Ultimate_Montage&#39; 입니다.</p>
</li>
</ul>
<h1 id="다시-bt-구현">다시, BT 구현</h1>
<ul>
<li><p>이제 최종적으로 BT 를 구현해볼겁니다.</p>
</li>
<li><p>앞서, Enemy 와 Player 사이의 거리가 1500보다 크거나 같을 때 Slash 를 하였습니다. 동일한 조건 하에, FlyAttack 도 하게끔 만들고 싶습니다.</p>
<blockquote>
<ul>
<li>우리는 0.5의 확률로 Slash, 0.5의 확률로 FlyAttack 을 하도록 하곘습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="randnum">RandNum</h2>
<ul>
<li>AI 폴더에 BTT 를 생성하고 이름은 RandNum 으로 해줍니다. 바로 열어서, 변수를 하나 생성해줍시다.<blockquote>
<ul>
<li>RandNum(블랙보드 키 선택 툴) : 블랙 보드에 있는 키를 연결하기 위한 변수입니다. 키에 Int 값을 전달합니다. (0 또는 1)</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/51b12f77-5c60-4e77-a28c-bafccb878b4f/image.png" alt=""></p>
<ul>
<li>잊지 말고 RandNum 의 오른쪽 디테일 창에서, 인스턴트 편집가능을 체크해줍시다.</li>
</ul>
<blockquote>
<ul>
<li>이제 이벤트 그래프를 채워봅시다!</li>
</ul>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3acc3a0d-6fc4-4419-a991-cb14313de666/image.png" alt=""></p>
<h3 id="블랙-보드-key-와-연결하기">블랙 보드 Key 와 연결하기</h3>
<ul>
<li>우선, 블랙 보드에서 RandNum 이라는 Key 를 만들어줍시다.<blockquote>
<ul>
<li>타입은 인티저, 이름은 RandNum 이라고 해줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/52d37c09-c480-4f3e-a573-29063f0a5e6d/image.png" alt=""></p>
<ul>
<li>BT 로 돌아와서 RandNum Task 를 생성한 뒤, 이를 클릭하여 디테일 - 디폴트 - RandNum 를 RandNum 로 바꿔줍니다.<blockquote>
<ul>
<li>SelfActor 로 설정되어 있을겁니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e8b77c9f-8135-4cc9-bf0a-717dca20eaae/image.png" alt=""></p>
<ul>
<li>연결을 완료했습니다. 이제 최종적으로 BT 를 구현해봅시다.</li>
</ul>
<h1 id="최종-bt-구현">최종 BT 구현</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/98785722-fcef-41b6-b73e-ec14e32f2339/image.png" alt=""></p>
<ul>
<li><p>Decorator 설정에 유의해주셨으면 좋겠습니다. 꼼꼼히 따라해보세요~</p>
</li>
<li><p>이렇게 BT 가 완성되었습니다. 한 번 플레이해봅시다!</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3a9d7f5c-7faf-4d77-8f49-ddd30b337b1a/image.gif" alt=""></p>
<ul>
<li><p>조건에 따라 잘 행동하는군요~ 좋습니다!</p>
</li>
<li><p>여기까지 2주차 Part.2 - AI Application 이었습니다. 다음 포스팅은 3주차 Part.1 - VFX 입니다~</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UE] AI Basic]]></title>
            <link>https://velog.io/@hkun_ho/UE-AI-Basic</link>
            <guid>https://velog.io/@hkun_ho/UE-AI-Basic</guid>
            <pubDate>Mon, 06 Feb 2023 18:54:08 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<ul>
<li>본 학습 자료는 경희대학교 게임 &amp; 실감형 컨텐츠 제작 동아리 <code>Ludens</code> 의 Unreal-Study 자료입니다.</li>
</ul>
<h1 id="paragon-에셋-임포트-하기">Paragon 에셋 임포트 하기</h1>
<ul>
<li>1주차에서 했던 것과 마찬가지로, 에픽 게임즈 런처 - 상단의 &#39;마켓플레이스&#39; - &#39;Paragon&#39; 검색 - &#39;Paragon:Countess&#39; 다운로드 및 프로젝트에 추가해줍시다.</li>
</ul>
<h1 id="폴더-만들기">폴더 만들기</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/07093728-dcc5-4011-9b10-0e39cbcad124/image.png" alt=""></p>
<ul>
<li>User 내부에 Enemy 폴더를 만들어줍시다.<blockquote>
<ul>
<li>우리는 Enemy 에 관련된 것은 모두 이 폴더에 넣을 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="enemybp">EnemyBP</h1>
<ul>
<li>Enemy 폴더 내에 블루프린트 클래스를 추가해줍니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c383fa6a-068c-4042-a320-d66d7f58dc82/image.png" alt=""></p>
<ul>
<li>캐릭터 클래스를 골라주시면 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0a8a415a-70d2-430c-8ade-5a501b952f68/image.png" alt=""></p>
<ul>
<li>이름은 EnemyBP 로 하고, 열어봅시다.</li>
</ul>
<h1 id="스켈레탈-메시-적용">스켈레탈 메시 적용</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3b8ff0d5-0d57-4c6e-8169-f92147a10bba/image.png" alt=""></p>
<ul>
<li>&#39;메시&#39; 컴포넌트 - 스켈레탈 메시 에서 &#39;SM_Countess&#39; 를 선택해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/916dd895-977b-422f-a997-a50be36f7f0f/image.png" alt=""></p>
<ul>
<li>둥 떠있는 캐릭터가 나왔습니다. &#39;메시&#39; 컴포넌트의 트랜스폼 - 위치 에서 z 값을 -88.0 으로 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/eda0b6f6-c993-41c4-9d68-e64c5eea1d85/image.png" alt=""></p>
<ul>
<li>카메라의 방향과 캐릭터가 바라보는 방향이 일치하지 않습니다. &#39;메시&#39; 컴포넌트의 트랜스폼 - 회전 - z 값을 270 으로 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3949b4d9-c740-4735-b75b-0bdcd3424e8a/image.png" alt=""></p>
<ul>
<li>기본 세팅 완료!</li>
</ul>
<h1 id="enemyanimbp">EnemyAnimBP</h1>
<ul>
<li>다시 Enemy 폴더로 돌아와서 애니메이션 블루프린트 클래스를 추가해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/85297a44-9d21-4bf2-aaf6-2fcbc6365ef2/image.png" alt=""></p>
<ul>
<li>Enemy 캐릭터인 S_Countess_Skeleton 를 선택해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/364472e1-15d1-441c-aba7-35aa34dda4f2/image.png" alt=""></p>
<ul>
<li>EnemyAnimBP 의 Logic 은 PlayerAnimBP 만큼 복잡하지 않습니다! 바로 시작해봅시다~</li>
</ul>
<h2 id="변수-생성">변수 생성</h2>
<ul>
<li>먼저, 변수를 생성해줍시다. 하나만 생성하면 됩니다.<blockquote>
<ul>
<li>Speed(플로트) : 캐릭터의 속도를 담을 변수</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bd76fcc9-b6a3-4c4c-ba7d-9a34cfc206eb/image.png" alt=""></p>
<h2 id="변수에-값-저장">변수에 값 저장</h2>
<ul>
<li>이벤트 그래프로 가봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a883437a-b069-47b2-bf7a-300b80bb437b/image.png" alt=""></p>
<ul>
<li>이제 &#39;AnimGraph&#39; 로 가봅시다. 애니메이션 Logic 을 짤겁니다!</li>
</ul>
<h2 id="idlerun">Idle/Run</h2>
<ul>
<li>스테이트 머신을 하나 추가해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0d93c3f9-e550-4d65-9806-f217fb3a9337/image.png" alt=""></p>
<ul>
<li>이름은 Locomotion 으로 해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ed5b5099-9833-4fa2-b77b-20e7260d3b9e/image.png" alt=""></p>
<ul>
<li><p>Locomotion 을 더블 클릭하여 들어가줍시다. Idle 상태를 만들어줄겁니다.</p>
</li>
<li><p>좌측 하단의 콘텐츠 드로어를 클릭하여 &#39;idle_relaxed&#39; 를 검색하여 블루 프린트 내로 드래그해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2f7aa46d-22cd-43ac-87cc-76c12872056e/image.png" alt=""></p>
<ul>
<li>마찬가지 방식으로 &#39;jog_fwd&#39; 를 검색하여 블루 프린트 내로 드래그해줍시다.<blockquote>
<ul>
<li>jog_fwd 가 여러 개 있는니, 캐릭터를 잘 보고 선택해주세요~</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e92cebc7-9d4e-4ca2-b350-877b604f0eda/image.png" alt=""></p>
<h3 id="idle---run">Idle -&gt; Run</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6d1b2cee-1765-4a13-98cf-d74ce424974a/image.png" alt=""></p>
<ul>
<li>빨간색 박스 속 아이콘을 더블 클릭합시다.<blockquote>
<ul>
<li>상태가 변할 조건을 정해줄겁니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8e34bfe2-1e27-4b4d-ae00-e333d9467970/image.png" alt=""></p>
<ul>
<li>간단합니다. Speed 가 0보다 클 때 Idle 에서 Run 상태로 변하게 됩니다.</li>
</ul>
<h3 id="run---idle">Run -&gt; Idle</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d2ea09ad-4542-464e-b55e-f4898955475f/image.png" alt=""></p>
<ul>
<li>더블 클릭해줍시다~</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bc534b4e-5eca-4f1d-bda7-055220b3aa95/image.png" alt=""></p>
<ul>
<li><p>마찬가지로 간단합니다. Speed 가 0이 되면 Run 에서 Idle 로 바뀝니다.</p>
</li>
<li><p>끝입니다. 다시 AnimGraph 로 돌아와 Locomotion 과 최종 애니메이션 포즈를 이어주면 됩니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c93cacb3-815a-4863-b810-f0ecb60152dd/image.png" alt=""></p>
<h2 id="enemybp-에서-enemyanimbp-연결하기">EnemyBP 에서 EnemyAnimBP 연결하기</h2>
<ul>
<li>다시 EnemyBP 로 돌아와서, &#39;메시 컴포넌트&#39; - 애니메이션 - 애님 클래스를 EnemyAnimBP 로 설정해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4e97f4b9-8bfe-44fc-b1ab-e6515da6f1fa/image.png" alt=""></p>
<ul>
<li>그리고 뷰포트(플레이 실행 창)에 EnemyBP 를 배치합시다. 그리고 플레이해주면..</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/80b4c634-23c8-46c6-9845-ed6d2fb6a84a/image.gif" alt=""></p>
<ul>
<li>잘 작동하는 것을 확인하실 수 있습니다!</li>
</ul>
<h1 id="enemyaicontroller">EnemyAIController</h1>
<ul>
<li><p>플레이어가 직접 컨트롤하는 PlayerBP 와 달리, EnemyBP 는 AIController 를 빙의시켜 주어야합니다.</p>
<blockquote>
<ul>
<li>꼭 이런 방식이 아니어도 되지만, 보편적인 방식입니다.</li>
</ul>
</blockquote>
</li>
<li><p>Enemy 폴더에서 블루 프린트 클래스를 생성해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e5c8bcb1-05e1-4b92-9d1f-79557cbaa42e/image.png" alt=""></p>
<ul>
<li>&#39;aicontroller&#39; 를 검색하여 선택해줍시다. 이름은 EnemyAIController 로 합시다.</li>
</ul>
<h2 id="enemybp-에서-enemyaicontroller-할당">EnemyBP 에서 EnemyAIController 할당</h2>
<ul>
<li><p>EnemyAIController 를 만들자마자 갑작스럽긴 하지만, EnemyBP 를 다시 열어봅시다.</p>
</li>
<li><p>그리고 좌측 상단의 컴포넌트에서 &#39;EnemyBP(셀프)&#39;를 클릭하고 우측의 디테일 탭의 &#39;폰&#39; - &#39;AI 컨트롤러 클래스&#39; 를 EnemyAIController 로 바꿔줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e3d8a497-1779-4685-a1dd-8b28ccb9906c/image.png" alt=""></p>
<ul>
<li>이로써 EnemyAIController 를 할당시켜주었습니다. 다시 EnemyAIController 돌아갑시다.</li>
</ul>
<h1 id="다시-enemyaicontroller">다시, EnemyAIController</h1>
<ul>
<li>생성된 EnemyAIController 를 열어, 이벤트 그래프로 갑시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/730282cd-e7b7-4ef2-88bb-59a318883923/image.png" alt=""></p>
<ul>
<li>틱 이벤트와 &#39;run behavior tree&#39; 라는 노드를 이어줍시다. 이 노드의 &#39;BTAsset&#39; 항목을 지정해주어야 하는데, 우리는 BTAsset 이 없습니다. 그런데 BT 가 무엇일까요?<blockquote>
<ul>
<li>바로 행동 트리(Behavior Tree)입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="behavior-tree">Behavior Tree</h1>
<ul>
<li><p>조금 생소하실 수도 있겠습니다. Behavior Tree 란, 쉽게 설명하여 AI 가 어떤 행동을, 어떤 상황에 할 것인가를 담고 있는 Tree 입니다.</p>
<blockquote>
<ul>
<li>여기서 Tree 라는 자료 구조를 사용하기 때문에 Behavior 뒤에 Tree 가 붙습니다. 말 그대로 행동(Behavior)을 담은 Tree 입니다.</li>
</ul>
</blockquote>
</li>
<li><p>Enemy 폴더로 돌아와, AI 라는 이름의 폴더를 하나 만들어줍시다.</p>
<blockquote>
<ul>
<li>여기에 AI 에 관련된 것을 모두 넣을 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1bb39912-b168-423c-8fa9-0dcbfe63178f/image.png" alt=""></p>
<ul>
<li>AI 폴더 내에서 빈공간에 우클릭하여, &#39;인공지능&#39; - &#39;비헤이비어 트리&#39; 를 생성해줍시다.<blockquote>
<ul>
<li>이름은 EnemyBT 로 합시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a87678e0-402d-4ae1-b7dc-fa11e985f73e/image.png" alt=""></p>
<ul>
<li>BT 에 대한 더 자세한 내용은 뒤에 설명하겠습니다. 일단 넘어갑시다!</li>
</ul>
<h1 id="black-board">Black Board</h1>
<ul>
<li><p>Behavior Tree 와 뗄 수 없는 관계인 Black Board 입니다. BB 는 BT 에 사용될 여러 Key(= 사용자 지정 변수)값들을 담고 있습니다.</p>
</li>
<li><p>다시 AI 폴더로 돌아와, &#39;인공지능&#39; - &#39;블랙보드&#39; 를 생성해줍시다.</p>
<blockquote>
<ul>
<li>이름은 EnemyBB 로 합시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d0873199-a8f5-4a0a-b65a-0b2af45212fa/image.png" alt=""></p>
<h1 id="다시-enemyaicontroller-1">다시, EnemyAIController</h1>
<ul>
<li>자, 아까 &#39;BTAsset&#39; 항목을 지정해주려고 했으나, BT 가 존재하지 않아 실패했었습니다. 이제는 BT 를 생성하였으므로 가능합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8f5f2ad2-ff9a-463b-8194-4b279aaabf02/image.png" alt=""></p>
<ul>
<li><p>EnemyBT 를 선택해줍시다!</p>
</li>
<li><p>이제 EnemyAIController 에서 할 일은 끝났습니다. EnemyBT 를 열어봅시다.</p>
</li>
</ul>
<h1 id="enemybt-enemybb">EnemyBT (+EnemyBB)</h1>
<ul>
<li>우측 디테일 탭에 BehaviorTree - 블랙보드 에셋에 EnemyBB 가 할당되어 있는 것을 보실 수 있습니다.<blockquote>
<ul>
<li>현재는 BT 와 BB 가 각각 하나이기 때문에 자동으로 할당이 되었는데, 한 쌍이 아닐 때는 직접 알맞는 BB 를 할당해 주어야합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/b3f26dce-7203-42e8-ba20-71a4c4bb0781/image.png" alt=""></p>
<ul>
<li><p>이제 AI 폴더로 가서 EnemyBB 를 열 필요 없이, 우측 상단에 &#39;블랙 보드&#39;를 클릭하면 EnemyBB 가 열립니다.</p>
</li>
<li><p>본격적으로 행동 트리의 &#39;행동&#39; 부분 Logic 을 작성하기 전에, 다시 한 번 전체적인 구조를 정리하겠습니다.</p>
</li>
</ul>
<blockquote>
<ol>
<li>EnemyAIController 할당<ul>
<li>별도의 컨트롤러가 없는 Enemy 를 컨트롤 해줄 AIController 생성 후 할당
<img src="https://velog.velcdn.com/images/hkun_ho/post/63425b54-7f5f-4e01-80b9-532134f556f4/image.png" alt=""></li>
</ul>
</li>
<li>EnemyAIController 에서 Behavior Tree 실행
<img src="https://velog.velcdn.com/images/hkun_ho/post/71d4b7e8-44c5-4769-b696-2fb622614c59/image.png" alt=""></li>
<li>BT 에 작성해둔 Logic 대로 행동<ul>
<li>아직 작성하지 않았지만, 여기에 작성해둔 Logic 대로 행동합니다.
<img src="https://velog.velcdn.com/images/hkun_ho/post/ac61fc6f-d903-43a7-9687-da138d9c9f6d/image.png" alt=""></li>
</ul>
</li>
</ol>
</blockquote>
<ul>
<li>정리가 되셨나요? 만약 정리가 되셨다면 이제 BT 를 작성하는 일밖에 남지 않았다는 사실을 아실겁니다. 작성해봅시다!<blockquote>
<ul>
<li>정리가 되지 않았다면, 몇 번 더 읽어보시길 권장합니다!</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="behavior-tree-basic">Behavior Tree Basic</h1>
<ul>
<li>놀랍게도 이번 주차의 본론은 지금부터입니다. 이제 BT 의 요소를 하나하나 알아볼겁니다.<blockquote>
<ul>
<li>전부 다는 아니고, 우리의 AI 를 구현하는데 필요한 만큼만요. (사실 거의 전부긴 합니다..ㅎㅎ)</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="root">Root</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a659cefd-d3c7-469d-beba-f21848a4b1aa/image.png" alt=""></p>
<ul>
<li>BT 의 시작점으로 BB 의 데이터를 기반으로 합니다.<blockquote>
<ul>
<li>루트, 말그대로 뿌리같은 존재입니다. 시작점이라고 이해하시면 충분합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="sequence">Sequence</h2>
<ul>
<li>BT 의 빈공간을 우클릭 해보시면 Composites/Tasks 두 항목을 생성할 수 있는 것을 확인할 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1495c408-1004-4ef8-9f7a-6a6f8f185f9f/image.png" alt=""></p>
<ul>
<li>Sequence 는 이 중 Composites 에 해당합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2c4ad56c-dbc5-4fdf-b707-a9aca3d68444/image.png" alt=""></p>
<ul>
<li>자식 노드를 왼쪽에서 오른쪽으로 실행하며, 실행 중인 자식 노드가 성공하면 그 다음 노드를 실행하고 실패하면 실행하지 않습니다.<blockquote>
<ul>
<li>여기서 자식 노드란, 부모 노드의 하위에 있는 노드를 뜻합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/42098ed4-3abd-46c7-9679-ab7b12e35873/image.png" alt=""></p>
<ul>
<li><p>위 그림에서 D, E 가 자식 노드입니다. 생소하신 분들은 자료 구조에서 배우시게 될겁니다!</p>
</li>
<li><p>Sequence 를 한 마디로 설명하면, &#39;실패할 때까지 해라!&#39; 입니다.</p>
</li>
</ul>
<h2 id="selector">Selector</h2>
<ul>
<li>Sequence 와 마찬가지로 Composites 항목에 해당합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/32315426-1e6b-46dc-b961-e5496174cdda/image.png" alt=""></p>
<ul>
<li><p>자식 노드를 왼쪽에서 오른쪽으로 실행하며, 실행 중인 자식 노드가 실패하면 그 다음 노드를 실행하고 성공하면 실행하지 않습니다.</p>
</li>
<li><p>마찬가지로, Selector 를 한 마디로 설명하면, &#39;성공할 때까지 해라!&#39; 입니다.</p>
</li>
</ul>
<h2 id="tasks">Tasks</h2>
<ul>
<li>앞서 살펴봤던 Composites 외의 항목인 Tasks 입니다. 이는 우리가 흔히 Function 이라고 표현하는 것과 역할이 매우 비슷합니다.<blockquote>
<ul>
<li>아직 감이 잡히시지 않으셔도 괜찮습니다. 이후 BT 의 Logic 을 작성하실 때 감이 오실겁니다!</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="decorator">Decorator</h2>
<ul>
<li>Composites 을 우클릭하면 Decorator 를 추가할 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2cc82dda-f209-40e7-a50b-2c0ef4980d4d/image.png" alt=""></p>
<ul>
<li><p>Decorator 는 &#39;조건문&#39; 이라고 명확하게 표현할 수 있을 것 같습니다.</p>
<blockquote>
<ul>
<li>이를 통해 특정 조건을 만족하면 특정 행동을 하게끔 만들 수 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>우리가 사용할 것은 이 정도입니다! 이외에도 Simple Parallel, Service 등이 있지만 당장은 사용하지 않아도 됩니다.</p>
<blockquote>
<ul>
<li>궁금하시다면, <a href="https://wergia.tistory.com/147">[UE4] AI - 비헤이비어 트리(Behavior Tree)</a> 를 참고하세요!</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="btt-생성">BTT 생성</h1>
<ul>
<li><p>Behavior Tree Task 의 약자입니다. 위에서 설명한 Task 에 해당합니다.</p>
<blockquote>
<ul>
<li>Function 과 기능이 유사하다고 하였습니다. 함수를 작성하는 느낌으로 만들어봅시다.</li>
</ul>
</blockquote>
</li>
<li><p>AI 폴더로 돌아와서, 블루 프린트 클래스를 생성해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0496f781-a469-48d6-9a46-d77400007cae/image.png" alt=""></p>
<ul>
<li>BTT 라고 검색하여, BTTask_BlueprintBase 를 선택해줍시다.<blockquote>
<ul>
<li>처음 만들 Task 이름은 MoveToPlayer 입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="movetoplayer">MoveToPlayer</h2>
<ul>
<li>생성한 MoveToPlayer 를 열어봅시다. 이벤트 그래프를 작성할겁니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d700d0ea-14c0-4ba6-ba80-13a864c98c93/image.png" alt=""></p>
<ul>
<li><p>눈치채셨을 수도 있지만, 이는 Player 에게 다가가기 위한 Task 입니다.</p>
</li>
<li><p>잘 실행되는지 확인해보기 위해 간단한 BT 를 작성해봅시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8feb9b63-04dd-4e78-9b90-3b98c5eaadce/image.png" alt=""></p>
<ul>
<li><p>앞선 내용을 잘 이해하셨다면, BT 가 실행되면 Enemy 가 따라오다가 잠시 멈추고(Wait) 다시 따라오는 것을 반복할 것이라고 예측할 수 있습니다.</p>
</li>
<li><p>그런데 플레이를 해보면, 움직이지 않습니다. 왜일까요?</p>
</li>
</ul>
<h3 id="navmeshboundsvolume">NavMeshBoundsVolume</h3>
<ul>
<li>네비게이션 메시를 깔아주지 않아서 그렇습니다. 아래 사진과 같이 NavMeshBoundsVolume 을 생성해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d9436541-8f95-4d40-b2d5-e38e4507f537/image.png" alt=""></p>
<ul>
<li>NavMeshBoundsVolume 의 크기를 키우고, 위치를 잘 조절하여 바닥을 전부 포함하도록 해줍시다.<blockquote>
<ul>
<li>참고로 P 를 누르면 네비게이션 메시가 잘 설치되었는지를 확인할 수 있습니다. 아래 그림의 초록색 부분이 AI 가 걸어다닐 수 있는 공간입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3b827bce-a2c7-415f-b658-d684e1850783/image.png" alt=""></p>
<ul>
<li>실행해보면, 잘 움직이는 것을 확인할 수 있습니다. 근데 조금 빠른 것 같으니 속도를 조절해줍시다!</li>
</ul>
<h2 id="최대-걷기-속도-조정">최대 걷기 속도 조정</h2>
<ul>
<li>EnemyBP 를 열고, &#39;캐릭터 무브먼트&#39; 컴포넌트 - 캐릭터 무브먼트: 걷기 - 최대 걷기 속도 를 300 으로 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/cd478d55-4784-4fb4-acd0-54cb5be0bb8c/image.png" alt=""></p>
<ul>
<li>이제 다시 플레이해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/354f12d1-9465-40de-95b8-051fc652e14f/image.gif" alt=""></p>
<ul>
<li>적당하네요~</li>
</ul>
<h2 id="setdistance">SetDistance</h2>
<ul>
<li><p>그런데 Enemy 가 너무 시도 때도 없이 따라옵니다. 따라서 일정 거리 내에 들어왔을 때에만 따라오도록 하고 싶습니다.</p>
<blockquote>
<ul>
<li>Decorator 가 쓰이겠구나~ 라고 생각하셨다면 베리 굳입니다~</li>
</ul>
</blockquote>
</li>
<li><p>우선은 Enemy 와 Player 사이의 거리를 측정하는 용도의 Task 를 만들겁니다.</p>
<blockquote>
<ul>
<li>이것이 바로 SetDistance 의 용도입니다.</li>
</ul>
</blockquote>
</li>
<li><p>앞서 했던 것처럼, AI 폴더로 돌아와서, 블루 프린트 클래스를 생성해준 뒤, BTT 라고 검색하여 BTTask_BlueprintBase 를 선택해줍시다.</p>
<blockquote>
<ul>
<li>Task 이름은 SetDistance 입니다. 생성한 뒤 바로 열어줍시다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="변수-생성-1">변수 생성</h3>
<ul>
<li>변수를 하나 생성해줍니다.<blockquote>
<ul>
<li>Distance(블랙 보드 키 선택 툴) : 블랙 보드에 있는 키를 연결하기 위한 변수입니다. 키에 float 값을 전달합니다. (Enemy 와 Player 간의 Distance)</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/98679ad9-49fa-45f6-97e8-3d58aa2706ff/image.png" alt=""></p>
<ul>
<li>중요한게 하나 더 있습니다. Distance 의 오른쪽 디테일 창에서, 인스턴트 편집가능을 체크해주어야 합니다.<blockquote>
<ul>
<li>이걸 체크해야 블랙 보드에서 Key 와 연결하기 수월해집니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4795cede-7e76-4996-abf0-bbf9e0386c02/image.png" alt=""></p>
<h2 id="다시-setdistance">다시, SetDistance</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e73c3b86-1cb0-4057-a489-7208d4e6289c/image.png" alt=""></p>
<ul>
<li>이 Task 는 이게 끝입니다. 간단하죠~</li>
</ul>
<h3 id="블랙-보드-key-와-연결하기">블랙 보드 Key 와 연결하기</h3>
<ul>
<li>우선, 블랙 보드에서 Distance 라는 Key 를 만들어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/42d0d904-d8dd-41f7-b778-dd5c071c562b/image.png" alt=""></p>
<ul>
<li><p>타입은 플로트, 이름은 Distance 라고 해줍시다.</p>
</li>
<li><p>BT 로 돌아와서 Distance Task 를 생성한 뒤, 이를 클릭하여 디테일 - 디폴트 - Distance 를 Distance 로 바꿔줍니다.</p>
<blockquote>
<ul>
<li>SelfActor 로 설정되어 있을겁니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/08337020-b4d1-4f0a-8eaf-64e282c6d879/image.png" alt=""></p>
<ul>
<li>연결을 완료했습니다! 이제 또 한 번 간단한 BT 를 통해 잘 작동하는지 확인해봅시다.</li>
</ul>
<h1 id="조건에-따라-움직이는-ai">조건에 따라 움직이는 AI</h1>
<ul>
<li>다음과 같은 간단한 BT 를 작성했습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bb9e46d3-3364-452c-a72e-540e1f18318b/image.png" alt=""></p>
<ul>
<li>이제 조건을 넣어줄 차례입니다. Decorator 를 사용합시다.</li>
</ul>
<h2 id="decorator-설정">Decorator 설정</h2>
<ul>
<li>우선 MoveToPlayer 노드를 우클릭하여, &#39;데코레이터 추가&#39; - Blackboard 를 선택해줍니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c68ac899-0cf4-4445-a6e3-ae7123f5f708/image.png" alt=""></p>
<ul>
<li>그 뒤, 파란색 부분의 Decorator 를 클릭하여 디테일 탭에서 몇 가지 설정을 바꿔줍니다.<blockquote>
<ul>
<li>블랙보드 키 : Distance 로 설정</li>
<li>키 쿼리 : Is Less Than 으로 설정</li>
<li>키 값 : 500 으로 설정</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bc6a0943-b5d1-4c0a-b09d-2268ec511538/image.png" alt=""></p>
<ul>
<li>같은 방식으로 왼쪽의 Wait 노드도 진행해줍시다.<blockquote>
<ul>
<li>다만 키 쿼리를 Is Greater Than or Equal To 로 설정해주어야합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d25e227d-0711-4c95-9a07-898c2eef1449/image.png" alt=""></p>
<ul>
<li><p>이렇게 완성된 BT 는, Enemy 와 Player 사이의 거리가 500 미만일 때에만 움직인다고 해석할 수 있습니다.</p>
</li>
<li><p>플레이 해봅시다!</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ad4fe062-f9d5-4c7f-87de-7d40bf65b259/image.gif" alt=""></p>
<ul>
<li><p>조건에 따라 잘 작동하네요.</p>
</li>
<li><p>여기까지 2주차 Part.1 - AI Basic 이었습니다. 다음 포스팅은 2주차 Part.2 - AI Application 입니다~</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UE] Player Attack]]></title>
            <link>https://velog.io/@hkun_ho/UE-Player-Attack</link>
            <guid>https://velog.io/@hkun_ho/UE-Player-Attack</guid>
            <pubDate>Thu, 02 Feb 2023 06:18:39 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<ul>
<li>본 학습 자료는 경희대학교 게임 &amp; 실감형 컨텐츠 제작 동아리 <code>Ludens</code> 의 Unreal-Study 자료입니다.</li>
</ul>
<h1 id="playerbp">PlayerBP</h1>
<ul>
<li>PlayerBP 를 열어줍시다.</li>
</ul>
<h2 id="custom-event-생성">Custom Event 생성</h2>
<ul>
<li><p>Attack 기능을 만들기 전에, 이에 필요한 Custom Event 를 생성할 것입니다.</p>
</li>
<li><p>이벤트 그래프의 빈공간을 우클릭한 뒤, &#39;customevent&#39;라고 검색하여 추가해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/07b4c871-67d9-4285-90a2-d69dfddeb914/image.png" alt=""></p>
<ul>
<li>2개의 Custom Event 를 추가해줄건데, 이름은 각각 SaveCombo, ResetCombo 로 합시다.<blockquote>
<ul>
<li>눈치채셨겠지만, 이는 콤보 공격을 위한 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/aac1ba67-5c16-4ec1-99c7-ed1190860954/image.png" alt=""></p>
<ul>
<li>이 상태라면 성공입니다!</li>
</ul>
<h2 id="변수-생성">변수 생성</h2>
<ul>
<li>이제 변수도 생성해줍시다. 총 3가지 변수를 만들겁니다.<blockquote>
<ul>
<li>SaveAttack : 직전 상황에 Attack 을 했는지 여부를 담는 변수</li>
<li>IsAttacking : 현재 Attack 중인지 여부를 담는 변수</li>
<li>AttackCount : Combo 를 누적하는 변수 (0부터 시작)</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/96e5d6b0-c092-4d4d-9241-194578792d1d/image.png" alt=""></p>
<h2 id="attack">Attack</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5d109b13-dfd9-45a7-8680-be617c441753/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ad1c7090-74b5-4204-90c4-54161bbf74b5/image.png" alt=""></p>
<ul>
<li><p>PlayAnimMontage 노드의 Anim Montage 부분에 들어갈 애니메이션 몽타주는 다음과 같습니다. (위에서 부터)</p>
<blockquote>
<ul>
<li>PrimaryAttack_A_Slow_Montage</li>
<li>PrimaryAttack_B_Slow_Montage</li>
<li>PrimaryAttack_C_Slow_Montage</li>
<li>PrimaryAttack_D_Slow_Montage</li>
</ul>
</blockquote>
</li>
<li><p>코드를 완성했습니다. 하지만 왜인지 플레이를 해보면 공격이 안됩니다. 왜일까요?</p>
<blockquote>
<ul>
<li>아직 PlayerAnimBP 에서 추가할 것이 남았기 때문입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="playeranimbp">PlayerAnimBP</h1>
<ul>
<li>PlayerAnimBP 를 열기 전에, PrimaryAttack_A_Slow_Montage 를 열어봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9d813a6a-c6e3-45bb-85e8-0fb0724e2767/image.png" alt=""></p>
<h2 id="animation-notification">Animation Notification</h2>
<ul>
<li>줄여서 AnimNotify 라고 흔히 부릅니다. 이는 애니메이션 시퀸스에서 이벤트를 구성하고 받아 외부 동작을 수행하는 알림 시스템입니다.<blockquote>
<ul>
<li>쉽게 말해, 애니메이션에 직접 Notify 를 넣어서 특정 시점에 Notify 가 발동하게 되면 이러한 발동 정보를 이용해 그 시점에 또 다른 이벤트가 발생하게끔 하는 것입니다.
ex) 걷는 동작 중, 발이 땅에 닿는 시점에 Notify 를 넣어 이 시점에 발걸음 소리가 나게끔 설정</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a0134489-e431-453a-bb00-ef3df4bd8674/image.png" alt=""></p>
<ul>
<li><p>PrimaryAttack_A_Slow_Montage 를 열어보면, 이미 AnimNotify 가 존재하는 것을 확인할 수 있습니다.</p>
<blockquote>
<ul>
<li>이는 Paragon 에셋 자체에 담겨있는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>따라서 우리가 해야할 것은 따로 없지만, 그래도 AnimNotify 를 생성하는 법을 간단히 소개하겠습니다.</p>
<blockquote>
<ul>
<li>매우매우 간단하니 그냥 봅시다!</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ce866b29-13e1-41aa-83f9-6ee7f1e248a9/image.png" alt=""></p>
<ul>
<li>표시된 부분에서 우클릭을 해줍니다.<blockquote>
<ul>
<li>꼭 저 부분에 추가해야하는 것은 아니지만, 예시니까 그냥 저 부분에 추가해봅시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9d033580-7607-40f5-815f-3f62b572d17d/image.png" alt=""></p>
<ul>
<li>그리고 &#39;노티파이 추가&#39; - &#39;새 노티파이&#39; 를 눌러줍시다.<blockquote>
<ul>
<li>노티파이 이름은 예시니까, Example 로 합시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ea30fb25-b878-495c-a96e-d51978a7d751/image.png" alt=""></p>
<ul>
<li>그럼 끝입니다. 매우 간단하죠? 이제 Example 은 지우셔도 됩니다. 연습 삼아 해본거니까요~</li>
</ul>
<h1 id="다시-playeranimbp">다시, PlayerAnimBP</h1>
<ul>
<li>PlayerAnimBP 로 돌아옵시다. 이제 위에서 만들었던 AnimNotify 를 불러올겁니다.<blockquote>
<ul>
<li>PlayerAnimBP 의 이벤트 그래프로 갑시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/46578247-06d7-409d-83e6-74302edcb579/image.png" alt=""></p>
<ul>
<li>조금 헷갈릴 수도 있으니 전반적인 구조를 다시 잡고 갑시다.</li>
</ul>
<blockquote>
<ol>
<li>Animation Montage 가 실행되면서 특정 시점에 Notify 발생
<img src="https://velog.velcdn.com/images/hkun_ho/post/7638f37d-8f8b-4ca2-b6f6-e2c8bc51f0fd/image.png" alt=""></li>
<li>발생한 Notify 를 PlayerAnimBP 이벤트 그래프에서 캐치</li>
</ol>
<p>-&gt; AnimNotify_SaveAttack, AnimNotify_ResetCombo 이벤트를 통해 캐치
<img src="https://velog.velcdn.com/images/hkun_ho/post/958b2817-105b-4dde-a7bc-69bc36fc1044/image.png" alt="">
3. 각각의 Notify 가 캐치되면 PlayerBP 에 생성해둔 커스텀 이벤트 SaveCombo, ResetCombo 가 실행됨
<img src="https://velog.velcdn.com/images/hkun_ho/post/38b2089c-3fe7-4ad0-ae8f-7d310ed96d03/image.png" alt=""></p>
</blockquote>
<ul>
<li>이해가 되셨을거라 생각하고, 이제 플레이 해봅시다. 하지만, 아무리 마우스를 클릭하여도 공격이 나가지 않습니다.</li>
</ul>
<h2 id="default-slot-추가">Default Slot 추가</h2>
<ul>
<li><p>Montage 가 재생되지 않을 때, 대부분은 이 문제일 가능성이 높습니다. 기억해두면 좋을 것 같습니다!</p>
</li>
<li><p>PlayerAnimBP 에서 AnimGraph 로 이동합시다. 그리고 빈 공간을 우클릭하여 &#39;defaultslot&#39; 이라고 검색해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/eeaf4377-16a6-4a24-a4ec-baef22657724/image.png" alt=""></p>
<ul>
<li>이를 생성한 후, Basic 과 Ground_Loco 사이에 넣어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/891f3ba2-a50a-4299-9049-44b0afab5f42/image.png" alt=""></p>
<ul>
<li>그 후, &#39;DefaultSlot&#39; 을 클릭하여 오른쪽 디테일 창에서 슬롯 이름을 &#39;DefaulGroup.UpperBody&#39; 로 바꿔줍시다.<blockquote>
<ul>
<li>이 과정은 보편적이진 않습니다. 보통은 슬롯 이름을 바꿔주지 않아도 잘 작동합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/56ce0843-ea66-4e3a-afb7-a9b1651bd354/image.png" alt=""></p>
<ul>
<li>그렇다면 Attack 기능이 잘 작동하는 것을 확인하실 수 있습니다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/fdd31241-1d72-4a95-aa76-a5d3bfb51015/image.gif" alt=""></p>
<h1 id="공격중-이동-제한">공격중 이동 제한</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/b8a65612-49a4-492d-96da-53314aaef069/image.gif" alt=""></p>
<ul>
<li><p>문제가 있습니다. 캐릭터가 공격중에 이상하게 이동합니다. 피겨 선수도 아니고 말이죠~</p>
<blockquote>
<ul>
<li>따라서 공격중 이동을 제한해줄겁니다.</li>
</ul>
</blockquote>
</li>
<li><p>다시 PlayerBP 를 열어봅시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f468fbde-86cc-4bd0-8ead-bf002d2b9cdf/image.png" alt=""></p>
<ul>
<li><p>Combo Attack 부분에 빨간색 박스로 표시한 부분을 추가해줍시다.</p>
<blockquote>
<ul>
<li>최대 걷기 속도 : &#39;set max walk speed&#39; 검색</li>
<li>무브먼트 방향으로 회전 조정 : &#39;set orient rotation to movement&#39; 검색</li>
<li>캐릭터 무브먼트 : &#39;get character movement&#39; 검색</li>
</ul>
</blockquote>
</li>
<li><p>최대 걷기 속도를 0으로 만들어 공격중에 움직이지 못하게 하고, 무브먼트 방향으로 회전 조정 옵션은 false 로 바꿔주어 마우스를 움직여도 시점이 고정되게끔 하는 것입니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e0214825-9cbc-4f81-968a-5989fd327403/image.png" alt=""></p>
<ul>
<li>Combo Attack 부분의 ResetCombo 이벤트의 마지막 부분에도 위와 같이 추가해줍시다.<blockquote>
<ul>
<li>콤보가 리셋되었을 때, 즉 공격이 멈췄을 때는 다시 속도를 원래대로 바꿔주고, 무브먼트 방향으로 회전 조정 옵션도 true 로 만들어줍니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="공격중-sprint-제한">공격중 Sprint 제한</h2>
<ul>
<li>공격중 이동은 제한하였는데, Shift 를 눌렀을 때는 여전히 슬라이딩을 하게 됩니다. 따라서 공격중 Shift 를 눌렀을 때, 즉 공격중 Sprint 도 제한해주어야 합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d7dfc441-66ed-4802-8c36-f0fe7049401d/image.png" alt=""></p>
<ul>
<li>간단합니다. IsAttacking 으로 공격중인지 여부를 판단하여, 공격중이지 않을 때만 Sprint 할 수 있게 하였습니다.</li>
</ul>
<h1 id="attack-montage-speed">Attack Montage Speed</h1>
<ul>
<li>공격 속도가 조금 느린 것 같아서 답답합니다. Montage 의 속도 스케일을 올려봅시다.<blockquote>
<ul>
<li>PrimaryAttack_A_Slow_Montage 를 찾아서 열어봅시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/083b3df6-e9e1-4922-b2a8-5cdeceaea9cf/image.png" alt=""></p>
<ul>
<li>여기서 속도 스케일을 1.5로 바꿔줍시다.<blockquote>
<ul>
<li>이 작업을 PrimaryAttack_B_Slow_Montage, PrimaryAttack_C_Slow_Montage,PrimaryAttack_D_Slow_Montage 에도 해주면 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e72dbf5c-eae7-41ff-b0e3-f21f7c33d195/image.gif" alt=""></p>
<ul>
<li><p>빠릿빠릿 하군요~</p>
</li>
<li><p>여기까지 1주차 Part.2 - Player Attack 이었습니다. 다음 포스팅은 2주차 Part.1 - AI Basic 입니다~</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Game Graphics] Graphics Pipeline]]></title>
            <link>https://velog.io/@hkun_ho/Game-Graphics-DirectX-12</link>
            <guid>https://velog.io/@hkun_ho/Game-Graphics-DirectX-12</guid>
            <pubDate>Tue, 31 Jan 2023 07:59:08 GMT</pubDate>
            <description><![CDATA[<h1 id="graphics-pipeline">Graphics Pipeline</h1>
<ul>
<li><p>3차원 컴퓨터 그래픽스에서 <code>그래픽스 파이프라인(graphics pipeline)</code> 또는 <code>렌더링 파이프라인(rendering pipeline)</code>은 3차원 이미지를 2차원 래스터 이미지로 표현을 하기위한 단계적인 방법을 말합니다.</p>
<blockquote>
<ul>
<li>여기서 <code>래스터(raster)</code>란 컴퓨터에서 화상 정보를 표현하는 한 가지 방법으로 이미지를 2차원 배열 형태의 픽셀로 구성하고 이 점들의 모습을 조합, 일정한 간격의 픽셀들로 하나의 화상 정보를 표현하는 것을 말합니다.</li>
<li>즉, 한 줄에서 연속된 픽셀들의 집합을 래스터라고 합니다.</li>
</ul>
</blockquote>
</li>
<li><p>다음은 Direct3D 12 의 Graphics Pipeline 입니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bcf073c9-df48-4f78-896c-28f89e40984f/image.png" alt=""></p>
<ul>
<li>Graphics Pipeline 은 크게 두 종류의 단계들로 구성되어 있습니다.</li>
</ul>
<h2 id="fixed-pipeline">Fixed Pipeline</h2>
<ul>
<li><p>GPU 에서 모든 처리가 진행되며 응용 프로그램에서 변경할 수 없는 단계</p>
<blockquote>
<ul>
<li>정해진 연산만 수행하므로 수행하므로 프로그래머가 GPU 연산에 관여할 수 없습니다. 즉, <code>non-programmable</code> 한 단계입니다.</li>
</ul>
</blockquote>
</li>
<li><p>Graphics Pipeline 에서 Fixed Pipeline 에 해당하는 단계는 다음과 같습니다.</p>
<blockquote>
<ul>
<li>Input Assembler (IA)</li>
<li>Tesselator (TS)</li>
<li>Stream Output (SO)</li>
<li>Rasterizer (RS)</li>
<li>Output Merger (OM)</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="programmable-pipeline">Programmable Pipeline</h2>
<ul>
<li><p>응용 프로그램에서 쉐이더 프로그램을 통해 제공해야 하는 단계</p>
<blockquote>
<ul>
<li>프로그래머가 GPU 연산에 직접 관여할 수 있습니다. 즉, <code>programmable</code> 한 단계입니다.</li>
<li><code>Shaders</code> 라고도 불립니다.</li>
</ul>
</blockquote>
</li>
<li><p>Graphics Pipeline 에서 Shader stages 에 해당하는 단계는 다음과 같습니다.</p>
<blockquote>
<ul>
<li>Vertex Shader (VS)</li>
<li>Hull Shader (HS)</li>
<li>Domain Shader (DS)</li>
<li>Geometry Shader (GS)</li>
<li>Pixel Shader (PS)</li>
</ul>
</blockquote>
</li>
<li><p>이제, 각 단계들을 세부적으로 살펴봅시다.</p>
</li>
</ul>
<h1 id="input-assembler-ia-stage">Input Assembler (IA) Stage</h1>
<ul>
<li><p>응용 프로그램에서 제공받은 <code>Vertex</code> 버퍼의 <code>Vertex</code> 데이터(점, 선, 삼각형)를 다른 파이프라인 단계에서 사용할 <code>Primitive</code> 데이터(Line List, Triangle List 등)로 조립하여 다른 그래픽 파이프라인에서 사용할 수 있도록 준비하는 단계입니다.</p>
<blockquote>
<ul>
<li>즉, 메모리에서 기하 자료(Vertex 데이터, Index)를 읽어 기하학적 기본 도형(삼각형, 선분 등)을 조립합니다.</li>
</ul>
</blockquote>
</li>
<li><p>또한,<code>Index</code> 버퍼를 이용하여 <code>Vertex</code> 의 복제나 중복을 막습니다.</p>
</li>
</ul>
<h2 id="vertex">Vertex</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0a33db23-66f2-4552-afa5-3a9b1d003f22/image.png" alt=""></p>
<ul>
<li><p>수학적으로, 한 삼각형의 정점은 두 변이 만나는 점입니다. 선분의 경우 선분의 양 끝점이 정점이고, 하나의 점의 경우에는 그 점 자체가 정점입니다.</p>
</li>
<li><p>Direct3D 에서의 정점은 공간적 위치, 즉 위치 값 이외의 정보를 담고 있으며 이를 통해 좀 더 복잡한 렌더링 효과를 구현할 수 있습니다.</p>
<blockquote>
<ul>
<li>예를 들면 조명 구현을 위해 정점에 법선 벡터를 추가하거나 텍스처를 적용하기 위해 텍스처 좌표를 추가하는 식으로 사용할 렌더링 효과에 따라 특정 정보를 추가할 수 있는 유연성을 갖고 있습니다. </li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="primitive">Primitive</h2>
<ul>
<li><p>기본적인 정의는 더 작은 상태로 쪼개거나 분해할 수 없는 &#39;무언가&#39; 또는 기하학적인 형태를 이르는 말입니다. 몇 가지 기본적인 타입이 존재하는데 <code>Point List</code>, <code>Line List</code>, <code>Line Strip</code>, <code>Triangle List</code>, <code>Triangle Strip</code> 등이 있습니다.  </p>
</li>
<li><p>정점들은 정점 버퍼라고 하는 Direct3D 자료구조 안에 담겨서 렌더링 파이프라인에 묶입니다. 정점 버퍼는 정점들을 연속적인 메모리에 저장하는 자료구조일 뿐이기 때문에 정점 버퍼 자체는 그 정점들을 어떤 식으로 조합해서 기본 도형을 생성할 것인지 말해주지 않습니다. 이 생성 방식을 Direct3D 에게 알려주는 데에 쓰이는 수단이 Primitive 입니다.</p>
<blockquote>
<ul>
<li>대부분은 삼각형 목록(Triangle List)을 기본 도형 위상 구조로 사용합니다. 이는 대부분의 Mesh 가 수많은 삼각형으로 근사하여 표현되기 때문입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="point-list">Point List</h3>
<pre><code>D3D12_PRIMITIVE_TOPOLOGY_POINTLIST</code></pre><ul>
<li>모든 정점은 개별적인 점으로 그려집니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/efe6449c-6c87-4121-ba71-ecc7128503f7/image.png" alt=""></p>
<h3 id="line-list">Line List</h3>
<pre><code>D3D12_PRIMITIVE_TOPOLOGY_LINELIST</code></pre><ul>
<li>매 정점 두 개가 개별적인 하나의 선분을 형성합니다. 2n 개의 정점으로 n 개의 선분이 만들어집니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0fd31bcd-adbe-49fd-89cc-e5d7dc97ce2e/image.png" alt=""></p>
<h3 id="line-strip">Line Strip</h3>
<pre><code>D3D12_PRIMITIVE_TOPOLOGY_LINESTRIP</code></pre><ul>
<li>정점들이 차례로 이어져 일련의 선분들이 그려집니다. Line List 와 다르게 정점을 따라 자동으로 선분이 이어집니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0660f929-addb-4904-a488-10127783ffa4/image.png" alt=""></p>
<h3 id="triangle-list">Triangle List</h3>
<pre><code>D3D12_PRIMITIVE_TOPOLOGY_TRIANGLELIST</code></pre><ul>
<li>매 정점 세 개가 하나의 개별적인 삼각형을 형성합니다. 3n 개의 정점으로 n 개의 삼각형이 만들어집니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/31537d2b-afb0-4459-a3d7-e2c4498af3ac/image.png" alt=""></p>
<h3 id="triangle-strip">Triangle Strip</h3>
<pre><code>D3D12_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP</code></pre><ul>
<li>정점들이 연결되어 일련의 삼각형들을 형성합니다. n 개의 정점으로 n - 2 개의 삼각형들이 만들어집니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/26625d3a-0648-468d-9968-297584209513/image.png" alt=""></p>
<h2 id="index">Index</h2>
<ul>
<li>앞서 언급했지만 3차원 물체의 기본 구축 요소는 삼각형입니다. </li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2b2b9231-c910-41f9-b0b8-f613b4f8ddc7/image.png" alt=""></p>
<ul>
<li><p>그림의 삼각형들은 다수의 정점들을 공유하고 있습니다.</p>
<blockquote>
<ul>
<li>삼각형 1과 삼각형 2는 정점 P2 와 P3를 공유하고 있습니다. 즉 2개의 정점에서 2번 중복이 있습니다다.</li>
<li>심지어 삼각형 2, 3, 4는 정점 P4 를 공유하고 있어 하나의 정점이 3번 중복됩니다. 이 중복 현상은 물체가 더 복잡해져 많은 삼각형으로 표현해야 하는 경우 더 심각해집니다.</li>
</ul>
</blockquote>
</li>
<li><p>정점들의 중복이 바람직하지 않은 이유는 크게 두 가지입니다.</p>
<blockquote>
<ul>
<li>메모리 요구량 증가 -&gt; 같은 정점을 여러 번 저장하기 때문</li>
<li>그래픽 하드웨어 처리량 증가 -&gt; 같은 정점 자료를 여러 번 처리하기 때문</li>
</ul>
</blockquote>
</li>
<li><p>따라서 Triangle List 에서 중복 정점들을 제거하는 방법은 가치가 있는 일입니다. 이 방법을 Index 가 제공합니다. 고유한 정점들로 정점 목록을 만들면, 어떤 정점을 어떤 순서로 사용해서 삼각형을 형성하는지를 그 정점들의 색인을 나열하여 지정하면 됩니다.</p>
</li>
</ul>
<pre><code>// 정점 버퍼
Vertex v[7] = {P1, P2, P3, P4, P5, P6, P7};

// 인덱스 버퍼
UINT indexList[] = {
    0, 1, 2, // 삼각형 1
    1, 3, 2, // 삼각형 2
    2, 3, 4, // 삼각형 3
    3, 5, 4, // 삼각형 4
    4, 5, 6  // 삼각형 5
};</code></pre><ul>
<li>그래픽 카드는 정점 목록의 고유한 정점들을 처리한 후, Index 목록을 이용하여 정점들을 조합해 삼각형을 형성합니다. Index 간의 중복이 생겼지만 두 가지 이유로 큰 문제가 되지 않습니다.<blockquote>
<ul>
<li>Index 는 정수이므로 정점 구조체보다 적은 양의 메모리를 차지합니다.</li>
<li>정점 캐시 순서가 좋은 경우 그래픽 하드웨어는 중복된 정점들을 처리하지 않아도 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="vertex-shader-vs-stage">Vertex Shader (VS) Stage</h1>
<ul>
<li><p>Input Assembler 단계에서 출력되는 Primitive 의 각 Vertex 에 대한 연산을 수행합니다.</p>
<blockquote>
<ul>
<li>정점 쉐이더는 항상 모든 정점들에 대해 한 번씩 실행되고, 하나의 정점에 대해 한 번만 호출됩니다. 이는 Pipeline 에서 항상 수행이 되어야 하는 단계이므로 정점에 대한 변환이 필요하지 않아도 정점 쉐이더를 생성해 연결해야 합니다.</li>
</ul>
</blockquote>
</li>
<li><p>Vertex Shader 함수의 구체적인 내용은 프로그래머가 구현해서 GPU 에 전달하게 됩니다. 이 함수는 각 정점에 대해 GPU 에서 실행되기 때문에 속도가 빠릅니다.</p>
</li>
<li><p><code>변환(Transformation)</code>, <code>스키닝(Skinning)</code>, <code>조명(Vertex Lighting)</code> 등 수많은 특수 효과를 정점 쉐이더에서 수행할 수 있습니다. 또한 입력 정점 자료는 텍스쳐, 변환 행렬, 장면 광원 정보 등 GPU 메모리에 담긴 다른 자료에도 접근할 수 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4cf423c4-0179-4790-a8a0-4c824dd0bfe0/image.png" alt=""></p>
<ul>
<li>위와 같이 Vertex Shader 에서는 <code>world transform</code>, <code>view transform</code>, <code>projection transform</code> 등 의 좌표계 변환이 이루어지는데, 이에 대해 알아보겠습니다.</li>
</ul>
<h2 id="world-transform">World Transform</h2>
<ul>
<li><p>물체가 가지는 object space 에서 정의된 물체를 world 에 두는 데 필요한 transform 입니다.</p>
</li>
<li><p>object space 에서 작업을 하면 좌표계 원점을 물체의 중심 가까이에 둘 수 있고 좌표축들을 물체에 맞게 정렬할 수 있기 때문에 편합니다. 따라서 object space 에서 작업을 하여 3차원 모형 정점들을 모두 정의했다면 그것들을 world space 에 적절한 위치와 방향으로 배치해야 합니다.</p>
<blockquote>
<ul>
<li>이를 위해 object space 와 world space 의 관계를 정의할 수 있어야 합니다. 즉, world space 기준으로 좌표 변경 변환을 수행해야 합니다.</li>
<li>이를 <code>World Transform</code> 이라고 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/dcee4aa3-4a18-47e4-a025-419ac9ae5908/image.png" alt=""></p>
<ul>
<li><p>World Transform 에 사용하는 변환 행렬을 세계 행렬(world matrix)이라고 부릅니다. 장면의 모든 물체에는 각자의 world matrix 가 있고, 각 물체를 world transform 하고 나면 모든 물체의 모든 좌표가 동일한 좌표계(세계 공간)를 기준으로 한 것이 됩니다.</p>
</li>
<li><p>변환 행렬은 어떻게 정의되는지 한번 살펴봅시다.</p>
</li>
<li><p>공간을 나타내는 벡터에 행렬을 곱한다는 것은 벡터를 변환하는 것입니다. 즉, 행렬이 곧 변환을 해주는 매개체라고 할 수 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a96b391c-d37f-49f2-874b-bb74894f690c/image.png" alt=""></p>
<ul>
<li>행렬에서 (1, 1) (2, 2) (3, 3) 위치의 값들은 크기를 나타냅니다. 각각의 값들을 조정하고 물체를 나타내는 정점 벡터들과 곱하면 물체가 x축, y축, z 축으로 크기가 늘거나 줄어듭니다. 이 행렬을 Scale(S) 이라고 합시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/60c17c29-05a0-438c-8440-67745520d49c/image.png" alt=""></p>
<ul>
<li>그리고 각 축마다 회전도 표현이 가능합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7939e335-8d7f-43c8-b02a-9e9f6cbf801a/image.png" alt=""></p>
<ul>
<li><p>여기서 세타 값을 정해준 뒤 물체 정점 벡터들과 곱하면 물체가 세타 값만큼 x, y, z 축으로 회전합니다.</p>
<blockquote>
<ul>
<li>x, y, z 축 모두 회전하고 싶다면 각각의 세타 값을 지정한 후 위 3개의 행렬을 차례대로 곱해주면 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>x축 회전 행렬 * y축 회전 행렬 * z 축 회전 행렬의 값을 Rotate(R) 이라고 합시다.</p>
</li>
<li><p>이제 크기와 회전을 변환하였으니 이동을 변환할 차례입니다. 하지만 벡터는 이동에 대해 불변한 특성을 갖고 있기 때문에 3x3 행렬은 평행이동을 표현할 수 없습니다. 이동은 오직 점에만 적용되기 때문에 우리는 동차 좌표계를 사용하여 점과 벡터를 동일한 방식으로 다룰 수 있게 해야 합니다.</p>
</li>
<li><p>동차 좌표계는 x, y, z에서 w 를 추가한 것입니다. 4차원 벡터 (x, y, z, w)가 있다면 이는
x1 = x/w, y1 = y/w, z1 = z/w 인 (x1, y1, z1)과 동차입니다.</p>
<blockquote>
<ul>
<li>즉, 4차원 벡터의 x, y, z 를 w 로 나누는 작업은 4차원 벡터를 3차원 벡터로 투영(Projection)하는 것입니다. 이는 w가 1인 경우 3차원 벡터로 직접 대응됩니다. 4차원 벡터의 w값을 0으로 설정하는 경우에는 이동 변환이 적용되지 않습니다.</li>
</ul>
</blockquote>
</li>
<li><p>동차 좌표계를 사용하여 평행이동을 표현하기 위한 행렬은 다음과 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/49b44be0-ed59-435f-b057-cc286805fa5e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a8834391-13cb-4abf-a333-724507572dab/image.png" alt=""></p>
<ul>
<li><p>이와 같은 평행이동 행렬을 Transform(T)이라고 합시다.</p>
</li>
<li><p>이제 모든 변환들을 살펴봤으니 종합해주면 됩니다. 크기, 회전, 이동 순으로 변환 행렬을 곱한 값을 물체의 정점 벡터와 곱해주면 물체를 올바르게 world space 상에 놓을 수 있게 됩니다.</p>
<blockquote>
<ul>
<li>즉, 월드 변환 행렬(world transform matrix)을 W 라고 했을 때 <code>W = SRT</code> 입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/05ae7ee4-0818-44d0-85dd-05aa9cb0970c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6528edbc-227a-4c56-a28a-f5811b8326ad/image.png" alt=""></p>
<h2 id="view-transform">View Transform</h2>
<ul>
<li>3차원 장면의 2차원 이미지를 만들어 내려면 장면에 가상의 카메라를 배치해야 합니다. 그 카메라는 world 에서 보이는 영역을 결정합니다. 그 영역이 바로 프로그램에서 2차원 이미지로 만들어 모니터에 표시할 영역입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/86e59d0e-5dae-4c81-8189-1bc4eaa2f7ff/image.png" alt=""></p>
<ul>
<li><p>위 그림처럼 가상 카메라를 중심으로 <code>Camera space</code> 를 부여한다고 합시다. 이 좌표계는 카메라 공간 또는 시야 공간(view space)을 정의합니다.</p>
</li>
<li><p>Camera 의 Pose 는 EYE, AT, UP 을 가집니다.</p>
<blockquote>
<ul>
<li>EYE : 카메라 위치</li>
<li>AT : 카메라가 향하는 방향</li>
<li>UP : 카메라가 가리키는 위치의 up 벡터 (카메라의 위아래로 꺾이는 정도)</li>
</ul>
</blockquote>
</li>
<li><p>이 카메라를 중심으로 {u, v, n} 벡터를 만들 수 있고, 이 세 기저는 직교 기저입니다.</p>
<blockquote>
<ul>
<li>n벡터 : EYE-AT 벡터의 정규화</li>
<li>u벡터 : UP벡터와 n의 외적의 정규화</li>
<li>v벡터 : n x u</li>
</ul>
</blockquote>
</li>
<li><p>이 벡터는 Camera Space의 축이 됩니다.</p>
</li>
</ul>
<p>하지만 World Space 와 Camera Space 의 공간 축의 좌표가 다릅니다. Camera Space 의 세 축 벡터도 하나의 도형이라고 생각하고, 이를 World Space 에 겹치도록 변환해줄 수 있습니다.</p>
<blockquote>
<ul>
<li>이를 위해서는 <code>Translation</code> 과 <code>Rotation</code> 의 과정이 필요합니다.</li>
</ul>
</blockquote>
<h3 id="translation">Translation</h3>
<ul>
<li>평행 이동은 덧셈으로 나타낼 수 있습니다. 따라서 Homogeneous Coordinate 를 도입해서 행렬의 곱셈으로 바꿔줄 수 있기 때문에 4x4 matrix을 가지게 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/374cfd10-47b0-4cc8-8b37-a249bc905526/image.png" alt=""></p>
<ul>
<li>이를 활용하여 EYEx, EYEy, EYEz 의 좌표를 넣어서 Translation 시킨 좌표의 값을 얻을 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/12d4c83b-da11-43d0-91cb-a9c655bb2d49/image.png" alt=""></p>
<ul>
<li>(18,8,0) 의 위치를 가지는 camera space 의 EYE 위치로 world space 에서 원점을 이동시키기 위해, 물체 기준에서 EYE 만큼 평행 이동시켜줍니다. 이를 위해 음수 부호를 붙여서 Translation Matrix T 를 만들고, World Space 에서의 좌표와 곱하여 Camera Space 에서 쓰이는 좌표 값을 얻을 수 있습니다.<blockquote>
<ul>
<li>이렇게 하면 EYE 좌표가 원점을 기준으로 translation 된 값을 얻을 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p>하지만 위의 그림과 같이 평행이동만 해서는 축이 일치하지 않습니다.</p>
<blockquote>
<ul>
<li>따라서 <code>Rotation</code> 도 해야합니다.</li>
</ul>
</blockquote>
<h3 id="rotation">Rotation</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/45c7c67c-c7f2-4634-908f-fe5fec7de22e/image.png" alt=""></p>
<ul>
<li><code>회전 변환을 기저의 관점에서 보면</code> 얼마의 각도로 회전하는지 회전 행렬 R 을 구해서 좌표와 곱셈을 해주지 않아도 기저의 전치행렬로 회전 행렬 R 을 구할 수 있습니다.</li>
</ul>
<h4 id="rotation-and-object-space-basis">Rotation and Object-space Basis</h4>
<ul>
<li>앞서 언급한 것처럼, 회전 변환을 Basis(기저)의 관점에서 볼 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4755cfcd-1d38-4c85-882e-df38e7a9b9fd/image.png" alt=""></p>
<ul>
<li><p>{e1, e2, e3} : 월드 좌표계에 나타나는 standard basis 입니다.</p>
<blockquote>
<ul>
<li>기저 벡터끼리 서로 수직이고, 크기는 1인 벡터입니다.</li>
</ul>
</blockquote>
</li>
<li><p>{u, v, n} : 오브젝트 좌표계에서 나타나는 orthonormal basis 입니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/91b6fa90-8bfa-497e-bed1-917aff3bc14a/image.png" alt=""></p>
<ul>
<li><p>수학적인 관점에서 보면, 처음 {e1, e2, e3} == {u, v, n} 인 좌표계에서 한 오브젝트를 &#39;회전&#39;시킨다는 것은, 월드 좌표계인 {e1, e2, e3} 값은 변함이 없고, 오브젝트 좌표계가 가지는 {u, v, n} 기저들이 이동한 것이라고 생각할 수 있습니다.</p>
</li>
<li><p>회전 변환 행렬 R 에 {e1, e2, e3} (단위 행렬)을 곱한 값은 오브젝트가 회전을 나타낸 행렬인 {u v n} 행렬로 나타낼 수 있습니다.</p>
<blockquote>
<ul>
<li>즉, 회전하는 값에 대한 기저를 알면 R 변환 행렬을 구할 수 있습니다. 따라서 θ값을 알지 못해도 R matrix 를 구할 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/809e6efb-c96f-41fd-903b-dce2daf99252/image.png" alt=""></p>
<ul>
<li>따라서 카메라 Space 의 회전 행렬 R 도 같은 방법으로 구할 수 있습니다.</li>
</ul>
<h3 id="view-transformation">View Transformation</h3>
<ul>
<li><code>Translation</code> 과 <code>Rotation</code> 과정을 합친 변환입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ec6577dd-1139-4cb5-a6bb-3b9bf1e0350c/image.png" alt=""></p>
<ul>
<li>다음과 같이 View Transform Matrix 를 세울 수 있습니다.<blockquote>
<ul>
<li>World Transform 은 Object 별로 정의할 수 있습니다. 따라서 View Transform 은 World 별로 정의할 수 있는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="projection-transform">Projection Transform</h2>
<ul>
<li>Camera Space 상에 배치된 오브젝트들(3D)을 우리가 모니터로 보는 2D 화면 창 하나에 투영시켜서 볼 수 있도록 <code>Projection Transform</code> 을 수행해야 합니다.</li>
</ul>
<h3 id="view-frustum">View Frustum</h3>
<ul>
<li><p>카메라 상의 모든 물체를 화면에 담을 수 없기 때문에, 카메라의 시야각 범위 안에 있는 오브젝트만 투영시키도록 합니다.</p>
</li>
<li><p>view frustum : 화면의 visible 한 영역만 나타내는 절두체를 <code>view frustum</code> 이라고 합니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9d47c533-19b2-4215-b3f8-4b6acf961d82/image.png" alt=""></p>
<ul>
<li>fovy (field of view y-axis) : 시야각, y-z 축으로 두었을 때 카메라로부터 물체를 바라볼 때 생기는 각도</li>
<li>n &amp; f : near &amp; far</li>
<li>aspect :  w(넓이) / h(높이) 로, view frustum의 종횡비</li>
</ul>
<h3 id="culling-and-clipping">Culling and Clipping</h3>
<ul>
<li>Vertex 연산을 줄이기 위해 연산이 필요없는 부분은 <code>culling</code> 시켜줍니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/55aa7e63-8c64-435e-b095-cb3a136279ee/image.png" alt=""></p>
<h4 id="culling">Culling</h4>
<ul>
<li>GPU rendering pipeline 이전에 view frustum 바깥쪽에 있는 오브젝트를 버려서 렌더링 하지 않도록 합니다.</li>
</ul>
<h4 id="clipping">Clipping</h4>
<ul>
<li>view frustum 내부에 오브젝트 전체가 들어있는 것이 아니라 경계에 걸친 경우입니다. 이 때, frustum 내부에 있는 오브젝트만 처리해줍니다.<blockquote>
<ul>
<li>이 과정은 <code>rasterization stage</code> 에서 진행합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="clip-space">Clip Space</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/256f8a65-2ce2-40b9-a287-b427d6473727/image.png" alt=""></p>
<ul>
<li>Clipping 은 피라미드형이 아닌, 정육면체 공간에서 처리합니다.</li>
<li>view frustum 을 2x2x2 정육면체로 옮겨 clip space 로 변환하는 과정을 <code>Projection Transform</code> 이라고 합니다.</li>
</ul>
<h3 id="lighting">Lighting</h3>
<ul>
<li><p>광선으로 밝게 비춤 또는 그 광선을 나타냅니다.</p>
</li>
<li><p>3D 공간에는 빛이 없지만 현실 세계의 빛을 3요소로 만들어 흉내냅니다.</p>
<blockquote>
<ul>
<li>조명의 요소에는 정반사광(Specular), 난반사광(Diffuse), 환경광(Ambient) 등이 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bd67dfe6-ae66-4ec8-90f7-a29efc7b8e28/image.png" alt=""></p>
<ul>
<li>3가지 광원으로  방향성 광원(Directional Light), 점 광원(Point Light), 스포트 광원(Spot Light)이 있습니다.</li>
</ul>
<h2 id="다시-projection-transform">다시, Projection Transform</h2>
<h3 id="view-frustum-to-cube">View Frustum to Cube</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4e3ed1c9-8361-44b6-b021-5cf0643453c4/image.png" alt=""></p>
<ul>
<li>camera(EYE) 위치에서 projection plane 에 대해 바라봤을 때, view frustum을 cube 로 옮겨줍니다. 원근법에 의해 L1 과 L2 의 길이는 cube 에서 같아집니다.</li>
</ul>
<h3 id="derivation-of-projection-transform-matrix">Derivation of projection transform matrix</h3>
<ul>
<li>View frustum 을 cube 로 옮길 때 projection transform 에 필요한 행렬과 수식을 이해해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/aa6f604b-7882-49d4-b2f3-54dc12b4eea4/image.png" alt=""></p>
<ul>
<li>y-z 좌표계 상에서 두 삼각형에 대해 닮음 법칙을 적용해서 y&#39;, x&#39; 의 값을 구할 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a5813f20-73e8-4390-8889-9c8b83ebe854/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/efaf3343-ac25-4b89-8ba8-7649e0ffbca4/image.png" alt=""></p>
<ul>
<li>수식에 의해 transformed 된 지점의 좌표를 구할 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4ca4dd85-b367-49e4-ad89-d0ebe71ee1f1/image.png" alt=""></p>
<ul>
<li>우리가 이미 알고 있는 상수값인 −f 값과 −n 값을 -1, 1에 매핑해서 연립방정식을 세우고 해를 구할 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6cbdbab2-6d27-4e03-bb06-389e7efa2c2c/image.png" alt=""></p>
<ul>
<li>따라서 Projection Matrix 를 구할 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8de89a62-86ec-432d-b16d-9bdf27bfda8a/image.png" alt=""></p>
<h2 id="다시-projection-transform-1">다시, Projection Transform</h2>
<ul>
<li>위에서 구한 Projection Matrix 를 이용해 view Frustum -&gt; Cubic view volume 으로의 Projeciton Transform 이 이루어지는 것입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/892df40a-a2bd-41ff-af77-b0e339a26f0e/image.png" alt=""></p>
<ul>
<li>각 좌표에 M(proj)를 곱해 새로운 좌표를 얻을 수 있습니다.</li>
</ul>
<h1 id="tessellation-stages">Tessellation Stages</h1>
<ul>
<li>Tessellation 은 주어진 메시의 삼각형들을 더 잘게 쪼개서 새로운 삼각형들을 만드는 과정을 말합니다. 새 삼각형들을 새로운 위치로 이동함으로써 원래 메시에 없는 세부적인 특징을 만들어 낼 수 있습니다.</li>
</ul>
<p><img src="blob:https://velog.io/3aedf058-8a07-4af5-a456-dc52de20d3e8" alt=""></p>
<ul>
<li><p>Tessellation 은 여러 장점이 있습니다.</p>
<blockquote>
<ul>
<li>카메라에 가까운 삼각형들에는 테셀레이션을 적용해서 세부도를 높이고, 먼 삼각형들에는 Tessellation 을 적용하지 않는 방식의 세부 수준(<code>Level-Of-Detail</code>, <code>LOD</code>)을 구현할 수 있습니다. LOD 를 구현하면 관찰자가 실제로 볼 수 있는 부분에만 많은 삼각형을 사용하게 되므로 효율적입니다.</li>
<li>적은 수의 삼각형들로 이루어진 메시를 메모리에 담아두고 즉석으로 삼각형을 추가하여 메모리를 절약할 수 있습니다.</li>
<li>애니메이션이나 물리 처리 같은 연산들을 단순한 다각형 메시에 대해 수행하고, Tessellation 된 다각형 메시는 렌더링에만 사용함으로써 계산량을 줄일 수 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>Tessellation 단계들은 꼭 필요한 단계가 아니기 때문에 생략이 가능합니다. 이제, 각 단계들을 살펴봅시다.</p>
</li>
</ul>
<h2 id="hull-shader-hs-stage">Hull Shader (HS) Stage</h2>
<ul>
<li>Primitive 의 어디에 혹은 어떻게 Vertex 를 추가할지를 결정합니다. 그 후, 결정된 정보를 <code>Tessellator stage</code> 와 <code>Domain shader stage</code> 에 전달합니다.</li>
</ul>
<h2 id="tessellator-ts-stage">Tessellator (TS) Stage</h2>
<ul>
<li>Hull Shader 로부터 전달받은 정보를 바탕으로 실제로 primitive 를 나누는 작업을 수행하고, output 을 Domain shader 에 전달합니다.</li>
</ul>
<h2 id="domain-shader-ds-stage">Domain Shader (DS) Stage</h2>
<ul>
<li>Hull Shader 로부터 전달받은 vertex 의 position 정보와 Tessellator 에서 만든 vertex 를 바탕으로 vertex 에 대한 transform 을 수행합니다.</li>
</ul>
<h1 id="geometry-shader-gs-stage">Geometry Shader (GS) Stage</h1>
<ul>
<li><p>Geometry Shader 단계는 선택적인 단계이기 때문에 생략이 가능합니다. 이는 하나의 기본 도형을 입력받아 그것을 임의로 변형합니다.</p>
<blockquote>
<ul>
<li>예를 들어 삼각형 목록을 그리는 경우 기하 셰이더에는 삼각형을 정의하는 (Vertex Shader 단계를 거친) 정점 세 개가 입력됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>Geometry Shader 의 주된 장점은 기하 구조를 GPU 에서 생성하거나 파괴할 수 있다는 것입니다.</p>
<blockquote>
<ul>
<li>예를 들어 입력 기하 구조를 여러 개의 기하 구조로 확장할 수도 있고, 조건에 따라 삭제할 수도 있습니다.</li>
<li>기하 셰이더의 흔한 용도는 점이나 선분을 사각형으로 확장하는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>또한 기하 셰이더의 출력은 바로 <code>Rasterizer stage</code> 에 넘겨줄 수도 있지만, 스트림 출력 단계를 통해 메모리의 버퍼에 저장해 두고 나중에 활용하는 것이 가능합니다.</p>
<blockquote>
<ul>
<li>이는 고급 기법입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="stream-output-so-stage">Stream Output (SO) Stage</h1>
<ul>
<li><p>Vertex 데이터를 얻기 위한 단계입니다.</p>
<blockquote>
<ul>
<li>일반적으로 Geometry Shader 단계에서 수행되지만, Geometry Shader 가 없는 경우에는 Vertex Shader 단계에서 수행됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>Stream Output 은 Vertex 데이터를 얻어서 메모리에 전달하고, 전달된 데이터는 Vertex buffer에 저장됩니다.</p>
</li>
<li><p>Triangle list, line list 등의 리스트 형태로 Vertex 데이터를 보내고, incomplete primitive 는 보내지지 않고 삭제됩니다.</p>
<blockquote>
<ul>
<li>incomplete primitive : two vertex triangle, one vertex line 등</li>
</ul>
</blockquote>
</li>
<li><p>Particle Effect 를 생성하거나 제거하는데 유용하게 활용됩니다.</p>
</li>
</ul>
<h1 id="rasterizer-stage-rs">Rasterizer Stage (RS)</h1>
<h2 id="preprocessing">Preprocessing</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c7f28af1-ef42-4e12-a129-f52ed638020a/image.png" alt=""></p>
<ul>
<li>Rasterzer Stage 는 Vertex Shader 에서 얻은 vertex 의 wire 형태를 Pixel Shader 에서 색상을 입히기 전에 각 pixel(Fragments)을 생성시키는 역할을 합니다.</li>
</ul>
<h3 id="clipping-1">Clipping</h3>
<ul>
<li>앞서 Projection Transform 에서 Clipping 에 대해 잠깐 언급했었습니다.<blockquote>
<ul>
<li>View frustum 절두체의 경계에 있을 때 clipping 하는 것에 대한 내부 처리를 Rasterizer Stage 에서 적용할 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1cf6c33f-e037-43a7-9dd9-4f0c8fa62880/image.png" alt=""></p>
<h3 id="perspective-division">Perspective Division</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f5a0956b-afa4-45ea-9871-015fb51ececb/image.png" alt=""></p>
<ul>
<li>M(proj)에서 w 좌표가 1이 아닌 −z 가 나오는 것을 볼 수 있습니다. 이 경우 각 항을 −z 로 나눠서 1로 바꿔줍니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ae4955c4-c8eb-4cc5-884f-c778ddae0f87/image.png" alt=""></p>
<ul>
<li>이를 나눠주어 w 좌표가 1이 된 결과의 좌표를 NDC(Normalized Device Coordinates) 라고 합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/40e676c4-0e93-4419-96b1-bc52b3fe109c/image.png" alt=""></p>
<ul>
<li>Perspective Division 을 하는 이유는 다음과 같습니다.<blockquote>
<ul>
<li>w 좌표는 동차 좌표로 이 값을 1로 두면, 다른 xyz 값에 대해서도 제대로 길이를 맞춰줄 수 있습니다.</li>
<li>Perspective Division 을 통해 제대로 원근법이 적용되는 것을 확인할 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="viewport-transformation">Viewport Transformation</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/fb1c7341-2a7d-4d58-a7ac-6742638ec136/image.png" alt=""></p>
<ul>
<li>Clip NDC Space 의 cube(Perspective division 이 이루어진 상태)를 우리의 모니터 상에서의 창으로 옮겨줘야 합니다.<blockquote>
<ul>
<li>이때 viewport 를 이용합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4142c26c-f5fa-4ddd-975f-34c7fff2962d/image.png" alt=""></p>
<ul>
<li>각각 Scaling, Translation 변환 행렬을 구할 수 있습니다. 또한 두 행렬을 Affine 행렬으로 합쳐서 정의할 수 있습니다.</li>
</ul>
<p><img src="blob:https://velog.io/bb91b38f-d90e-4179-b218-df2dbbc02778" alt=""></p>
<h3 id="face-culling">Face Culling</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bda4429b-e015-4a60-b9a9-e56f52b04d70/image.png" alt=""></p>
<ul>
<li>카메라가 관측하지 않는 공간(Back face)에 대해 연산을 하지 않는 것을 의미합니다.<blockquote>
<ul>
<li>하나의 삼각형에 대해 3개의 vertex 와 이를 채우는 fragment 들은 100개가 넘습니다. 이런 무거운 연산을 줄이기 위한 방법입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a4e0161e-6818-4e67-8247-efb3875a2b22/image.png" alt=""></p>
<ul>
<li><p>Face 가 BackFace 인지, FrontFace 인지는 winding 의 방향을 알면 알 수 있습니다.</p>
</li>
<li><p>행렬식의 부호를 알면, 일일이 face 의 winding 을 알지 않아도 해당 face가 CW, CCW 인지 알 수 있습니다.</p>
</li>
<li><p>back face culling 이 항상 이뤄지는 것은 아닙니다.</p>
<blockquote>
<ul>
<li>global illumination 등 보이지 않는 간접적인 영역에 대해 계산이 필요한 경우에는 back face 도 연산을 해주어야 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="processing">Processing</h2>
<ul>
<li>본격적으로 픽셀을 채우는 단계입니다.</li>
</ul>
<h3 id="edge-equation">Edge Equation</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bb03018c-8ea0-4a33-9e99-05264d043102/image.png" alt=""></p>
<ul>
<li>Edge Equation 은 직선이 주어졌을 때 pixel 이 어느 편에 존재하는지 적용시킬 수 있습니다.<blockquote>
<ul>
<li>right : positive number</li>
<li>left : negative number</li>
<li>on the line : zero number</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c98467bf-9e43-4526-937c-adf5ca4c61ad/image.png" alt=""></p>
<ul>
<li>즉, Egde Equation 으로 pixel 이 삼각형 내부에 있는지, 아닌지 판별할 수 있습니다.<blockquote>
<ul>
<li>해당 삼각형의 내부의 픽셀 p 의 경우 모든 직선의 오른쪽에 존재하기 때문에 해당 pixel 은 삼각형 내부에 존재하는 픽셀입니다.</li>
<li>이 경우, edge funtion 은 3개의 edge 에 대해 positive number 을 return 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="definition-of-edge-equation">Definition of Edge Equation</h3>
<ul>
<li><p>그렇다면 Edge Equation 식의 정의는 무엇이고, 어떻게 부호에 따라 pixel 의 위치관계를 결정할 수 있는지 알아보도록 합시다.</p>
</li>
<li><p>우선 벡터 v0p 와 v0v1 의 외적을 구해봅시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a31facd7-d819-49c9-a9f9-eae0edfa9c03/image.png" alt=""></p>
<ul>
<li>외적으로 새로 생기는 벡터의 부호에 따라 pixelpoint 의 위치 관계를 알 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/14a83d24-ecd9-478a-a402-f38b8bfdd857/image.png" alt=""></p>
<ul>
<li><p>위의 그림과 같이 A 벡터의 위치가 각각 다를때,</p>
<blockquote>
<ul>
<li>외적의 부호가 양수이면, pixel 은 오른편에 존재합니다.</li>
<li>외적의 부호가 음수이면, pixel 은 왼쪽에 존재합니다.</li>
<li>외적의 부호가 0이면, pixel 은 동일한 선상에 존재합니다.</li>
</ul>
</blockquote>
</li>
<li><p>이를 기하하적 의미로도 해석할 수 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5ffbcb5a-ff2f-4df9-ba06-ff98d1907dac/image.png" alt=""></p>
<h3 id="assigning-atrributes-for-fragments">Assigning Atrributes for Fragments</h3>
<ul>
<li><p>Vertex Shader 에서는 Vertex 의 position, RGB, Normal 등의 값을 cpu 에서 gpu 로 넘겨주었습니다.</p>
</li>
<li><p>하지만, fragment 에 대해서는 따로 전달해주는 것이 없기 때문에 이를 할당해주어야 합니다.</p>
<blockquote>
<ul>
<li>즉, 이미 가지고 있는 정보들을 가지고 결정할 수 있도록 하는 단계가 필요합니다.</li>
<li>이를 <code>Interpolation</code> 이라고 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bb26f007-2444-4ebd-bd0f-fc9c0cd4c95c/image.png" alt=""></p>
<ul>
<li><p>Vertex Shader 에 들어온 vertex Position 과 RGB 색상 정보등을 가지고 fragment 의 position, RGB 에 가중치를 두어서 결정할 수 있습니다.</p>
<blockquote>
<ul>
<li>각 가중치의 총합은 λ0 + λ1 + λ2 = 1 입니다.</li>
</ul>
</blockquote>
</li>
<li><p>삼각형 내부의 pixel p 는 3개의 vertex 에 대해 각 가중치 비율에 따라 RGB 좌표를 곱해서 나타낼 수 있습니다.</p>
<blockquote>
<ul>
<li>P = λ0 ∗ v0 + λ1 ∗ v1 + λ2 ∗ v2 으로 나타낼 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="barycentric-coordinate">Barycentric Coordinate</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/b28ff4fa-99d7-44ec-8fb1-20c673ab710d/image.png" alt=""></p>
<ul>
<li><p>삼각형 내부의 pixel p 의 위치에 따라서 가중치 값을 다르게 가집니다.</p>
</li>
<li><p>각 가중치 좌표 (λ0, λ1, λ2)은 삼각형 (T0, T1, T2)를 마주보며 가중치 값을 가집니다.</p>
</li>
<li><p>삼각형의 면적은 두 벡터를 외적한 크기, 즉 평행사변형의 면적이므로 이를 2로 나눠줍니다.</p>
<blockquote>
<ul>
<li>T0 의 경우 0.5 ∗ E(p, v1, v2) 로부터 삼각형 면적을 구할 수 있습니다.</li>
<li>T1 의 경우 0.5 ∗ E(p, v2, v0) 로부터 삼각형 면적을 구할 수 있습니다.</li>
<li>T2 의 경우 0.5 ∗ E(p, v0, v1) 로부터 삼각형 면적을 구할 수 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>가중치는 총합이 1이므로 전체 넓이 대비 자신의 weight 가 가지는 부분 면적의 비로 나타낼 수 있습니다.</p>
</li>
</ul>
<h3 id="fragments-color-값-계산">Fragments color 값 계산</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f2af49db-2fa8-4fc8-a589-530460fca09d/image.png" alt=""></p>
<ul>
<li>위의 내용을 바탕으로 삼각형 내부의 pixel p 의 위치에 따라서 가중치 값을 다르게 가지는 color 를 결정할 수 있습니다.</li>
</ul>
<h1 id="pixel-shader-ps-stage">Pixel Shader (PS) Stage</h1>
<ul>
<li><p>화면 안에 보일 각 pixel fragment 에 대해 조명, 반사, 그림자 효과 등 더 복잡한 작업을 수행하여 최종 색상을 결정하는 것입니다.</p>
<blockquote>
<ul>
<li>pixel fragment 란 화면 안에 그려질 잠재적인 픽셀을 말합니다.</li>
</ul>
</blockquote>
</li>
<li><p>Rasterizer Stage 에서는 각 픽셀 당 한 번씩 Pixel Shader 를 호출합니다.</p>
<blockquote>
<ul>
<li>Vertex Stage 와 비슷하게 하나의 pixel 을 받아서 하나의 pixel 을 리턴합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="output-merger-om-stage">Output Merger (OM) Stage</h1>
<ul>
<li><p>pixel fragment 와 depth/stencil buffer 를 받아서 실제로 그려질 픽셀을 결정합니다.</p>
<blockquote>
<ul>
<li>설정에 따라 blending 을 적용하기도 합니다.</li>
</ul>
</blockquote>
</li>
<li><p>Pixel Shader 가 생성한 pixel fragment 들은 Output Merger 단계로 입력됩니다.</p>
<blockquote>
<ul>
<li>이 단계에서 일부 pixel fragment 들이 깊이 혹은 stencil 판정에 의해 삭제될 수 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>삭제되지 않은 pixel fragment 들은 Back buffer 에 기록됩니다.</p>
<blockquote>
<ul>
<li>Blending 도 이 단계에서 일어납니다. 이는 새 pixel 이 Back buffer 의 기존 pixel 을 완전히 덮어쓰는 것이 아니라 두 pixel 을 일정한 공식에 따라 섞은 결과를 기록하는 것을 말합니다.</li>
<li>Blending 은 반투명과 같은 특수 효과를 내는 데에 쓰입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="introduction">Introduction</h2>
<ul>
<li>Output merger Stage 에서 pixel 들의 최종 color 를 결정하는데 다음의 과정이 필요합니다.<blockquote>
<ul>
<li>pipeline state</li>
<li>pixel shader stage 에서 return 한 pixel (texturing, lighting) 데이터</li>
<li>render targets</li>
<li>depth/stencil buffers</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="render-target">Render target</h3>
<ul>
<li>최종적으로 그려지는 buffer 가 아닌 임시 메모리 buffer 에 그린 후 최종 GPU 에 넘길 buffer 로 전달해주는 역할을 합니다.</li>
</ul>
<h3 id="back-bufferframe-buffer">Back buffer/Frame buffer</h3>
<ul>
<li><p>Frame Buffer : 최종적으로 그려지는 buffer 중 송출되고 있는 buffer 입니다. RAM 에 저장된 최종 color data 들이 저장되어 있습니다.</p>
</li>
<li><p>최종적으로 그려지는 buffer 중 실제 완성되어 송출되기 전에 미리 뒤에서 그려놓고 업데이트 시켜주는 역할을 하는 버퍼가 Back buffer 입니다.</p>
</li>
</ul>
<h2 id="depth-stencil-testing">Depth-Stencil Testing</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ce045990-f325-4a24-acbc-9b6241564236/image.png" alt=""></p>
<ul>
<li><p>위의 그림을 보면 초록색 삼각형과 파란색 삼각형은 꼬인 위치의 관계를 가져 한쪽은 초록색이 위로, 다른 한쪽은 파란색이 위에 놓여있도록 렌더링됩니다.</p>
<blockquote>
<ul>
<li>pixel shader 에서 받아온 각각의 삼각형에 대해서 누가 더 앞에 있는지 판단해서 그릴 부분과 그리지 않는 부분을 처리하는 것이 Depth-Testing 입니다.</li>
</ul>
</blockquote>
</li>
<li><p>위의 그림과 같이 0과 1로 나타난 데이터에서 1로 된 영역에만 렌더링을 진행합니다.</p>
<blockquote>
<ul>
<li>pixel shader 에서 받아온 오브젝트에 대해 stencil 로 지정된 영역을 통과하는 픽셀만 렌더링해주도록 처리하는 것이 Stencil-Testing 입니다.</li>
</ul>
</blockquote>
</li>
<li><p>Depth, Stencil 모두 Output-Merger 단계에서 픽셀을 그릴 것인지 그리지 않을 것인지 결정하는 것입니다.</p>
</li>
</ul>
<h3 id="depth-test">Depth test</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8cb40555-f38b-4e61-94d1-537670dc82d9/image.png" alt=""></p>
<ul>
<li><p>Pixel shader 에서 받아온 각각의 삼각형에 대해서 누가 더 앞에 있는지 판단하는 버퍼를 depth buffer 라고 부릅니다 (z - buffering).</p>
</li>
<li><p>Output-merger 단계에서 depth 값이 들어오면 viewport 내부로 clamp 됩니다.</p>
</li>
<li><p>z = min(Viewport.MaxDepth, max(Viewport.MinDepth,z))</p>
</li>
<li><p>즉, viewport의 최소 깊이와 z 버퍼의 깊이를 먼저 비교해서 고정을 시키고, viewport의 최대 Depth 값보다는 작도록 z 값을 결정합니다.</p>
</li>
</ul>
<h3 id="depth-test-stage">Depth Test Stage</h3>
<ul>
<li><p>우선 Depth 는 per-sample operation 이 이루어집니다.</p>
</li>
<li><p>어떤 오브젝트가 screen 에 projection 될 때, 생성된 pixel 과 현재의 depth buffer 값의 비교를 통해 생성된 pixel 의 depth 를 결정합니다.</p>
<blockquote>
<ul>
<li>이때, depth 가 더 깊은 픽셀들이 생성된 경우는 draw 하지 않고 작은 경우에는 현재의 버퍼에 새로 생성된 depth 를 버퍼에 update 하는 것입니다.</li>
<li>즉, existing 한 값과의 비교를 통해 결정하는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/efb404b8-86fa-4c5e-b66d-e7106b688c6f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/b2460f75-ca95-4a74-b9d6-94be10761503/image.png" alt=""></p>
<ul>
<li>위의 Depth Test 과정을 예시로 들어 설명할 수 있습니다.</li>
</ul>
<h2 id="다시-depth-stencil-testing">다시, Depth-Stencil Testing</h2>
<h3 id="transition-effect">Transition Effect</h3>
<ul>
<li>한 scene에 두 개의 텍스쳐를 겹쳐서 렌더링할 때, 두 개를 모두 렌더링할 수 도 있지만 이럴 경우 보이지 않게 되는 부분에 대해서도 연산이 필요하기 때문에 비효율적입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8eed6cd6-9991-41e1-9a2d-10e612fbf1f8/image.png" alt=""></p>
<ul>
<li>따라서 stencil test 를 통과한 buffer 값에 대해서만 update 시켜줄 수 있습니다.</li>
</ul>
<h3 id="discarding-ui-area">Discarding UI area</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/46bd03cc-96a7-48cd-9762-cfedb3069c8b/image.png" alt=""></p>
<ul>
<li>UI 의 경우에는 행동이 변하지 않기 때문에 계속 렌더링을 시켜주는 것이 비효율적입니다.<blockquote>
<ul>
<li>따라서 해당 area 의 경우 stencil 로 update 할 영역에서 UI 를 빼서 통과하지 못하게 만들어 update 시켜주지 않습니다. 그렇게 되면 UI 를 제외한 나머지 영역만 통과되어 update 하게 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="color-blending">Color Blending</h2>
<ul>
<li><p>지금까지 Depth-Stencil 로 겹치는 부분에 대해서 무엇을 앞에 그릴 지를 결정해주었습니다. 하지만 오브젝트의 투명도를 고려해줄 때 문제가 발생할 수 있습니다.</p>
<blockquote>
<ul>
<li>따라서 Color Blending 을 통해 최종 pixel color 를 혼합해서 결정해줍니다.</li>
</ul>
</blockquote>
</li>
<li><p>color blending 이 이루어지는 시기는 render target 에 들어가기 전에 결정됩니다.</p>
</li>
<li><p>Output Merger 단계에서 render target 을 이용하여 최종 buffer 로 전달하였는데, color blending 에서 어떤 색깔을 blending 할지에 대한 값은 render targe 에 들어가기 전에 결정된다는 것입니다.</p>
<blockquote>
<ul>
<li>즉, 최종 buffer 에 기록되는 것이 아니라 render target 에 기록됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="blending-equation">Blending Equation</h3>
<ul>
<li><p>c = αc(f) + (1−α)c(p)</p>
<blockquote>
<ul>
<li>c : blending color, 최종 color</li>
<li>α : pixel&#39;s opacity</li>
<li>c(f) : fragment color, 새로 쓰여진 값 (αcf)</li>
<li>c(p) : pixel color, 기존 (1−α)c(p)</li>
</ul>
</blockquote>
</li>
<li><p>opacity는 0~255의 값을 가지는데, 0인 경우 <code>fully transparent</code>하고, 255인 경우 <code>fully opaque</code> 합니다.</p>
</li>
<li><p>[0,255]를 정규화시켜 [0,1] 로 나타낼 수 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4dbec05d-b7b7-41d2-b4d3-f94632c886c8/image.png" alt=""></p>
<ul>
<li>primitive 는 먼저 불투명한 primitive 를 렌더링한 다음에, back-to-front 순서로 transparent 한 primitive 를 고려합니다.<blockquote>
<ul>
<li>따라서 반투명한 오브젝트에 대해 순서를 정해주어야 합니다.</li>
</ul>
</blockquote>
</li>
<li>위의 그림과 같이 먼저 α 값이 1인 빨간색 삼각형, 즉 불투명한 primitive 에 대해 먼저 pixel 을 채웁니다. 그 다음에 α 값이 0.5인 파란색 삼각형을 그 위에 blending color 를 연산해서 채워줍니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/83188b7f-0060-4ff5-9eb0-20f39cfac0f1/image.png" alt=""></p>
<ul>
<li>순서에 따라 다른 blending color 값을 가지는 것을 알 수 있습니다.</li>
</ul>
<blockquote>
<ol>
<li>Transparent Or Opaque</li>
</ol>
</blockquote>
<ul>
<li>가장 우선 순위는 Opaque 한 primitive 입니다. 이를 먼저 렌더링해줘야 합니다.</li>
</ul>
<ol start="2">
<li>Depth - Z 값</li>
</ol>
<ul>
<li>현재 Z 값이 0.8인 빨간색 삼각형이 Z 값이 0.5인 파란색 삼각형 보다 더 먼저 렌더링됩니다.</li>
</ul>
<ol start="3">
<li>Blending - α 값</li>
</ol>
<ul>
<li>blending 을 해줄 때에는 Back 순서의 빨간색 삼각형에서 Front 순서의 파란색 삼각형 순서로 Blending Equation 을 풀어 blending color 값을 얻게 됩니다.<blockquote>
<blockquote>
<ul>
<li>(1,0,0)의 값에 (1-α) = 0.1 를 곱해주어, 0.1 ∗ (1,0,0) 으로 color 값을 얻고 여기에 위에 생기는 (0,0,1) ∗ 0.9에 더해주면 최종 컬러가 나옵니다.</li>
</ul>
</blockquote>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e47cbf8b-9240-44bf-abaf-cb5354606dfb/image.png" alt=""></p>
<h1 id="reference">Reference</h1>
<ul>
<li><a href="https://www.braynzarsoft.net/viewtutorial/q16390-03-initializing-directx-12">Initializing DirectX 12</a></li>
<li><a href="https://showmiso.tistory.com/38">[3D] 그래픽스 파이프 라인</a></li>
<li><a href="https://lipcoder.tistory.com/119">렌더링 파이프라인</a></li>
<li><a href="https://novemberfirst.tistory.com/27">렌더링 파이프 라인? (Rendering Pipeline)</a></li>
<li><a href="https://learn.microsoft.com/ko-kr/windows/win32/direct3d11/direct3d-11-advanced-stages-tessellation#hull-shader-stage">Tessellation phase</a></li>
<li><a href="https://m.blog.naver.com/jyh0841/220465959342">파이프라인 (Pipeline)</a></li>
<li><a href="https://m.blog.naver.com/jsjhahi/206651669">DirectX 그래픽스 파이프라인 순서 및 기본 설명과 기본 지식</a></li>
<li><a href="https://gamedevlog.tistory.com/95">렌더링 파이프라인(rendering pipeline)</a></li>
<li><a href="https://mkblog.co.kr/gpu-graphics-pipeline/">[GPU] 그래픽스 파이프라인 (Graphics Pipeline)</a></li>
<li><a href="https://parodev.tistory.com/30">3D 그래픽스 - 그래픽스 파이프라인이란? (Graphics Pipeline)</a></li>
<li><a href="https://ihatelinux.tistory.com/50#:~:text=DirectX%2012%20Graphics%20Pipeline%20DirectX%2012%EC%9D%98%20%EA%B7%B8%EB%9E%98%ED%94%BD%20%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8%EC%9D%80,APIs%EC%9D%98%20%ED%95%A8%EC%88%98%EB%93%A4%EC%9D%84%20%ED%86%B5%ED%95%B4%EC%84%9C%EB%A7%8C%20%EA%B5%AC%EC%84%B1%20%5BConfigure%5D%ED%95%A0%20%EC%88%98%20%EC%9E%88%EB%8B%A4%EB%8A%94%20%EB%9C%BB%EC%9E%85%EB%8B%88%EB%8B%A4.">[DirectX 12] - Graphics Pipeline - 1</a></li>
<li><a href="https://velog.io/@mmindoong/GG2022-Vertex-Processing-%EC%9D%B4%EB%A1%A0">[GG2022] Vertex Processing 이론</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Unity] Alt F4 장르 게임 만들기 (2)]]></title>
            <link>https://velog.io/@hkun_ho/Unity-Alt-F4-%EC%9E%A5%EB%A5%B4-%EA%B2%8C%EC%9E%84-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</link>
            <guid>https://velog.io/@hkun_ho/Unity-Alt-F4-%EC%9E%A5%EB%A5%B4-%EA%B2%8C%EC%9E%84-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</guid>
            <pubDate>Mon, 30 Jan 2023 17:45:18 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<ul>
<li><p>이번에는 저번에 작성해둔 스크립트를 활용한 기능이 많습니다. 따라서 <code>클리어 방법</code> 위주로 포스팅하겠습니다.</p>
</li>
<li><p>제가 맡은 부분은 <code>Hellroom Scene</code> 입니다.</p>
<blockquote>
<ul>
<li>난이도가 지옥이라 그렇습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="start-point">Start Point</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1101d836-b580-4770-bf70-0feaeaec33ff/image.png" alt=""></p>
<h2 id="right">Right</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f78bed30-9bb5-4b14-8c51-b7448eee124d/image.gif" alt=""></p>
<ul>
<li>오른쪽에 클리어 포탈이 보입니다. 바로 가면 정말 좋겠지만 연필 때문에 갈 수 없습니다.</li>
</ul>
<h2 id="left---wall">Left - Wall</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/955cc565-87cf-4c30-a58f-d84e736e39e3/image.gif" alt=""></p>
<ul>
<li>왼쪽으로 이동하려면 벽 바깥쪽으로 점프했다가 다시 안쪽으로 들어와야 합니다. 이렇게 벽이 안 보일 때까지 이동합니다.</li>
</ul>
<h1 id="jump--land">Jump &amp; Land</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ff29d304-9feb-4161-bc20-9d3c8e6309e1/image.gif" alt=""></p>
<ul>
<li>낙하 지점 근처에 투명 트리거가 존재합니다. 이를 타고 날아올라 발판(Fall Board)에 착지해야 합니다. </li>
</ul>
<h1 id="rotater">Rotater</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/36dda3a5-4d31-48f2-b696-ce8cde717c1d/image.gif" alt=""></p>
<ul>
<li>돌아가는 Rotater 에 타이밍을 맞춰 착지해야 합니다. 발판(Fall Board)에 머물 수 있는 시간이 제한적이기 때문에 이전 단계인 Jump &amp; Land 부터 Rotater 를 고려해야 합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ef7aacec-381e-45f8-9f62-3854e4775d19/image.gif" alt=""></p>
<ul>
<li>그리고 돌아가는 타이밍에 맞춰 앞으로 걸어간 뒤 발판(Fall Board)으로 점프합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/fb9599c9-b292-42c5-8060-ccc80791c2f5/image.gif" alt=""></p>
<ul>
<li>발판(Fall Board) 착지 후 또 타이밍에 맞게 Rotater 진입합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c209574e-e82d-4112-b66f-3e1edc733ab3/image.gif" alt=""></p>
<ul>
<li>이전과 동일하게 타이밍에 맞춰 앞으로 걸어간 뒤 발판(Fall Board)으로 점프합니다.</li>
</ul>
<h1 id="fall-board">Fall Board</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5a0f268e-b071-46a6-a762-43f321b5c32d/image.gif" alt=""></p>
<ul>
<li>일정 시간이 지나면 떨어지는 발판입니다.</li>
</ul>
<h1 id="trampoline--gate">Trampoline &amp; Gate</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/770939a5-00cb-457c-b7b3-fdabb97ac921/image.gif" alt=""></p>
<ul>
<li>Gate 가 열리고 닫히는 타이밍에 맞춰 Trampoline 에서 점프해야 합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Unity] Alt F4 장르 게임 만들기 (1)]]></title>
            <link>https://velog.io/@hkun_ho/Unity-Alt-F4-%EC%9E%A5%EB%A5%B4-%EA%B2%8C%EC%9E%84-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</link>
            <guid>https://velog.io/@hkun_ho/Unity-Alt-F4-%EC%9E%A5%EB%A5%B4-%EA%B2%8C%EC%9E%84-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</guid>
            <pubDate>Sun, 22 Jan 2023 17:42:19 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<ul>
<li><p>팀원들과 함께 제작중이며 제가 맡은 부분에 대한 내용만 <code>기능</code> 위주로 포스팅하겠습니다.</p>
</li>
<li><p>이번에 제가 맡은 부분은 <code>BathRoom Scene</code> 입니다.</p>
</li>
</ul>
<h1 id="hand-dryer">Hand Dryer</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7b731019-3d36-4530-8530-df5d0436c044/image.png" alt=""></p>
<ul>
<li>바람이 나오는 위치에 Trigger 를 배치하여 이와 접촉했을 시 바람을 타고 위로 뜨는 듯한 느낌을 받게 하였습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f35bc22d-8220-4bf9-b4fe-bc4cc74c61fa/image.gif" alt=""></p>
<ul>
<li>참고로 Hand Dryer 를 통해 도달할 수 있는 곳은 총 2곳입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6943aba2-c2b7-4643-8a62-d1028644dc11/image.png" alt=""></p>
<h1 id="rotating-tap">Rotating Tap</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f533f5f1-9443-4889-ad03-ca098a816173/image.gif" alt=""></p>
<ul>
<li>말그대로 회전하는 수도꼭지입니다. 별다른 기능은 없습니다.</li>
</ul>
<h1 id="ball-launcher-e-w">Ball Launcher (E-W)</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/cc08e316-b1d7-4553-a739-289851c9088c/image.gif" alt=""></p>
<ul>
<li>공을 동쪽(E)에서 서쪽(W)으로 발사하는 런처입니다.</li>
</ul>
<h1 id="ball-launcher-n-s">Ball Launcher (N-S)</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1267b08a-3834-4fc0-afc7-0c0d5769fad9/image.gif" alt=""></p>
<ul>
<li><p>공을 북쪽(N)에서 남쪽(S)으로 발사하는 런처입니다.</p>
</li>
<li><p>특이한 점은 공이 Fan 을 통과하면 속도가 빨라집니다. 바람이 속도를 빠르게 해준다는 느낌으로 구현하였습니다.</p>
<blockquote>
<ul>
<li>여기서 Fan 은 속도를 올려주는 장치이기도 하지만, 닿지 않고 지나가야 하는 장애물이기도 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c62eef38-2a37-4624-9dd4-559ebec6b5db/image.gif" alt=""></p>
<h1 id="pencils">Pencils</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4194a88c-293f-4d7d-83ec-e0c1d8cb2109/image.gif" alt=""></p>
<ul>
<li>상하 운동을 하는 연필들입니다. 마찬가지로 별다른 기능은 없습니다.</li>
</ul>
<h1 id="fall-boards">Fall Boards</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e72ce855-6ccf-4eed-8a4e-6bce49185b6d/image.gif" alt=""></p>
<ul>
<li>밟으면 일정 시간 후에 추락하는 발판입니다.</li>
</ul>
<h1 id="racket">Racket</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/df967ca5-535d-4278-b5bd-975cc5fc1c19/image.gif" alt=""></p>
<ul>
<li>열심히 발판을 밟으며 건너다 보면 갑자기 옆에 달려있던 라켓이 다가옵니다. 일반적으로 생성되어 있는 발판을 밟다가는 라켓에 치이기 때문에, 새롭게 생기는 하나의 발판을 통해 이동해야합니다.<blockquote>
<ul>
<li>라켓 이동/발판 생성 이벤트는 하나의 Trigger 를 통해 동시에 발동됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="moving-portal">Moving Portal</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/63d13008-3707-410b-86b3-12784593c7b2/image.gif" alt=""></p>
<ul>
<li>공과 비슷하게 생긴 것이 포탈입니다. 이를 통해 다음 스테이지로 넘어가야 하기 때문에 포탈로 달려들게 됩니다. 하지만 예상과는 달리 포탈이 이동하여 다음 스테이지로 넘어가지 못하게 됩니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UE] Player Movement & Animation]]></title>
            <link>https://velog.io/@hkun_ho/UE</link>
            <guid>https://velog.io/@hkun_ho/UE</guid>
            <pubDate>Thu, 19 Jan 2023 14:32:29 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<ul>
<li>본 학습 자료는 경희대학교 게임 &amp; 실감형 컨텐츠 제작 동아리 <code>Ludens</code> 의 Unreal-Study 자료입니다.</li>
</ul>
<h1 id="paragon-에셋-임포트-하기">Paragon 에셋 임포트 하기</h1>
<ul>
<li>에픽 게임즈 런처 - 상단의 &#39;마켓플레이스&#39; - &#39;Paragon&#39; 검색 - &#39;Paragon:Kwang&#39; 다운로드 및 프로젝트에 추가 (프로젝트는 당연히 본인이 이제 사용할 프로젝트여야 합니다.)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/120a2d68-1ef8-4f3d-9997-b339b8c6d19e/image.png" alt=""></p>
<h1 id="폴더-만들기">폴더 만들기</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8758fd8a-3f4d-4b5a-9c4c-47a131b612c7/image.png" alt=""></p>
<ul>
<li><p>폴더를 하나 만들어줍시다. 이름은 User 로 합시다. (뭘로 해도 상관없습니다.)</p>
</li>
<li><p>User 폴더 안에 PlayerCharacter 폴더를 만들어줍시다.</p>
<blockquote>
<ul>
<li>우리는 캐릭터에 관련된 것은 모두 이 폴더에 넣을 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="playerbp">PlayerBP</h1>
<ul>
<li>PlayerCharacter 폴더 내로 들어와 빈 공간을 우클릭 하면 많은 것이 뜹니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f2a025a4-bdaf-49f4-808c-44c07ac31ed3/image.png" alt=""></p>
<ul>
<li>우리는 이 중 &#39;블루프린트 클래스&#39;를 클릭하면 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/35c465e5-5dbd-4e82-8578-ee82cb461758/image.png" alt=""></p>
<ul>
<li><p>그리고 &#39;캐릭터&#39;를 클릭합시다.</p>
</li>
<li><p>그렇다면 블루프린트가 생성됩니다. 이름은 &#39;PlayerBP&#39;로 합시다.</p>
<blockquote>
<ul>
<li>더블 클릭해서 열어봅시다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="스켈레탈-메시-적용">스켈레탈 메시 적용</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8c93114b-e8d3-4fda-a26b-c693968e65fc/image.png" alt=""></p>
<ul>
<li>메시 - 스켈레탈 메시 에서 &#39;Kwang_GDC&#39; 를 선택해줍시다. 아마 맨 위에 있을겁니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bdcdc1e3-93ec-4486-9841-01f964472657/image.png" alt=""></p>
<ul>
<li><p>이렇게 둥 떠있는 캐릭터가 나오게 됩니다. 정상이니까 놀라지 않으셔도 됩니다. 트랜스폼 - 위치 에서 z 값을 -88.0 으로 바꿔주면 해결됩니다.</p>
</li>
<li><p>이제 늠름한 캐릭터의 모습을 한 번 봅시다. 그런데 플레이를 하면 우리의 캐릭터가 아닌 고철 덩어리가 뛰어다닙니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/aac578db-980b-4646-8f97-736c3c777460/image.png" alt=""></p>
<ul>
<li>내 캐릭터 내놔 ㅠㅠ</li>
</ul>
<h2 id="월드-세팅">월드 세팅</h2>
<ul>
<li>이는 간단한 월드 세팅으로 해결 가능합니다. 우측 상단의 &#39;세팅&#39; - 월드 세팅을 클릭해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/cc8c1801-5e8f-43ef-8aca-ea906e6c7fdd/image.png" alt=""></p>
<ul>
<li>월드 세팅의 Game Mode - 선택된 게임 모드 - 디폴트 폰 클래스 를 우리가 만든 PlayerBP 로 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/782ec65c-3a93-49e0-982d-3534934408e2/image.png" alt=""></p>
<ul>
<li>다시 플레이를 해보면, 뭔가 이상합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3bd29936-cfa4-4f60-9cb6-5879175d95cd/image.png" alt=""></p>
<ul>
<li>이는 카메라를 설정해주지 않았기 때문입니다.</li>
</ul>
<h2 id="카메라-설정">카메라 설정</h2>
<ul>
<li>다시 PlayerBP 로 돌아와서, 좌측 상단 &#39;컴포넌트&#39; 아래 &#39;+추가&#39;를 클릭해줍시다. 그리고 &#39;camera&#39; 항목의 &#39;스프링 암 컴포넌트&#39; 를 생성해줍시다. 이름은 CameraBoom 으로 합시다.<blockquote>
<ul>
<li>스프링 암 컴포넌트는 카메라와 캐릭터 사이의 거리를 유지시켜주는 역할을 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/713d9665-e08f-4513-866f-8180815cad11/image.png" alt=""></p>
<ul>
<li>그리고 CameraBoom 컴포넌트 안에서 &#39;+추가&#39;를 눌러 &#39;카메라 컴포넌트&#39;를 추가해줍시다. 이름은 FollowCamera 로 합시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3760d363-c1fe-42d5-a023-1d2445adee62/image.png" alt=""></p>
<ul>
<li>그런데 카메라의 방향과 플레이어가 바라보는 방향이 일치하지 않습니다. 이는 &#39;메시&#39; 컴포넌트의 트랜스폼 - 회전 - z 값을 270 으로 바꿔주면 해결됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5b74d15f-8cb2-49fc-a108-8bd8ab00d9db/image.png" alt=""></p>
<ul>
<li>이제, 플레이해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6a7e1249-8bd6-4530-ac34-9f3f00e3ab8b/image.png" alt=""></p>
<ul>
<li>잘 나오는 것 같습니다. 하지만 썩 맘에 드는 시점은 아니므로 카메라 위치를 조금만 옮겨보겠습니다.<blockquote>
<ul>
<li>FollowCamera 컴포넌트 - 트랜스폼 에서 x 값을 -200, z 값을 50 으로 바꿔봅시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d037fdd0-2696-4d1f-989c-986890d17f56/image.png" alt=""></p>
<ul>
<li>꽤나 맘에 드네요.</li>
</ul>
<h2 id="캐릭터-움직이기">캐릭터 움직이기</h2>
<ul>
<li>이제 캐릭터에게 활력을 불어넣어봅시다. 여태까지는 PlayerBP 의 &#39;뷰포트&#39;에서만 작업을 했는데, 이제는 &#39;이벤트그래프&#39;를 열어봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/642c5c67-6a84-4b1e-9ffe-4e10ad6f6f71/image.png" alt=""></p>
<ul>
<li>이상한 노드 3개가 있네요. 지워버립시다. 우리는 키보드 WASD 를 입력 받아 동서남북 방향으로 움직여볼겁니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e3dc64e7-86b0-4628-931b-a9bd9634dcd0/image.png" alt=""></p>
<ul>
<li><p>Get Control Rotation 노드의 출력과 Get Forward Vector 노드의 입력은 초기에 하나의 핀으로 되어있을 것입니다.</p>
<blockquote>
<ul>
<li>핀을 우클릭하여 &#39;구조체 핀 분할&#39;을 해줍시다.</li>
</ul>
</blockquote>
</li>
<li><p>본래는 입력 축에 대한 설정을 &#39;프로젝트 설정&#39;에서 해주어야 하지만 고맙게도 설정이 되어있습니다. 이를 활용합시다.</p>
<blockquote>
<ul>
<li>참고로 위와 같이 앞뒤/좌우 를 나누는 것이 일반적입니다.</li>
</ul>
</blockquote>
</li>
<li><p>참고로 흰 바탕의 Move 항목으로 묶은 것은 전체를 드래그한 후, 우클릭하여 &#39;선택에서 코멘트 생성&#39;을 한 것입니다.</p>
<blockquote>
<ul>
<li>편의를 위한 것이니 필수는 아닙니다.</li>
</ul>
</blockquote>
</li>
<li><p>이렇게 하고 플레이 해보면 동작은 없어도 움직이는 것을 확인할 수 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a8883a16-e2c8-46ec-a172-c0e91bc3cbd9/image.gif" alt=""></p>
<h2 id="마우스를-통해-시점-이동하기">마우스를 통해 시점 이동하기</h2>
<ul>
<li>지금까지는 캐릭터의 시점이 앞을 바라보는 방향으로 고정되어 있었습니다. 이를 마우스의 위치에 따라 변하도록 바꿔보고자 합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3c27acb7-72df-4d6b-8861-570f6bcdd8d5/image.png" alt=""></p>
<ul>
<li><p>캐릭터를 움직일 때와 비슷한 방식이지만 더 간단합니다. 마찬가지로 입력 축에 대한 설정이 되어있으므로 이를 활용해줍시다.</p>
</li>
<li><p>플레이 해보면 마우스를 따라 시점이 잘 움직이는 것을 확인할 수 있습니다.</p>
</li>
<li><p>혹시 뭔가 이상하신 분들이 있다면, CameraBoom 컴포넌트(스프링 암) 에서 카메라 세팅 - 폰 제어 회전 사용이 체크되어있는지 확인해보시기 바랍니다. 체크되어 있지 않다면 체크해주시면 됩니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/432e58ad-040e-4bf4-86b2-1b0ba7e268ee/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6128bbd9-87df-4a67-95d7-d1cfdcfc2e3b/image.gif" alt=""></p>
<h2 id="점프">점프</h2>
<ul>
<li>내친김에 점프 기능도 만들어봅시다. 매우 간단합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/01760ef5-4a16-4f07-bccd-fe2b0712ccd9/image.png" alt=""></p>
<ul>
<li><p>마찬가지로 &#39;Jump 입력 액션&#39;도 본래는 설정해 주어야 하지만 친절한 언리얼이 제공해두었으므로 가져다가 쓰도록 합시다.</p>
</li>
<li><p>이제 점프도 완성입니다! 쉽죠?</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/807cecbe-5494-4ef1-aedb-2ffc50b150d3/image.gif" alt=""></p>
<h2 id="키보드-입력-방향과-캐릭터-방향-맞추기">키보드 입력 방향과 캐릭터 방향 맞추기</h2>
<ul>
<li><p>지금은 캐릭터의 등밖에 보이지 않습니다. 키보드 입력 방향과 캐릭터 방향을 맞춰줍시다. 이건 더 쉽습니다.</p>
</li>
<li><p>PlayerBP의 캐릭터 무브먼트 컴포넌트 - 캐릭터 무브먼트(회전 세팅) - 무브먼트 방향으로 회전 조정을 체크해줍시다.</p>
</li>
<li><p>그리고 편의상 회전 속도의 z 값을 360에서 400으로 바꿔줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/aad44958-41a1-4c53-b5c1-057a7fc33350/image.png" alt=""></p>
<ul>
<li>그리고 PlayerBP(셀프) 컴포넌트의 폰 - 컨트롤러 회전 요 사용을 체크 해제해주면 됩니다.<blockquote>
<ul>
<li>이 항목이 체크 헤제가 되어있다면, 그냥 넘어가시면 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/36a71269-f296-4b3c-a871-90f3312c3caf/image.png" alt=""></p>
<ul>
<li>결과를 확인해봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1c20a6ed-4878-4193-a0f2-d8620b52e813/image.gif" alt=""></p>
<ul>
<li>잘 나옵니다. 이제 애니메이션 부분으로 넘어갑시다!</li>
</ul>
<h1 id="playeranimbp">PlayerAnimBP</h1>
<ul>
<li>다시 User - PlayerCharacter 폴더로 돌아와서 빈공간에 우클릭을 해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5d055694-d467-4ca8-b24e-f67c4cf47be7/image.png" alt=""></p>
<ul>
<li>우리는 이 중에 애니메이션 블루프린트를 생성할겁니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7970665b-21d4-4662-a1ed-3ffa12d48aac/image.png" alt=""></p>
<ul>
<li><p>우리의 캐릭터인 Kwang_Skeleton 을 선택해줍시다.</p>
<blockquote>
<ul>
<li>애니메이션을 적용할 뼈대를 정하는 것이기 때문에 다른 것을 선택하면 애니메이션이 정상적으로 작동하지 않습니다.</li>
</ul>
</blockquote>
</li>
<li><p>다음과 같은 화면에서 우리는 우선 이벤트 그래프에서 작업을 할겁니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8481d9b0-8077-4680-8f5e-a03da7ad0228/image.png" alt=""></p>
<h2 id="변수-생성">변수 생성</h2>
<ul>
<li>우선 변수를 만들겁니다.<blockquote>
<ul>
<li>이벤트 그래프에 있는 노드 2개는 쓰이므로 그냥 둡시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6894a3a1-30e8-47d5-a880-5ee681a15e0c/image.png" alt=""></p>
<ul>
<li><p>3가지 변수를 만들어줍시다.</p>
<blockquote>
<ul>
<li>Speed(플로트) : 캐릭터의 속도를 담을 변수</li>
<li>IsInAir(부울) : 캐릭터가 지면에 닿아 있는지를 담을 변수</li>
<li>IsAccelerating(부울) : 캐릭터가 가속 중인지를 담을 변수</li>
</ul>
</blockquote>
</li>
<li><p>추후에 아시게 되겠지만, Speed 변수가 있는데 IsAccelerating 변수가 또 있는 이유는 Run 모드와 Sprint 모드를 구분하기 위함입니다.</p>
<blockquote>
<ul>
<li>Sprint 와 Run 은 둘 다 IsAccelerating 이 True 지만 Sprint 의 Speed 가 Run 보다 빠릅니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ac4b5749-eb85-44bf-b647-4ef5c74e0d19/image.png" alt=""></p>
<ul>
<li>이렇게 보인다면 성공입니다. 이제 이벤트 그래프에서 변수에 값을 담아봅시다.</li>
</ul>
<h2 id="변수에-값-저장">변수에 값 저장</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/433f4229-b09d-45eb-9c9a-c8c8c5ca32aa/image.png" alt=""></p>
<ul>
<li>이제 이벤트 그래프가 아닌 &#39;AnimGraph&#39; 로 가봅시다. 본격적으로 애니메이션을 다뤄볼겁니다.</li>
</ul>
<h2 id="idlerunsprint">Idle/Run/Sprint</h2>
<ul>
<li>스테이트 머신을 하나 추가해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9df3bed5-03d5-491d-8fa1-ca3bb1a38080/image.png" alt=""></p>
<ul>
<li>이름은 Basic 으로 해줍시다. 마찬가지로 상관 없습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3f3588a2-42f4-402c-b751-f8a1a96d3a95/image.png" alt=""></p>
<ul>
<li><p>최종 애니메이션 포즈는 나중에 연결될 예정입니다. 그냥 둡시다. (어차피 못 지웁니다.)</p>
</li>
<li><p>이제 Basic 을 더블 클릭해 들어가 봅시다. Idle 상태를 먼저 만들겁니다.</p>
</li>
<li><p>좌측 하단의 콘텐츠 드로어를 클릭하여 idle 를 검색하면 다음과 같이 나옵니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8ae6e070-95f1-492c-8914-e3094126845a/image.png" alt=""></p>
<ul>
<li><p>이를 애니메이션 블루 브린트 내로 드래그 해주면 됩니다.</p>
<blockquote>
<ul>
<li>빨간색으로 안된다고 뜨는데 해보시면 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>이런 식으로 Jog_Fwd 를 검색하여 드래그해서 스테이트 이름을 Run, Sprint_Fwd 를 검색하여 드래그 해서 스테이트 이름을 Sprint 로 해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/21e6a767-506a-421a-bf74-182265ad51d0/image.png" alt=""></p>
<ul>
<li>이제 각 스테이트들을 연결해볼겁니다. Entry 에서 Idle 는 그냥 연결해주면 됩니다.</li>
</ul>
<h3 id="idel---run">Idel -&gt; Run</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9bc1489c-a427-4ccb-9579-b0e083ebb23d/image.png" alt=""></p>
<ul>
<li>위의 빨간 박스 내의 표시가 바로 Idle 에서 Run 으로 바뀔 조건입니다. 한 번 봐봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/621a3676-eb82-4914-8961-98d023ff9093/image.png" alt=""></p>
<ul>
<li><p>&#39;속력 0보다 크고, 지면에 닿아있고, 가속중이면 Idel 에서 Run 으로 바꾼다&#39; 라는 뜻입니다.</p>
</li>
<li><p>그렇다면 반대는 뭘까요?</p>
</li>
</ul>
<h3 id="run---idle">Run -&gt; Idle</h3>
<ul>
<li>간단합니다. &#39;가속중이 아니라면&#39; Run 에서 Idle 로 바꾸면 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8b85bee7-4f57-44f1-86cf-ad7c38b0cbd2/image.png" alt=""></p>
<h3 id="run---sprint">Run -&gt; Sprint</h3>
<ul>
<li>이제 연결하는 방법은 아실거라 생각하고, 조건을 살펴보겠습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e4155eaa-6d4e-4f43-a175-2fac77416cc7/image.png" alt=""></p>
<ul>
<li>속력이 650 보다 크거나 같다고 정한 이유는, 추후 우리의 캐릭터의 Run 속력을 500, Sprint 속력을 800으로 할 것이기 때문입니다.<blockquote>
<ul>
<li>점프할 때 속력이 올라가는 등 여러 변수를 고려한 속력입니다. 정확하다고는 못하지만 대부분의 상황에서 잘 작동하는 것을 확인하였습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="sprint---run">Sprint -&gt; Run</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/57838908-4f4a-4778-ab78-4451e8253d3b/image.png" alt=""></p>
<h3 id="sprint---idle">Sprint -&gt; Idle</h3>
<ul>
<li>Run -&gt; Idel 와 마찬가지로 &#39;가속중이 아니라면&#39; 바꾸면 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/18dc8fae-61a6-420c-bcea-0b35deb73d0a/image.png" alt=""></p>
<ul>
<li>일반적으로 속력은 0에서 부터 증가하기에 Idle 에서 Sprint 는 Run 을 거쳐갑니다. 따라서 Idle -&gt; Sprint 는 따로 연결하지 않았습니다.</li>
</ul>
<h2 id="다시-idlerunsprint">다시, Idle/Run/Sprint</h2>
<ul>
<li>이제 Idle/Run/Sprint 가 완성되었습니다. 한 번 봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/fe7a332f-1d62-43be-9643-64b43b86e4fd/image.png" alt=""></p>
<ul>
<li>동작하는 것을 확인하려면 AnimGraph 로 돌아와 Basic 스테이트와 최종 애니메이션 포즈를 연결해주면 됩니다. 그리고 컴파일 해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d8198e3f-33ff-4fd4-8dc6-f152879ef185/image.png" alt=""></p>
<ul>
<li>플레이해서 확인해봤는데, 움직이지 않습니다. 무슨 일일까요?</li>
</ul>
<h2 id="playerbp-에서-playeranimbp-연결하기">PlayerBP 에서 PlayerAnimBP 연결하기</h2>
<ul>
<li>PlayerBP 에서 PlayerAnimBP 연결해주지 않아서 입니다. PlayerBP 를 열어봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/db0be1f4-4826-4ebc-b04b-fe2fbfb9a967/image.png" alt=""></p>
<ul>
<li>메시 컴포넌트 - 애니메이션 - 애님 클래스 에서 PlayerAnimBP 를 찾아서 설정해줍시다.<blockquote>
<ul>
<li>애니메이션 모드는 Use Animation Blueprint 입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="최대-걷기-속도-조정">최대 걷기 속도 조정</h2>
<ul>
<li><p>PlayerBP 에 온 김에 최대 걷기 속도도 조정해줍시다.</p>
<blockquote>
<ul>
<li>여기서 Run 속도가 최대 걷기 속도입니다.</li>
</ul>
</blockquote>
</li>
<li><p>캐릭터 무브먼트 - 캐릭터 무브먼트:걷기 - 최대 걷기 속도 를 500 으로 재설정해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/be79c8db-8e98-4eff-977f-9c1e03555fe9/image.png" alt=""></p>
<ul>
<li>이제 확인해볼까요?</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/cd4745d7-b8ba-4a46-94b1-6eca9e9e9fb0/image.gif" alt=""></p>
<ul>
<li>좋습니다. 잘 걸어다니네요.</li>
</ul>
<h2 id="sprint-기능-추가">Sprint 기능 추가</h2>
<ul>
<li>Sprint 애니메이션은 있지만 정작 기능은 없었습니다. 따라서 우리는 Shift 에 Sprint 기능을 추가하고자 합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2442dd95-9abf-4531-8365-3721d7ffd020/image.png" alt=""></p>
<ul>
<li>앞서 언급한대로 Sprint 속도는 800으로 설정해줍니다. 그럼 끝입니다! 매우 간단하죠?</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bba7000c-4ea6-4a0f-a4ad-4d46ecd00ec1/image.gif" alt=""></p>
<h2 id="점프-애니메이션-추가-locomotion">점프 애니메이션 추가 (Locomotion)</h2>
<ul>
<li><p>우리는 Idle/Run/Sprint 애니메이션만 짰기 때문에 점프 시에는 별도의 애니메이션이 발생하지 않습니다. 이제부터 점프 애니메이션을 짜볼겁니다.</p>
</li>
<li><p>우선, PlayerAnimBP 로 돌아와 AnimGraph 에서 Basic 스테이트와 최종 애니메이션 포즈를 끊어줍시다. Basic 스테이트를 다른 것에 연결해야해서 그렇습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1168c10e-39b8-4892-a74e-11bd0e45ae10/image.png" alt=""></p>
<ul>
<li>애니메이션 블루프린트를 우클릭하여 &#39;캐시 포즈 새로 저장&#39;을 만들어줍시다. 이름은 Ground_Loco 로 합시다.<blockquote>
<ul>
<li>쉽게 말해, Basic 에서의 상태를 Ground_Loco 에 저장해두는 것이라고 생각합시다. 이 상태를 저장하는 이유는 나중에 어딘가에서 이 상태를 불러와서 사용하기 위함입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6b023152-17f8-46b0-8fac-b04ff7305311/image.png" alt=""></p>
<ul>
<li>그리고 Basic 과 연결해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9cf9bf7e-fd38-4f57-91d3-7204f63f00ff/image.png" alt=""></p>
<ul>
<li>이제 이 상태를 불러와서 사용할 스테이트 머신을 하나 만듭시다. 이름은 Locomotion 으로 합시다. 그리고 이를 최종 애니메이션 포즈와 이어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4a7f111c-9bfc-4b2b-8bb0-f4c6c3bf9a3a/image.png" alt=""></p>
<ul>
<li>이제 Locomotion 스테이트를 더블 클릭하여 들어가줍시다. 그리고 스테이트를 추가해줍시다. 이름은 Idle/Run/Sprint 로 해줍시다.<blockquote>
<ul>
<li>이 스테이트는 앞서 설명한 캐시 포즈를 불러와서 사용할겁니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/33a1cf42-b849-4c2c-8e64-2bf3417f8c56/image.png" alt=""></p>
<ul>
<li>만들어진 Idle/Run/Sprint 를 더블 클릭하고, 내부에서 &#39;Ground_Loco&#39; 캐시 포즈를 불러와줍니다. 그리고 애니메이션 포즈 출력 노드와 이어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/878c1dd4-51b9-48b6-8f72-ddc12a25238a/image.png" alt=""></p>
<ul>
<li>앞서 했던 것처럼 콘텐츠 드로어에서 애니메이션을 드래그하지 않고, 새 스테이트 2개를 추가해줍시다. 하나는 Jumps, 그리고 나머지 하나는 Jump_Land 로 해줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/845e0db3-0082-4933-ae33-f600034626b6/image.png" alt=""></p>
<h3 id="jumps">Jumps</h3>
<ul>
<li>Jumps 를 더블 클릭하여 내부로 들어와줍니다. 그리고 새 스테이트 머신을 하나 추가해줍시다. 이름은 Jump 로 합시다. 그리고 애니메이션 포즈 출력 노드와 이어줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3d28eabf-9022-49eb-a816-fcf25df58c1a/image.png" alt=""></p>
<ul>
<li><p>이제 또 Jump 스테이트 머신 내부로 들어가 세부 애니메이션 출력을 짜볼겁니다.</p>
</li>
<li><p>이번엔 앞서 했던 것처럼 콘텐츠 드로어에서 Jump_start, Jump_Apex, Jump_Land 를 검색하여 각각을 드래그해옵시다. 여기서 각각의 이름은 그대로 사용하되, Jump_Land 의 이름을 Jump_PreLand 로 바꿔줍시다.</p>
<blockquote>
<ul>
<li>이후에 Jump_Land 라는 스테이트를 따로 만들어둘 것이기 때문입니다.</li>
</ul>
</blockquote>
</li>
<li><p>그리고 각각을 쭉 이어줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5247da86-5618-4a0a-b342-28adc9858a3c/image.png" alt=""></p>
<ul>
<li><p>여기서 주의해야할 점은 스테이트를 이은 후에 스테이트간의 트랜지션이 자동으로 이루어지게 해야합니다.</p>
<blockquote>
<ul>
<li>즉, 조건없이 Jump_Start 에서 Jump_Apex 로, Jump_Apex 에서 Jump_PreLand 로 넘어가게 해야합니다.</li>
</ul>
</blockquote>
</li>
<li><p>따라서 트랜지션(화살표 위의 흰 원)을 클릭하여 우측의 &#39;트랜지션&#39; 항목에서 &#39;스테이트의 시퀸스 플레이어에 따른 자동 규칙&#39;을 체크해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a27656d1-b0ca-40a5-8f53-cee74dd6f2ba/image.png" alt=""></p>
<ul>
<li><p>Jump_Apex 에서 Jump_PreLand 로 넘어가는 트랜지션에도 똑같이 해줍시다.</p>
</li>
<li><p>그 후 Jump_PreLand 스테이트로 들어가서 Jump_Land 시퀸스 플레이어의 세부 설정을 바꿔줄겁니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a3b9e7a1-6494-44d6-88a2-2bdd3ffb1178/image.png" alt=""></p>
<ul>
<li><p>세팅 - 재생 속도 를 0.2로 바꾸고, 애니메이션 루프도 체크 해제해줍시다.</p>
</li>
<li><p>이제 Jumps 세부 설정이 끝났습니다. 다시 Locomotion 스테이트 머신으로 가봅시다!</p>
</li>
</ul>
<h3 id="jump_land">Jump_Land</h3>
<ul>
<li>이제 Locomotion 스테이트 머신의 Jump_Land 스테이트 세부 설정을 해줄겁니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/65bf439e-4d98-4c7a-8ff6-413a23e0b8d1/image.png" alt=""></p>
<ul>
<li>사진과 같이 노드들을 배치하고, Jump_Recovery_Addictive 를 클릭하여 세부설정을 바꿔줍시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5ed3118c-8737-4813-82f1-4e648cb9a254/image.png" alt=""></p>
<ul>
<li><p>세팅 - 재생 속도를 1.2로, 애니메이션 루프는 체크 해제해줍시다.</p>
</li>
<li><p>그리고 마지막으로 &#39;애디티브 적용&#39; 노드의 Alpha 값을 0.4로 바꿔줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7dfececc-4119-489d-95e6-282944646f6c/image.png" alt=""></p>
<ul>
<li>이제 스테이트 내부 작업은 끝났습니다. 각각의 스테이트들을 이어줄 차례입니다!</li>
</ul>
<h3 id="idlerunsprint---jumps">Idle/Run/Sprint -&gt; Jumps</h3>
<ul>
<li>매우 간단합니다. 캐릭터가 지면에 닿아있는지만 확인하면 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/36f4575d-1aec-47e0-93af-51c509cf39b3/image.png" alt=""></p>
<h3 id="jumps---jump_land">Jumps -&gt; Jump_Land</h3>
<ul>
<li>마찬가지로 간단합니다. 캐릭터가 지면에 닿아있지 않다면 실행해줍니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/79486da2-6065-482f-a84e-bc72589cc710/image.png" alt=""></p>
<h3 id="jump_land---idlerunsprint">Jump_Land -&gt; Idle/Run/Sprint</h3>
<ul>
<li>2가지 트랜지션을 생성할겁니다. 그냥 Jump_Land 에서 Idle/Run/Sprint 방향으로 2번 이어주면 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3d855b73-8207-406b-8c26-7dfefb73def2/image.png" alt=""></p>
<ul>
<li><p>하나는 자동으로 이루어지게 합니다.</p>
<blockquote>
<ul>
<li>앞서 설명한 것처럼 &#39;트랜지션&#39; 항목에서 &#39;스테이트의 시퀸스 플레이어에 따른 자동 규칙&#39;을 체크하면 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>나머지 하나는 지면에 닿아있는지 확인해줍시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/591c0c09-bb8b-4aff-90c3-94c404173812/image.png" alt=""></p>
<ul>
<li>그렇다면 이제 완성입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/79684df5-649a-4c66-96ad-01d054b1120f/image.gif" alt=""></p>
<ul>
<li>여기까지 1주차 Part.1 - Player Movement &amp; Animation 이었습니다. 다음 포스팅은 1주차 Part.2 - Player Attack 입니다~</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Seminar] Graph Representation Learning With 3D applications]]></title>
            <link>https://velog.io/@hkun_ho/Seminar-Graph-Representation-Learning-With-3D-applications</link>
            <guid>https://velog.io/@hkun_ho/Seminar-Graph-Representation-Learning-With-3D-applications</guid>
            <pubDate>Mon, 16 Jan 2023 18:57:57 GMT</pubDate>
            <description><![CDATA[<h1 id="about-the-graph">About the Graph</h1>
<h2 id="what-is-graph">What is Graph?</h2>
<ul>
<li><p>그래프는 점들과 그 점들을 잇는 선으로 이루어진 데이터 구조입니다. 관계나 상호작용을 나타내는 데이터를 분석할 때 주로 쓰입니다.</p>
<blockquote>
<ul>
<li>대표적인 예 : 페이스북 친구 관계, 유튜브, 넷플릭스 등의 유저-영상 감상 여부</li>
</ul>
</blockquote>
</li>
<li><p>G = (V, E) 로 나타내며 V 는 꼭짓점(vertex) 의 집합, E 는 에지(edge) 의 집합입니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d0b90142-b605-47ae-b7a9-1f44ca898b40/image.png" alt=""></p>
<ul>
<li>에지에는 방향이 있을 수도 있고 없을 수도 있는데, 그래프의 모든 에지에 방향이 존재한다면 이를 유향 그래프(directed graph), 방향이 없는 경우에는 무향 그래프(undirected graph)라고 부릅니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2254fa8a-3570-433c-9cfc-3ff58be3c7ee/image.png" alt=""></p>
<h3 id="adjacency-matrix-인접-행렬">Adjacency matrix (인접 행렬)</h3>
<ul>
<li>인접 행렬은 그래프에서 정점이 어떤 간선으로 연결되었는지를 나타내는 행렬입니다. 정점 n 개의 그래프에 대해서 n * n 행렬을 이용합니다.<blockquote>
<ul>
<li>이때 정점끼리 연결되어 있다면 행렬의 값을 1로, 연결되어있지 않다면 행렬의 값을 0으로 이용합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f62ce4b7-eb37-4310-be88-68a8deeabb08/image.png" alt=""></p>
<h3 id="degree-matrix-차수-행렬">Degree matrix (차수 행렬)</h3>
<ul>
<li>무방향 그래프의 차수 행렬은 각 꼭짓점의 차수, 즉 각 꼭짓점에 연결된 간선 수에 대한 정보를 포함하는 대각 행렬입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c20ff0f2-ca76-4eb5-99a1-590865d530ab/image.png" alt=""></p>
<h3 id="graph-tasks">Graph tasks</h3>
<ul>
<li>Node Level : 각 Node 의 feature 를 예측</li>
<li>Edge Level : Node 간의 관계(Edge) 를 예측</li>
<li>Graph Level : Graph 전체를 예측</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a1942bc8-8e50-43fe-a416-d3160789e26b/image.png" alt=""></p>
<h2 id="why-graph">Why Graph?</h2>
<ul>
<li><p>CNN 은 혁명적인 Neural Network 였지만, <em><strong>Euclidean data</strong></em> 만을 input 으로 받았기 때문에, <em><strong>Non - Euclidean data</strong></em> 로 학습을 할 수 없었습니다.</p>
<blockquote>
<ul>
<li>이에 따라 Non - Euclidean data 를 학습할 수 있는 방법으로 Graph 가 제시되었습니다.</li>
</ul>
</blockquote>
</li>
<li><p>당연하게도, Graph 는 Euclidean Space 에 있지 않습니다.</p>
<blockquote>
<ul>
<li>이는 우리에게 익숙한 좌표계로 표현할 수 없다는 것을 의미하지만, Non - Euclidean Space 에 있는 무언가를 그래프로 표현할 수 있다고도 볼 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="euclidean-space">Euclidean Space</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f5c75235-2b47-4aa2-a7fb-b03a0c787880/image.png" alt=""></p>
<ul>
<li>평면과 공간을 거리와 길이와 각도, 좌표계를 도입하여, 임의 차원의 공간으로 확장한 것을 말합니다. 이는 표준적인 유한 차원, 실수, 내적 공간입니다.</li>
</ul>
<h3 id="non---euclidean-space">Non - Euclidean Space</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bcdcd6a4-2e68-43e4-958e-4baa7c5bef3f/image.png" alt=""></p>
<ul>
<li>평면이 아닌 곡면의 세계에서 점, 선, 면을 설명하는 공간입니다.</li>
</ul>
<h1 id="the-rise-of-gnn-graph-neural-network">The Rise of GNN (Graph Neural Network)</h1>
<ul>
<li><p>앞서 말했던 것처럼, Non - Euclidean data 를 이용해 학습을 하기 위해 Graph 를 사용한 Neural Network, GNN 이라는 개념이 등장하였습니다.</p>
<blockquote>
<ul>
<li>GNN 은 이름에서도 알 수 있듯이 그래프에 직접 적용할 수 있는 신경망입니다.</li>
</ul>
</blockquote>
</li>
<li><p>GNN의 핵심은 점이 이웃과의 연결에 의해 정의된다는 것입니다.</p>
<blockquote>
<ul>
<li>만약 어떤 점이 이웃과의 연결을 다 끊으면 그 점은 고립되고 아무 의미를 갖지 않게 됩니다.</li>
<li>즉, 노드의 이웃과 이웃에 대한 연결이 노드의 개념을 정의합니다.</li>
</ul>
</blockquote>
</li>
<li><p>이를 염두하고, 모든 점(node)이 각각의 특징을 설명하는 어떤 상태(state)로 표현되어 있다고 생각해봅시다.</p>
<blockquote>
<ul>
<li>우리는 output 을 만들기 위해서 node state 를 사용합니다.</li>
</ul>
</blockquote>
</li>
<li><p>GNN은 주로 연결 관계와 이웃들의 상태를 이용하여 각 점의 상태를 업데이트(학습)하고 마지막 상태를 통해 예측 업무를 수행합니다.</p>
<blockquote>
<ul>
<li>일반적으로 마지막 상태를 ‘node embedding’이라고 부릅니다.</li>
</ul>
</blockquote>
</li>
<li><p>간단히 말해서, GNN 은 임의의 구조의 그래프 G 가 들어왔을 때 이를 Representation 으로 표현해야 합니다.</p>
<blockquote>
<ul>
<li>즉, F(G) = embedding 으로 변환할 수 있는 함수 F를 찾는 것이 GNN 의 목표입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="recurrent-graph-neural-network">Recurrent Graph Neural Network</h2>
<ul>
<li><p>Recurrent Graph Neural Network 는 GNN의 시초로서 의미가 있습니다. 이는 고수준의 node representation 을 추출하기 위해 노드들의 파라미터들을 재귀적으로 적용합니다.</p>
</li>
<li><p>GNN과 다른 점은, GGNN 에서 BPTT(Back Propagation Through Time)을 사용하여 모델을 학습시킨다는 점입니다.</p>
<blockquote>
<ul>
<li>이는 큰 그래프에서는 문제가 될 수도 있는데, GGNN 이 모든 노드에 대해 재귀 함수를 여러번 실행하려면 모든 노드의 중간 상태들이 전부 메모리에 저장되어야 하기 때문입니다.</li>
</ul>
</blockquote>
</li>
<li><p>Recurrent 모델은 그래프를 탐색하는 가장 직관적인 방법에서 떠올린 모델로서 의미를 갖습니다.</p>
<blockquote>
<ul>
<li>이 탐색 과정에서 얻는 결과들이 바로 hidden state가 되고, 이 hidden state 가 모여 결국 그래프의 특성을 결정짓게 되는 방식입니다.</li>
</ul>
</blockquote>
</li>
<li><p>하지만 마찬가지로 가장 문제가 되는 부분도 역시 recurrent 부분입니다.</p>
<blockquote>
<ul>
<li>이 부분의 연산이 너무 비효율적입니다. 이러한 재귀 연산의 연산량만큼 그 결과가 가치가 있지 않습니다.</li>
<li>다른 네트워크로 재귀 없이 병렬 계산하여도 결국 좋은 결과들을 얻을 수 있었고, 재귀 방식은 그 재귀의 깊이만큼 의미를 가지지 못했습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="graph-convolution-network">Graph Convolution Network</h2>
<ul>
<li>Graph 를 Euclidean space 로 보내기 위해 <em><strong>Convolution</strong></em> 연산을 사용합니다.</li>
</ul>
<h3 id="convolution">Convolution</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/33e4140b-f284-4efb-821d-7bb53ea5fe60/image.png" alt=""></p>
<ul>
<li>위와 같이 어떤 입력 이미지가 들어왔을 때, 여기서 Feature를 감지할 Detector가 존재합니다.<blockquote>
<ul>
<li>Detector 를 Kernel 이나 Filter 라고도 표현할 수 있는데, 말 그대로 Detector 가 Input Image 의 모든 영역을 훑으면서 특정 Feature를 뽑게 됩니다.</li>
<li>이를 바탕으로 해당 입력에 대한 Feature Map 을 그리게 되는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7cdcdec4-ac66-482a-81a8-76ef21d104ff/image.png" alt=""></p>
<ul>
<li>이때 Input Image 의 pixel 과 Feature Detector 의 각 kernel 을 곱한 결과를 합하게 되고, 그 결과가 Feature Map 의 하나를 채우게 됩니다.<blockquote>
<ul>
<li>이 과정을 Feature Detector 가 입력 이미지를 모두 훑을 때까지 계속합니다. </li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1b3ec63f-b6fc-4e88-82b6-cce47e94fdc9/image.png" alt=""></p>
<ul>
<li><p>이렇게 Feature Map을 만들고, 원래 입력 이미지와 크기를 비교해보면 원래의 7x7 이미지가 5x5 이미지로 작아진 것을 알 수 있습니다.</p>
<blockquote>
<ul>
<li>다시 말해 pixel 별로 비교해도 49회 걸리던 일이 25회만 비교하면 되는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>이로 인해 이미지 비교시 속도라는 이점을 얻을 수 있는게 Convolution 연산의 특징입니다.</p>
<blockquote>
<ul>
<li>물론 속도가 빠른만큼 원래 정보가 소실된다는 점도 있긴 하나, 우리의 목적이 모든 pixel을 비교하는 게 아닌, 이미지의 특징을 뽑아내는 것이므로 이런 과정이 필요합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ecb69024-9736-4b63-bb5d-2464709810e1/image.png" alt=""></p>
<ul>
<li>이렇게 뽑아낸 Feature Map 들을 잘 살펴보면 얻어낸 Feature 중에서도 가장 중요한 Feature 를 뽑아낼 수 있을 것이고, 이를 위해서 학습하는 역할을 CNN 중 Convolutional Layer 에서 수행합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2ea2c10e-b99d-4151-ab10-fdaeff320565/image.png" alt=""></p>
<ul>
<li>간단히 요약하면, 기존에 나와있던 Convolution 연산을 활용해서 입력 이미지의 특징을 찾는 과정을 수행하는 것이 CNN 내에서 Convolution Layer가 수행하는 역할입니다.<blockquote>
<ul>
<li>이를 GNN 에도 적용해보고자 했습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="spatial-convolutional-network">Spatial Convolutional Network</h3>
<ul>
<li><p>Spatial graph convolution 은 convolution 연산을 graph 위에서 직접 수행하는 방식으로, 각 노드와 가깝게 연결된 이웃 노드들에 한해서 convolution 연산을 수행합니다.</p>
<blockquote>
<ul>
<li>즉, 노드와 이웃 노드들을 특정 grid form 으로 재배열하여 convolution 연산을 수행하는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>그러나 우리가 일반적으로 아는 CNN 의 filter 는 고정된 사이즈를 가집니다.</p>
</li>
<li><p>따라서, spatial graph convolution 방식의 관건은 고정된 크기의 이웃 노드를 선택하는 것입니다. 뿐만 아니라, CNN의 특징 중 하나는 “local invariance” 입니다.</p>
<blockquote>
<ul>
<li>이는 입력의 위치가 바뀌어도 출력은 동일함을 의미합니다.</li>
</ul>
</blockquote>
</li>
<li><p>마찬가지로, Spatial graph convolution의 또다른 관건은 바로 “local invariance”를 유지를 해야한다는 것입니다.</p>
</li>
<li><p>앞에서 언급한 spatial graph convolution 이 다뤄야 할 문제점과 별개로 또다른 문제점이 존재합니다. Spatial graph convolution 은 고정된 이웃 노드에서만 정보를 받아서 노드의 정보를 업데이트를 한다는 점입니다.</p>
</li>
<li><p>그러나, 그래프에서의 한 노드의 정보는 시간에 따라 여러 노드들의 정보의 혼합으로 표현될 수 있습니다.</p>
<blockquote>
<ul>
<li>즉, 고정된 이웃 노드 말고도 멀리 연결되어 있는 노드의 정보도 시간이 흐르면서 밀려 들어올 수 있는 것입니다. 이를 노드 간 message passing이라 합니다.</li>
</ul>
</blockquote>
</li>
<li><p>즉, 한 노드의 정보는 여러 노드의 signal 이 혼재해 있는 것으로, 이를 time domain 이 아닌 frequency 도메인으로 분석한다면, 한 노드 내에 혼재된 signal 들을 여러 signal 의 요소로 나눠서 node의 특징을 더 잘 추출할 수 있습니다.</p>
<blockquote>
<ul>
<li>이것에 관한 것이 바로 “Spectral Graph Convolution”입니다.</li>
<li>이는 spectral 영역에서 convolution을 수행하는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="spectral-convolutional-network">Spectral Convolutional Network</h3>
<ul>
<li>Signal Processing 분야에서 “spectral analysis” 라는 것은 이미지/음성/그래프 신호(signal)을 time/spatial domain 이 아니라 frequency domain 으로 바꿔서 분석을 진행하는 것입니다.<blockquote>
<ul>
<li>즉, 어떤 특정 신호를 단순한 요소의 합으로 분해하는 것을 의미합니다. 대표적으로 이를 수행할 수 있는 방법이 푸리에 변환(Fourier Transform)입니다.<blockquote>
<ul>
<li>spectral analysis에서 입력 신호가 전파/음성신호면 time domain을 frequency domain으로 변환하고, 컴퓨터 비전/그래프/영상처리 분야이면 spatial domain을 frequency domain으로 변환합니다.</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="fourier-transform">Fourier Transform</h4>
<ul>
<li>푸리에 변환이란, 임의의 입력 신호를 다양한 주파수를 갖는 주기 함수들의 합으로 분해하여 표현하는 것입니다. 아래 그림처럼 빨간색 신호를 파란색의 주기 함수들의 성분으로 나누는 작업이 바로 푸리에 변환입니다.<blockquote>
<ul>
<li>즉, 파란색 주기함수들을 합하면 결국 빨간색 신호가 되는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/104f7b26-0925-4d49-bb76-c2b4f600de08/image.png" alt=""></p>
<ul>
<li>먼저, 푸리에 변환 식에 대해서 살펴보겠습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2b940a51-f6b5-42dd-b371-0e65bcb861e2/image.png" alt=""></p>
<ul>
<li><p>위 식은 f 의 푸리에 변환이고, 아래 식은 푸리에 역변환입니다.</p>
<blockquote>
<ul>
<li>푸리에 변환은 time domain 을 frequency domain 으로, 푸리에 역변환은 frequency domain 의 함수를 다시 time domain 으로 변환합니다.</li>
</ul>
</blockquote>
</li>
<li><p>푸리에 변환을 바라보는 관점 중 하나는 &#39;내적&#39;입니다.</p>
<blockquote>
<ul>
<li>&#39;내적&#39;은 유사도라는 의미를 내포하고 있습니다. 따라서 푸리에 변환을 다음과 같이 풀어쓸 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/99215e11-402a-47ca-8b50-4a1b9525c0f9/image.png" alt=""></p>
<ul>
<li>그렇다면, e^(-2πixξ) 의 의미를 알아보겠습니다. 이를 오일러 공식으로 표현하면 다음과 같습니다.<blockquote>
<ul>
<li>오일러 공식은 복소지수함수(complext exponential function)를 삼각함수(trigonometric function)로 표현하는 유명한 식입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/65f2b174-c68a-46e3-8e47-057c1908fc3b/image.png" alt=""></p>
<ul>
<li><p>즉, 주어진 주파수 f(x) 에 대해 cosine 에서 유사한 정도와 sine 에서 유사한 정도의 합이 푸리에 변환이라고 생각할 수 있습니다.</p>
</li>
<li><p>이번엔 푸리에 변환의 선형 대수적인 의미를 살펴봅시다. 선형 대수에서, d 차원에 속한 벡터 a 에 대한 d 차원의 orthonormal basis 를 찾을 수 있다면, 벡터 a 를 orhonormal basis의 선형결합으로 표현할 수 있습니다.</p>
<blockquote>
<ul>
<li>이 orthonormal basis 를 찾는 방법 중 하나가 바로 Eigen-value decomposition 입니다.<blockquote>
<ul>
<li>orthonormal 이란 서로 직교하면서 길이가 1인 벡터들을 의미합니다. 또한, 모든 matrix에 대해서 eigen-value decomposition 결과로 찾은 basis 가 orthonormal 은 아닙니다. 하지만 real-symmetric matrix 에 대하여 구한 eigenvector 들은 orthgonal한 관계입니다.</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</li>
<li><p>참고로, sine 과 sine, sine 과 cosine, cosine 과 cosine을 내적하면 모두 다 0이 나옵니다.</p>
<blockquote>
<ul>
<li>즉, 삼각함수는 직교함을 알 수 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>그렇다면 선형대수 관점에서, sine 과 cosine 기저들의 선형 결합이 푸리에 변환이 되는 것입니다.</p>
<blockquote>
<ul>
<li>즉, 어떤 특정 graph signal 에 관한 행렬이 존재하고 이 행렬이 real-symmetric matrix 이며 이들의 eigenvectors 를 구할 수 있다면, eigenvector 의 선형 결합이 graph signal 의 푸리에 변환임을 의미하는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="laplacian">Laplacian</h4>
<ul>
<li><p>Graph laplacian 을 보기 전에 Laplace Operator 에 대해 살펴보도록 하겠습니다.</p>
<blockquote>
<ul>
<li>Laplace operator 는 differential operator 로, 벡터 기울기의 발산(Divergence)을 의미합니다.</li>
</ul>
</blockquote>
</li>
<li><p>Divergence가 나타내는 의미, 즉, Laplace operator가 나타내는 의미는 함수의 높고 낮음입니다.</p>
<blockquote>
<ul>
<li>이는 이계 도함수의 성질과 비슷합니다. 도함수의 미분 값이 양수면 아래로 볼록이고, 도함수의 미분 값이 음수면 위로 볼록인 것과 유사합니다.</li>
</ul>
</blockquote>
</li>
<li><p>그렇다면, graph signal 영역에서 Laplace operator 가 갖는 의미가 무엇일까요?</p>
<blockquote>
<ul>
<li>graph signal 영역에서 Laplace operator 를 적용한다는 것은, 한 노드에서의 signal 의 흩어짐 정도, 다시 말해 흐르는 정도를 알고자 하는 것입니다. 특정 노드에서 signal 이 들어왔을 때 그 signal 이 특정 노드와 연결된 노드들로 각각 얼마만큼 빠르게 흩어지는지를 알 수 있고 이는 즉 그 노드의 특징이 될 수 있는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>쉽게 말해, 한 노드의 특징은 해당 노드와 연결된 이웃 노드와의 관계라는 관점에서 표현될 수 있고, 이 표현을 위해 이웃 노드와의 차이를 이용한 것이 laplacian operator 입니다.</p>
</li>
</ul>
<h4 id="laplacian-matrix">Laplacian matrix</h4>
<ul>
<li><p>Laplacian matrix 란 graph representation 중에서 이웃 노드와의 변화 흐름을 통해 노드의 특징을 나타내는 그래프 표현이라고 생각할 수 있습니다.</p>
</li>
<li><p>이웃 노드와의 차이(variation)는 결국 노드 간의 매끄러움 정도(smoothness)를 의미합니다.</p>
<blockquote>
<ul>
<li>한 노드가 이웃 노드와의 차이가 작다는 것은 그 노드는 이웃 노드와 특성이 비슷한 경우이고, 이를 ‘매끄럽다’라고 생각할 수 있습니다. 면에, 이웃 노드와의 차이가 크다는 건 그 노드는 이웃 노드와 특성이 상이하다는 것이고 이는 ‘매끄럽지 않다’라고 생각할 수 있습니다.</li>
<li>Laplacian Matrix 는 graph 의 smoothness 와 관련이 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>이를 ‘신호’라는 관점에서 다시 생각해봅시다. 어떤 한 노드 내에서 흐르는 신호를 크게 2가지로 나눈다면, 나와 비슷한 특성을 가진 이웃 노드에서 들어오는 신호와 나와 상이한 특성을 가진 이웃 노드에서 들어오는 신호로 나눌 수 있습니다.</p>
<blockquote>
<ul>
<li>즉, 한 노드 내에 혼잡해 있는 신호는 나와 유사한 특성을 가진 노드에서 오는 신호와 나와 상이한 특성을 가진 노드에서 오는 신호의 결합으로 생각할 수 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>이는 결국 푸리에 변환과 관련된 개념입니다. 그리고 나와 유사한 속성의 노드와 상이한 속성의 노드를 나눌 수 있는 것에 관한 정보가 바로 Laplacian matrix 에 담겨져 있는 것입니다. 따라서, lapalcian matrix 를 이용한 푸리에 변환이 바로 “Graph Fourier Transform” 이며, 이는 앞서 언급한 “eigen-value decomposition” 과 관련이 있는 것입니다.</p>
</li>
<li><p>Laplacian Matrix 앞서 설명한 Degree Matrix 와 Adjacency Matrix 의 차로 표현됩니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5bbec07d-3729-4366-957b-5e19795faa8d/image.png" alt=""></p>
<h4 id="graph-fourier-transform">Graph Fourier Transform</h4>
<ul>
<li><p>그렇다면, graph fourier transform 이 왜 Laplacian matrix 를 eigen - decomposition 을 할까요?</p>
</li>
<li><p>다음 식은 노드 간의 차이의 합에 관한 식입니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/da0f8735-df45-4f4c-8823-d2a28d7db3ee/image.png" alt=""></p>
<ul>
<li><p>이는 결국 graph 의 smoothness 와 관련된 것이며, Laplacian quadratic form 으로 표현이 가능합니다. 위의 식을 최소화하게 하는 f 를 찾는다면, 특정 노드와 특성이 유사한 노드 집단과 상이한 노드 집단을 구분할 수 있습니다.</p>
</li>
<li><p>Lagrange 방정식에 의해 최적화 방정식으로 바꾸면 다음과 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/928a3076-35ee-48dc-8904-a1450a97f945/image.png" alt=""></p>
<ul>
<li>위 식을 미분하여 최소가 되게 하는 f 를 찾으면 다음과 같습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/527e3b8f-f863-43cd-b2b4-7bc0725f4638/image.png" alt=""></p>
<ul>
<li><p>위의 식은 laplacian 행렬의 eigen-value decomposition 입니다. laplacian matrix 의 eigenvector eigen vector 들이 특정 노드와 유사한 노드 집단과 상이한 노드집단을 구분하는 기준이 되고, 특히 작은 값의 eigenvalue 의 대응하는 eigenvector 일수록 graph 를 더욱 smooth 하게 나누는 기준이 됩니다.</p>
</li>
<li><p>이를 fourier transform 관점에서 해석해 봅시다.</p>
</li>
<li><p>graph의 특정 노드 signal을 노드의 작은 값의 eigenvalue 에 대응되는 eigenvector 에 사영시키면, 혼재되어 있는 signal 중 가까운 이웃 노드에서 들어오는 signal 의 성분을 추출한 것으로 볼 수 있고, 큰 값의 eigenvalue 에 대응되는 eigenvector에 사영시키면, 혼재되어 있는 signal 중 멀리 있는 상이한 노드에서 들어오는 signal의 성분을 추출한 것입니다.</p>
<blockquote>
<ul>
<li>따라서, 혼재되어 있는 graph signal 을 eigenvector의 선형 결합으로 표현하여, 여러 집단에서 들어오는 signal 의 합으로 표현할 수 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>또한 위에서, fourier transform 은 혼합 signal 을 sine 과 cosine 의 주파수의 성분으로 쪼갠 성분들의 선형 결합이라고 하였습니다. 그리고, 이 때 주파수의 성분은 삼각 함수의 직교성으로 인해, 직교 기저를 이룬다고 하였습니다.</p>
<blockquote>
<ul>
<li>마찬가지로, laplacian matrix 은 real-symmetric 행렬이어서 eigenvector 들이 직교 기저를 이룹니다.</li>
<li>즉, graph signal 을 laplacian eigenvector 행렬에 사영시키면, graph signal을 laplacian의 직교 기저들의 성분으로 분해하여 이를 합한 선형결합에 해당됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>따라서 Graph Fourier Transform 은 Laplacian 행렬의 Eigen-value decomposition 과 관련이 있게 되는 것입니다.</p>
</li>
<li><p>마지막으로, Graph Fourier Transform의 수식을 정리해보도록 하겠습니다.</p>
</li>
<li><p>Laplacian 행렬의 eigen-value decomposition은 아래와 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/83c2c80d-677f-4630-b262-1c589dce29d3/image.png" alt=""></p>
<ul>
<li>이를 이용한 graph fourier transform과 inverse graph fourier transform은 아래와 같습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/649890be-0e17-4314-9082-0c09aa2c0757/image.png" alt=""></p>
<ul>
<li>아래는 inverse fourier transform 인데, 이는 frequency domain 으로 변환된 signal 을 다시 time domain 으로 변환하는 것입니다.</li>
</ul>
<h3 id="다시-spectral-convolutional-network">다시, Spectral Convolutional Network</h3>
<ul>
<li><p>graph convolution 은 어떤 graph의 특징을 추출해 낼 수 있는 filter 를 학습으로 얻고자 하는 것입니다.</p>
</li>
<li><p>convolution theorem 의 핵심은 time 영역에서의 signal 과 시스템 함수와의 convolution 연산은 각각 frequency 영역으로 변환한 뒤의 곱과 같다는 것이었습니다.</p>
<blockquote>
<ul>
<li>frequency 영역에서의 convolution 은 단순 곱으로 계산될 수 있기 때문에 훨씬 편리합니다.</li>
</ul>
</blockquote>
</li>
<li><p>마찬가지로 graph 영역에서도 graph signal 을 fourier transform 으로 frequency 도메인으로 바꿔서 계산하면 편리합니다. 또한 노드와 가까이 있는 이웃 노드에서부터 멀리 떨어져 있는 노드에서 오는 신호까지 모두 고려하여 graph signal 의 특징을 추출할 수 있게 되는 것입니다.</p>
<blockquote>
<ul>
<li>이것이 바로 ‘Spectral Graph Convolution’ 입니다.</li>
</ul>
</blockquote>
</li>
<li><p>Spectral Graph Convolution 식은 아래와 같습니다.</p>
<blockquote>
<ul>
<li>이 식에서 학습할 filter는 g 입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3a1dd7ed-c157-421e-98bf-b082abccb2a7/image.png" alt=""></p>
<ul>
<li>이 식을 다음과 같이 가정(학습할 filter가 대각요소만 있다고 가정)하면,</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/54f11e5f-5501-4935-9a1a-cc5b9914533e/image.png" alt=""></p>
<ul>
<li>다음과 같은 식이 됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/80c9d9e2-b076-4da7-a02d-007076e0aa69/image.png" alt=""></p>
<h3 id="graph-pooling">Graph Pooling</h3>
<ul>
<li><p>그러나 Spatial Convolutional Network 와 Spectral Convolutional Network 모두 Scalability issue 가 존재했습니다.</p>
<blockquote>
<ul>
<li>이를 방지하기 위해, Graph Pooling 을 도입하였습니다.</li>
</ul>
</blockquote>
</li>
<li><p>Pooling 은 CNN 에서 계산의 효율성을 높이기 위해 사용하였는데, 이를 Graph 에도 사용해보고자 한 것입니다.</p>
<blockquote>
<ul>
<li>Pooling 을 하는 가장 큰 이유는 입력 데이터의 차원 감소입니다. 또한, 오버피팅을 방지하는 효과도 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7fe7cf39-e109-4193-8f76-4ea113887342/image.png" alt=""></p>
<h2 id="variational-graph-auto-encoder">Variational Graph Auto Encoder</h2>
<h3 id="auto-encoder">Auto Encoder</h3>
<ul>
<li><p>Auto Encoder 는 딥러닝에서 가장 대표적인 unsupervised learning 방식 중 하나입니다.</p>
</li>
<li><p>Auto Encoder 에 대해서는 다음 링크를 참고해주시면 감사하겠습니다.</p>
<blockquote>
<ul>
<li><a href="https://deepinsight.tistory.com/126">AutoEncoder의 모든 것</a></li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="다시-variational-graph-auto-encoder">다시, Variational Graph Auto Encoder</h2>
<ul>
<li>Input 을 Graph 의 형태로 입력 받아 실행하려는 시도가 바로 GAE 입니다.<blockquote>
<ul>
<li>GAE 에서는 주로 VAE 를 사용합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a6651585-37ff-475c-808b-b4b05c68a904/image.png" alt=""></p>
<ul>
<li>활용 분야로는 Block Planner 가 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3bb624c1-cb2f-4358-a374-ab9a334904ad/image.png" alt=""></p>
<h2 id="spatial---temporal-graph-neural-network">Spatial - Temporal Graph Neural Network</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/9a189dc5-f6c4-487a-b7f3-f6baf987ef29/image.png" alt=""></p>
<ul>
<li><p>Spatial Convolution 과 Temporal Convolution 을 결합한 GNN 입니다.</p>
<blockquote>
<ul>
<li>시간에 따라 feature 가 달라지는 Graph 를 활용할 때 이점을 가집니다.</li>
</ul>
</blockquote>
</li>
<li><p>활용 분야로는 Motion puzzle 이 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d5eeff48-53b3-40e3-b709-2bdc9ac90dfa/image.png" alt=""></p>
<h1 id="referenece">Referenece</h1>
<ul>
<li><a href="https://www.theteams.kr/teams/2849/post/73222">GNN 소개 - 기초부터 논문까지</a></li>
<li><a href="https://ok-lab.tistory.com/169">Graph Neural Network 시작하기</a></li>
<li><a href="https://wonbae.github.io/2021-02-26-Graph9-GNN/">그래프 신경망이란 무엇인가 (기본)</a></li>
<li><a href="https://thejb.ai/comprehensive-gnns-1/">Graph Neural Networks 개념정리 1 - 개요</a></li>
<li><a href="https://thejb.ai/comprehensive-gnns-2/">Graph Neural Networks 개념정리 2 - Recurrent GNN</a></li>
<li><a href="https://talkingaboutme.tistory.com/entry/DL-Convolution%EC%9D%98-%EC%A0%95%EC%9D%98">[DL] Convolution의 정의</a></li>
<li><a href="https://ralasun.github.io/deep%20learning/2021/02/15/gcn/#:~:text=Graph%20convolution%EC%9D%80%20%ED%81%AC%EA%B2%8C%202%EA%B0%80%EC%A7%80%20%EB%B0%A9%EB%B2%95%EC%9D%B4%20%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4.%20Spatial%20graph,%EA%B0%80%EA%B9%9D%EA%B2%8C%20%EC%97%B0%EA%B2%B0%EB%90%9C%20%EC%9D%B4%EC%9B%83%20%EB%85%B8%EB%93%9C%EB%93%A4%EC%97%90%20%ED%95%9C%ED%95%B4%EC%84%9C%20convolution%20%EC%97%B0%EC%82%B0%EC%9D%84%20%EC%88%98%ED%96%89%ED%95%A9%EB%8B%88%EB%8B%A4.">Graph Convolutional Network에 대하여 - Spectral Graph Convolution</a></li>
<li><a href="https://towardsdatascience.com/tutorial-on-variational-graph-auto-encoders-da9333281129">Tutorial on Variational Graph Auto-Encoders</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RL] MDP를 알 때의 플래닝]]></title>
            <link>https://velog.io/@hkun_ho/RL-MDP%EB%A5%BC-%EC%95%8C-%EB%95%8C%EC%9D%98-%ED%94%8C%EB%9E%98%EB%8B%9D</link>
            <guid>https://velog.io/@hkun_ho/RL-MDP%EB%A5%BC-%EC%95%8C-%EB%95%8C%EC%9D%98-%ED%94%8C%EB%9E%98%EB%8B%9D</guid>
            <pubDate>Thu, 12 Jan 2023 16:57:30 GMT</pubDate>
            <description><![CDATA[<h1 id="시작하기-전에">시작하기 전에</h1>
<ul>
<li><p>이번에 다룰 내용은 다음 두 조건을 만족하는 상황입니다.</p>
<blockquote>
<ol>
<li>작은 문제 (상태 집합 S 나 액션 집합 A 의 크기가 작은 경우)</li>
<li>MDP 를 알 때</li>
</ol>
</blockquote>
</li>
<li><p>이번에 다룰 문제는 작은 문제이기 때문에, <em><strong>테이블 기반 방법론</strong></em> 에 기반합니다.</p>
<blockquote>
<ul>
<li>테이블 기반 방법론이란 모든 상태 s 혹은 상태와 액션의 페어 (s, a) 에 대한 테이블을 만들어서 값을 기록해 놓고, 그 값을 조금씩 업데이트하는 방식을 의미합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="밸류-평가하기---반복적-정책-평가">밸류 평가하기 - 반복적 정책 평가</h1>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8552782f-d60e-4d8c-a692-a10c9fdef03d/image.jpg" alt=""></p>
<ul>
<li><p>이 문제는 4방향 랜덤이라는 정책 함수 π 가 주어졌고 이 때 각 상태 s 에 대한 가치 함수 v(s) 를 구하는 전형적인 prediction 문제입니다.</p>
</li>
<li><p>이제 <em><strong>반복적 정책 평가</strong></em> 라는 방법론을 통해 문제를 해결할 수 있습니다.</p>
<blockquote>
<ul>
<li>반복적 정책 평가는 테이블의 값들을 초기화한 후, 벨만 기대 방정식을 반복적으로 사용하여 테이블에 적어 놓은 값을 조금씩 업데이트해 나가는 방법론입니다.</li>
</ul>
</blockquote>
</li>
<li><p>또한 이 방법론은 MDP 에 대한 모든 정보를 알 때 사용할 수 있습니다.</p>
<blockquote>
<ul>
<li>보상은 어느 액션을 하든 -1이므로 r(s, a) = -1 로 모든 액션에 대해 고정입니다.</li>
<li>또한 환경에 확률적인 요소가 없기 때문에 전이 확률 P(s, a, s&#39;) 은 모두 1입니다.</li>
</ul>
</blockquote>
</li>
<li><p>본 문제에서 편의상 γ=1 로 계산하여 반복적 정책 평가 방법론을 단계별로 나누어 자세히 설명하겠습니다.</p>
</li>
</ul>
<h2 id="1-테이블-초기화">1. 테이블 초기화</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0caee550-7f0d-4e76-a1d2-af4253044350/image.jpg" alt=""></p>
<ul>
<li><p>먼저 테이블을 초기화하는 것으로부터 시작합니다.</p>
<blockquote>
<ul>
<li>어떤 값으로 초기화해도 상관없지만, 일단 0으로 초기화합시다.</li>
</ul>
</blockquote>
</li>
<li><p>지금은 아무 의미가 없는 값이지만 반복적 과정을 거치면서 점차 실제 각 상태의 가치에 해당하는 값으로 수렴해 갈 것입니다.</p>
</li>
</ul>
<h2 id="2-한-상태의-값을-업데이트">2. 한 상태의 값을 업데이트</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/19e641d2-0bbb-4e26-a1b7-412ede63f132/image.jpg" alt=""></p>
<ul>
<li><p>일단 16개의 값들 중 1개의 값에 대해 어떻게 업데이트하는지 설명하겠습니다.</p>
<blockquote>
<ul>
<li>위 그림에서 파란색으로 칠해진 상태 s5 를 생각해 봅시다.</li>
</ul>
</blockquote>
</li>
<li><p>우리는 MDP 를 알기 때문에 이 상태의 다음 상태의 후보가 동서남북으로 인접해 있는 노란색 상태들인 것을 알 수 있습니다.</p>
<blockquote>
<ul>
<li>현재 상태와 다음 상태의 밸류 사이 관계식인 벨만 기대 방정식의 2단계 수식을 사용합시다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e5ddbbad-03c5-4ca9-b275-dda189a34fc9/image.png" alt=""></p>
<ul>
<li><p>여기서 정책 함수는 4방향으로 균등하게 랜덤하므로 π(aㅣs) 는 모든 액션에 대해 각각 0.25입니다.</p>
</li>
<li><p>이를 토대로 실제 값을 대입하여 다음과 같이 간단하게 계산할 수 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ffcd0b58-086f-49c3-b4ed-7dec4246b09f/image.jpg" alt=""></p>
<ul>
<li><p>따라서 테이블의 s5 자리 값을 -1.0으로 업데이트합니다.</p>
</li>
<li><p>임의로 정해진 0이라는 값을 이용해 현재 상태의 값을 업데이트하는 게 왜 더 정확한 값이 디는 것일까요?</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/cec36aad-d3f1-4241-b8c4-a96be60af753/image.jpg" alt=""></p>
<ul>
<li><p>우리는 다음 상태의 값만 가지고 업데이트 하는 것이 아니라, 보상이라는 실제 환경이 주는 정확한 시그널을 섞어서 업데이트합니다.</p>
<blockquote>
<ul>
<li>따라서 처음에는 무의미 하더라도 점차 실제 값에 가까워지게 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>게다가 다음 상태의 값이 항상 엉터리인 것은 아닙니다.</p>
<blockquote>
<ul>
<li>오른쪽 맨 아래 상태인 &quot;종료 상태&quot;의 경우 가치가 0으로 초기화 되어있는데, 종료 상태의 입장에서는 그 뒤의 미래라는 것이 존재하지 않기 때문에 정확한 값입니다.</li>
</ul>
</blockquote>
</li>
<li><p>따라서 마지막 상태에 인접한 상태들의 경우, 더 유의미한 시그널을 통해 업데이트가 이루어집니다.</p>
</li>
</ul>
<h2 id="3-모든-상태에-대해-2의-과정을-적용">3. 모든 상태에 대해 2의 과정을 적용</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ddb07d3b-a8fc-4099-befe-242c43199706/image.jpg" alt=""></p>
<ul>
<li><p>마지막 상태를 제외한 15개의 상태를 업데이트합니다.</p>
<blockquote>
<ul>
<li>참고로 가장자리에서 바깥을 향하는 액션을 취하면 같은 자리에 그대로 남게 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>모든 상태의 값을 업데이트하고 나면 비로소 한 바퀴를 돈 것입니다.</p>
<blockquote>
<ul>
<li>종료 상태를 제외한 모든 상태의 값이 -1로 업데이트되었습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="4-앞의-23-과정을-계속해서-반복">4. 앞의 2~3 과정을 계속해서 반복</h2>
<ul>
<li>이렇게 한 번 테이블의 모든 값을 업데이트하는 과정을 여러 번 반복합니다.<blockquote>
<ul>
<li>몇 번 반복했는지를 k로 표기하겠습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6b9d9d84-6062-4f03-9a9b-585a4a0a523e/image.jpg" alt=""></p>
<ul>
<li>이 과정을 계속하다 보면 각 상태의 값이 어떤 값에 수렴하게 됩니다.<blockquote>
<ul>
<li>그 값이 바로 해당 상태의 실제 밸류입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="정리">정리</h2>
<ul>
<li><p>지금까지 우리는 정책 π 가 주어졌을 때 각 상태의 밸류를 계산하는 법을 배웠습니다.</p>
</li>
<li><p>MDP 에 대한 정보를 알고 그 크기가 충분히 작다면, 그 어떤 정책 함수에 대해서도 해당 정책 함수를 따랐을 때 각 상태의 밸류를 구할 수 있게 됩니다.</p>
</li>
</ul>
<h1 id="최고의-정책-찾기---정책-이터레이션">최고의 정책 찾기 - 정책 이터레이션</h1>
<ul>
<li><p>정책 이터레이션은 정책 평가와 정책 개선을 번갈아 수행하여 정책이 수렴할 때까지 반복하는 방법론입니다.</p>
</li>
<li><p>앞서 배운 반복적 정책 평가의 결과를 잠시 생각해 봅시다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4e6ea7bc-578e-4854-a66d-178021a72595/image.jpg" alt=""></p>
<ul>
<li><p>여기서 우리가 파란색 상태인 s5 에 있다고 생각해 봅시다.</p>
<blockquote>
<ul>
<li>s5 에서는 동쪽 혹은 남쪽으로 움직이는 a 를 선택하는 것이 최선입니다.</li>
</ul>
</blockquote>
</li>
<li><p>따라서 다음과 같은 정책 π&#39; 을 생각해볼 수 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7f2e31e8-7c70-47f2-9a03-25bcc6092055/image.jpg" alt=""></p>
<ul>
<li><p>이렇게 만들어진 π&#39; 은 원래의 정책 π 보다는 나은 정책입니다.</p>
<blockquote>
<ul>
<li>이러한 정책을 <em><strong>그리디 정책</strong></em> 이라고 합니다. </li>
</ul>
</blockquote>
</li>
<li><p>여기서 <em><strong>그리디</strong></em> 는 탐욕스럽다는 뜻으로 먼 미래까지 보지 않고 그저 눈 앞의 이익을 최대화하는 선택을 취하는 방식을 뜻합니다.</p>
</li>
<li><p>그러면 재미있는 결과를 얻게 됩니다.</p>
<blockquote>
<ul>
<li>바로 s5 에서의 그리디 정책이 s5 에서의 최적 정책과 일치하는 것이죠.</li>
</ul>
</blockquote>
</li>
<li><p>요약하면 이상한 정책(랜덤 정책)의 가치를 평가했을 뿐인데 s5 에서의 더 나은 정책을 알게 된 것입니다. 그렇다면 마찬가지 방법으로 모든 상태에서 더 나은 정책을 알 수 있지 않을까요?</p>
</li>
<li><p>s5 뿐만 아니라 모든 상태에 대해 그리디 정책을 표기한 결과는 다음 그림과 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/fd455912-182f-4170-8e95-2fefe3c0c6a1/image.jpg" alt=""></p>
<ul>
<li><p>놀랍게도 모든 상태에서 그리디 액션을 택했을 뿐인데 더 나은 정책 π&#39; 을 얻었습니다.</p>
</li>
<li><p>본 예시에서는 π&#39; 이 최적 정책과 일치하는데 이런 경우는 많지 않습니다.</p>
<blockquote>
<ul>
<li>대개는 이전 정책에 비해 소폭 향상되는 정도입니다.</li>
</ul>
</blockquote>
</li>
<li><p>여기서 중요한 부분은 π&#39; 이 π 에 비해 개선되었다는 점입니다.</p>
<blockquote>
<ul>
<li>이것이 바로 이번에 배울 <em><strong>정책 이터레이션</strong></em> 의 핵심입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="평가와-개선의-반복">평가와 개선의 반복</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/99d7635d-8739-47f0-9f2d-bba22ba5ae89/image.jpg" alt=""></p>
<ul>
<li><p>정책 이터레이션은 총 2단계로 이루어져 있습니다.</p>
<blockquote>
<ol>
<li>정책 평가 : 고정된 π 에 대해 &quot;반복적 정책 평가&quot; 방법론을 사용해 각 상태의 밸류를 구합니다.</li>
<li>정책 개선 : 새로운 정책(그리디 정책) π&#39; 를 생성합니다.</li>
</ol>
</blockquote>
</li>
<li><p>그리고 생성된 π&#39; 에 대해 다시 정책 평가를 진행합니다.</p>
<blockquote>
<ul>
<li>즉, 정책의 평가와 개선을 반복하는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>그러다보면 어느 순간 정책도 변하지 않고, 그에 따른 가치도 변하지 않는 단계에 도달하게 됩니다.</p>
<blockquote>
<ul>
<li>이렇게 수렴하는 곳이 바로 <em><strong>최적 정책</strong></em> 과 <em><strong>최적 가치</strong></em> 가 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>참고로, 그리디 정책 π&#39; 는 기존 정책 π 에 비해 나은 정책으로 이어집니다.</p>
<blockquote>
<ul>
<li>이는 보장된 사실이므로 안심하셔도 좋습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="정책-평가-부분을-간소화하기">정책 평가 부분을 간소화하기</h2>
<ul>
<li>정책 이터레이션은 <em><strong>루프</strong></em> 안에 루프가 있기 때문에 많은 연산을 필요로 합니다. 이 과정을 풀어서 도식화하면 다음 그림과 같습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e0dc37c9-9825-48ac-89d7-8ddbf724f7e7/image.jpg" alt=""></p>
<ul>
<li><p>위 루프에서 연산을 가장 많이 필요로 하는 단계는 사실 &quot;정책 개선&quot; 단계 보다는 &quot;정책 평가&quot; 단계입니다.</p>
<blockquote>
<ul>
<li>평가 단계에서는 &quot;반복적 정책 평가&quot; 방법을 사용하기 때문에 평가하는 데에도 여러 스텝이 필요합니다.</li>
</ul>
</blockquote>
</li>
<li><p>그런데 과연 평가를 끝까지 해야할까요?</p>
<blockquote>
<ul>
<li>우리의 목적은 최고의 정책을 찾는 것이지 정확한 가치를 평가하는 것이 아닙니다.</li>
<li>실제로 정책 이터레이션에서는 가치 함수가 오로지 그리디 정책을 찾는 데에만 쓰일 뿐 테이블에 적혀 있는 구체적 값이 사용되지는 않습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0a631c9e-9bb5-4fe2-bfbb-ca4d5ebadc83/image.jpg" alt=""></p>
<ul>
<li><p>위의 예시에서는 6번만 업데이트해도 그리디 정책이 이미 최적 정책에 도달하게 됩니다.</p>
</li>
<li><p>심지어 극단적으로는 단 한 번만 업데이트해도 됩니다.</p>
<blockquote>
<ul>
<li>그리디 정책이 현재의 정책과 조금이라도 다르기만 하면 일단은 &quot;개선&quot;할 수 있고, &quot;개선&quot;하여 새로운 정책을 얻은 순간 이전에 구했던 가치 테이블은 버려지게 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>그래서 극단적으로 정책 평가 단계에서 반복적 정책 평가를 딱 k=1 까지만 진행하도록 하겠습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7678cddd-e261-4acc-bd3d-2d74b9f6af6a/image.jpg" alt=""></p>
<ul>
<li><p>한결 간단해졌습니다.</p>
</li>
<li><p>요점은 정책 평가 단계에서 가치가 수렴할 때까지 과정을 반복하지 않아도 된다는 것입니다.</p>
<blockquote>
<ul>
<li>간결해진 정책 이터레이션을 통해 우리는 더욱 빠르게 평가와 개선을 진행할 수 있고, 그만큼 빠르게 최적 정책을 찾을 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="최고의-정책-찾기---밸류-이터레이션">최고의 정책 찾기 - 밸류 이터레이션</h1>
<ul>
<li>밸류 이터레이션은 오로지 최적 정책이 만들어내는 최적 밸류 하나만 바라보고 달려갑니다.<blockquote>
<ul>
<li>이는 벨만 최적 방정식을 이용해 단번에 최적의 정책을 찾습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/bc5d5279-e61f-4cdc-8b09-34c6efabd7f4/image.jpg" alt=""></p>
<ul>
<li><p>우선 테이블을 초기화합니다.</p>
</li>
<li><p>정책 이터레이션에서 봤던 그림과 유사하지만 테이블에 담겨 있는 값들은 이번에는 다른 의미를 갖고 있습니다.</p>
<blockquote>
<ul>
<li>정책 이터레이션에서는 해당 평가 단계에서 사용하는 정책 π 의 밸류였지만, 여기서는 최적 정책 π* 의 밸류를 뜻합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a33488a6-8ad4-4465-94f3-cb53a6479faa/image.jpg" alt=""></p>
<ul>
<li><p>이번에도 먼저 한 칸 s5 의 값을 업데이트해 봅니다.</p>
</li>
<li><p>벨만 최적 방정식 2단계를 사용하여 s5 의 최적 가치 v*(s)를 계산해보면 다음과 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a01daaa2-6378-40e6-9c78-e817dc2b5c92/image.jpg" alt=""></p>
<ul>
<li>테이블의 s5 에 해당하는 값을 -1.0으로 업데이트해 줍니다.<blockquote>
<ul>
<li>같은 방식을 모든 칸에 대해 적용하면 다음과 그림과 같습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2ada0153-b1c8-444e-a388-97d307bf3bc2/image.jpg" alt=""></p>
<ul>
<li>같은 방식을 계속해서 반복하면 다음 그림과 같습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/118633b1-1ee2-4b5e-86a7-d4965b7d2a1f/image.jpg" alt=""></p>
<ul>
<li><p>테이블의 값들이 수렴하였고, 이 값은 각 상태의 최적 밸류를 의미합니다.</p>
<blockquote>
<ul>
<li>이는 우리의 직관과 일치합니다.</li>
</ul>
</blockquote>
</li>
<li><p>위 상황에서는 최적 밸류를 알면 최적 정책을 곧바로 얻을 수 있습니다.</p>
<blockquote>
<ul>
<li>최적 밸류를 높이는 방향으로 그리디 정책을 시행하면 그것이 최적 정책이기 때문입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="reference">Reference</h1>
<ul>
<li>노승은(2020), 바닥부터 배우는 강화 학습</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RL] 벨만 방정식]]></title>
            <link>https://velog.io/@hkun_ho/RL-%EB%B2%A8%EB%A7%8C-%EB%B0%A9%EC%A0%95%EC%8B%9D</link>
            <guid>https://velog.io/@hkun_ho/RL-%EB%B2%A8%EB%A7%8C-%EB%B0%A9%EC%A0%95%EC%8B%9D</guid>
            <pubDate>Thu, 12 Jan 2023 16:56:07 GMT</pubDate>
            <description><![CDATA[<h1 id="벨만-방정식">벨만 방정식</h1>
<ul>
<li><p>시점 t 에서의 밸류와 시점 t+1 에서의 밸류 사이의 관계를 다루고 있으며 또 가치 함수와 정책 함수 사이의 관계도 다루고 있습니다.</p>
</li>
<li><p>벨만 방정식에는 <em><strong>벨만 기대 방정식</strong></em> 과 <em><strong>벨만 최적 방정식</strong></em> 이 있습니다.</p>
</li>
</ul>
<h2 id="재귀-함수">재귀 함수</h2>
<ul>
<li>벨만 방정식은 기본적으로 재귀적 관계에 대한 식입니다.<blockquote>
<ul>
<li>재귀 함수는 자기 자신을 호출하는 함수를 가리킵니다.</li>
<li>다시 말해, 재귀 함수는 자기 자신과의 관계를 이용해 자기 자신을 표현합니다.<blockquote>
<ul>
<li>대표적인 예시로 피보나치 수열이 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="벨만-기대-방정식">벨만 기대 방정식</h1>
<ul>
<li>벨만 기대 방정식을 편의상 세 단계로 나누겠습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/f56dcd66-95c2-4a16-96e4-f798e2124216/image.jpg" alt=""></p>
<h2 id="0단계">0단계</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/055d45f3-181b-4612-a984-bf0a1c67e66b/image.jpg" alt=""></p>
<ul>
<li>이 식은 현재 상태의 밸류와 다음 상태의 밸류 사이 관계를 나타내고 있습니다.<blockquote>
<ul>
<li>위와 같은 관계가 성립하는 이유를 알아보기 위해 vπ 의 정의부터 생각해보겠습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/68c14ffd-6426-469a-9140-0f549404cc8d/image.jpg" alt=""></p>
<ul>
<li>수식으로 보면 이와 같이 증명할 수 있습니다.<blockquote>
<ul>
<li>말로 풀어 설명하자면 현재 상태 st의 밸류는 리턴의 기댓값인데 이를 쪼개서 생각해 보자는 것입니다.</li>
<li>다시 말해, 리턴이 먼저 한 스텝만큼 진행하여 보상을 받고, 그 다음 상태인 s(t+1) 부터 미래에 받을 보상을 더해줘도 똑같지 않겠느냐 하는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="1단계">1단계</h2>
<ul>
<li>1단계는 액션 밸류 qπ(s, a) 를 이용하여 상태 밸류 vπ(s) 를 표현하는 첫 번째 식과 vπ(s) 를 이용하여 qπ(s, a) 를 표현하는 두 번째 식으로 이루어져 있습니다.</li>
</ul>
<h3 id="qπ-를-이용해-vπ-계산하기">qπ 를 이용해 vπ 계산하기</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4f01eceb-c208-46ea-ad79-1c4589bc7296/image.jpg" alt=""></p>
<ul>
<li>위의 식을 이해하기 위해 다음 그림을 참고해 봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5a2f0682-e10b-4cf2-95ee-4d5efa833ca7/image.jpg" alt=""></p>
<ul>
<li>위와 같이<blockquote>
<ol>
<li>정책 π 가 두 액션을 선택할 확률을 알고,</li>
<li>액션 밸류 q 의 값을 알고 있다면,</li>
</ol>
</blockquote>
</li>
</ul>
<p>s 의 밸류를 구할 수 있습니다.</p>
<blockquote>
<ul>
<li>이 때, 정책은 π 로 고정되어 있습니다.</li>
</ul>
</blockquote>
<ul>
<li>이를 식으로 풀어 써보면 다음과 같습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/6c0f7338-f82c-4e24-a55f-a7810d9ed5b5/image.jpg" alt=""></p>
<ul>
<li>정리해보면 어떤 상태에서 선택할 수 있는 모든 액션의 밸류를 알고 있다면, 이를 이용해 해당 상태의 밸류를 계산할 수 있습니다.<blockquote>
<ul>
<li>액션의 밸류에 액션을 선택할 확률을 곱해서 시그마를 이용해 모두 더해주는 방식입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="vπ-를-이용해-qπ-계산하기">vπ 를 이용해 qπ 계산하기</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d5991ec6-1f66-4ee6-9f21-d9e706cda7c4/image.jpg" alt=""></p>
<ul>
<li>이번에는 반대로, 상태의 밸류를 이용해 액션의 밸류를 평가해보겠습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/fd3bff86-62d2-4dac-bf78-22b542b1baf7/image.jpg" alt=""></p>
<ul>
<li><p>위와 같이</p>
<blockquote>
<ol>
<li>a1 을 선택하자마자 얻는 보상의 값을 알고,</li>
<li>액션 a1을 선택하면 다음 상태가 어디가 될지 그 각각에 대한 전이 확률도 알고,</li>
<li>각 상태의 밸류 또한 알고 있다면,</li>
</ol>
</blockquote>
</li>
<li><p>상태 s 의 밸류를 구할 수 있습니다.</p>
</li>
<li><p>우선 받는 보상을 더해주고, 그 다음에 도달하게 되는 상태의 밸류와 그 확률을 곱해서 더해주면 됩니다. 식으로 표현해보면 다음과 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0d3e4286-638b-4e06-8a34-6a50fc83ee91/image.jpg" alt=""></p>
<h2 id="2단계">2단계</h2>
<ul>
<li><p>2단계는 앞서 설명한 1단계의 수식들을 대입만 하면 끝입니다.</p>
</li>
<li><p>1단계의 qπ 에 대한 식을 vπ 에 대한 식에 대입하면 다음과 같은 결과를 얻습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/252f6c88-5ba4-4c6a-a492-4944fa75e7fd/image.jpg" alt=""></p>
<ul>
<li>반대로 vπ 에 대한 식을 qπ 에 대한 식에 대입하면 다음과 같은 결과를 얻습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8eccbedc-f40f-47fc-81d5-9ae5acd60bbf/image.jpg" alt=""></p>
<ul>
<li>이렇게 하여 얻은 최종 수식은 각각 다음과 같습니다.<blockquote>
<ul>
<li>바로 벨만 기대 방정식 2단계 수식입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/21e2e0a6-5501-41fa-8ceb-f5a35339365c/image.jpg" alt=""></p>
<h2 id="정리">정리</h2>
<ul>
<li><p>그래서 이러한 복잡한 식이 무엇을 위한 수식일까요?</p>
</li>
<li><p>최종적으로 얻어진 식 중에서 vπ(s) 에 대한 식을 벨만 기대 방정식 0단계의 식과 나란히 써 보겠습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/619fda7c-08d9-4c22-ad89-b22dee6d7a5b/image.jpg" alt=""></p>
<ul>
<li><p>0단계 식은 현재 상태의 밸류와 다음 상태의 밸류를 기댓값 연산자를 통해 연결해 놓은 식이었습니다.</p>
<blockquote>
<ul>
<li>그래서 그 기댓값을 어떻게 계산하지? 에 대한 대답이 바로 벨만 기대 방정식 2단계 수식이 되는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>2단계 식을 계산하기 위해서 다음 2가지를 반드시 알아야 합니다.</p>
<blockquote>
<ul>
<li>보상 함수 r(s, a) : 각 상태에서 액션을 선택하면 얻는 보상</li>
<li>전이 확률 P(s, a, s&#39;) : 각 상태에서 액션을 선택하면 다음 상태가 어디가 될지에 관한 확률 분포</li>
</ul>
</blockquote>
</li>
<li><p>보상 함수와 전이 확률은 환경의 일부이므로, 이 2가지에 대한 정보를 알 때 &quot;MDP 를 안다&quot; 고 표현합니다.</p>
<blockquote>
<ul>
<li>이런 종류의 접근법을 <em><strong>모델 기반</strong></em> 혹은 <em><strong>플래닝</strong></em> 이라고 합니다.</li>
<li><blockquote>
<p>이 때에는 벨만 기대 방정식 중에서 2단계 식을 이용합니다.</p>
</blockquote>
</li>
</ul>
</blockquote>
</li>
<li><p>반대로 MDP 에 대한 정보를 모를 때, <em><strong>경험</strong></em> 을 통해 학습하는 접근법을 <em><strong>모델-프리</strong></em> 접근법이라고 합니다.</p>
<blockquote>
<p>-&gt; 이 때에는 벨만 기대 방정식 중에서 0단계를 이용합니다.</p>
</blockquote>
</li>
</ul>
<h1 id="벨만-최적-방정식">벨만 최적 방정식</h1>
<h2 id="최적-밸류와-최적-정책">최적 밸류와 최적 정책</h2>
<ul>
<li><p>벨만 기대 방정식이 vπ(s) 와 qπ(s, a) 에 대한 수식이라면 벨만 최적 방정식은 v＊(s) 와 q＊(s, a) 에 대한 수식입니다.</p>
<blockquote>
<ul>
<li><em><strong>v＊(s) 와 q＊(s, a)</strong></em> 는 최적 밸류 에 대한 함수입니다.</li>
</ul>
</blockquote>
</li>
<li><p>최적 밸류의 정의는 다음과 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5abb52ba-5810-4bcf-95d1-3090e0bafc6b/image.jpg" alt=""></p>
<ul>
<li><p>말로 풀어서 설명해보면, 어떤 MDP 가 주어졌을 때 그 MDP 안에 존재하는 모든 π 중에서 가장 좋은 π 를 선택하여 계산한 밸류가 곧 최적 밸류 v*(s) 라는 뜻입니다.</p>
</li>
<li><p>만약 상태별로 가장 높은 밸류를 주는 정책이 모두 다르면 어떡할까요?</p>
<blockquote>
<ul>
<li>각각의 상태에 대해 서로 다른 정책을 따르는 새로운 정책 π* 를 정의하면 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>정책 π* 를 따르면 모든 상태에 대해 그 어떤 정책보다도 높은 밸류를 얻게 됩니다.</p>
<blockquote>
<ul>
<li>이러한 정책 π* 를 <em><strong>최적 정책</strong></em> 이라고 부릅니다.</li>
</ul>
</blockquote>
</li>
<li><p>최적의 정책만 정의되고 나면 최적의 밸류, 최적의 액션 밸류는 다음과 같은 등식을 만족합니다.</p>
<blockquote>
<ul>
<li>최적의 정책 : π*</li>
<li>최적의 밸류 : v＊(s) = vπ＊(s) (π* 를 따랐을 때의 밸류)</li>
<li>최적의 액션 밸류 : q＊(s, a) = qπ＊(s, a) (π* 를 따랐을 때의 액션 밸류)</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="다시-벨만-최적-방정식">다시, 벨만 최적 방정식</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/37b8540e-4873-4828-ac8e-d7e1bf3f31b0/image.jpg" alt=""></p>
<h3 id="0단계-1">0단계</h3>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5c6de9de-c343-4200-a85a-ad54cae87343/image.jpg" alt=""></p>
<ul>
<li><p>이 식은 벨만 기대 방정식의 0단계 수식과 같은 취지의 식입니다.</p>
<blockquote>
<ul>
<li>상태 s 에서의 최적 밸류는 일단 한 스텝만큼 진행하여 보상을 받고, 다음 상태인 s&#39; 의 최적 밸류를 더해줘도 똑같지 않겠느냐 하는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>벨만 기대 방정식 0단계 수식과 비교하여 눈여겨볼 부분은 Eπ 가 E 로 바뀌었다는 점입니다.</p>
<blockquote>
<ul>
<li>원래는 주어진 π 가 있어서 π 가 액션을 선택했지만 이제는 할 수 있는 모든 액션들 중에 E[ r+γv*(s&#39;) ] 의 값을 가장 크게 하는 액션 a 를 선택해야 하기 때문에 π 의 역할은 없어지게 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="1단계-1">1단계</h3>
<ul>
<li>벨만 기대 방정식과 마찬가지로 1단계는 최적 액션 밸류 q＊(s, a) 를 이용하여 최적 상태 밸류 v＊(s) 를 표현하는 첫 번째 식과 v＊(s) 를 이용하여 q＊(s, a) 를 표현하는 두 번째 식으로 이루어져 있습니다.</li>
</ul>
<h4 id="q＊-를-이용해-v＊-계산하기">q＊ 를 이용해 v＊ 계산하기</h4>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e0588a7c-ffcb-48fb-ad06-530365130339/image.jpg" alt=""></p>
<ul>
<li><p>상태 s 의 최적 밸류는 s 에서 선택할 수 있는 액션들 중에 밸류가 가장 높은 액션의 밸류와 같다는 뜻입니다.</p>
</li>
<li><p>각 액션을 선택할 확률을 고려하지 않아도 되는 이유는 무엇일까요?</p>
<blockquote>
<ul>
<li>100퍼 센트의 확률로 최적의 액션 a 를 선택하는 것이 최적의 밸류를 얻게 해주기 때문입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="v＊-를-이용해-q＊-계산하기">v＊ 를 이용해 q＊ 계산하기</h4>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a5c6a8b4-4464-4475-9361-28bcddf34857/image.jpg" alt=""></p>
<ul>
<li>이 식은 벨만 기대 방정식의 1단계와 완전히 같은 구조입니다.<blockquote>
<ul>
<li>다만 원래의 π 자리에 * 가 들어갔다는 점만 다릅니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="2단계-1">2단계</h3>
<ul>
<li>2단계 수식 또한 벨만 기대 방정식 때와 마찬가지로 1단계의 수식 2개를 조합하여 만들 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c52b6b60-73a5-4433-a7ed-a41936c50154/image.jpg" alt=""></p>
<ul>
<li><p>이 관계식을 이용해 MDP 를 알 때에 최적 밸류를 구할 수 있습니다.</p>
</li>
<li><p>반대로 v＊(s) 의 식을 q＊(s, a) 의 식에 대입하면 벨만 최적 방정식 2단계의 두 번째 식을 얻게 됩니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c9de8df0-84e8-4916-8a86-63d838558170/image.jpg" alt=""></p>
<ul>
<li>최종적으로 얻은 v＊(s) 와 q＊(s, a) 에 대한 식을 정리하면 다음과 같습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/1bf219ec-69fc-435b-87f4-58384fea36a6/image.jpg" alt=""></p>
<h1 id="정리-1">정리</h1>
<ul>
<li><p>무언가 정책 π 가 주어져 있고, π 를 평가하고 싶을 때에는 벨만 기대 방정식을 사용합니다.</p>
</li>
<li><p>최적의 밸류를 찾는 일을 할 때에는 벨만 최적 방정식을 사용합니다.</p>
</li>
</ul>
<h1 id="reference">Reference</h1>
<ul>
<li>노승은(2020), 바닥부터 배우는 강화 학습</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RL] 마르코프 결정 프로세스 (Markov Decision Process)]]></title>
            <link>https://velog.io/@hkun_ho/RL-Markov-Decision-Process</link>
            <guid>https://velog.io/@hkun_ho/RL-Markov-Decision-Process</guid>
            <pubDate>Thu, 12 Jan 2023 16:53:09 GMT</pubDate>
            <description><![CDATA[<h1 id="마르코프-프로세스-markov-process">마르코프 프로세스 (Markov Process)</h1>
<h2 id="아이가-잠이-드는-마르코프-프로세스">아이가 잠이 드는 마르코프 프로세스</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/db69addb-99a9-4efa-bb20-bbf7d8b7dc29/image.png" alt=""></p>
<ul>
<li><p>아이가 취할 수 있는 <em><strong>상태</strong></em> 의 종류는 총 5가지입니다.</p>
<blockquote>
<ul>
<li>누워있는 상태 s0</li>
<li>일어나서 노는 상태 s1</li>
<li>눈을 감고 있는 상태 s2</li>
<li>서서히 잠이 오는 상태 s3</li>
<li>마침내 잠이 든 상태 s4</li>
</ul>
</blockquote>
</li>
<li><p>아이는 상태 s0 에서 시작하여 미리 정해진 확률에 따라 <em><strong>상태 전이</strong></em> 를 합니다.</p>
<blockquote>
<ul>
<li>상태 전이는 현재 상태에서 다음 상태로 넘어간다는 것의 다른 말입니다.</li>
</ul>
</blockquote>
</li>
<li><p>s4 는 종료 상태이고, 여기에 도달하는 순간 마르코프 프로세스는 끝이 납니다.</p>
</li>
</ul>
<h1 id="다시-마르코프-프로세스">다시, 마르코프 프로세스</h1>
<ul>
<li><p>앞서 보았던 것처럼 마르코프 프로세스는 미리 정의된 어떤 확률 분포를 따라서 상태와 상태 사이를 이동해 다니는 여정입니다.</p>
</li>
<li><p>어떤 상태에 도착하게 되면 그 상태에서 다음 상태가 어디가 될지 각각에 해당하는 확률이 있고, 그 확률에 따라 다음 상태가 정해집니다.</p>
</li>
<li><p>마르코프 프로세스를 엄밀하게 정의하기 위해서는 2가지 요소가 필요합니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4826d1b0-d008-43b0-a100-ee972a5255c7/image.png" alt=""></p>
<ul>
<li><p>상태의 집합 S</p>
<blockquote>
<ul>
<li>가능한 상태들을 모두 모아놓은 집합입니다. 아이가 잠드는 마르코프 프로세스의 경우에는 이 집합의 원소가 5개로, S = {s0, s1, s2, s3, s4} 였습니다.</li>
</ul>
</blockquote>
</li>
<li><p>전이 확률 행렬 P</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/2f80b26e-0690-494e-92a8-b485e153b90f/image.png" alt=""></p>
<blockquote>
<ul>
<li><em>*<em>전이 확률 *</em></em> Pss&#39; 는 상태 s 에서 다음  상태 s&#39; 에 도착할 확률을 가리킵니다.</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>Pss&#39; 을 조건부 확률을 이용해서 조금 다른 방식으로 표현해 볼 수 있습니다.</li>
</ul>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/225c8255-83cf-44ae-9178-2a308bf8bc0e/image.png" alt=""></p>
<blockquote>
<ul>
<li>시점 t 에서의 상태가 s 였다면 t+1 에서의 상태가 s&#39; 이 될 확률이라는 뜻입니다.</li>
</ul>
</blockquote>
<h2 id="마르코프-성질">마르코프 성질</h2>
<ul>
<li>&quot;미래는 오로지 현재에 의해 결정된다&quot;</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e74c3493-4ca4-48df-bcd5-4f7eb7d61095/image.png" alt=""></p>
<ul>
<li>마르코프 프로세스에서 다음 상태가 s(t+1) 이 될 확률을 계산하려면 현재의 상태 st 가 무엇인지만 주어지면 충분하다는 뜻입니다.<blockquote>
<ul>
<li>다시 말해, 미래는 오로지 현재에 의해 결정되는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="마르코프한-상태---체스-게임">마르코프한 상태 - 체스 게임</h3>
<ul>
<li>체스 게임에서는 현재 상황에서 해야 하는 일과 과거 경기 양상이 어떠했는지 여부는 아무런 관련이 없습니다.<blockquote>
<ul>
<li>당장 맞닥뜨린 상황을 잘 읽고 미래를 내다보며 최선의 수를 둬야 하는 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="마르코프-하지-않은-상태---운전">마르코프 하지 않은 상태 - 운전</h3>
<ul>
<li><p>운전하고 있는 운전자의 상태를 생각해 봅시다.</p>
</li>
<li><p>운전을 하고 있는 상태의 특정 시점에 사진을 찍어서 해당 사진으로만 운전을 지속해야 한다고 가정해봅시다.</p>
</li>
<li><p>이 사진만 가지고 브레이크를 밟아야 할지, 엑셀을 밟아야 할 지 알 수 없습니다.</p>
<blockquote>
<ul>
<li>따라서 사진만 가지고 구성한 운전자의 상태는 마르코프한 상태가 아닙니다.</li>
</ul>
</blockquote>
</li>
<li><p>하지만 &quot;최근 10초 동안의 사진 10장을 묶어서&quot; 상태로 제공한다면, 이 상태는 마르코프 상태라고 볼 수 있습니다.</p>
<blockquote>
<ul>
<li>완전히 마르코프한지는 모르겠지만, 적어도 마르코프한 상태에 더 가까워졌다는 것은 의심의 여지가 없을 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>또한, 굳이 사진을 묶지 않더라도 특정 시점에 사진과 더불어 속도 벡터, 가속도 벡터 등을 함께 제공한다면 이 또한 마르코프 성질을 더 잘 만족시킬 수 있습니다.</p>
</li>
</ul>
<h1 id="마르코프-리워드-프로세스-markov-reword-process">마르코프 리워드 프로세스 (Markov Reword Process)</h1>
<ul>
<li>마르코프 프로세스에 보상의 개념이 추가되면 <em><strong>마르코프 리워드 프로세스</strong></em> 가 됩니다.</li>
</ul>
<h2 id="아이가-잠이-드는-mrp">아이가 잠이 드는 MRP</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0440069b-d0b6-442a-b99f-4e3c08bb5716/image.png" alt=""></p>
<ul>
<li><p>아까 보았던 아이가 잠이 드는 MP 에 빨간 색으로 보상 값이 추가된 것을 확인할 수 있습니다.</p>
<blockquote>
<ul>
<li>이제는 어떤 상태에 도착하게 되면 그에 따르는 보상을 받게 되는 것이죠.</li>
</ul>
</blockquote>
</li>
<li><p>마르코프 프로세스는 상태의 집합 S 와 전이 확률 행렬 P 로 정의 되었는데, MRP 를 정의하기 위해서는 R 과 γ 라는 2가지 요소가 추가로 필요합니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/316557ce-ab45-49d1-b060-e279ba1b3734/image.png" alt=""></p>
<ul>
<li><p>상태의 집합 S</p>
<blockquote>
<ul>
<li>마르코프 프로세스의 S 와 같고, 상태의 집합입니다.</li>
</ul>
</blockquote>
</li>
<li><p>전이 확률 행렬 P</p>
<blockquote>
<ul>
<li>마르코프 프로세스의 P 와 같고, 상태 s 에서 상태 s&#39; 으로 갈 확률을 행렬의 형태로 표현한 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>보상 함수 R</p>
<blockquote>
<ul>
<li>R 은 어떤 상태 s 에 도착했을 때 받게 되는 보상을 의미합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0891847c-acb7-4c8e-abe6-c51dfef8eafc/image.png" alt=""></p>
<blockquote>
<ul>
<li>기댓값이 등장하는 이유는 특정 상태에 도달했을 때 받는 보상이 매번 조금씩 다를 수도 있기 때문입니다.<blockquote>
<ul>
<li>예컨데 어떤 상태에 도달하면 500원짜리 동전을 던져서 앞면이 나오면 500원을 갖고 뒷면이 나오면 갖지 못한다고 할 때, 보상의 값이 매번 바뀌지만 그 기댓값은 250원으로 정해지게 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
<ul>
<li>감쇠 인자 γ<blockquote>
<ul>
<li>γ 은 0에서 1사이의 숫자입니다.</li>
<li>이는 강화 학습에서 미래 얻을 보상에 비해 당장 얻는 보상을 얼마나 더 중요하게 여길 것인지를 나타내는 파라미터입니다.</li>
<li>구체적으로는 미래에 얻을 보상의 값에 γ 가 여러 번 곱해지며 그 값을 작게 만드는 역할을 합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<blockquote>
<ul>
<li>감쇠 인자 γ 을 자세하게 설명하기 전에, 현재부터 미래에 얻게 될 보상의 합을 가리키는 <em><strong>리턴</strong></em> 이라는 개념을 먼저 설명하겠습니다.</li>
</ul>
</blockquote>
<h3 id="감쇠된-보상의-합-리턴">감쇠된 보상의 합, 리턴</h3>
<ul>
<li><p>MRP 에서는 MP 와 다르게 상태가 바뀔 때마다 해당하는 보상을 얻습니다.</p>
<blockquote>
<ul>
<li>상태 s0 에서 보상 R0 을 받고 시작하여 종료 상태인 sT에 도착할 때 보상 RT 를 받으며 끝이 납니다.</li>
</ul>
</blockquote>
<ul>
<li>그러면 s0 에서 시작하여 sT 까지 가는 여정을 다음과 같이 표현할 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3f8ca1d2-87f7-4850-b7c7-6198f6bc124f/image.png" alt=""></p>
<ul>
<li>이와 같은 하나의 여정을 강화 학습에서는 <em><strong>에피소드</strong></em> 라고 합니다.</li>
<li>이런 표기법을 이용하여 바로 <em><strong>리턴 Gt</strong></em> 를 정의할 수 있습니다.<blockquote>
<ul>
<li>리턴이란 t 시점부터 미래에 받을 감쇠된 보상의 합을 말합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e82261ec-f5e5-4e1d-952f-dac801b3ce38/image.png" alt=""></p>
</li>
<li><p>현재 타임 스텝이 t 라면 그 이후에 발생하는 모든 보상의 값을 더해줍니다.</p>
</li>
<li><p>또 현재에서 멀어질수록, 즉 더 미래에 발생할 보상일수록 γ 가 여러 번 곱해집니다.</p>
<blockquote>
<ul>
<li>γ는 0에서 1 사이의 실수이기 때문에 여러 번 곱해질수록 그 값은 점점 0에 가까워집니다.</li>
</ul>
</blockquote>
</li>
<li><p>따라서 γ 의 크기를 통해 미래에 얻게 될 보상에 비해 현재 얻는 보상에 가중치를 줄 수 있습니다.</p>
</li>
<li><p>&quot;강화 학습은 보상을 최대화 하도록 학습하는 것이 목적이다&quot;라는 말은 엄밀하게 이야기하면 틀린 말입니다.</p>
<blockquote>
<ul>
<li>강화 학습은 보상이 아니라 리턴을 최대화 하도록 학습하는 것입니다.</li>
<li>다시말해, 보상의 합인 리턴이 바로 우리가 최대화하고 싶은 궁극의 목표입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="γ는-왜-필요할까">γ는 왜 필요할까?</h3>
<ul>
<li><p>앞서 말했듯, 감마는 미래를 평가 절하해주는 항입니다.</p>
</li>
<li><p>이런 γ가 꼭 필요한 이유에 대해 3가지 관점에서 이야기해 보겠습니다.</p>
</li>
</ul>
<h4 id="수학적-편리성">수학적 편리성</h4>
<ul>
<li><p>γ 를 1보다 작게 해줌으로써 리던 Gt 가 무한의 값을 가지는 것을 방지할 수 있습니다.</p>
<blockquote>
<ul>
<li>리턴이 무한한 값을 가질 수 없게 된 덕분에 이와 관련된 여러 이론들을 수학적으로 증명하기가 한결 수월해집니다.</li>
</ul>
</blockquote>
</li>
<li><p>좀 더 쉽게 이야기하면, 에피소드에서 얻는 각각의 보상의 최댓값이 정해져 있다면, Gt 는 유한하다는 것입니다.</p>
<blockquote>
<ul>
<li>γ 덕분에 MRP 를 무한한 스텝동안 진행하더라도 리턴 Gt 는 절대 무한한 값이 될 수 없습니다.</li>
</ul>
</blockquote>
</li>
<li><p>리턴이 무한이라면 어느 쪽이 더 좋을지 비교하기도 어렵고, 그 값을 정확하게 예측하기도 어려워집니다.</p>
<blockquote>
<ul>
<li>감마가 1보다 작은 덕분에 이 모든 것이 가능해집니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="사람의-선호-반영">사람의 선호 반영</h4>
<ul>
<li><p>사람은 기본적으로 눈앞의 보상을 더 선호합니다.</p>
</li>
<li><p>예를 들어, 사람은 당장 100만원을 받는 것을 5년 후에 100만원을 받는 것보다 선호합니다.</p>
</li>
<li><p>이런 이유에서 에이전트를 학습하는데 있어서 감마의 개념을 도입합니다.</p>
</li>
</ul>
<h4 id="미래에-대한-불확실성-반영">미래에 대한 불확실성 반영</h4>
<ul>
<li>현재와 미래 사이에는 다양한 확률적 요소들이 있고 이로 인해 당장 느끼는 가치에 비해 미래에 느끼는 가치가 달라질 수 있습니다.<blockquote>
<ul>
<li>그렇기 때문에 미래의 가치에는 불확실성을 반영하고자 감쇠를 해줍니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="mrp-에서-각-상태의-밸류-평가하기">MRP 에서 각 상태의 밸류 평가하기</h3>
<ul>
<li><p>아이가 잠드는 MRP 에서 눈을 감고 있는 상태 s2의 밸류 혹은 가치를 숫자 하나로 평가한다고 해봅시다.</p>
</li>
<li><p>어떤 상태를 평가할 때에는 그 시점으로부터 미래에 일어날 보상을 기준으로 평가해야 합니다.</p>
<blockquote>
<ul>
<li>그러니 아이가 잠드는 MRP 에서 아이가 눈을 감고 있는 상태를 평가하고자 한다면 마찬가지로 해당 상태를 지나 미래에 받을 보상들을 더해야 합니다.</li>
<li><blockquote>
<p>이것이 바로 리턴입니다.</p>
</blockquote>
</li>
</ul>
</blockquote>
</li>
<li><p>하지만 리턴이라는 값은 매번 바뀐다는 문제가 있습니다.</p>
<blockquote>
<ul>
<li>왜냐하면 MRP 자체가 확률적인 요소에 의해 다음 상태가 정해지기 때문에 같은 s2 에서 출발해도 아이가 잠들 때까지 각기 다른 상태를 방문하며 그때마다 얻는 리턴의 값은 달라지기 때문입니다.</li>
</ul>
</blockquote>
</li>
<li><p>이러한 이유 때문에 리턴의 <em><strong>기댓값</strong></em> 을 사용하는 것입니다.</p>
</li>
<li><p>하지만 논의를 이어가기 전에 &quot;에피소드를 샘플링한다&quot;라는 개념을 설명하고, 그에 따라 정말 매번 다른 리턴 값을 얻게 되는지를 확인하고 넘어가겠습니다.</p>
</li>
</ul>
<h3 id="에피소드의-샘플링">에피소드의 샘플링</h3>
<ul>
<li><p>하나의 에피소드 안에서 방문하는 상태들은 매번 다릅니다. 그리고 그에 따라 리턴도 달라집니다.</p>
<blockquote>
<ul>
<li>즉, 매번 에피소드가 어떻게 <em><strong>샘플링</strong></em> 되느냐에 따라 리턴이 달라집니다.</li>
</ul>
</blockquote>
</li>
<li><p>샘플링이란, 말그대로 샘플을 뽑아본다는 뜻을 가집니다.</p>
<blockquote>
<ul>
<li>어떤 확률 분포가 있을 때 해당 분포에서 샘플을 뽑아보는 것이 샘플링입니다.</li>
</ul>
</blockquote>
</li>
<li><p>예를 들어 앞뒷면의 확률이 반반인 동전 X의 확률 분포는 다음과 같습니다.</p>
<blockquote>
<ul>
<li>P(X = 앞면) = 0.5</li>
<li>P(X = 뒷면) = 0.5</li>
</ul>
</blockquote>
</li>
<li><p>이를 샘플링 해보면, 즉 동전을 던져보면, 앞면 또는 뒷면이 나옵니다.</p>
<blockquote>
<ul>
<li>이 때 나온 하나의 면을 샘플이라고 합니다.</li>
</ul>
</blockquote>
</li>
<li><p>우리는 주어진 확률 분포에서 샘플링을 계속해서 할 수 있습니다.</p>
</li>
<li><p>정리하면 위와 같은 샘플링 기법을 통해 주어진 MRP 에서 여러 에피소드를 샘플링해 볼 수 있습니다.</p>
<blockquote>
<ul>
<li>각 상태에서 마치 동전 던지기와 같은 과정을 거쳐서 다음 상태가 정해집니다.</li>
<li>각 상태마다 다음 상태를 샘플링하며 진행하면 언젠가 종료 상태에 도달할 것이고 하나의 에피소드가 끝이 납니다.</li>
</ul>
</blockquote>
</li>
<li><p>중요한 것은, 우리에게 전이 확률 행렬 P 가 주어져 있기 때문에 이런 샘플들을 원한다면 무한히 뽑아낼 수 있다는 점입니다.</p>
</li>
</ul>
<h3 id="상태-가치-함수-state-value-function">상태 가치 함수 (State Value Function)</h3>
<ul>
<li><p>상태를 인풋으로 넣으면 그 상태의 밸류를 아웃풋으로 출력하는 함수</p>
</li>
<li><p>앞서 살펴본 것처럼 에피소드마다 리턴이 다르기 때문에 어떤 상태 s의 밸류 v(s)는 기댓값을 이용하여 정의합니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4785709b-ec45-474c-bbfc-f53b74efabde/image.png" alt=""></p>
<ul>
<li><p>조건부로 붙는 St = s 의 의미는 시점 t 에서 상태 s 부터 시작하여 에피소드가 끝날 때까지의 리턴을 계산하라는 뜻이 됩니다.</p>
</li>
<li><p>아이가 잠드는 MRP 에서 상태 s0 에서 출발하여 발생할 수 있는 에피소드는 무한히 많고, 그때마다 리턴도 항상 다릅니다.</p>
</li>
<li><p>기댓값을 구하려면 에피소드별로 해당 에피소드가 발생할 확률과 그때의 리턴 값을 곱해서 더해주어야 합니다.</p>
<blockquote>
<ul>
<li>가능한 에피소드가 무한히 많기 때문에 이런 접근법은 현실적으로 불가능합니다.</li>
</ul>
</blockquote>
</li>
<li><p>그래서 간단한 방법은 샘플로 얻은 리턴의 평균을 통해 밸류를 근사하게나마 계산해볼 수 있습니다.</p>
<blockquote>
<ul>
<li>더 정확한 방법은 추후에 다루도록 하겠습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="마르코프-결정-프로세스-markov-decision-process">마르코프 결정 프로세스 (Markov Decision Process)</h1>
<ul>
<li><p>앞서 소개했던 MP 와 MRP 에서는 상태 변화가 자동으로 이루어졌습니다.</p>
<blockquote>
<ul>
<li>따라서 MP 나 MRP 만 가지고는 순차적 의사결정 문제를 모델링 할 수 없습니다.</li>
<li>순차적 의사결정에서는 <em><strong>의사결정</strong></em> 이 핵심이기 때문입니다.</li>
</ul>
</blockquote>
</li>
<li><p>이러한 이유로 <em><strong>마르코프 결정 프로세스(Markov Decision Process)</strong></em> 가 등장합니다.</p>
</li>
</ul>
<h2 id="mdp-의-정의">MDP 의 정의</h2>
<ul>
<li><p>MDP 는 MRP 에 에이전트가 더해진 것입니다.</p>
<blockquote>
<ul>
<li>에이전트는 각 상황마다 액션(행동)을 취합니다.</li>
<li>해당 액션에 의해 상태가 변하고 그에 따른 보상을 받습니다.</li>
</ul>
</blockquote>
</li>
<li><p>이 때문에 MDP 를 정의하기 위해서는 액션의 집합 A 라는 요소가 추가됩니다.</p>
<blockquote>
<ul>
<li>A 가 추가되면서 기존의 전이 확률 행렬 P 나 보상 함수 R 의 정의도 MRP 에서의 정의와 약간씩 달라지게 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>정리하면 MDP 의 구성요소는 (S, A, P, R, γ) 입니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0da41d84-b113-4d4d-a08e-40c1c1bdc06e/image.png" alt=""></p>
<ul>
<li><p>상태의 집합 S</p>
<blockquote>
<ul>
<li>MP 와 MRP 에서의 S 와 같습니다. 가능한 상태의 집합입니다.</li>
</ul>
</blockquote>
</li>
<li><p>액션의 집합 A</p>
<blockquote>
<ul>
<li>에이전트가 취할 수 있는 액션들을 모아놓은 것입니다.</li>
<li>에이전트는 스텝마다 액션의 집합 중에서 하나를 선택하여 액션을 취하며, 그에 따라 다음에 도착하게 될 상태가 달라집니다.</li>
</ul>
</blockquote>
</li>
<li><p>전이 확률 행렬 P
<img src="https://velog.velcdn.com/images/hkun_ho/post/bccd7fb2-e5df-45ae-966a-defcee1fdcd4/image.png" alt=""></p>
<blockquote>
<ul>
<li>MDP 에서는 에이전트가 선택한 액션에 따라서 다음 상태가 달라집니다.</li>
<li>따라서 &quot;현재 상태가 s 이며 에이전트가 액션 a 를 선택했을 때 다음 상태가 s&#39; 이 될 확률&quot; 을 정의해야 합니다.<blockquote>
<ul>
<li>여기서 주의해야 할 부분은 상태 s 에서 액션 a 를 선택했을 때 도달하게 되는 상태가 결정론적이 아니라는 점입니다.</li>
<li>같은 상태 s 에서 같은 액션 a 를 선택해도 매번 다른 상태에 도착할 수 있습니다.</li>
<li>말하자면 액션 실행 후 도달하는 상태 s&#39; 에 대한 확률 분포가 있고 그게 바로 전이 확률 행렬 P 입니다.</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</li>
</ul>
<blockquote>
<ul>
<li>조건부 확률의 개념을 이용한 전이 확률 행렬 P 의 엄밀한 정의는 다음과 같습니다.</li>
</ul>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/eef36586-c3b6-4bc8-8b43-dfcee51cb00d/image.png" alt=""></p>
<ul>
<li>보상 함수 R<blockquote>
<ul>
<li>MDP 에서는 액션이 추가 되었기 때문에 현재 상태 s 에서 어떤 액션을 선택하느냐에 따라 받는 보상이 달라집니다.</li>
<li>이를 반영하기 위해 R 에도 액션을 가리키는 a 의 첨자가 하나 붙게 됩니다.</li>
</ul>
</blockquote>
</li>
</ul>
<blockquote>
<ul>
<li>상태 s 에서 액션 a 를 선택하면 받는 보상을 가리키며, 이는 확률적으로 매번 바뀔 수 있기 때문에 마찬가지로 기댓값을 이용하여 표기합니다.</li>
</ul>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ff274364-5f94-43b7-8fb8-eb091715df7b/image.png" alt=""></p>
<ul>
<li>감쇠 인자 γ<blockquote>
<ul>
<li>MRP 에서의 γ 와 정확히 같습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="아이-재우기-mdp">아이 재우기 MDP</h2>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e6d30d1c-740f-4dac-9952-8e4d7c079962/image.jpg" alt=""></p>
<ul>
<li><p>아이가 잠드는 상황에서 어머니라는 에이전트가 개입되기 시작하였습니다.</p>
<blockquote>
<ul>
<li>어머니가 선택할 수 있는 액션은 자장가를 불러주는 액션 a0 와 함께 놀아주는 액션 a1 2가지가 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>눈여겨 볼 부분은 아이가 눈을 감은 상태인 s2 에서 아이를 놀아주는 액션을 선택하면 아이의 다음 상태는 그날 아이의 상태에 따라 s0 가 될 수도 있고, s1 이 될 수도 있습니다. 이때의 전이 확률을 수식으로 표현하면 다음과 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/0829e589-d0e6-441d-8b48-68199b1749cd/image.png" alt=""></p>
<ul>
<li><p>그렇다면 아이 재우기 MDP 에서 보상의 합을 최대화하기 위해서 어머니는 어떤 행동을 선택해야 할까요?</p>
<blockquote>
<ul>
<li>자세히 관찰하면 계속해서 a0 만을 선택하면 최적이라는 것을 어렵지 않게 알 수 있습니다.</li>
</ul>
</blockquote>
</li>
<li><p>이처럼 MDP 가 간단한 경우는 최적의 전략을 찾기 쉬웠습니다.</p>
<blockquote>
<ul>
<li>반면 실제 세계에서 마주하는 MDP 는 상태의 개수 및 액션의 개수가 훨씬 많기 때문에 최적 행동을 찾는 것이 그렇게 쉽지만은 않습니다.</li>
</ul>
</blockquote>
</li>
<li><p>따라서 이러한 상황에서도 좋은 전략(=정책)을 찾는 것이 우리의 목적입니다.</p>
</li>
</ul>
<h2 id="정책-함수와-2가지-가치-함수">정책 함수와 2가지 가치 함수</h2>
<h3 id="정책-함수">정책 함수</h3>
<ul>
<li>각 상태에서 어떤 액션을 선택할지 정해주는 함수</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/8b7a781f-ebf8-4d3f-9b52-b52a5c6c7871/image.png" alt=""></p>
<ul>
<li>확률을 이용한 정의는, 상태 s 에서 액션 a 를 선택할 확률로 해석할 수 있습니다.</li>
</ul>
<h3 id="상태-가치-함수">상태 가치 함수</h3>
<ul>
<li><p>MDP 에서는 에이전트의 정책 함수에 따라서 얻는 리턴이 달라집니다.</p>
<blockquote>
<ul>
<li>따라서 가치 함수는 정책 함수에 의존적입니다.</li>
</ul>
</blockquote>
</li>
<li><p>π 가 주어졌다고 가정했을 때 가치 함수의 정의는 다음과 같습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7f12577b-be6e-4a13-ac92-865e87cb8591/image.png" alt=""></p>
<ul>
<li>이는 s 부터 끝까지 π 를 따라서 움직일 때 얻는 리턴의 기댓값입니다.<blockquote>
<ul>
<li>이 식은 정책 함수를 π 로 고정해놓고 생각한 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="액션-가치-함수">액션 가치 함수</h3>
<ul>
<li><p>액션 가치 함수는 q(s, a)로 표현합니다.</p>
<blockquote>
<ul>
<li>상태에 따라 액션의 결과가 달라지기 때문에 상태와 액션이 동시에 인풋으로 들어가야 합니다.</li>
</ul>
</blockquote>
</li>
<li><p>마찬가지로 π 를 고정시켜 놓고 평가합니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/53ee002f-3ce6-45ed-8725-471a9c14a441/image.png" alt=""></p>
<ul>
<li><p>이는 s 에서 a 를 선택하고, 그 이후에는 π 를 따라서 움직일 때 얻는 리턴의 기댓값입니다.</p>
</li>
<li><p>일단 s 에서 a 를 선택하고 나면 이후의 상태를 진행하기 위해 계속해서 누군가가 액션을 선택해야 하는데, 그 역할은 정책 함수 π 에게 맡기는 것입니다.</p>
</li>
<li><p>따라서 v(s) 와 q(s, a) 는 &quot;s 에서 어떤 액션을 선택하는가&quot; 하는 부분에만 차이가 있습니다.</p>
<blockquote>
<ul>
<li>v(s) 를 계산할 때는 s 에서 π 가 액션을 선택하는 반면, q(s, a) 를 계산할 때는 s 에서 강제로 a 를 선택합니다.</li>
<li>일단 액션을 선택한 이후에는 2가지 가치 함수 모두 정책 함수 π 를 따라서 에피소드가 끝날 때까지 진행합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="prediction-과-control">Prediction 과 Control</h1>
<h2 id="prediction">Prediction</h2>
<ul>
<li>π 가 주어졌을 때 각 상태의 밸류를 평가하는 문제<blockquote>
<ul>
<li>즉, 임의의 정책 π 에 대해 각 상태의 밸류 v(s) 를 구하고자 하는 것</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="control">Control</h2>
<ul>
<li><p>최적 정책 π* 를 찾는 문제</p>
<blockquote>
<ul>
<li>최적의 정책이란 이 세상에 존재하는 모든 π 중에 가장 기대 리턴이 큰 π 를 뜻합니다.</li>
</ul>
</blockquote>
</li>
<li><p>최적 정책 π* 를 따를 때의 가치 함수를 <em><strong>최적 가치 함수</strong></em> 라고 하며 v* 라고 표기합니다.</p>
<blockquote>
<ul>
<li>π* 와 v* 를 찾았다면 &quot;이 MDP 는 풀렸다&quot; 고 말할 수 있습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h1 id="reference">Reference</h1>
<ul>
<li>노승은(2020), 바닥부터 배우는 강화 학습</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RL] 강화 학습이란]]></title>
            <link>https://velog.io/@hkun_ho/RL</link>
            <guid>https://velog.io/@hkun_ho/RL</guid>
            <pubDate>Mon, 02 Jan 2023 18:31:06 GMT</pubDate>
            <description><![CDATA[<h1 id="강화-학습">강화 학습</h1>
<ul>
<li><p>강화 학습이란?</p>
<blockquote>
<ul>
<li>&quot;<em><strong>순차적 의사결정 문제</strong></em> 에서 누적 보상을 최대화 하기 위해 시행착오를 통해 행동을 교정하는 학습 과정&quot;</li>
<li>쉽게 말해, &quot;시행착오를 통해 발전해 나가는 과정&quot;</li>
</ul>
</blockquote>
</li>
<li><p>강화 학습의 간단한 예시</p>
<blockquote>
<ul>
<li>스스로 시행착오를 통해 자전거 타는 법을 학습하는 아이</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="순차적-의사결정-문제">순차적 의사결정 문제</h2>
<ul>
<li>강화 학습이 풀고자 하는 문제는 바로 <em><strong>순차적 의사결정</strong></em> 문제입니다.</li>
</ul>
<h3 id="순차적-의사결정의-예시---샤워하는-남자">순차적 의사결정의 예시 - 샤워하는 남자</h3>
<ul>
<li>우리는 샤워를 할 때 대략적으로 다음과 같은 4단계를 거칩니다.</li>
</ul>
<blockquote>
<ol>
<li>옷을 벗는다.</li>
<li>샤워를 한다.</li>
<li>물기를 닦는다.</li>
<li>옷을 입는다.</li>
</ol>
</blockquote>
<ul>
<li>그리고 이 4단계는 반드시 순서에 맞게 이루어져야 합니다. 만일 순서가 뒤바뀌면 어떻게 될까요?</li>
</ul>
<blockquote>
<p>④ 옷을 입고, ② 샤워를 하고, ③ 물기를 닦고, ① 옷을 벗는다
-&gt; 벌거 벗은 채로 끝나겠네요.</p>
</blockquote>
<blockquote>
<p>③ 물기를 닦고, ② 샤워를 하고, ① 옷을 벗고, ④ 옷을 입는다.
-&gt; 물기는 왜 닦는걸까요?</p>
</blockquote>
<ul>
<li><p>이처럼 아무리 간단한 과정이라 하더라도 이를 성공적으로 마치기 위해서 우리는 몇 가지 의사결정을 순차적으로 해 주어야 합니다.</p>
</li>
<li><p>각 상황에 따라 하는 행동이 다음 상황에 영향을 주며, 결국 연이은 행동을 잘 선택해야 하는 문제가 바로 순차적 의사결정 문제입니다.</p>
</li>
</ul>
<h2 id="보상">보상</h2>
<ul>
<li><p>의사결정을 얼마나 잘하고 있는지 알려주는 신호</p>
</li>
<li><p>강화 학습의 목적은 과정에서 받는 보상의 총합, 즉 <em><strong>누적 보상</strong></em> 을 최대화하는 것입니다.</p>
</li>
</ul>
<h3 id="보상의-특징---어떻게-x-얼마나-o">보상의 특징 - 어떻게 X 얼마나 O</h3>
<ul>
<li><p>보상은 &quot;어떻게&quot;에 대한 정보를 담고 있지 않고, 어떠한 행동을 하면 그것에 대해 &quot;얼마나&quot; 잘 하고 있는지 평가해 줍니다.</p>
</li>
<li><p>그렇다면 &quot;어떻게&quot;에 대한 정보를 아무도 알려주지 않는데 어떻게 학습을 할 수 있는 것일까요?</p>
<blockquote>
<ul>
<li>그것은 바로 수많은 시행착오 덕분입니다.</li>
</ul>
</blockquote>
</li>
<li><p>에이전트가 자신의 행동을 교정할 수 있는 이유는 에이전트가 잘 했을때는 잘했다 하고, 못 했을 때는 못 했다고 평가해 주는 신호가 있기 때문입니다.</p>
<blockquote>
<ul>
<li>그것이 바로 보상입니다.</li>
</ul>
</blockquote>
</li>
<li><p>보상이 어떻게 해야 할지를 직접적으로 알려주지는 않지만, 사후적으로 보상이 낮았던 행동들은 덜 하고, 보상이 높았던 행동들은 더 하면서 보상을 최대화하도록 행동을 조금씩 수정해 나갑니다.</p>
</li>
</ul>
<h3 id="보상의-특징---스칼라">보상의 특징 - 스칼라</h3>
<ul>
<li><p>보상은 <em><strong>스칼라</strong></em> 입니다.</p>
<blockquote>
<ul>
<li>스칼라는 <em><strong>벡터</strong></em> 와 달리 크기를 나타내는 값 하나로 이루어져 있습니다.</li>
<li><blockquote>
<p>따라서 오직 하나의 목표만을 가져야 합니다.</p>
</blockquote>
</li>
</ul>
</blockquote>
</li>
<li><p>그렇다면 다수의 목표들을 어떻게 하나의 스칼라로 표현할 수 있을까요?</p>
<blockquote>
<ul>
<li>여러 방법이 있겠지만 그 중 하나는 바로 가중치를 두는 방법입니다.</li>
</ul>
</blockquote>
</li>
<li><p>대학교 신입생을 예로 들어보겠습니다. 이들은 학점, 동아리 활동, 연애 등 여러 목표를 가질 수 있습니다. 각각을 x, y, z로 표현하고 이들의 가중치를 각각 50%, 25%, 25% 라고 합시다.</p>
</li>
<li><p>이렇게 되면 3개의 목표를 0.5x + 0.25y + 0.25z 라는 하나의 숫자, 즉 스칼라로 표현할 수 있습니다.</p>
</li>
<li><p>강화 학습은 스칼라 형태의 보상이 있는 경우에만 적용할 수 있습니다. 만일 어떤 문제는 도저히 하나의 목표만을 설정하기 어렵다면 그 문제에 강화 학습을 적용하는 것은 적절하지 못할 수 있습니다. 다만 잘 정해진 하나의 숫자로 된 목표가 있다면, 강화 학습은 불도저처럼 해당 목표를 최대로 취하도록 최적화할 것입니다.</p>
</li>
</ul>
<h3 id="보상의-특징---희소하고-지연된-보상">보상의 특징 - 희소하고 지연된 보상</h3>
<ul>
<li><p>보상은 <em><strong>희소</strong></em> 할 수 있으며 또 <em><strong>지연</strong></em> 될 수 있습니다.</p>
</li>
<li><p>행동과 보상이 일대일로 대응이 된다면 강화 학습은 한결 쉬워집니다.</p>
<blockquote>
<ul>
<li>행동에 대한 평가가 즉각적으로 이루어지는 만큼 좋은 행동과 안 좋은 행동을 가려내기 쉽기 때문입니다.</li>
</ul>
</blockquote>
</li>
<li><p>하지만 보상은 선택했던 행동의 빈도에 비해 훨씬 가끔 주어지거나, 행동이 발생한 후 한참 뒤에 나올 수 있고 이 때문에 행동과 보상의 연결이 어려워집니다.</p>
</li>
<li><p>만일 행동을 10번 해야 보상이 1번 나타나거나, 행동을 10번 하고 나서야 과거 처음 한 행동의 보상이 주어진다면 이 보상이 어떤 행동 덕분인지 책임 소재가 불분명해지면서 그만큼 학습도 어려워집니다.</p>
<blockquote>
<ul>
<li>강화 학습에서 다루는 문제는 순차적 의사결정 문제이기 때문에 순차성, 즉 시간에 따른 흐름이 중요하고 이 흐름에서 보상이 뒤늦게 주어지는 것이 가능합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="에이전트와-환경">에이전트와 환경</h2>
<ul>
<li>앞서 설명한 순차적 의사결정 문제를 도식화하면 다음 그림과 같습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/fb54ddc0-a89e-4f3d-a236-1035666446d3/image.png" alt=""></p>
<blockquote>
<ul>
<li>에이전트가 <em><strong>액션</strong></em> 을 하고 그에따라 상황이 변하는 것을 하나의 <em><strong>루프</strong></em> 라 했을 때 이 루프가 끈임없이 반복되는 것을 순차적 의사결정 문제라 할 수 있습니다.</li>
</ul>
</blockquote>
<h3 id="에이전트">에이전트</h3>
<ul>
<li><p>강화 학습의 주인공이자 주체, 학습하는 대상이며 동시에 환경 속에서 행동하는 개체</p>
</li>
<li><p>에이전트의 입장에서 위의 루프는 구체적으로 3개의 단계로 이루어져 있습니다.</p>
</li>
</ul>
<blockquote>
<ol>
<li>현재 상황 st 에서 어떤 액션을 해야 할지 at 를 결정</li>
<li>결정된 행동 at 를 환경으로 보냄</li>
<li>환경으로부터 그에 따른 보상과 다음 상태의 정보를 받음</li>
</ol>
</blockquote>
<h3 id="환경">환경</h3>
<ul>
<li><p>에이전트를 제외한 모든 요소</p>
</li>
<li><p>에이전트가 어떤 행동을 했을 때, 그 결과에 영향을 아주 조금이라도 미치는 모든 요소들이 환경이라고 할 수 있습니다.</p>
</li>
<li><p>현재 상태에 대한 모든 정보를 숫자로 표현하여 기록해 놓은 것을 <em><strong>상태</strong></em> 라고 하는데, 환경은 <em><strong>상태 변화</strong></em> 를 일으키는 역할을 담당합니다.</p>
<blockquote>
<ul>
<li>즉, 행동의 결과를 알려주는 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>환경이 하는 일은 다음과 같은 단계로 이루어집니다.</p>
</li>
</ul>
<blockquote>
<ol>
<li>에이전트로부터 받은 액션 at 를 통해서 상태 변화를 일으킴</li>
<li>그 결과 상태는 st -&gt; s(t+1) 로 바뀜</li>
<li>에이전트에게 줄 보상 r(t+1) 도 함께 계산</li>
<li>s(t+1) 과 r(t+1) 을 에이전트에게 전달</li>
</ol>
</blockquote>
<ul>
<li><p>이처럼 에이전트가 st 에서 at 를 시행하고, 이를 통해 환경이 s(t+1) 로 바뀌면, 즉 에이전트와 환경이 한 번 상호 작용하면 하나의 루프가 끝납니다.</p>
<blockquote>
<ul>
<li>이를 한 <em><strong>틱</strong></em> 이 지났다고 표현합니다.</li>
</ul>
</blockquote>
</li>
<li><p>실제 세계는 앞의 그림과 다르게 시간의 흐름이 <em><strong>연속적(continous)</strong></em> 이겠지만 순차적 의사결정 문제에서는 시간의 흐름을 <em><strong>이산적(discrete)</strong></em> 으로 생각합니다.</p>
<blockquote>
<ul>
<li>이산적이란, 뚝뚝 끊어져서 변화가 발생한다는 뜻입니다.</li>
</ul>
</blockquote>
</li>
<li><p>그리고 그 시간의 단위를 틱 혹은 <em><strong>타임 스텝</strong></em> 이라고 합니다.</p>
</li>
</ul>
<h2 id="강화-학습의-위력">강화 학습의 위력</h2>
<h3 id="병렬성의-힘">병렬성의 힘</h3>
<ul>
<li><p>인서가 자전거를 배우는 것을 예로 들어 보겠습니다. 여기서 학습시간 (인서 혼자서 수많은 시행착오를 겪으며 배우는 것)이 대략 5시간 정도의 시간이 걸린다고 가정해보겠습니다.</p>
</li>
<li><p>하지만 만약 100명의 인서가 시행착오를 겪으며 자전거를 배우고, 모든 시행착오를 서로 공유할 수 있다면 학습시간은 어떻게 될까요?</p>
<blockquote>
<ul>
<li>분명히 혼자 하는 것보다는 훨씬 빠르게 학습이 가능할 것입니다.</li>
<li>몇 명의 인서가 정보를 공유하냐에 따라 5시간이라는 시간이 5분으로 줄어들 수도 있습니다.</li>
<li>이것이 바로 강화 학습이 가지고 있는 병렬성의 힘입니다.</li>
</ul>
</blockquote>
</li>
<li><p>에이전트 하나로는 굉장히 오래 걸리는 학습시간을 병렬성의 힘으로 최대한으로 단축시키며 동일한 학습결과를 얻을 수 있습니다.</p>
</li>
</ul>
<h3 id="자가-학습-self-learning의-매력">자가 학습 (self-learning)의 매력</h3>
<ul>
<li><p>알파고를 예시로 들어보겠습니다.</p>
</li>
<li><p>알파고는 학습 초기에 프로 바둑 기사들의 기보를 통해 지도 학습을 진행하였습니다.</p>
<blockquote>
<ul>
<li>즉, 사람이 두었던 수를 정답으로 입력받아 그것을 잘 따라 하도록 학습했습니다.</li>
</ul>
</blockquote>
</li>
<li><p>하지만 그렇게만 학습했다면 사람을 이길 리는 만무했을 것입니다. 사람을 뛰어넘는 것이 가능했던 이유는 자가 학습에 기반을 둔 강화 학습 덕분입니다.</p>
</li>
<li><p>승리라는 목표만 알려줬을 뿐 그 과정은 알아서 찾도록 했기 때문에 충분한 <em><strong>계산 능력</strong></em> 과 어우러져 사람이 생각해낼 수 없는 수를 찾아냈던 것이죠.</p>
</li>
<li><p>사람이 알려준 지식을 잘 따라하는 데에 그쳤다면 그것을 위대한 지능이라 부를 수 없었을 것입니다.</p>
</li>
</ul>
<h1 id="reference">Reference</h1>
<ul>
<li>노승은(2020), 바닥부터 배우는 강화 학습</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Seminar] Diffusion Model]]></title>
            <link>https://velog.io/@hkun_ho/Seminar-Diffusion-Model</link>
            <guid>https://velog.io/@hkun_ho/Seminar-Diffusion-Model</guid>
            <pubDate>Mon, 02 Jan 2023 17:50:39 GMT</pubDate>
            <description><![CDATA[<h1 id="diffusion-models">Diffusion Models?</h1>
<ul>
<li><p>확산 모델은 최근에 새롭게 등장한 생성 모델(Generative Model)의 일종으로, 기존의 생성 모델에 비해 더 우수한 성능과 유용한 특성들로 인해 많은 관심을 받고 있는 모델입니다.</p>
</li>
<li><p>이는 Data 로부터 Noise를 조금씩 더해가면서 Data를 완전한 Noise로 만드는 Forward process와 이와 반대로 Noise 로부터 조금씩 복원해가면서 Data를 만들어내는 Reverse process를 활용합니다.</p>
</li>
</ul>
<h1 id="generative-models">Generative Models?</h1>
<ul>
<li>생성 모델은 상대적으로 낮은 차원의 데이터로부터 높은 차원의 데이터를 만들어내는 작업을 합니다 (e.g. 강아지/고양이 레이블 -&gt; 사진, 텍스트 -&gt; 음성).</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/a9b76bce-160a-4f5f-99e6-91b51ef56073/image.png" alt=""></p>
<h2 id="대표적인-생성-모델">대표적인 생성 모델</h2>
<h3 id="vae">VAE</h3>
<ul>
<li>VAE는 오토 인코더(AE)의 파생형으로, 인코더를 통해 입력 값을 특정 확률 분포 상의 한 점으로 만들고, 디코더를 통해 해당 점으로부터 입력 값을 생성해냅니다. VAE는 명시적인 확률 분포를 모델링 한다는 장점이 있으나, 가능도(likelihood)가 아닌 ELBO를 통한 학습이라는 점에서 다소 아쉬움이 존재합니다. 또한 다른 모델들에 비해 비교적 생성된 결과물의 품질이 떨어진다는 단점이 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/103eadd4-dc90-4ed3-b183-06fe0b2a92a3/image.png" alt=""></p>
<blockquote>
<ul>
<li>더 자세한 정보 -&gt; <a href="https://lilianweng.github.io/posts/2018-08-12-vae/">VAE</a></li>
</ul>
</blockquote>
<h3 id="gan">GAN</h3>
<ul>
<li>데이터를 생성하는 생성자(generator), 그리고 주어진 데이터가 실제 데이터인지 생성된 데이터인지를 판별하는 판별자(discriminator)를 동시에 학습시키는 방식입니다. 학습 후에는 생성자를 이용하여 원하는 값을 만들게 됩니다. GAN은 묵시적(implicit)으로 확률 분포를 모델링 하기 때문에 모델 구성에 제한이 없으며 생성된 결과물의 품질이 뛰어난 편입니다. 다만 생성자와 판별자가 같이 학습이 되어야 한다는 점, 모드 붕괴 등 학습에 어려움이 있는 것으로 알려져 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/4ebb87b9-1eb8-42e4-8494-1e09c69a9c2b/image.png" alt=""></p>
<blockquote>
<ul>
<li>더 자세한 정보 -&gt; <a href="https://lilianweng.github.io/posts/2017-08-20-gan/">GAN</a></li>
</ul>
</blockquote>
<h3 id="flow-based-models">Flow-based models</h3>
<ul>
<li>단순한 확률 분포에서 추출된 값에 여러 단계의 변환을 거쳐 복잡한 분포를 만드는 방법입니다 (e.g. 노이즈 데이터 -&gt; 개/고양이 사진). 변환 함수를 파라미터화하여 딥러닝 모델로 학습하는 해당 방법은 명시적으로 정확한 likelihood를 모델링한다는 장점이 있고 생성된 결과물의 품질이 좋습니다. 하지만 변환 함수에 역함수가 존재해야 한다는 제한이 있기 때문에 모델을 만들 때 사용하는 연산자에 제한이 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e16cae8c-1dc9-4e6d-a010-df4564f607c9/image.png" alt=""></p>
<blockquote>
<ul>
<li>더 자세한 정보 -&gt; <a href="https://lilianweng.github.io/posts/2018-10-13-flow-models/">Flow-based models</a></li>
</ul>
</blockquote>
<h1 id="다시-diffusion-models">다시, Diffusion Models</h1>
<ul>
<li><p>앞서 살펴본 생성 모델들이 하는 일은 노이즈와 실제 사진과의 관계를 간략화하여 나타내는 것입니다.</p>
<blockquote>
<ul>
<li>VAE는 인코더와 디코더를 통해, [사진 -&gt; <em><strong>Latent Variable</strong></em> -&gt; 사진] 에서 <em><strong>Latent Variable</strong></em> 를 정규 분포로 만드는 방법을 학습하였고,</li>
<li>GAN은 [정규 분포 -&gt; 사진] 의 디코더를 학습하였습니다.</li>
<li>Flow-based model은 이를 여러 단계의 가역함수로 나눈 것입니다.</li>
</ul>
</blockquote>
</li>
<li><p>확산 모델은 Flow-based model과 비슷합니다. 확산 모델은 초기 상태의 분자들이 시간이 흐름에 따라 흩어지는 것을 나타내는 Langevin dynamics 에서 아이디어를 가져왔습니다. </p>
<blockquote>
<ul>
<li>간단히 말하자면, 특정 사진의 픽셀들이 시간이 지나면서 흩어져서 노이즈로 변하는 것을 수식을 통해 나타낸 것입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<ul>
<li><p>이 변환은 정방향 변환(forward)과 역방향 변환(reverse)으로 나뉩니다. 정변환은 데이터가 노이즈로 변하는 것이며, 역변환은 노이즈로부터 데이터가 만들어지는 것입니다.</p>
</li>
<li><p>확산 모델에서는 역변환 단계를 파라미터화 하여 딥러닝 모델로 학습하고, 학습된 역변환을 통해 노이즈로부터 데이터를 생성합니다. 따라서 확산 모델은 유한한 시간 후에 사진을 생성하도록 학습된 파라미터화 된 <em><strong>마르코프 연쇄(Markov chain)</strong></em> 라고 할 수 있습니다. 또한 확산 확률 모델에서는 학습에 <em><strong>negative log-likelihood의 ELBO</strong></em> 를 사용합니다.</p>
</li>
</ul>
<h2 id="주요-개념">주요 개념</h2>
<h3 id="latent-variable">Latent Variable</h3>
<ul>
<li><p>관찰을 통해 얻을 수 있는 확률벡터 x가 있다고 합시다. 확률벡터 x의 분포를 설명하기 위해 나온 것이 Latent Variable 입니다. 기호로는 z를 쓰도록 합시다. x, z 의 관계는 prior 에 의해 묘사됩니다. 여기서 prior 는 현재 가지고 있는 정보를 기초로 하여 정한 초기 확률을 뜻합니다.</p>
</li>
<li><p>p(z)를 가정해 주고, x는 latent variable 의 상태에 따라 달라진다는 것을 표현하기 위해 p(x|z)도 가정해 줍니다.</p>
</li>
<li><p>위와 같이 prior 와 p(x|z)를 가정해주고 시작하면 다음과 같은 설명이 됩니다.</p>
<blockquote>
<ul>
<li>랜덤벡터 x는 보이지 않는 잠재적 변수 z에 의해 확률적으로 결정됩니다.</li>
</ul>
</blockquote>
</li>
<li><blockquote>
<p>z는 보이지 않지만 z가 가지는 값에 따라 x가 존재할 수 있는 공간이 달라질 수 있습니다.</p>
</blockquote>
</li>
</ul>
<h3 id="markov-chain">Markov Chain</h3>
<ul>
<li><p>Definition</p>
<blockquote>
<ul>
<li>마르코프 성질을 가진 이산 확률 과정</li>
</ul>
</blockquote>
</li>
<li><p>Property</p>
<blockquote>
<ul>
<li>특정 상태의 확률은 오직 과거의 상태에 의존</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="elbo-evidence-lower-bound">ELBO (Evidence Lower Bound)</h3>
<ul>
<li>Evidence : Data 의 log likelihood (로그 우도)<blockquote>
<ul>
<li>따라서 ELBO 는 말 그대로 Evidence 의 최저점</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/5e6f3b09-21be-4893-a49b-cc6d63214a90/image.png" alt=""></p>
<ul>
<li><p>앞서, VAE에서는 ELBO를 통해 학습을 한다고 언급하였습니다. 따라서 VAE의 상황을 예로 들겠습니다.</p>
</li>
<li><p>우리는 VAE에서 사후 확률 분포(posterior distribution)인 p를 알고 싶은데, 이를 직접 구하는 것은 어려우므로 이에 근사할 수 있는 사후 확률 분포(variational approximation of the posterior distribution)인 q를 찾는 변분 추론을 해야합니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/ce5d5859-fdaf-40c0-a65c-6df4dee91bac/image.png" alt=""></p>
<ul>
<li>우리의 최종 목적은 <em><strong>p와 q 분포의 차이를 줄이는 것</strong></em> 인데, 이는 두 확률 분포의 KL Divergence가 작아져야 됨을 뜻합니다.<blockquote>
<ul>
<li>log p(x)의 값이 상수이므로, ELBO가 커지면 KL Divergence 값이 작아지게 됩니다.</li>
</ul>
</blockquote>
</li>
<li><blockquote>
<p>따라서 우리는 ELBO를 Maximize 하면 된다는 결론에 다다르게 됩니다.</p>
</blockquote>
</li>
</ul>
<h2 id="forward-process">Forward Process</h2>
<ul>
<li><p>실제 데이터 분포로 샘플링된 초기 데이터 포인트가 주어지면 Forward 프로세스는 Markov Gaussian diffusion kernel (Markov chain)을 반복적으로 적용하여 분포를 간단하고 다루기 쉬운 분포(Gaussian, Binomial)로 변환합니다.</p>
</li>
<li><p>특히, 마르코프 체인의 t번째 단계에서 <em><strong>Diffusion rate βt</strong></em> 를 사용하여 Gaussian noise 를 생성하고 이를 x(t−1)에 추가하며, 이 과정은 분포 q(xt|x(t−1))에서 새로운 latent variable xt를 샘플링하는 것으로 정의됩니다.</p>
</li>
</ul>
<h3 id="diffusion-rate-β">Diffusion rate β</h3>
<ul>
<li><p>Diffusion rate βt 는 t단계에 어느 정도의 노이즈를 추가할 것인지를 정합니다.</p>
</li>
<li><p>βt 값의 집합은 알고리즘에 따라 예약되고 학습 전체에서 고정됩니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/c2d55a45-9945-407b-bacf-f4f9112a22be/image.png" alt=""></p>
<h2 id="다시-forward-process">다시, Forward Process</h2>
<ul>
<li>Forward process에 대한 조건부 분포는 가우스 분포로 공식화됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/58268d7a-c783-46e2-882b-81191fc5816d/image.png" alt=""></p>
<ul>
<li>xt를 생성하기 위해 Gaussian noise 를 추가하는 것은 샘플링 형태로 공식화됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/58aeaaf0-1d4b-4abe-8478-4f17d3e56eb2/image.png" alt=""></p>
<ul>
<li><em><strong>Reparametrization trick</strong></em> 을 사용하면 임의 평균 μ 및 분산이 σ^2인 정규 분포 x ~ N(x ; μ, σ^2)의 표본을 다음과 같이 다시 작성할 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/3bd42ab9-cc29-4b37-a080-5387d4dae176/image.png" alt=""></p>
<ul>
<li>이 공식은 평균이 0에서 목표 평균 μ까지 이동하고 분산이 목표 분산 σ^2로 늘어나는 표준 Gaussian(이 중 ε는 샘플)으로 해석될 수 있습니다.</li>
</ul>
<h3 id="reparametrization-trick">Reparametrization trick</h3>
<ul>
<li><p>Backpropagation 과정에서 확률적 샘플링 절차에 의해 생성된 값에 대해 손실이 계산될 때 gradient flow가 발생하지 않습니다.</p>
</li>
<li><p>Reparametrization trick 은 랜덤 변수를 노이즈 변수의 결정론적 함수로 다시 작성하므로 경사하강법을 통해 비확률적 항을 최적화할 수 있습니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/7fa2663c-e1d3-443c-98ec-f4e0697e81d6/image.png" alt=""></p>
<blockquote>
<ul>
<li>한 마디로, stochastic node를 stochastic한 부분과 deterministic한 부분으로 분해시켜서 deterministic한 부분으로 backpropagation을 흐르게 하자는게 핵심</li>
</ul>
</blockquote>
<h2 id="다시-forward-process-1">다시, Forward Process</h2>
<ul>
<li>Gaussian noise를 지속적으로 추가하면 q(xt)의 분포가 표준 Gaussian 으로 수렴합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/e7e2e0ba-abd8-455e-b6db-61017f5ac347/image.png" alt=""></p>
<h2 id="reverse-process">Reverse Process</h2>
<ul>
<li>역 조건부 분포 q(x(t−1) | xt) 를 학습하면, 정규 분포 N(0,1)에서 xt를 샘플링하고, 역 프로세스를 실행하며, q(x0)에서 샘플을 수집하여 원래 데이터 분포에서 새로운 데이터 포인트를 생성할 수 있습니다.<blockquote>
<ul>
<li>그러나 q(x(t−1) | xt) 의 통계적 추정치를 구하는 데에 데이터 분포와 관련된 계산이 필요하기 때문에 거의 불가능에 가깝습니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/742915b8-49a0-47fd-b779-c13d76e8fa18/image.png" alt=""></p>
<h3 id="how---intuition-from-feller">How? - Intuition from Feller</h3>
<ul>
<li><p>연속적인 Gaussian diffusion (충분히 작은 β)의 경우, 확산 과정의 Reverse 과정은 Forward 과정과 동일한 기능적 형태를 갖는다는 것이 입증되었습니다.</p>
<blockquote>
<ul>
<li>1949년, Feller에 의해 입증</li>
</ul>
</blockquote>
</li>
<li><p>즉, 확산 속도 βt가 충분히 작을 때, q(xt | x(t−1))가 Gaussian 분포를 따르는 경우, q(x(t−1) | xt)도 Gaussian 분포를 따르게 됩니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/d424f491-8d57-4a56-a7c5-f527de29bf45/image.png" alt=""></p>
<h3 id="dnn">DNN</h3>
<ul>
<li><p>이제 목표 분포가 Gaussian을 따른다는 것을 알고 있지만 이를 어떻게 공식화할지에 대해서는 알 수 없습니다.</p>
<blockquote>
<ul>
<li>Deep Neural Network (DNN) 를 사용하게 됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>앞서 언급했지만, 확산 모델의 궁극적인 목표는 p와 q의 차이를 줄이는 것, 즉 q에 근사하는 p를 학습시키는 것입니다.</p>
<blockquote>
<ul>
<li>이 학습 과정에 DNN을 도입한다는 것이 Reverse process의 핵심입니다.</li>
</ul>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hkun_ho/post/292b0204-782f-4ec1-b80d-e69f0643a206/image.png" alt=""></p>
<blockquote>
<ul>
<li>더 자세한 정보 -&gt; <a href="https://www.topbots.com/introduction-to-diffusion-models-for-machine-learning/">Introduction to Diffusion Models</a></li>
</ul>
</blockquote>
<h2 id="evaluations">Evaluations</h2>
<ul>
<li><p>생성된 latents 은 해석할 수 없습니다. </p>
<blockquote>
<ul>
<li>VAE는 인코더의 최적화를 통해 구조화된 latent space 를 학습할 수 있는 반면, 확산 모델에서는 각 단계의 인코더가 이미 선형 Gaussian 모델로 제공되어 유연하게 최적화할 수 없습니다. </li>
<li>따라서 중간 단계의 latents 는 원본 입력의 노이즈가 있는 버전으로만 제한됩니다.</li>
</ul>
</blockquote>
</li>
<li><p>샘플링은 여러 노이즈 제거 단계를 실행해야 하므로 비용이 많이 드는 절차입니다. </p>
<blockquote>
<ul>
<li>제한 사항 중 하나는 최종 latent 가 완전히 Gaussian noise 임을 보장하기 위해 매우 많은 시간 단계 T가 선택된다는 것입니다. 샘플링하는 동안 샘플을 생성하기 위해 이러한 모든 시간 단계를 반복해야 합니다.</li>
</ul>
</blockquote>
</li>
<li><p>확산 모델의 성공은 생성 모델로서의 계층적 VAE의 힘을 강조합니다.</p>
<blockquote>
<ul>
<li>이는 복잡한 인코더와 의미 있는 latent space 를 잠재적으로 학습할 수 있는 일반적이고 심층적인 HVAE의 경우, 추가 성능 향상을 달성할 수 있음을 시사합니다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://blog.est.ai/2022/02/%EC%83%9D%EC%84%B1-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%9D%90%EB%A6%84-%ED%99%95%EC%82%B0-%EB%AA%A8%EB%8D%B8diffusion-model%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC/">생성 모델의 새로운 흐름 확산 모델(Diffusion model)에 관하여</a></li>
<li><a href="https://lilianweng.github.io/posts/2021-07-11-diffusion-models/">What are Diffusion Models?</a></li>
<li><a href="https://process-mining.tistory.com/182">Diffusion model 설명 (Diffusion model이란? Diffusion model 증명)</a></li>
<li><a href="https://234sdq234q232454.tistory.com/entry/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EB%94%A5%EB%9F%AC%EB%8B%9DLatent-Variable%EC%9E%A0%EC%9E%AC%EB%B3%80%EC%88%98-%EC%9D%B4%EB%9E%80">[머신러닝,딥러닝]Latent Variable(잠재변수) 이란?</a></li>
<li><a href="https://sjwannabe.tistory.com/13">Markov Chain 마르코프 체인</a></li>
<li><a href="https://glanceyes.tistory.com/entry/VAE-%EA%B3%84%EC%97%B4-%EB%AA%A8%EB%8D%B8%EC%9D%98-ELBOEvidence-Lower-Bound-%EB%B6%84%EC%84%9D">VAE 계열 모델의 ELBO(Evidence Lower Bound) 분석</a></li>
<li><a href="https://www.topbots.com/introduction-to-diffusion-models-for-machine-learning/">Introduction to Diffusion Models for Machine Learning</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>