<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>techartnomad</title>
    <link>https://techartnomad.tistory.com/</link>
    <description>메이즈라인 주식회사 대표 컨설턴트. 시그라프 상해쳅터 정회원
ex.넷이즈,바이트덴스,거인네트워크,신동네트워크,알레고리드믹 등에서 Technical Specialist.
협력 경험: NVIDIA + QUALCOMM

https://www.mazeline.tech/</description>
    <language>ko</language>
    <pubDate>Mon, 29 Jun 2026 10:12:44 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>jplee</managingEditor>
    <image>
      <title>techartnomad</title>
      <url>https://tistory1.daumcdn.net/tistory/6333236/attach/4ffab9c97956485d95e0d4632691b535</url>
      <link>https://techartnomad.tistory.com</link>
    </image>
    <item>
      <title>【INDEX】 OPEN WORLD DEV. UPDATE</title>
      <link>https://techartnomad.tistory.com/423</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236636108&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역] 넷이즈 레이훠 LGDC 시리즈 《영겁무간 모바일》RenderGraph 개조 공유&quot; data-og-description=&quot;역자의 말: 중국 넷이즈 항저우 스튜디오에서 첫 중국 직장생활을 할 때 근무했던 곳이라 할 수 있다. 레이훠와 형제 스튜디오인 반구 스튜디오가 레이훠 스튜디오로 통합되었다. 자체 엔진 개&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/738&quot; data-og-url=&quot;https://techartnomad.tistory.com/738&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bxEprP/dJMb88GeU3t/tQcQmCWcJnxEPVDgD6qqzK/img.png?width=800&amp;amp;height=260&amp;amp;face=0_0_800_260,https://scrap.kakaocdn.net/dn/bgmNYo/dJMb83kCRDg/lXygnHxNK6hkoR4e8CEt1K/img.png?width=800&amp;amp;height=260&amp;amp;face=0_0_800_260,https://scrap.kakaocdn.net/dn/bU7GuT/dJMb84X8Csl/OynHlHZL6UDIvx7m9HL6E0/img.png?width=1440&amp;amp;height=1042&amp;amp;face=0_0_1440_1042&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/738&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/738&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bxEprP/dJMb88GeU3t/tQcQmCWcJnxEPVDgD6qqzK/img.png?width=800&amp;amp;height=260&amp;amp;face=0_0_800_260,https://scrap.kakaocdn.net/dn/bgmNYo/dJMb83kCRDg/lXygnHxNK6hkoR4e8CEt1K/img.png?width=800&amp;amp;height=260&amp;amp;face=0_0_800_260,https://scrap.kakaocdn.net/dn/bU7GuT/dJMb84X8Csl/OynHlHZL6UDIvx7m9HL6E0/img.png?width=1440&amp;amp;height=1042&amp;amp;face=0_0_1440_1042');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역] 넷이즈 레이훠 LGDC 시리즈 《영겁무간 모바일》RenderGraph 개조 공유&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;역자의 말: 중국 넷이즈 항저우 스튜디오에서 첫 중국 직장생활을 할 때 근무했던 곳이라 할 수 있다. 레이훠와 형제 스튜디오인 반구 스튜디오가 레이훠 스튜디오로 통합되었다. 자체 엔진 개&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236619485&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;룰 기반 터레인 데코레이터 GPU 프로세싱 처리.&quot; data-og-description=&quot;Emrecan &amp;Ccedil;ubuk&amp;ccedil;u 가 4년 전에 공개 해 놨던 룰 기반 터레인 데코레이터를 약간 개선 했습니다.리얼타임 수준까지는 못했고 전적으로 CPU 의존 프로세싱을 일부분 GPU 로 가져왔어요. 좀 더 머리를 짜&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/742&quot; data-og-url=&quot;https://techartnomad.tistory.com/742&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cPds7V/dJMb8VNFAe1/ldc3pSaK1r0PvYS5EvX4Bk/img.png?width=800&amp;amp;height=533&amp;amp;face=0_0_800_533,https://scrap.kakaocdn.net/dn/nswEi/dJMb8U83zsa/K3SF4q8SdW2y9Z7Rk5IecK/img.png?width=800&amp;amp;height=533&amp;amp;face=0_0_800_533,https://scrap.kakaocdn.net/dn/JByuP/dJMb8RR1Pch/HVxtLBJjNKkmQb6akKYRaK/img.jpg?width=340&amp;amp;height=340&amp;amp;face=0_0_340_340&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/742&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/742&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cPds7V/dJMb8VNFAe1/ldc3pSaK1r0PvYS5EvX4Bk/img.png?width=800&amp;amp;height=533&amp;amp;face=0_0_800_533,https://scrap.kakaocdn.net/dn/nswEi/dJMb8U83zsa/K3SF4q8SdW2y9Z7Rk5IecK/img.png?width=800&amp;amp;height=533&amp;amp;face=0_0_800_533,https://scrap.kakaocdn.net/dn/JByuP/dJMb8RR1Pch/HVxtLBJjNKkmQb6akKYRaK/img.jpg?width=340&amp;amp;height=340&amp;amp;face=0_0_340_340');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;룰 기반 터레인 데코레이터 GPU 프로세싱 처리.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Emrecan &amp;Ccedil;ubuk&amp;ccedil;u 가 4년 전에 공개 해 놨던 룰 기반 터레인 데코레이터를 약간 개선 했습니다.리얼타임 수준까지는 못했고 전적으로 CPU 의존 프로세싱을 일부분 GPU 로 가져왔어요. 좀 더 머리를 짜&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236602358&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역] 넷이즈 레이훠 LGDC 시리즈|게임 개발에서 &amp;lsquo;마법&amp;rsquo;처럼 쓰이는 기술(상): 날씨 시스템 설&quot; data-og-description=&quot;읽기 전에: 날씨 시스템(환경 제어 시스템)은 게임의 품질감과 몰입감을 크게 끌어올립니다. 이 글은 상&amp;middot;하 두 편으로 구성되며, 상편에서는 날씨 시스템이 보통 어떤 구성과 일을 담당하는지 &quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/750&quot; data-og-url=&quot;https://techartnomad.tistory.com/750&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/t38Hd/dJMb9dHx1Gr/TGV4mqe0Ps6Jl2fIk25Gd1/img.gif?width=640&amp;amp;height=296&amp;amp;face=0_0_640_296,https://scrap.kakaocdn.net/dn/bpXXIW/dJMb9cBRNVN/V9G9APN8Z9TaVeoKHdfwx1/img.gif?width=640&amp;amp;height=296&amp;amp;face=0_0_640_296,https://scrap.kakaocdn.net/dn/r7f1n/dJMb9b31PmN/AkZRkb3lJgS5vqEl38Nll0/img.png?width=1052&amp;amp;height=434&amp;amp;face=0_0_1052_434&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/750&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/750&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/t38Hd/dJMb9dHx1Gr/TGV4mqe0Ps6Jl2fIk25Gd1/img.gif?width=640&amp;amp;height=296&amp;amp;face=0_0_640_296,https://scrap.kakaocdn.net/dn/bpXXIW/dJMb9cBRNVN/V9G9APN8Z9TaVeoKHdfwx1/img.gif?width=640&amp;amp;height=296&amp;amp;face=0_0_640_296,https://scrap.kakaocdn.net/dn/r7f1n/dJMb9b31PmN/AkZRkb3lJgS5vqEl38Nll0/img.png?width=1052&amp;amp;height=434&amp;amp;face=0_0_1052_434');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역] 넷이즈 레이훠 LGDC 시리즈|게임 개발에서 &amp;lsquo;마법&amp;rsquo;처럼 쓰이는 기술(상): 날씨 시스템 설&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;읽기 전에: 날씨 시스템(환경 제어 시스템)은 게임의 품질감과 몰입감을 크게 끌어올립니다. 이 글은 상&amp;middot;하 두 편으로 구성되며, 상편에서는 날씨 시스템이 보통 어떤 구성과 일을 담당하는지&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236583804&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역] 넷이즈 레이훠 LGDC 시리즈 게임 개발에서 비바람을 부르는 마법(하편): 3D 번개, 폭풍운, 지&quot; data-og-description=&quot;도입: 이 글은 《날씨 시스템 설계와 실천》의 보충편입니다. 세 가지 렌더링 효과의 구현을 공유합니다. 먼저 형태를 편집할 수 있는 3D 프랙털 번개, 그리고 지평선 폭풍운, 지표면 구름바다, Ra&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/752&quot; data-og-url=&quot;https://techartnomad.tistory.com/752&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PB0Le/dJMb9cBRNVH/kM7LSPqaMSSkEMqWF3mW51/img.gif?width=640&amp;amp;height=389&amp;amp;face=0_0_640_389,https://scrap.kakaocdn.net/dn/bXcoU7/dJMb9frPc5b/nlJkt48527kKf90SxK9gh1/img.gif?width=640&amp;amp;height=389&amp;amp;face=0_0_640_389,https://scrap.kakaocdn.net/dn/bkDZBM/dJMb86n7u7M/yflRKJIW27myH3fJTKGrIK/img.png?width=1440&amp;amp;height=715&amp;amp;face=0_0_1440_715&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/752&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/752&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PB0Le/dJMb9cBRNVH/kM7LSPqaMSSkEMqWF3mW51/img.gif?width=640&amp;amp;height=389&amp;amp;face=0_0_640_389,https://scrap.kakaocdn.net/dn/bXcoU7/dJMb9frPc5b/nlJkt48527kKf90SxK9gh1/img.gif?width=640&amp;amp;height=389&amp;amp;face=0_0_640_389,https://scrap.kakaocdn.net/dn/bkDZBM/dJMb86n7u7M/yflRKJIW27myH3fJTKGrIK/img.png?width=1440&amp;amp;height=715&amp;amp;face=0_0_1440_715');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역] 넷이즈 레이훠 LGDC 시리즈 게임 개발에서 비바람을 부르는 마법(하편): 3D 번개, 폭풍운, 지&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;도입: 이 글은 《날씨 시스템 설계와 실천》의 보충편입니다. 세 가지 렌더링 효과의 구현을 공유합니다. 먼저 형태를 편집할 수 있는 3D 프랙털 번개, 그리고 지평선 폭풍운, 지표면 구름바다, Ra&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236568276&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;MARTINI/RTIN 알고리즘 이해&quot; data-og-description=&quot;역자의 말: 이 문서는 지형 렌더링 최적화를 위해 널리 사용되는 MARTINI 및 RTIN(Right-Triangulated Irregular Networks) 알고리즘의 핵심 원리를 다루고 있습니다. 이 알고리즘은 고해상도 하이트맵(Heightmap) &quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/756&quot; data-og-url=&quot;https://techartnomad.tistory.com/756&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/KkMVx/dJMb8TCjI2p/5Scz4E1EFu3bwbnY58BtkK/img.jpg?width=800&amp;amp;height=436&amp;amp;face=0_0_800_436,https://scrap.kakaocdn.net/dn/bQ4SwE/dJMb8VNFAeK/hS2pnSD214YmrAHfDkhcp0/img.jpg?width=800&amp;amp;height=436&amp;amp;face=0_0_800_436,https://scrap.kakaocdn.net/dn/btHa7Z/dJMb8SpRWgH/oa2FSYfpLpKoU3i72H1aX1/img.png?width=3080&amp;amp;height=1746&amp;amp;face=0_0_3080_1746&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/756&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/756&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/KkMVx/dJMb8TCjI2p/5Scz4E1EFu3bwbnY58BtkK/img.jpg?width=800&amp;amp;height=436&amp;amp;face=0_0_800_436,https://scrap.kakaocdn.net/dn/bQ4SwE/dJMb8VNFAeK/hS2pnSD214YmrAHfDkhcp0/img.jpg?width=800&amp;amp;height=436&amp;amp;face=0_0_800_436,https://scrap.kakaocdn.net/dn/btHa7Z/dJMb8SpRWgH/oa2FSYfpLpKoU3i72H1aX1/img.png?width=3080&amp;amp;height=1746&amp;amp;face=0_0_3080_1746');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MARTINI/RTIN 알고리즘 이해&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;역자의 말: 이 문서는 지형 렌더링 최적화를 위해 널리 사용되는 MARTINI 및 RTIN(Right-Triangulated Irregular Networks) 알고리즘의 핵심 원리를 다루고 있습니다. 이 알고리즘은 고해상도 하이트맵(Heightmap)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236558221&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[GITHUB] MARTINI/RTIN 유니티 구현 공유&quot; data-og-description=&quot;유니티 6.4 에서 작업 했습니다.저장소 라이센스는 MIT 라서 마음대로 변형 및 사용하셔도 됩니다.원래 월드파티션 유니티 라는 솔루션 개발하고 있었는데 일부만 때어냈어요.고객사 요청으로 유&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/759&quot; data-og-url=&quot;https://techartnomad.tistory.com/759&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cUrc0T/dJMb887iD2A/SgdrY62yKAjalMWnDctwPK/img.png?width=800&amp;amp;height=427&amp;amp;face=0_0_800_427,https://scrap.kakaocdn.net/dn/kuQ79/dJMb85vYU8X/0vbkztYOXY9ryrkAysGbM0/img.png?width=800&amp;amp;height=427&amp;amp;face=0_0_800_427,https://scrap.kakaocdn.net/dn/digAV9/dJMb83kCRC9/jgJk78c2UW5DknL2hCiSPK/img.png?width=2606&amp;amp;height=1394&amp;amp;face=0_0_2606_1394&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/759&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/759&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cUrc0T/dJMb887iD2A/SgdrY62yKAjalMWnDctwPK/img.png?width=800&amp;amp;height=427&amp;amp;face=0_0_800_427,https://scrap.kakaocdn.net/dn/kuQ79/dJMb85vYU8X/0vbkztYOXY9ryrkAysGbM0/img.png?width=800&amp;amp;height=427&amp;amp;face=0_0_800_427,https://scrap.kakaocdn.net/dn/digAV9/dJMb83kCRC9/jgJk78c2UW5DknL2hCiSPK/img.png?width=2606&amp;amp;height=1394&amp;amp;face=0_0_2606_1394');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[GITHUB] MARTINI/RTIN 유니티 구현 공유&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;유니티 6.4 에서 작업 했습니다.저장소 라이센스는 MIT 라서 마음대로 변형 및 사용하셔도 됩니다.원래 월드파티션 유니티 라는 솔루션 개발하고 있었는데 일부만 때어냈어요.고객사 요청으로 유&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236521301&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역] Unity에서 가상 텍스처 구현&quot; data-og-description=&quot;저자: 멍청한 아구몬(傻头傻脑亚古兽)기술 배경Virtual Texture(가상 텍스처)는 실시간 렌더링에서 다양한 제약으로 인해 초고해상도 텍스처를 직접 표시할 수 없는 문제를 해결하기 위해 주로 사용&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/776&quot; data-og-url=&quot;https://techartnomad.tistory.com/776&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cB3Vs0/dJMb8Yp5ios/nJP9iHxNjmOukpZel0l5s0/img.png?width=488&amp;amp;height=171&amp;amp;face=0_0_488_171,https://scrap.kakaocdn.net/dn/dcUIiN/dJMb8RR1Pb3/quam9UPjuffVdMgRKvBS11/img.png?width=488&amp;amp;height=171&amp;amp;face=0_0_488_171,https://scrap.kakaocdn.net/dn/ckp20I/dJMb9cBRNVD/YFRwv29qECvW3POjxhkJGK/img.png?width=906&amp;amp;height=705&amp;amp;face=0_0_906_705&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/776&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/776&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cB3Vs0/dJMb8Yp5ios/nJP9iHxNjmOukpZel0l5s0/img.png?width=488&amp;amp;height=171&amp;amp;face=0_0_488_171,https://scrap.kakaocdn.net/dn/dcUIiN/dJMb8RR1Pb3/quam9UPjuffVdMgRKvBS11/img.png?width=488&amp;amp;height=171&amp;amp;face=0_0_488_171,https://scrap.kakaocdn.net/dn/ckp20I/dJMb9cBRNVD/YFRwv29qECvW3POjxhkJGK/img.png?width=906&amp;amp;height=705&amp;amp;face=0_0_906_705');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역] Unity에서 가상 텍스처 구현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저자: 멍청한 아구몬(傻头傻脑亚古兽)기술 배경Virtual Texture(가상 텍스처)는 실시간 렌더링에서 다양한 제약으로 인해 초고해상도 텍스처를 직접 표시할 수 없는 문제를 해결하기 위해 주로 사용&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236511405&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역] FastGeo Documentation 5.8 한국어 버전&quot; data-og-description=&quot;요즘 Fable 도 막혔고요. 여러사람이 토큰 소비하면 미국만 돈 벌어주는거자나요? 그래서 뭐 오늘 리미트 다 소진 했지만 한국어 버전으로 바꿨습니다. -_-;이게 코드 짜는거 보다 PPTX 를 변환 하는&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/778&quot; data-og-url=&quot;https://techartnomad.tistory.com/778&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jgLO5/dJMb87ggnEV/IdbbopMg57xHi4FgwalsE0/img.gif?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/b9VHID/dJMb86PbDxn/Ct8utA9QiL8L5d9Uyo4eE1/img.gif?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/b66sSL/dJMb9ia0VCR/Tn047GPcDi033iMcrkCo7K/img.jpg?width=340&amp;amp;height=340&amp;amp;face=0_0_340_340&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/778&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/778&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jgLO5/dJMb87ggnEV/IdbbopMg57xHi4FgwalsE0/img.gif?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/b9VHID/dJMb86PbDxn/Ct8utA9QiL8L5d9Uyo4eE1/img.gif?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/b66sSL/dJMb9ia0VCR/Tn047GPcDi033iMcrkCo7K/img.jpg?width=340&amp;amp;height=340&amp;amp;face=0_0_340_340');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역] FastGeo Documentation 5.8 한국어 버전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;요즘 Fable 도 막혔고요. 여러사람이 토큰 소비하면 미국만 돈 벌어주는거자나요? 그래서 뭐 오늘 리미트 다 소진 했지만 한국어 버전으로 바꿨습니다. -_-;이게 코드 짜는거 보다 PPTX 를 변환 하는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236492126&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역] 텐센트 델타포스 대형 월드 RVT 지형 렌더링 분석과 재현&quot; data-og-description=&quot;저작: Lamp꽤 오래전에 만든 거라, 그냥 물 타듯이 한 편 써 본다.먼저 기술 포인트를 간단히 요약하면 이렇다.10km급 대형 월드에서 RVT를 사용하고, 1m당 512 texel을 쓴다.지형 머티리얼 32종을 지원&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/782&quot; data-og-url=&quot;https://techartnomad.tistory.com/782&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/7Inhm/dJMb8XSfKR9/ZKABa03bTRRL6VVFXn3BP0/img.jpg?width=800&amp;amp;height=426&amp;amp;face=0_0_800_426,https://scrap.kakaocdn.net/dn/iepht/dJMb8UHY9CK/q1CNfwT0VitDKOuJZsrIS1/img.jpg?width=800&amp;amp;height=426&amp;amp;face=0_0_800_426,https://scrap.kakaocdn.net/dn/cdavK7/dJMb8PGF5Bc/uPacTyPw2mtppjQku0Szd0/img.jpg?width=1912&amp;amp;height=1224&amp;amp;face=0_0_1912_1224&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/782&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/782&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/7Inhm/dJMb8XSfKR9/ZKABa03bTRRL6VVFXn3BP0/img.jpg?width=800&amp;amp;height=426&amp;amp;face=0_0_800_426,https://scrap.kakaocdn.net/dn/iepht/dJMb8UHY9CK/q1CNfwT0VitDKOuJZsrIS1/img.jpg?width=800&amp;amp;height=426&amp;amp;face=0_0_800_426,https://scrap.kakaocdn.net/dn/cdavK7/dJMb8PGF5Bc/uPacTyPw2mtppjQku0Szd0/img.jpg?width=1912&amp;amp;height=1224&amp;amp;face=0_0_1912_1224');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역] 텐센트 델타포스 대형 월드 RVT 지형 렌더링 분석과 재현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저작: Lamp꽤 오래전에 만든 거라, 그냥 물 타듯이 한 편 써 본다.먼저 기술 포인트를 간단히 요약하면 이렇다.10km급 대형 월드에서 RVT를 사용하고, 1m당 512 texel을 쓴다.지형 머티리얼 32종을 지원&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236475099&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[UFSH2025] 《록왕국 세계》 모바일 파이프라인 설계와 최적화 &amp;mdash; 주곡재, 텐센트 게임 모어펀 스튜&quot; data-og-description=&quot;역자의 말: 2019년 겨울 모어펀 스튜디오 테크니컬 아트 디렉터(홍콩사람)가 보직해임 되어 그 후보자에 제가 추천을 받아 인터뷰 진행 하고 합격했었던 스튜디오입니다. 보직 해임된 모어펀 스&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/786&quot; data-og-url=&quot;https://techartnomad.tistory.com/786&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dUQnly/dJMb87ggnEC/nseBvhavqk2QqDahgwSdoK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bfYMUf/dJMb887iD1C/udf8dNkkVn5EaXHirmKfp1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/c1lqWk/dJMb9b31PlU/LOUkLsVogz8z88M9bNiL8k/img.jpg?width=1440&amp;amp;height=810&amp;amp;face=0_0_1440_810&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/786&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/786&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dUQnly/dJMb87ggnEC/nseBvhavqk2QqDahgwSdoK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bfYMUf/dJMb887iD1C/udf8dNkkVn5EaXHirmKfp1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/c1lqWk/dJMb9b31PlU/LOUkLsVogz8z88M9bNiL8k/img.jpg?width=1440&amp;amp;height=810&amp;amp;face=0_0_1440_810');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[UFSH2025] 《록왕국 세계》 모바일 파이프라인 설계와 최적화 &amp;mdash; 주곡재, 텐센트 게임 모어펀 스튜&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;역자의 말: 2019년 겨울 모어펀 스튜디오 테크니컬 아트 디렉터(홍콩사람)가 보직해임 되어 그 후보자에 제가 추천을 받아 인터뷰 진행 하고 합격했었던 스튜디오입니다. 보직 해임된 모어펀 스&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236431040&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역][NVIDIA] Depth Precision Visualized&quot; data-og-description=&quot;Depth precision은 그래픽스 프로그래머라면 언젠가는 반드시 씨름하게 되는 골칫거리입니다. 이 주제에 대해서는 이미 많은 글과 논문이 쓰였고, 게임&amp;middot;엔진&amp;middot;디바이스마다 서로 다른 depth buffer 포&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/753&quot; data-og-url=&quot;https://techartnomad.tistory.com/753&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c2PrDw/dJMb8Xkpns5/YR13WEGlvL7XmofNKlkrw0/img.jpg?width=800&amp;amp;height=414&amp;amp;face=0_0_800_414,https://scrap.kakaocdn.net/dn/Ksonv/dJMb9jOwHQ9/m2QfvZa3Ak0YtXdOOCrCak/img.jpg?width=800&amp;amp;height=414&amp;amp;face=0_0_800_414,https://scrap.kakaocdn.net/dn/dAC21j/dJMb8QMl3ji/jfTKuDVNlleE6j0O4bKth1/img.jpg?width=830&amp;amp;height=730&amp;amp;face=0_0_830_730&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/753&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/753&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c2PrDw/dJMb8Xkpns5/YR13WEGlvL7XmofNKlkrw0/img.jpg?width=800&amp;amp;height=414&amp;amp;face=0_0_800_414,https://scrap.kakaocdn.net/dn/Ksonv/dJMb9jOwHQ9/m2QfvZa3Ak0YtXdOOCrCak/img.jpg?width=800&amp;amp;height=414&amp;amp;face=0_0_800_414,https://scrap.kakaocdn.net/dn/dAC21j/dJMb8QMl3ji/jfTKuDVNlleE6j0O4bKth1/img.jpg?width=830&amp;amp;height=730&amp;amp;face=0_0_830_730');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역][NVIDIA] Depth Precision Visualized&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Depth precision은 그래픽스 프로그래머라면 언젠가는 반드시 씨름하게 되는 골칫거리입니다. 이 주제에 대해서는 이미 많은 글과 논문이 쓰였고, 게임&amp;middot;엔진&amp;middot;디바이스마다 서로 다른 depth buffer 포&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1782236404542&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역][기술 분석] 대규모 오픈 월드 게임 제작 프로세스 및 기술 탐구 - 대규모 환경 제작 기술 &quot; data-og-description=&quot;저자: Kerry이전 글에 이어 이번에는 대규모 오픈 월드 환경 제작 기술에 대해 알아보겠습니다. 이 글은 현재 업계의 전반적인 방식을 훑어보고 거시적인 지식 청사진을 제공하는 것을 목표로 합&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/772&quot; data-og-url=&quot;https://techartnomad.tistory.com/772&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cu4HHs/dJMb9llgTCi/raMjWN6r7jid1tbWHnwqvk/img.jpg?width=800&amp;amp;height=809&amp;amp;face=0_0_800_809,https://scrap.kakaocdn.net/dn/yqnU0/dJMb9iIQGMx/UTcbXbmMzq7Kst6kjsytd1/img.jpg?width=800&amp;amp;height=809&amp;amp;face=0_0_800_809,https://scrap.kakaocdn.net/dn/KqxXL/dJMb9dHx1FB/JyzgDy99y8o1dAk7FnRyX0/img.jpg?width=1112&amp;amp;height=1125&amp;amp;face=0_0_1112_1125&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/772&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/772&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cu4HHs/dJMb9llgTCi/raMjWN6r7jid1tbWHnwqvk/img.jpg?width=800&amp;amp;height=809&amp;amp;face=0_0_800_809,https://scrap.kakaocdn.net/dn/yqnU0/dJMb9iIQGMx/UTcbXbmMzq7Kst6kjsytd1/img.jpg?width=800&amp;amp;height=809&amp;amp;face=0_0_800_809,https://scrap.kakaocdn.net/dn/KqxXL/dJMb9dHx1FB/JyzgDy99y8o1dAk7FnRyX0/img.jpg?width=1112&amp;amp;height=1125&amp;amp;face=0_0_1112_1125');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역][기술 분석] 대규모 오픈 월드 게임 제작 프로세스 및 기술 탐구 - 대규모 환경 제작 기술&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저자: Kerry이전 글에 이어 이번에는 대규모 오픈 월드 환경 제작 기술에 대해 알아보겠습니다. 이 글은 현재 업계의 전반적인 방식을 훑어보고 거시적인 지식 청사진을 제공하는 것을 목표로 합&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1742101328979&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역] Unreal Engine 5 Open World Production&quot; data-og-description=&quot;역자의 말. 이틀 전에 이어서 추가로 괜찮은 토픽이 있어서 공유 해 봅니다. 중국어는 글을 읽는 수준이 제가 좋지 않기 때문에 번역기의 도움을 받은 후 음성으로 다시 듣고 어색한 곳은 교정을&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/146&quot; data-og-url=&quot;https://techartnomad.tistory.com/146&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FIunR/hyYqaKgfnD/3rEKStbjkB61xCvnJsaG81/img.png?width=1521&amp;amp;height=1354&amp;amp;face=0_0_1521_1354&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/146&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/146&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FIunR/hyYqaKgfnD/3rEKStbjkB61xCvnJsaG81/img.png?width=1521&amp;amp;height=1354&amp;amp;face=0_0_1521_1354');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역] Unreal Engine 5 Open World Production&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;역자의 말. 이틀 전에 이어서 추가로 괜찮은 토픽이 있어서 공유 해 봅니다. 중국어는 글을 읽는 수준이 제가 좋지 않기 때문에 번역기의 도움을 받은 후 음성으로 다시 듣고 어색한 곳은 교정을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1742101281327&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;World Partition-&amp;gt; Runtime Partition&quot; data-og-description=&quot;UE5의 새로운 레벨 분할 기술은 런타임에서 그 장점이 두드러집니다.레벨의 정적 오브젝트들은 레벨 시작 시 단 한 번만 계산되어 메모리에 저장되므로, 이전의 Bake 방식과 비교해도 게임 실행 &quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/381&quot; data-og-url=&quot;https://techartnomad.tistory.com/381&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bg3wHX/hyYr1627CR/wLY8DcN7WLZEgPlWAege4K/img.png?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/8E09f/hyYrQxGCBy/2Y0S2iFSwxI8P8G0qo1WYk/img.png?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/bwd8Zy/hyYuj6BYsC/okmke3phIoxy0I0T11MqOk/img.png?width=809&amp;amp;height=541&amp;amp;face=0_0_809_541&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/381&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/381&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bg3wHX/hyYr1627CR/wLY8DcN7WLZEgPlWAege4K/img.png?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/8E09f/hyYrQxGCBy/2Y0S2iFSwxI8P8G0qo1WYk/img.png?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/bwd8Zy/hyYuj6BYsC/okmke3phIoxy0I0T11MqOk/img.png?width=809&amp;amp;height=541&amp;amp;face=0_0_809_541');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;World Partition-&amp;gt; Runtime Partition&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;UE5의 새로운 레벨 분할 기술은 런타임에서 그 장점이 두드러집니다.레벨의 정적 오브젝트들은 레벨 시작 시 단 한 번만 계산되어 메모리에 저장되므로, 이전의 Bake 방식과 비교해도 게임 실행&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1742101363960&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역] Gdc2024 Open World Rendering Techniques in 'Hogwarts Legacy'&quot; data-og-description=&quot;제공&amp;nbsp;프로젝트에 대한 전반적인 정보LOD 전환 페이드뿐만 아니라 햇빛 방향에 따라 그림자가 바뀌는 큰 월드도 페이드하는 크로스 페이드에 매우 중점을 둡니다.바인드리스에 많은 노력을 기울&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/249&quot; data-og-url=&quot;https://techartnomad.tistory.com/249&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/4ItAH/hyYqdUvnnL/dQhuFfW5XzQYGxOnebx5Nk/img.jpg?width=800&amp;amp;height=443&amp;amp;face=0_0_800_443,https://scrap.kakaocdn.net/dn/bueqF3/hyYuec91M6/iq53znOoHwCYXtJwHLloMk/img.jpg?width=800&amp;amp;height=443&amp;amp;face=0_0_800_443&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/249&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/249&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/4ItAH/hyYqdUvnnL/dQhuFfW5XzQYGxOnebx5Nk/img.jpg?width=800&amp;amp;height=443&amp;amp;face=0_0_800_443,https://scrap.kakaocdn.net/dn/bueqF3/hyYuec91M6/iq53znOoHwCYXtJwHLloMk/img.jpg?width=800&amp;amp;height=443&amp;amp;face=0_0_800_443');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역] Gdc2024 Open World Rendering Techniques in 'Hogwarts Legacy'&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;제공&amp;nbsp;프로젝트에 대한 전반적인 정보LOD 전환 페이드뿐만 아니라 햇빛 방향에 따라 그림자가 바뀌는 큰 월드도 페이드하는 크로스 페이드에 매우 중점을 둡니다.바인드리스에 많은 노력을 기울&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1742101379218&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역]gdc2024 Large Scale GPU-Based Skinning for Vegetation in 'Alan Wake 2'&quot; data-og-description=&quot;저자콘텐츠 개요노스 라이트 엔진(레메디 독점 엔진)의 스키닝 애니메이션이 모두 컴퓨트쉐이더에서 계산 된 후 스킨 버퍼에 저장된 다음 그려지도록 변경되었으며, 컨트롤의 일부 머티리얼은 &quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/248&quot; data-og-url=&quot;https://techartnomad.tistory.com/248&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eEa3m/hyYumCgqF2/m3t0G8ZxCd3mQxnjQCAB61/img.jpg?width=800&amp;amp;height=447&amp;amp;face=0_0_800_447,https://scrap.kakaocdn.net/dn/lrvxc/hyYqOHd0Lx/FcoRRPKykaSHkHwmn8WUpK/img.jpg?width=800&amp;amp;height=447&amp;amp;face=0_0_800_447&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/248&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/248&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eEa3m/hyYumCgqF2/m3t0G8ZxCd3mQxnjQCAB61/img.jpg?width=800&amp;amp;height=447&amp;amp;face=0_0_800_447,https://scrap.kakaocdn.net/dn/lrvxc/hyYqOHd0Lx/FcoRRPKykaSHkHwmn8WUpK/img.jpg?width=800&amp;amp;height=447&amp;amp;face=0_0_800_447');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역]gdc2024 Large Scale GPU-Based Skinning for Vegetation in 'Alan Wake 2'&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저자콘텐츠 개요노스 라이트 엔진(레메디 독점 엔진)의 스키닝 애니메이션이 모두 컴퓨트쉐이더에서 계산 된 후 스킨 버퍼에 저장된 다음 그려지도록 변경되었으며, 컨트롤의 일부 머티리얼은&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1742101434032&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[주석번역] 렌더링 갓오브워:라그라로크 GDC2023 파트1&quot; data-og-description=&quot;내 커리어 스토리? - 2020년 8월 산타모니카 스튜디오에 합류. -- 리드 렌더링 프로그래머로 입사: 당시 렌더링 팀은 6명으로 구성되었습니다. -- 프로젝트 진행 과정에서 성장했습니다. - 이전에는 &quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/95&quot; data-og-url=&quot;https://techartnomad.tistory.com/95&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bH5Er0/hyYqTocHGa/Kz7YPirBGfVcnA8qTqtuRk/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/BPI8f/hyYqLKtEFL/N8fG3hGpVpe6VSzEXI7iI1/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/bxnuNI/hyYrV6QO1A/ZBkFGeaqfH0kfmlwZty9ak/img.png?width=2336&amp;amp;height=1314&amp;amp;face=0_0_2336_1314&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/95&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bH5Er0/hyYqTocHGa/Kz7YPirBGfVcnA8qTqtuRk/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/BPI8f/hyYqLKtEFL/N8fG3hGpVpe6VSzEXI7iI1/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/bxnuNI/hyYrV6QO1A/ZBkFGeaqfH0kfmlwZty9ak/img.png?width=2336&amp;amp;height=1314&amp;amp;face=0_0_2336_1314');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[주석번역] 렌더링 갓오브워:라그라로크 GDC2023 파트1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;내 커리어 스토리? - 2020년 8월 산타모니카 스튜디오에 합류. -- 리드 렌더링 프로그래머로 입사: 당시 렌더링 팀은 6명으로 구성되었습니다. -- 프로젝트 진행 과정에서 성장했습니다. - 이전에는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1742101493134&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[번역]테크니컬 아트 노트 | 언리얼 5 프로시저럴 제너레이션 프레임워크의 기본에 대한 가이드.&quot; data-og-description=&quot;역자의 말.2015년 넷이즈 항저우 연구센터에 합류 했을 때 2016년 기술 촉진 계획에 후디니와 절차적 생성이라는 주제를 넣고 발표 한 적이 있는데요... 그 당시에는 엔진센터 센터장의 의견에 따&quot; data-og-host=&quot;techartnomad.tistory.com&quot; data-og-source-url=&quot;https://techartnomad.tistory.com/181&quot; data-og-url=&quot;https://techartnomad.tistory.com/181&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cmEL11/hyYr0UAqWx/iKaTYkKeI3s7RmpkafaKJK/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/ctKqrT/hyYrPFxuVc/JacwNIFPHJep6xdWxpKaJ0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cQVa4P/hyYufiPRbP/Fr3FSKkBpta7AMvIR2u5Ck/img.png?width=1440&amp;amp;height=810&amp;amp;face=0_0_1440_810&quot;&gt;&lt;a href=&quot;https://techartnomad.tistory.com/181&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techartnomad.tistory.com/181&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cmEL11/hyYr0UAqWx/iKaTYkKeI3s7RmpkafaKJK/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/ctKqrT/hyYrPFxuVc/JacwNIFPHJep6xdWxpKaJ0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cQVa4P/hyYufiPRbP/Fr3FSKkBpta7AMvIR2u5Ck/img.png?width=1440&amp;amp;height=810&amp;amp;face=0_0_1440_810');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[번역]테크니컬 아트 노트 | 언리얼 5 프로시저럴 제너레이션 프레임워크의 기본에 대한 가이드.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;역자의 말.2015년 넷이즈 항저우 연구센터에 합류 했을 때 2016년 기술 촉진 계획에 후디니와 절차적 생성이라는 주제를 넣고 발표 한 적이 있는데요... 그 당시에는 엔진센터 센터장의 의견에 따&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techartnomad.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>INDEX</category>
      <category>Openworld</category>
      <category>TechArt</category>
      <category>개발</category>
      <category>공유</category>
      <category>기술공유</category>
      <category>번역</category>
      <category>오픈월드</category>
      <category>인덱스</category>
      <category>테크아트</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/423</guid>
      <comments>https://techartnomad.tistory.com/423#entry423comment</comments>
      <pubDate>Wed, 24 Jun 2026 02:44:52 +0900</pubDate>
    </item>
    <item>
      <title>[번역] UF2025(Orlando) &amp;mdash; Unity의 그림자, UEFN Scene Graph와 Verse 심층 분석</title>
      <link>https://techartnomad.tistory.com/789</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;역자의 말: 제목의 Unity의 그림자 이거 Shadow 그거 아닙니다. ㅋ UEFN 에서의 Verse 와 UE6 에서의 Verse 는 좀 분리 해 놓고 봐야하겠지만 어차피 VerseVM 런타임에서 돌아가는건 같지 않나 싶습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자: wlxklyh&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이번 글도 꽤 재미있다. 보자마자 든 생각은, 이거 Unity의 Entity + Component 아닌가? 왜 메인라인 UE에는 없고 UEFN 안에 이런 설계가 들어가 있는 걸까? UE가 Unity를 베끼고, Unity가 UE를 베끼고, 하하하하하.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;907&quot; data-origin-height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zniqK/dJMcacQ4qyK/lTnBuA0ulnP7Nx7AOeJ6c0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zniqK/dJMcacQ4qyK/lTnBuA0ulnP7Nx7AOeJ6c0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zniqK/dJMcacQ4qyK/lTnBuA0ulnP7Nx7AOeJ6c0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzniqK%2FdJMcacQ4qyK%2FlTnBuA0ulnP7Nx7AOeJ6c0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;907&quot; height=&quot;721&quot; data-origin-width=&quot;907&quot; data-origin-height=&quot;721&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 영상: &lt;b&gt;Powering Up Your Projects With Scene Graph and Verse | Unreal Fest Orlando 2025&lt;/b&gt;&lt;br /&gt;발표자: Evan Brown, Epic Games Programmer Writer&lt;br /&gt;영상 링크: &lt;a href=&quot;https://www.youtube.com/watch?v=IW8HjoO-Uj0&quot;&gt;https://www.youtube.com/watch?v=IW8HjoO-Uj0&lt;/a&gt;&lt;br /&gt;영상 길이: 31분 13초. 자막은 영상 자체 영어 자동 자막 기준.&lt;br /&gt;이 글은 해당 발표를 바탕으로 정리한 &lt;b&gt;한국어 심층 기술 글&lt;/b&gt;이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;들어가며&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph는 또 하나의 장면 정리 패널이 아니다. UEFN의 오브젝트 세계를 &lt;b&gt;통일된 Entity-Component 모델&lt;/b&gt;로 전환하는 것이다.&lt;br /&gt;여기서 Verse가 맡는 역할도 단순한 스크립트 언어가 아니다. 강타입, 하위 호환성, 전역 네임스페이스, &lt;b&gt;트랜잭션 롤백(transactional rollback)&lt;/b&gt; 이 함께 Scene Graph에 필요한 안정성과 이식성을 받쳐준다.&lt;br /&gt;기존 UEFN 사용자에게 가장 큰 사고방식 전환은 이것이다. &lt;b&gt;하나의 중앙 Verse device가 모든 오브젝트를 제어하게 하지 말고&lt;/b&gt;, 오브젝트 자신이 컴포넌트를 통해 데이터와 행동을 갖게 하라.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 읽을 때는 UEFN 에디터, Verse device, Creative prop, Prefab, Actor / Component 같은 기본 개념은 어느 정도 알고 있다고 가정한다. Scene Graph에 대한 사전 지식은 필요 없다. 글에서 정의부터 시작할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여기서 AI로 Creative Prop과 Verse Device를 잠깐 설명해보자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UEFN 개발 방식은 Prop + Device의 역할 분담이다. UEFN(Unreal Editor for Fortnite)은 포트나이트의 공식 에디터이고, 여기서 만든 콘텐츠는 Fortnite Creative 샌드박스 안에서 돌아가야 한다. 이 제한 때문에 일반 UE 프로젝트와 가장 큰 차이가 생긴다. 임의의 Actor에 Blueprint나 C++ 스크립트를 붙일 수 없다. 모든 커스텀 로직은 특수한 것 하나, 즉 Verse device 안에만 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 종류의 세계 시민이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Creative Prop(크리에이티브 소품)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장면 안에 배치되는 &amp;ldquo;말 없는 물체&amp;rdquo;다. 나무 한 그루, 상자 하나, 벽 하나, 코인 모델 하나 같은 것.&lt;/li&gt;
&lt;li&gt;자체 로직은 없다. 본질적으로는 메시 + 충돌 + 간단한 상호작용(공격당함, 닿음)을 가진 인스턴스다.&lt;/li&gt;
&lt;li&gt;비유하자면 UE에서 아무 Blueprint도 붙이지 않은 StaticMeshActor에 가깝다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Verse Device(Verse 장치)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Verse 언어로 작성한 스크립트 오브젝트다. 이것도 하나의 엔티티처럼 월드에 배치된다. 보일 수도 있고 안 보일 수도 있다.&lt;/li&gt;
&lt;li&gt;생명주기 훅이 있다. OnBegin()은 게임 시작 시 호출되고, OnEnd()는 종료 시 호출된다.&lt;/li&gt;
&lt;li&gt;비유하자면 UE에서 렌더링은 하지 않고 로직만 담당하는 GameMode / Manager Actor에 가깝다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전형적인 흐름은 이렇다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;에디터에서 N개의 prop을 장면에 끌어다 놓는다. 즉, 장면을 만든다.&lt;/li&gt;
&lt;li&gt;Verse device 하나를 장면에 끌어다 놓는다.&lt;/li&gt;
&lt;li&gt;device 스크립트 안에서 @editable 변수를 선언해 그 prop들을 &amp;ldquo;지정&amp;rdquo;한다. Inspector에서 레퍼런스를 드래그하는 것과 비슷하다.&lt;/li&gt;
&lt;li&gt;게임이 시작되면 device의 OnBegin()이 실행되고, prop 레퍼런스를 가져온 뒤, 이후 device가 prop에 명령을 보낸다. 이동, 숨김, prop의 &amp;ldquo;상호작용됨&amp;rdquo; 이벤트 구독 같은 것들이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 이렇게 설계했을까&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;배치되는 것&amp;rdquo;과 &amp;ldquo;제어 로직&amp;rdquo;을 강하게 두 층으로 나눈 것은 Epic의 의도적인 제약이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;prop은 Fortnite 기존 시스템에 의해 직렬화, 복제, 롤백될 수 있어야 한다. 그래서 사용자가 그 안에 임의의 스크립트를 집어넣게 둘 수 없다.&lt;/li&gt;
&lt;li&gt;로직은 device에 집중된다. 심사, 샌드박스, 성능 경계를 관리하기 쉽다.&lt;/li&gt;
&lt;li&gt;부작용으로 자연스럽게 ECS 스타일이 형성된다. 데이터(prop)는 월드 안에 있고, 행동(device)은 스크립트에 있으며, 둘은 @editable 레퍼런스로 묶인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &amp;ldquo;prop 배치, device 시작 로직, device가 계속 prop을 구동&amp;rdquo;하는 구조는 UEFN에서 거의 모든 게임플레이가 따르는 표준 패턴이다. 특정 글만의 특수한 작성 방식이 아니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KehqB/dJMcai4M2gv/hTxFzBhvHFLxZJozj6hZZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KehqB/dJMcai4M2gv/hTxFzBhvHFLxZJozj6hZZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KehqB/dJMcai4M2gv/hTxFzBhvHFLxZJozj6hZZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKehqB%2FdJMcai4M2gv%2FhTxFzBhvHFLxZJozj6hZZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표 아젠다: Scene Graph와 Verse의 동기에서 시작해 플랫폼 레벨 실전, 그리고 미래 로드맵까지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 시작하자마자 큰 줄기를 설명한다. 먼저 Scene Graph와 Verse의 what / why를 이야기하고, 이어 플랫폼 레벨 예시를 통해 &lt;b&gt;전통적인 device-driven 방식&lt;/b&gt;과 &lt;b&gt;Scene Graph component-driven 방식&lt;/b&gt;을 비교한다. 마지막으로 현재 단계의 시스템 제한과 향후 방향을 설명한다. 이 네 줄기가 이 글 전체의 구조다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 왜 UEFN은 Scene Graph를 도입하려 하는가&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.1 전통적인 방식에서 &amp;ldquo;오브젝트에 소속이 없다&amp;rdquo;는 문제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 주류 UEFN 워크플로에서 전형적인 개발 방식은 이렇다. &lt;b&gt;Creative prop은 월드에 배치되고, Verse device는 게임 시작 시 로직을 시작하며, 이후 해당 device가 그 prop들을 계속 제어한다.&lt;/b&gt; 이 방식은 동작한다. 하지만 오브젝트 수, 행동 조합, 런타임 생성 요구가 늘어날수록 몇 가지 구조적 문제가 드러난다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;오브젝트 자체에 행동의 소속이 없다&lt;/b&gt;: Creative prop은 조작 가능한 기하 오브젝트에 더 가깝고, 실제 상태와 로직은 종종 외부 device 클래스 안으로 흘러간다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오브젝트 간 협력이 중앙 스케줄링에 의존한다&lt;/b&gt;: prop끼리는 직접 대화할 수 없다. 모든 정보가 device를 거쳐 돌아가야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재사용 단위가 거칠다&lt;/b&gt;: 새로운 행동 하나는 종종 새 device 클래스를 만들거나 기존 베이스 클래스의 editables를 계속 부풀리는 일을 뜻한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 생성 비용이 높다&lt;/b&gt;: 런타임에 갑자기 &amp;ldquo;움직이고, 공격하고, 몬스터를 생성하는&amp;rdquo; 플랫폼을 만들고 싶다면 prop spawn, 목표 지점, key frame, 관리 클래스, setup 호출을 모두 함께 처리해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 후반부에서 구체적인 플랫폼 레벨 예시를 통해 &amp;ldquo;복잡도가 왜 폭발하는가&amp;rdquo;를 매우 구체적으로 보여준다(5절 참고). 여기서는 먼저 이것을 설계 문제로 기억해두자. &lt;b&gt;행동을 누가 들고 있는가, 데이터를 누가 들고 있는가, 시뮬레이션을 누가 구동하는가. device-driven 방식에서는 이 세 질문의 답이 모두 &amp;ldquo;중앙 device&amp;rdquo;로 떨어진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.2 Scene Graph의 기본 정의&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상에서 제시한 공식적인 기본 정의는 이렇다. &lt;b&gt;Scene Graph는 월드 안의 모든 오브젝트를 연결하는 통일된 구조&lt;/b&gt;다. 장면 오브젝트를 최상위 &lt;b&gt;simulation entity&lt;/b&gt; 아래에 조직하고, 오브젝트 계층, 컴포넌트, 리소스, Verse 행동을 모두 하나의 모델 안에 넣는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nmjf4/dJMcai4M2gC/n9PCaRQNdFgjG0KHUofkXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nmjf4/dJMcai4M2gC/n9PCaRQNdFgjG0KHUofkXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nmjf4/dJMcai4M2gC/n9PCaRQNdFgjG0KHUofkXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnmjf4%2FdJMcai4M2gC%2Fn9PCaRQNdFgjG0KHUofkXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph는 장면 오브젝트를 통일된 엔티티 트리 안에 조직한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림의 집 예시는 매우 단순하다. 지붕, 벽, 바닥 같은 하위 부분은 Outliner 안에 임의로 중첩된 오브젝트가 아니라 simulation entity 아래에 있는 엔티티 트리로 나타난다. 각 노드는 &lt;b&gt;컴포넌트&lt;/b&gt;를 통해 자신의 위치, 외형, 행동을 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자가 반복해서 강조한 말이 있다. Scene Graph의 의미 중 하나는 &lt;b&gt;Unreal Engine의 Actor 체계에서 Entity + Component 체계로 이동하는 것&lt;/b&gt;이다. 이 이동은 UEFN 쪽에서 일어나는 것이지, UE 메인라인 프로젝트에 Actor를 버리라고 말하는 것은 아니다. 하지만 Epic이 &amp;ldquo;메타버스급&amp;rdquo; 콘텐츠 조직 방식을 조합 우선(composition-first)의 엔지니어링 패러다임으로 끌고 가려 한다는 점은 분명히 보여준다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Entity: 의도적으로 &amp;ldquo;아무것도 없는&amp;rdquo; 컨테이너&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.1 Entity는 처음에는 비어 있다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상은 꽤 많은 시간을 들여 한 가지 사실을 강조한다. &lt;b&gt;Entity는 처음에 아무것도 없다.&lt;/b&gt; &amp;ldquo;아무것도 아니다&amp;rdquo;라는 구호 같은 말이 아니라, 말 그대로 비어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치도 없고, 메시도 없고, 빛도 없고, 상호작용성도 없다. 심지어 3D 공간 안에 존재한다는 감각조차 없다. 어떤 능력이든 갖게 하려면 반드시 명시적으로 &lt;b&gt;컴포넌트를 추가&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 좌표에 존재하게 하고 싶다면 &lt;b&gt;transform component&lt;/b&gt;를 붙인다.&lt;/li&gt;
&lt;li&gt;보이게 하고 싶다면 &lt;b&gt;mesh component&lt;/b&gt;를 붙인다.&lt;/li&gt;
&lt;li&gt;빛나게 하고 싶다면 &lt;b&gt;light component&lt;/b&gt;를 붙인다.&lt;/li&gt;
&lt;li&gt;로직을 실행하게 하고 싶다면 커스텀 &lt;b&gt;Verse component&lt;/b&gt;를 붙인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 &amp;ldquo;최소 초기 상태&amp;rdquo;는 의도적인 설계 선택이다. Actor가 처음부터 여러 기본 컴포넌트와 기본 행동을 상속받는 것과 대비된다. Entity는 컨테이너로서 &lt;b&gt;최소 출발점&lt;/b&gt;만 노출하고, 개발자는 조합을 통해 필요한 오브젝트를 점진적으로 &amp;ldquo;자라게&amp;rdquo; 만든다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b25M67/dJMcacQ4qyN/F2NiRhJDtMy2agtUX5w4mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b25M67/dJMcacQ4qyN/F2NiRhJDtMy2agtUX5w4mk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b25M67/dJMcacQ4qyN/F2NiRhJDtMy2agtUX5w4mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb25M67%2FdJMcacQ4qyN%2FF2NiRhJDtMy2agtUX5w4mk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Entity는 컴포넌트를 통해 데이터와 행동을 얻는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 그림은 영상에서 반복해서 나온 문장과 대응된다. &lt;b&gt;Entity는 컴포넌트를 사용해 데이터(data)와 행동(behavior)을 싣는다.&lt;/b&gt; 평범한 entity를 램프, 자동차, 장치로 진화시키는 것은 전부 어떤 컴포넌트를 얹느냐에 달려 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.2 Prefab: Entity + Component 묶음을 재사용 가능한 asset으로 봉인하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상에서 제시한 또 다른 핵심 구조는 &lt;b&gt;Prefab&lt;/b&gt;이다. Prefab이 저장하는 것은 &amp;ldquo;몇 개의 Creative prop 그룹&amp;rdquo;이 아니라, &lt;b&gt;엔티티와 컴포넌트의 완전한 구조&lt;/b&gt;다. 그것이 하나의 asset으로 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FxjlF/dJMcai4M2gy/XdkdhSI7pCTR0QkDnKn6D1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FxjlF/dJMcai4M2gy/XdkdhSI7pCTR0QkDnKn6D1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FxjlF/dJMcai4M2gy/XdkdhSI7pCTR0QkDnKn6D1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFxjlF%2FdJMcai4M2gy%2FXdkdhSI7pCTR0QkDnKn6D1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prefab은 엔티티와 컴포넌트 구조를 재사용 가능한 asset으로 고정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상에서는 lamp prefab의 전체 구조를 설명한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;lampost 엔티티&lt;/b&gt;: transform + mesh + gameplay 요소 하나. 이것은 Verse 코드일 수도 있고 interactable component일 수도 있다.&lt;/li&gt;
&lt;li&gt;그 아래에 &lt;b&gt;lamp 자식 엔티티&lt;/b&gt;: transform + mesh + light component.&lt;/li&gt;
&lt;li&gt;이 둘을 함께 저장해 lamp prefab으로 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 prefab을 레벨에 끌어다 놓으면 바로 사용할 수 있는 &amp;ldquo;가로등 기둥 + 램프&amp;rdquo; 단위가 된다. 더 중요한 것은 Prefab이 &lt;b&gt;두 가지 수정 방식&lt;/b&gt;을 동시에 지원한다는 점이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Prefab 에디터에서 수정: lampost의 메시를 교체하면 &lt;b&gt;레벨 안의 모든 가로등 인스턴스가 즉시 갱신&lt;/b&gt;된다.&lt;/li&gt;
&lt;li&gt;단일 인스턴스에서 수정: 이 램프 하나의 light 색상만 바꾸고, 다른 인스턴스는 그대로 둔다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 발표자가 정리한 말, &amp;ldquo;&lt;b&gt;원하는 방식으로 콘텐츠를 구조화하라(structure content the way you like)&lt;/b&gt;&amp;rdquo;의 의미다. 대량 재사용과 로컬 커스터마이즈는 둘 중 하나를 포기해야 하는 선택지가 아니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Component: 엔진 기능이면서, 사용자의 Verse 행동이기도 하다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph에서 컴포넌트는 두 종류의 책임을 맡는다. 영상에서는 이를 꽤 완전하게 설명한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;내장 컴포넌트(Built-in Components)&lt;/b&gt;: API가 직접 제공한다. 예를 들어 transform, mesh, light, 그리고 뒤에서 등장하는 key frame movement가 있다. 엔지니어링 관점에서는 &amp;ldquo;다시 직접 작성하지 않아도 되는 기본 능력&amp;rdquo;이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자 정의 Verse 컴포넌트&lt;/b&gt;: 과거 Verse device 안에 쓰던 행동을 컴포넌트로 작성해 엔티티에 붙인다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XN3vg/dJMcacQ4qyR/RvjvOq6xWEhnMlnFBbCtR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XN3vg/dJMcacQ4qyR/RvjvOq6xWEhnMlnFBbCtR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XN3vg/dJMcacQ4qyR/RvjvOq6xWEhnMlnFBbCtR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXN3vg%2FdJMcacQ4qyR%2FRvjvOq6xWEhnMlnFBbCtR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트는 내장 능력일 수도 있고, 사용자 Verse 코드나 가져온 asset일 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 세 번째 차원도 덧붙였다. &lt;b&gt;컴포넌트는 asset reference로도 표현될 수 있다.&lt;/b&gt; 가져온 mesh, VFX, 나아가 Prefab 자체도 assets 파일을 통해 Verse에 노출될 수 있고, 런타임에서 컴포넌트 방식으로 인스턴스화, 교체, 생성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.1 사용자 정의 Verse 컴포넌트: device 사고방식에서 벗어나기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상에서는 아주 간단한 예시 컴포넌트를 보여준다. 대략 다음과 같다. 아래 코드는 영상에 나온 코드 조각을 바탕으로 Verse 스타일 의사 코드로 다시 그린 것이다. [AI 추정] 부분은 코드가 자족적으로 보이도록 타입 선언을 보완한 것이지, 영상의 완전한 코드 복사는 아니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# [AI 추정] 영상 예시를 바탕으로 정리한 최소 의사 코드.
# 컴포넌트 생명주기를 설명하기 위한 용도다.
my_cool_new_component := class(component):
    OnBeginSimulation():void =
        Print(&quot;hello world&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 변화는 &amp;ldquo;이 코드는 언제 실행되는가?&amp;rdquo;라는 질문에 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;과거 Verse device 방식: 코드는 &lt;b&gt;레벨에 끌어다 놓은 그 device 오브젝트&lt;/b&gt;가 시작될 때 실행된다.&lt;/li&gt;
&lt;li&gt;컴포넌트 방식: 코드는 &lt;b&gt;컴포넌트가 붙어 있는 엔티티&lt;/b&gt;가 시뮬레이션을 시작할 때(OnBeginSimulation) 실행된다. 더 이상 중앙 device를 진입점으로 필요로 하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c078ma/dJMcacQ4qyO/fklwwTnyqbjZ1YX2GMczH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c078ma/dJMcacQ4qyO/fklwwTnyqbjZ1YX2GMczH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c078ma/dJMcacQ4qyO/fklwwTnyqbjZ1YX2GMczH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc078ma%2FdJMcacQ4qyO%2FfklwwTnyqbjZ1YX2GMczH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prefab은 전체 구조로 저장되며 asset처럼 인스턴스화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 극단적인 예를 든다. 같은 컴포넌트를 집 Prefab 안의 모든 자식 엔티티에 붙이면 벽돌 하나하나가 모두 Hello World를 실행하게 만들 수 있다. 그는 이것이 **&amp;ldquo;아마 좋은 설계는 아닐 것&amp;rdquo;**이라고도 말한다. 하지만 이 예시는 능력의 경계를 보여준다. 행동은 임의의 입자도 높은 엔티티 단위까지 내려갈 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.2 컴포넌트화의 설계 이점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;컴포넌트를 붙일 것인가&amp;rdquo;를 조절 스위치처럼 다룰 수 있게 되면, 컴포넌트화는 몇 가지 체감 가능한 엔지니어링 이점을 준다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;상속이 아니라 능력 조합&lt;/b&gt;: 새 행동을 추가하기 위해 어떤 베이스 클래스를 확장할 필요가 없다. 새 컴포넌트를 쓰면 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;행동과 시각 표현의 분리&lt;/b&gt;: mesh와 gameplay 행동은 모두 컴포넌트이므로 독립적으로 교체할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;더 자연스러운 쿼리 의미론&lt;/b&gt;: 뒤에서 &amp;ldquo;장면 안의 light component를 가진 모든 엔티티 찾기&amp;rdquo; 같은 쿼리가 나온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. Verse: Scene Graph가 안정적으로 돌아가는 진짜 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상의 핵심 관점 중 하나는 이것이다. &lt;b&gt;Verse를 평범한 스크립트 언어로 보지 말라.&lt;/b&gt; Epic은 Verse를 &amp;ldquo;장기간 실행, 월드 간 이동, 사용자 공유 콘텐츠&amp;rdquo;를 감당할 수 있는 언어로 설계했다. 이런 엔지니어링 제약이 Verse를 다른 스크립트 언어와 다른 모습으로 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.1 왜 &amp;ldquo;메타버스&amp;rdquo;는 언어에 추가 제약을 요구하는가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 먼저 메타버스 경험이 해결해야 하는 세 가지 엔지니어링 전제를 설명한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Always on&lt;/b&gt;: 섬과 경험은 계속 실행되어야 하며, 어떤 사용자 코드 하나 때문에 쉽게 죽어서는 안 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Transferable&lt;/b&gt;: 콘텐츠는 서로 다른 월드 사이를 이동할 수 있어야 한다. 이사할 때 고립된 라이브러리와 리소스를 잔뜩 끌고 다녀야 해서는 안 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Strong and stable&lt;/b&gt;: 사용자가 공개한 콘텐츠가 다른 사람의 경험을 쉽게 망가뜨려서는 안 된다. 예를 들어 자동차 한 대가 다른 사람의 섬으로 들어갔다고 해서 그 섬의 모든 엔티티를 지워버릴 수 있어서는 안 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dV9hKt/dJMcacQ4qyL/r9fjU9PXKZI9xLjl6dan21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dV9hKt/dJMcacQ4qyL/r9fjU9PXKZI9xLjl6dan21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dV9hKt/dJMcacQ4qyL/r9fjU9PXKZI9xLjl6dan21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdV9hKt%2FdJMcacQ4qyL%2Fr9fjU9PXKZI9xLjl6dan21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Verse는 Scene Graph에 안정성과 이식성을 위한 제약 기반을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 속 &amp;ldquo;남의 섬에 차가 들어와 모든 엔티티를 지워버리는&amp;rdquo; 반례는 영상이 제시한 구체적인 위협 모델이다. Verse의 많은 설계 선택은 &lt;b&gt;이런 파괴가 언어 차원에서 불가능해지도록&lt;/b&gt; 하기 위한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.2 Verse의 네 가지 핵심 속성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상에서 명확히 언급한 Verse 특성은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;강타입 + 하위 호환성&lt;/b&gt;: Scene Graph 오브젝트의 장기 사용 가능성을 보장한다. 발표자는 가상의 상황을 예로 든다. 2030년에 누군가 2025년에 공개한 당신의 Verse 코드를 다운로드해 실행하더라도, 새 버전에서 여전히 돌아간다. Verse가 하위 호환성을 약속하기 때문이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전역 공유 네임스페이스&lt;/b&gt;: 공개된 Verse 코드는 evan.epic.com/...citybuilder.verse 같은 전역 유일 네임스페이스에 놓인다. 창작자 간 이름 충돌을 피하기 위해서다. 처음 공개된 tycoon builder.verse가 그 이름을 독점하지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션성(transactional)&lt;/b&gt;: 발표자는 이것을 Verse의 &amp;ldquo;가장 큰 초능력 중 하나&amp;rdquo;라고 부른다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;낮은 진입 장벽&lt;/b&gt;: 메모리 관리, 멀티스레딩, 멀티플레이 네트워크 같은 전통적인 난점이 언어 차원에서 감싸진다. 창작자는 코드를 쓰고, Verse device를 끌어다 놓고, Play를 누르기만 해도 이미 멀티플레이에서 쓸 수 있는 경험을 만들게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.3 트랜잭션성: 제약이 붙은 rollback 모델&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gxp0W/dJMcai4M2gA/n6EKf1EXrylxebj8A4VGKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gxp0W/dJMcai4M2gA/n6EKf1EXrylxebj8A4VGKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gxp0W/dJMcai4M2gA/n6EKf1EXrylxebj8A4VGKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGxp0W%2FdJMcai4M2gA%2Fn6EKf1EXrylxebj8A4VGKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Verse의 트랜잭션 컨텍스트는 예외를 롤백해 경험을 망가뜨리지 않게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 매우 엔지니어링적인 예를 든다. 플레이어에게 팀 무기를 배정하는 함수다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;playspace를 가져온다.&lt;/li&gt;
&lt;li&gt;team collection을 가져온다.&lt;/li&gt;
&lt;li&gt;player를 기준으로 team을 찾는다.&lt;/li&gt;
&lt;li&gt;이 team의 player에게 무기를 지급한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 네 단계는 모두 &lt;b&gt;failable(실패할 수 있음)&lt;/b&gt; 하다. 전통적인 언어에서는 중간 단계 하나가 실패하면 직접 null check를 하고, 상태를 직접 롤백해야 한다. Verse의 트랜잭션 모델은 &lt;b&gt;전체 컨텍스트를 하나의 트랜잭션&lt;/b&gt;으로 본다. 어떤 단계든 실패하면, 예를 들어 배열 범위 초과, null pointer, 비즈니스 실패가 발생하면, &lt;b&gt;전체 트랜잭션이 rollback되고 heap에 쓰지 않으며, 경험을 망가뜨리지 않는다.&lt;/b&gt; 섬은 계속 실행되고, 다른 플레이어는 영향을 받지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 증거의 경계는 분명히 해야 한다. 영상은 트랜잭션 의미론과 그 엔지니어링 가치를 강조했지만, &lt;b&gt;구체적인 성능 데이터, rollback 비용, 모든 API의 정확한 정의는 제시하지 않았다.&lt;/b&gt; 따라서 이 글은 어떤 benchmark 결론도 추론하지 않는다. 실제 프로젝트에서는 직접 측정해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 핵심 예시: 컴포넌트로 장면 안의 모든 엔티티 조회하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상에서 Scene Graph와 Verse가 함께 만들어내는 가치를 가장 잘 보여주는 코드 예시는 &amp;ldquo;시뮬레이션 시작 시 장면 안의 모든 light가 있는 엔티티에 파티클 효과를 붙이는&amp;rdquo; 컴포넌트다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKuW7C/dJMcahLEhcO/kVy91J3KWCcAk9iSHaD0HK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKuW7C/dJMcahLEhcO/kVy91J3KWCcAk9iSHaD0HK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKuW7C/dJMcahLEhcO/kVy91J3KWCcAk9iSHaD0HK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKuW7C%2FdJMcahLEhcO%2FkVy91J3KWCcAk9iSHaD0HK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커스텀 Verse 컴포넌트가 컴포넌트 쿼리로 전체 엔티티 트리를 탐색한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 이 코드가 무엇을 하는지 단계별로 설명한다. 아래는 영상 설명을 바탕으로 한국어 흐름에 맞게 정리한 의사 코드다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# [AI 추정] 영상 설명을 바탕으로 정리한 최소 의사 코드.
light_vfx_bolt := class(component):
    OnBeginSimulation():void =
        # 1. 컴포넌트가 붙은 엔티티에서 simulation entity(최상위 entity)를 가져온다.
        SimEntity := GetEntity().GetSimulationEntity[]

        # 2. 컴포넌트 타입으로 전체 엔티티 트리를 조회해
        # light_component를 가진 모든 엔티티를 반환한다.
        LitEntities := SimEntity.FindDescendantEntitiesWithComponent[light_component]

        # 3. 각 대상 엔티티에 particle system component를 만들고 추가한다.
        for (LitEntity : LitEntities):
            VFX := particle_system_component{ ParticleSystem := blowing_particles_asset }
            LitEntity.AddComponents[array{ VFX }]
            VFX.Enable()
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예시를 자세히 볼 가치가 있는 이유는, device 모델에서는 매우 하기 어려웠던 몇 가지를 보여주기 때문이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;조회 대상이 특정 Creative prop 클래스가 아니다.&lt;/b&gt; 수동으로 관리하는 배열도 아니다. &amp;ldquo;light component를 가진 모든 엔티티&amp;rdquo;다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조회 범위가 simulation entity에서 시작해 전체 트리를 덮을 수 있다.&lt;/b&gt; 모든 엔티티가 이 통일 구조 아래에 있기 때문이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새 능력은 대상에 &amp;lsquo;외부에서 붙이는&amp;rsquo; 것이 아니라&lt;/b&gt;, 컴포넌트로서 &lt;b&gt;그 엔티티의 일부가 된다.&lt;/b&gt; 이것은 접착이 아니라 조합이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;같은 로직을 임의의 컴포넌트에 붙일 수 있다.&lt;/b&gt; 생명주기는 그 컴포넌트가 붙어 있는 엔티티가 구동한다. 더 이상 전역 device에 의존하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 이것을 &amp;ldquo;really, really, really hard to do with devices&amp;rdquo;, 즉 &amp;ldquo;device 모델에서는 정말 정말 정말 어렵다&amp;rdquo;고 평가했다. 이것이 이 절의 엔지니어링 핵심이다. Scene Graph는 본질적으로 UEFN의 &amp;ldquo;오브젝트-행동&amp;rdquo; 관계를 &lt;b&gt;중앙 스케줄링&lt;/b&gt;에서 &lt;b&gt;통일된 쿼리&lt;/b&gt;로 바꾼다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 샘플 레벨: 먼저 devices로 만들고, 다시 Scene Graph로 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.1 왜 플랫폼 레벨을 예시로 골랐는가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상의 데모 부분은 가장 고전적인 플랫폼 레벨(platformer)을 선택했다. 플레이어가 태어나고, 여러 장애물을 건너 목적지에 도달한다. 장애물 중 가장 흔한 것은 &amp;ldquo;깊은 구덩이 위를 가로지르는 움직이는 플랫폼&amp;rdquo;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UZO1h/dJMcai4M2gB/YcBkxpvUrdlc58ukGCWL60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UZO1h/dJMcai4M2gB/YcBkxpvUrdlc58ukGCWL60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UZO1h/dJMcai4M2gB/YcBkxpvUrdlc58ukGCWL60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUZO1h%2FdJMcai4M2gB%2FYcBkxpvUrdlc58ukGCWL60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 플랫폼 하나는 entity + transform + mesh만으로도 돌아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 이 최소 플랫폼을 매우 깔끔하게 추상화한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그것은 하나의 &lt;b&gt;엔티티&lt;/b&gt;다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;transform component&lt;/b&gt;가 있어 월드 안의 위치를 알려준다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;mesh component&lt;/b&gt;가 있어 플레이어가 보고 올라설 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 컴포넌트를 붙이고 Prefab으로 저장하면, 전체 맵 안에 수십 개의 플랫폼을 끌어다 놓을 수 있다. &lt;b&gt;5분 만에 기초 플랫폼 레벨을 만드는 것이 과장이 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 문제는 능력을 확장하기 시작할 때 생긴다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플랫폼을 움직이고 싶다? movement component를 붙인다.&lt;/li&gt;
&lt;li&gt;플레이어가 오래 서 있으면 피해를 주고 싶다? damage-on-stand component를 붙인다.&lt;/li&gt;
&lt;li&gt;플레이어가 밟을 때 폭발하거나 NPC를 생성하고 싶다? 해당 컴포넌트를 붙인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 능력들은 &lt;b&gt;컴포넌트 형태로 필요에 따라 조합&lt;/b&gt;된다. &amp;ldquo;device A가 이동 담당, device B가 피해 담당, device C가 몬스터 생성 담당&amp;rdquo; 같은 다중 device 연결 방식으로 되돌아갈 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.2 먼저 devices 버전 보기: 왜 400줄까지 갔는가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀이 처음 이 플랫폼 예제를 만들 때는 전통적인 device 모델을 사용했다. 출발점은 UEFN 문서의 &amp;ldquo;animating prop movement&amp;rdquo; 튜토리얼이고, Fall Guys 템플릿 섬을 사용했다. 레벨에는 몇 그룹의 애니메이션이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;좌우로 이동하는 플랫폼&lt;/li&gt;
&lt;li&gt;제자리에서 회전하는 플랫폼&lt;/li&gt;
&lt;li&gt;transform scale을 기반으로 커졌다 작아지는 플랫폼&lt;/li&gt;
&lt;li&gt;이동 + 회전을 동시에 하는 플랫폼&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zr8F0/dJMcacQ4qyM/NRKakPSAy2d8Yihhfggwhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zr8F0/dJMcacQ4qyM/NRKakPSAy2d8Yihhfggwhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zr8F0/dJMcacQ4qyM/NRKakPSAy2d8Yihhfggwhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzr8F0%2FdJMcacQ4qyM%2FNRKakPSAy2d8Yihhfggwhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Device 모델의 이동 플랫폼은 중앙 관리 클래스에 의존한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 device 구현 방식을 다시 정리한다. 여기서는 영상의 논리 순서에 맞게 정리한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Creative prop 자체는 Verse 코드를 실행할 수 없다.&lt;/b&gt; 그것은 월드 안의 오브젝트일 뿐, 데이터도 없고 행동도 없다.&lt;/li&gt;
&lt;li&gt;그래서 먼저 movable prop class를 만든다. 그 안에는 prop reference, 이동 시간, 이동 타입, easing, 시작점, 되돌아갈지 여부 같은 파라미터가 들어간다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;애니메이션 자체&lt;/b&gt;는 key frame으로 쪼개야 한다. 각 key frame은 목표 transform + 다음 key frame까지 걸리는 시간이다. 보간도 직접 만들고, key frame 배열도 직접 조립한 뒤, 해당 prop의 animation controller에 넘겨 재생해야 한다.&lt;/li&gt;
&lt;li&gt;여기까지만 해서는 &lt;b&gt;Play를 눌러도 아무 일도 일어나지 않는다.&lt;/b&gt; 이 movable prop class 인스턴스들을 시작해줄 &amp;ldquo;누군가&amp;rdquo;가 없기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ysmtX/dJMcahLEhcP/OsgRXHJXZahQ6ko3SaVnZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ysmtX/dJMcahLEhcP/OsgRXHJXZahQ6ko3SaVnZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ysmtX/dJMcahLEhcP/OsgRXHJXZahQ6ko3SaVnZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FysmtX%2FdJMcahLEhcP%2FOsgRXHJXZahQ6ko3SaVnZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Creative prop은 스스로 Verse를 실행할 수 없기 때문에 prop movement initiator 같은 중앙 장치가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;누가 시작할 것인가&amp;rdquo; 문제를 해결하기 위해 팀은 다시 prop movement initiator라는 Verse device를 추가했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 animating prop의 레퍼런스를 보유한다.&lt;/li&gt;
&lt;li&gt;OnBegin에서 이들을 순회하며 setup을 호출한다.&lt;/li&gt;
&lt;li&gt;이들을 통일적으로 구동한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 이 initiator를 &amp;ldquo;거대한 손 하나가 말들을 움직이는 것 같다&amp;rdquo;고 묘사한다. prop 자체는 자신이 무엇을 해야 하는지 모른다. 이 손이 그것을 옮기고, 시작시키고, 다른 prop과 조율해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 또 다른 문제가 나온다. &lt;b&gt;이 prop들은 서로 소통할 방법이 없다.&lt;/b&gt; 플레이어가 어디까지 갔는지 알고 싶은가? 안 된다. prop에는 상태가 없기 때문이다. 어떤 교차 오브젝트 조율도 반드시 중앙 device를 거쳐야 한다. 모델은 필연적으로 &amp;ldquo;별 모양 + 중앙 권위&amp;rdquo;로 향한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자가 제시한 규모는 이렇다. &lt;b&gt;전체 device 버전은 약 400줄의 코드&lt;/b&gt;다. 이것은 성능 데이터가 아니다. 예제 자체는 복잡하지 않은데, &amp;ldquo;오브젝트가 자체 행동을 가질 수 없다&amp;rdquo;는 사실이 코드량과 사고 복잡도를 모두 키웠다는 의미다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zmi35/dJMcai4M2gx/oF66Nxcww2H92TZ2VqLMg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zmi35/dJMcai4M2gx/oF66Nxcww2H92TZ2VqLMg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zmi35/dJMcai4M2gx/oF66Nxcww2H92TZ2VqLMg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzmi35%2FdJMcai4M2gx%2FoF66Nxcww2H92TZ2VqLMg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Device 버전의 또 다른 고통점은 동적 생성 비용이 매우 높다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상이 강조한 또 다른 핵심 비용은 &lt;b&gt;정적성&lt;/b&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레벨에 새 플랫폼 하나를 추가하고 싶다. prop을 복사하고, 목표 지점을 복사하고, 이름을 바꾸고, device로 돌아가 설정 항목을 추가하고, prop과 목표 지점을 모두 끌어다 연결해야 한다.&lt;/li&gt;
&lt;li&gt;런타임 동적 생성은 더 힘들다. prop을 spawn하고, 목표 지점을 spawn하고, movable prop 클래스를 new하고, 모든 파라미터를 할당하고, key frame을 생성하고, 배열에 push해야 한다. 게다가 다른 시스템이 setup을 호출해야 실제로 움직인다.&lt;/li&gt;
&lt;li&gt;행동을 확장하고 싶다. 예를 들어 플랫폼을 오래 밟으면 체력을 깎고 싶다. 그러면 베이스 클래스에 계속 쌓아 더러워지거나, 새 device를 만들고 접착 코드를 다시 써야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.3 Scene Graph로 바꾸기: entity가 자기 행동을 스스로 책임진다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Scene Graph 모델로 전환한다. 발표자는 전체 사고방식을 뒤집는다. &lt;b&gt;하나의 중앙 device가 모든 플랫폼을 움직이게 하지 말고, 플랫폼 엔티티가 스스로 이동 능력을 갖게 하라.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYCpXK/dJMcai4M2gu/J4Rxn3RXcqnNxVlYbgu8K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYCpXK/dJMcai4M2gu/J4Rxn3RXcqnNxVlYbgu8K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYCpXK/dJMcai4M2gu/J4Rxn3RXcqnNxVlYbgu8K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYCpXK%2FdJMcai4M2gu%2FJ4Rxn3RXcqnNxVlYbgu8K0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;animate targets 컴포넌트는 엔티티가 스스로 key frame movement를 구동하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구체적인 구현은 animate_targets_component라는 사용자 정의 Verse 컴포넌트다. 의사 코드 흐름은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# [AI 추정] 영상 설명을 바탕으로 정리한 최소 의사 코드.
animate_targets_component := class(component):
    Targets : []transform = array{}
    Segments : []segment_info = array{}  # 각 segment는 정지 시간 등을 설명한다.

    OnBeginSimulation():void =
        # 이 엔티티에서 내장 key_frame_movement_component를 가져온다.
        KeyFrameMover := GetEntity().GetComponent[key_frame_movement_component]

        loop:
            for (I -&amp;gt; Target : Targets):
                KeyFrameMover.MoveToTransform(Target)
                if (Seg := Segments.FindSegmentAtIndex[I]):
                    Sleep(Seg.PauseSeconds)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 두 가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호출하는 것은 &lt;b&gt;엔진 내장 key frame movement component&lt;/b&gt;다. transform / mesh / light / key frame movement는 영상에서 명확히 &amp;ldquo;이미 노출된&amp;rdquo; 컴포넌트로 언급된다. 선형 보간을 직접 쓸 필요가 없다.&lt;/li&gt;
&lt;li&gt;이 컴포넌트는 &amp;ldquo;나, 이 엔티티&amp;rdquo;가 어떻게 움직일지만 신경 쓴다. 레벨 안의 다른 플랫폼을 알 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 device 버전의 initiator 문제가 바로 사라진다. &lt;b&gt;각 플랫폼 엔티티가 자기 시뮬레이션 루프를 스스로 시작한다.&lt;/b&gt; 이 행동이 필요한 오브젝트는 그냥 이 컴포넌트를 붙이면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6n2eD/dJMcacQ4qyQ/pA2URZbUjCdkNzDHRXWkFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6n2eD/dJMcacQ4qyQ/pA2URZbUjCdkNzDHRXWkFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6n2eD/dJMcacQ4qyQ/pA2URZbUjCdkNzDHRXWkFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6n2eD%2FdJMcacQ4qyQ%2FpA2URZbUjCdkNzDHRXWkFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 컴포넌트 구조가 전혀 다른 두 시각 표현, 즉 회색 박스와 건물 전체를 구동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 일부러 비교 이미지를 보여준다. 왼쪽은 지루한 회색 박스가 좌우로 움직이고, 오른쪽은 &lt;b&gt;건물 한 채 전체&lt;/b&gt;가 같은 움직임을 한다. 둘은 밑바닥에서 &lt;b&gt;완전히 같은 Prefab, 같은 컴포넌트 조합, 같은 행동&lt;/b&gt;이다. 차이는 mesh와 자식 엔티티 구조뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 그림의 엔지니어링 의미는 흥미롭다. &lt;b&gt;행동이 더 이상 특정 시각 오브젝트에 묶이지 않는다.&lt;/b&gt; &amp;ldquo;수평 왕복 이동&amp;rdquo; Prefab의 mesh를 태양으로 바꿀 수도 있고, 도시 전체로 바꿀 수도 있다. 발표자는 농담처럼 말했다. &amp;ldquo;진짜 그렇게 하지는 마라. 컴퓨터가 폭발할 것이다. 하지만 그런 능력은 갖고 있다.&amp;rdquo; 이동 로직은 그대로 재사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.4 작업 흐름: 수십 초에서 몇 초로&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 &amp;ldquo;에디터에서 새 플랫폼 하나를 추가하는&amp;rdquo; 전체 과정을 비교한 영상도 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uFaXB/dJMcahLEhcQ/vYWH4KePLNKCQer0vhL9kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uFaXB/dJMcahLEhcQ/vYWH4KePLNKCQer0vhL9kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uFaXB/dJMcahLEhcQ/vYWH4KePLNKCQer0vhL9kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuFaXB%2FdJMcahLEhcQ%2FvYWH4KePLNKCQer0vhL9kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Device 버전에서 새 플랫폼 하나를 추가하려면 editables, targets, keyframes를 묶어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;device 버전은 화면을 3배속으로 재생했는데, 실제로는 약 1분이 걸린다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;플랫폼 prop을 복사한다.&lt;/li&gt;
&lt;li&gt;그 목표 지점들을 복사한다.&lt;/li&gt;
&lt;li&gt;모든 위치를 수동으로 조정한다.&lt;/li&gt;
&lt;li&gt;식별하기 쉽도록 목표 지점 이름을 바꾼다.&lt;/li&gt;
&lt;li&gt;Verse device로 돌아간다.&lt;/li&gt;
&lt;li&gt;animating prop 항목을 새로 추가한다.&lt;/li&gt;
&lt;li&gt;플랫폼과 모든 목표 지점을 끌어다 연결한다.&lt;/li&gt;
&lt;li&gt;저장한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brQjmP/dJMcahLEhcN/Qd05mpxh4IKITlQoc5JFW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brQjmP/dJMcahLEhcN/Qd05mpxh4IKITlQoc5JFW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brQjmP/dJMcahLEhcN/Qd05mpxh4IKITlQoc5JFW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrQjmP%2FdJMcahLEhcN%2FQd05mpxh4IKITlQoc5JFW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph 버전: Prefab을 끌어다 놓으면 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph 버전은 이렇다. &lt;b&gt;Prefab 패널을 열고, 레벨에 끌어다 놓는다. 끝.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 이 경험을 네 단어로 정리한다. &lt;b&gt;easy, fast, dynamic, reusable&lt;/b&gt;. 엔지니어링식으로 번역하면, &amp;ldquo;행동을 가진 오브젝트를 월드에 배치하는 일&amp;rdquo;의 &lt;b&gt;한계 비용을 최소화했다&lt;/b&gt;는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.5 런타임 동적 생성: 진짜 차이는 여기서 나온다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph가 진짜 힘을 발휘하는 곳은 사실 정적 레벨이 아니라 런타임이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I3YOB/dJMcacQ4qyS/rdPc53lDVnpfDpJIGjaCy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I3YOB/dJMcacQ4qyS/rdPc53lDVnpfDpJIGjaCy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I3YOB/dJMcacQ4qyS/rdPc53lDVnpfDpJIGjaCy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI3YOB%2FdJMcacQ4qyS%2FrdPc53lDVnpfDpJIGjaCy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prefab이 런타임에 인스턴스화되고, 컴포넌트가 즉시 시뮬레이션을 시작한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플레이어가 스위치를 밟으면 좌우로 움직이는 플랫폼 한 줄을 동적으로 생성하고 싶다. 이 Prefab을 바로 spawn하면 된다.&lt;/li&gt;
&lt;li&gt;엔티티가 인스턴스화될 때 그 위의 animate_targets_component가 OnBeginSimulation에서 실행을 시작한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;device를 새로 만들 필요도 없고, editables를 연결할 필요도 없고, 수동 setup도 필요 없다.&lt;/b&gt; 스스로 움직인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 &amp;ldquo;Prefab은 spawn되는 순간 완전한 실행 단위가 된다&amp;rdquo;는 행동은 영상 시작 부분의 추상 원칙을 검증 가능한 장면으로 떨어뜨린다. &lt;b&gt;시뮬레이션 로직의 소속이 완전히 엔티티로 내려간다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. 컴포넌트화 사고와 중앙 관리 사고의 경계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상 마지막 부분에서 발표자는 &amp;ldquo;device 사고방식으로 되돌아가지 말라&amp;rdquo;는 점을 여러 번 강조한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pKUNL/dJMcacQ4qyT/L7LkaFKdPh8dfd7h7kph0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pKUNL/dJMcacQ4qyT/L7LkaFKdPh8dfd7h7kph0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pKUNL/dJMcacQ4qyT/L7LkaFKdPh8dfd7h7kph0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpKUNL%2FdJMcacQ4qyT%2FL7LkaFKdPh8dfd7h7kph0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;entity는 중앙 device에 의해 원격 조종되는 것이 아니라, 자기 의사결정권을 가져야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자의 의도를 엔지니어링 원칙 두 가지로 나누면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;컴포넌트가 데이터와 행동을 부여하게 하고, 엔티티가 스스로 판단하게 하라&lt;/b&gt;: 컴포넌트는 중앙 device의 원격 핸들이 아니다. 엔티티가 가진 모듈이고, 외부에는 쿼리 지점을 제공하며 내부에서는 자기 로직을 실행한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;ldquo;보이지 않는 손&amp;rdquo;을 다시 등장시키지 말라&lt;/b&gt;: 흔한 퇴행 경로가 있다. 형식상으로는 컴포넌트를 썼지만, 실제로는 &amp;ldquo;God Component / Manager&amp;rdquo;를 만들어 모든 엔티티를 원격 조종하는 방식이다. 발표자는 이 패턴을 명확히 피해야 한다고 말한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7.1 컴포넌트화가 Creative device 폐기를 뜻하지는 않는다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상은 &lt;b&gt;Creative device가 이제 낡은 방식이라고 선언하지 않는다.&lt;/b&gt; 오히려 발표자는 매우 절제된 톤으로 중요한 점을 짚는다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Creative devices are still incredibly incredibly useful. 발표자는 특히 mutator zones가 없다면 자신도 바다 위의 배처럼 길을 잃을 것이라고 말한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 문맥상 다음과 같은 엔지니어링 판단을 할 수 있다. 이것은 영상 맥락에 기반한 추론이지 Epic의 공식 규정은 아니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Scene Graph(컴포넌트 구동)가 더 적합한 경우&lt;/b&gt;: 오브젝트가 자체 상태와 행동을 가지며, 자주 재사용되고, 런타임에 대량으로 동적 생성되는 장면. 대표적으로 플랫폼, 장치, 조명, 상호작용 오브젝트, NPC spawner가 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Verse device(중앙 스케줄링)가 더 적합한 경우&lt;/b&gt;: 전역 규칙 진입점, 라운드 / 레벨 상태, 오브젝트 간 조율, 기존 Creative 장치(mutator zones, game modes 등)와 깊게 통합된 로직.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;혼합 방식이 현실 프로젝트의 일반적인 형태&lt;/b&gt;: &amp;ldquo;컴포넌트 순도&amp;rdquo;를 위해 모든 전역 규칙을 억지로 entity 하나에 밀어 넣지 말고, 반대로 mega-device 하나가 모든 로컬 행동을 계속 제어하게 두지도 말라.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;8. 현재 제한과 로드맵&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 마지막에 매우 솔직하게 한 가지를 설명한다. &amp;ldquo;왜 Scene Graph로 그 플랫폼 레벨 전체를 완전히 재현하지 않았는가?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Er2nh/dJMcai4M2gz/dm7vjMdKzjNxnXPX4Ime4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Er2nh/dJMcai4M2gz/dm7vjMdKzjNxnXPX4Ime4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Er2nh/dJMcai4M2gz/dm7vjMdKzjNxnXPX4Ime4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEr2nh%2FdJMcai4M2gz%2Fdm7vjMdKzjNxnXPX4Ime4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph는 현재도 아직 노출되지 않은 저수준 컴포넌트가 있다. 특히 physics가 그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상에서 명확히 언급된 경계는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이미 노출되었거나 사용 중인 컴포넌트&lt;/b&gt;: transform, mesh, light, key frame movement 등.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Physics는 아직 진행 중&lt;/b&gt;이다. 특히 캐릭터와의 상호 운용에는 더 많은 저수준 작업이 필요하다. 이것이 영상에서 완전한 Scene Graph 버전 플랫폼 레벨을 시연하지 않은 핵심 이유다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fortnite characters는 최종적으로 entity + component 형태로 존재하게 될 것&lt;/b&gt;이지만, 단계적으로 출시될 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fab의 Scene Graph 지원도 아직 개발 중&lt;/b&gt;이다. 이후에야 창작자 간 asset 재사용을 더 자연스럽게 이야기할 수 있을 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Itemization(아이템화 시스템)은 로드맵에 있으며 graph가 구동한다.&lt;/b&gt; 이후 출시될 예정이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 보수적이어야 한다. &lt;b&gt;영상은 구체적인 버전 번호, 출시 날짜, 완전한 API 목록을 제시하지 않았다.&lt;/b&gt; 실제 프로젝트에서 의존성을 평가할 때는 현재 사용 가능한 API를 기준으로 해야 하며, roadmap 항목을 이미 존재하는 기능처럼 취급해서는 안 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;9. 실전 적용 제안&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상의 큰 흐름과 엔지니어링 맥락에 기반한 판단을 합쳐, 바로 가져갈 수 있는 규칙을 정리해보자. 단, &lt;b&gt;피해야 할 점 / 베스트 프랙티스&lt;/b&gt; 두 부분은 영상의 의미 + 일반 엔지니어링 경험을 바탕으로 정리한 것이며 Epic의 공식 규범은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;9.1 방식 비교&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;전통적인 device-driven 방식&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적합한 곳: 전역 규칙 진입점, mutator zones / 라운드제 / 전역 점수 관리, 기존 Creative 장치와 밀접하게 통합된 로직.&lt;/li&gt;
&lt;li&gt;비용: 오브젝트 행동이 중앙화되기 쉽고, 동적 생성 비용이 높으며, 확장은 보통 새 device 추가 또는 클래스 비대화를 뜻한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Scene Graph / component-driven 방식&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적합한 곳: 자체 행동을 가진 오브젝트(플랫폼, 장치, 조명, NPC 생성기), 고빈도 Prefab화 콘텐츠, 런타임 동적 인스턴스화.&lt;/li&gt;
&lt;li&gt;비용: 엔티티와 컴포넌트 모델링 습관을 다시 세워야 한다. 현재 노출된 컴포넌트 집합은 계속 확장 중이므로 physics / characters / Fab 같은 경계를 주의해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;혼합 방식&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적합한 곳: 현 단계 대부분의 프로덕션 프로젝트.&lt;/li&gt;
&lt;li&gt;핵심 원칙: Scene Graph로 오브젝트를 관리하고, Verse device / Creative 장치로 전역 조율을 처리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;9.2 피해야 할 점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예전의 &amp;ldquo;중앙 관리자 사고방식&amp;rdquo;을 그대로 컴포넌트 안으로 옮기지 말라. 컴포넌트는 엔티티의 일부여야지, &amp;ldquo;중앙 device의 원격 리모컨&amp;rdquo;이어서는 안 된다.&lt;/li&gt;
&lt;li&gt;재사용을 이유로 여러 능력을 하나의 초대형 컴포넌트에 몰아넣지 말라. 이동, 피해, 상호작용, 생성 같은 능력은 조합 가능한 작은 컴포넌트로 나눠야 한다.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;모든 엔진 기능이 이미 컴포넌트화되었다&amp;rdquo;고 가정하지 말라. 특히 physics, character, Fab처럼 영상에서 아직 진행 중이라고 명확히 언급한 방향은 개발 전에 실제 API를 확인해야 한다.&lt;/li&gt;
&lt;li&gt;전체 장면 쿼리를 남용하지 말라. 컴포넌트 기반 쿼리는 강력하지만, 매 프레임 전체 트리를 스캔하면 체감 가능한 비용이 생길 수 있다. 영상은 성능 데이터를 제시하지 않았으므로, 프로덕션에서는 직접 profile해야 한다.&lt;/li&gt;
&lt;li&gt;Prefab을 정적인 템플릿으로만 보지 말라. Prefab의 진짜 가치는 &amp;ldquo;구조 + 컴포넌트 + 행동&amp;rdquo;을 함께 재사용하고, Prefab 레벨과 인스턴스 레벨의 두 가지 override 지점을 유지하는 데 있다.&lt;/li&gt;
&lt;li&gt;하위 호환성이 과거의 모든 작성 방식을 완전히 보호한다고 가정하지 말라. 영상은 Verse가 하위 호환성을 약속한다고 말하지만, &lt;b&gt;당신의 모든 UEFN 설계 결정이 무손실로 이전된다는 뜻은 아니다.&lt;/b&gt; 컴포넌트화 리팩터링을 염두에 둔다면 마이그레이션 window를 남겨둬야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;9.3 베스트 프랙티스&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;엔티티 이름&lt;/b&gt;은 외형만 묘사하지 말고 역할을 드러내라. 예를 들어 BlueBlock_01보다 MovingPlatform_Prefab이 장기 유지보수에 더 낫다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴포넌트 이름&lt;/b&gt;은 능력을 우선해서 설명하라. AnimateToTargetsComponent, DamageOnTouchComponent, SpawnGuardsOnOverlapComponent 같은 식이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;독립적으로 재사용 가능한 오브젝트는 Prefab으로 만들고&lt;/b&gt;, &lt;b&gt;반드시 전역적으로 알아야 하는 규칙&lt;/b&gt;은 더 높은 레벨 시스템에 둔다.&lt;/li&gt;
&lt;li&gt;동적으로 생성되는 콘텐츠는 Prefab 인스턴스화 후 컴포넌트 생명주기가 자동으로 실행되는지 먼저 검증하라. 수동 setup 흐름을 조용히 다시 도입하지 않도록 한다.&lt;/li&gt;
&lt;li&gt;엔티티 간 통신은 우선 &lt;b&gt;컴포넌트 쿼리 + 엔티티 계층 + 명확한 인터페이스&lt;/b&gt;를 사용하라. 암묵적 전역 상태로 되돌아가지 말라.&lt;/li&gt;
&lt;li&gt;Verse의 트랜잭션성은 &amp;ldquo;여러 단계로 된 실패 가능 작업&amp;rdquo;의 방어 코드를 단순화하는 데 쓸 수 있다. 하지만 이것을 &amp;ldquo;아무것도 검사하지 않아도 되는 만능 방패&amp;rdquo;로 취급하지는 말라.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;10. &amp;ldquo;Scene Graph dev 사고방식&amp;rdquo;의 좌표를 잡기&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FPMCU/dJMcai4M2gw/Vz4j7uyhxv97HsgBrtoKyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FPMCU/dJMcai4M2gw/Vz4j7uyhxv97HsgBrtoKyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FPMCU/dJMcai4M2gw/Vz4j7uyhxv97HsgBrtoKyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFPMCU%2FdJMcai4M2gw%2FVz4j7uyhxv97HsgBrtoKyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph를 devices 및 다른 API와 결합하는 것을 두려워하지 말라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자의 마지막 조언은 매우 명확하다. &lt;b&gt;Scene Graph dev처럼 생각하기 시작하라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 가능한 세 문장으로 바꾸면 이렇다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Entity는 백지다. 피와 살이 있는 &amp;ldquo;물체&amp;rdquo;가 아니다.&lt;/b&gt; 기존 클래스에서 잘라내는 것이 아니라, 컴포넌트로 그것이 무엇인지 결정한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Component는 능력의 단위다.&lt;/b&gt; 하나의 컴포넌트는 되도록 한 가지 문제만 해결한다. 능력은 상속이 아니라 조합으로 얻는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Verse device / Creative 장치는 여전히 유효하다.&lt;/b&gt; &amp;ldquo;순수 Scene Graph&amp;rdquo;를 위해 기존 도구와 싸우지 말라. 혼합 방식이 현 단계에서 가장 현실적인 경로다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd2iQg/dJMcahLEhcM/nU52wU8EycPbf4KcB1g4t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd2iQg/dJMcahLEhcM/nU52wU8EycPbf4KcB1g4t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd2iQg/dJMcahLEhcM/nU52wU8EycPbf4KcB1g4t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd2iQg%2FdJMcahLEhcM%2FnU52wU8EycPbf4KcB1g4t1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맺음말: Scene Graph 위에서 계속 무언가를 만들어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자는 마지막에 열린 힌트도 남겼다. Scene Graph 실험 단계에서는 이미 &amp;ldquo;미친 것처럼 보이고, 심지어 게임을 crash시킬 수도 있지만, 매우 인상적인&amp;rdquo; 커뮤니티 실험들이 있었다. 엔지니어링 관점에서 이 말의 진짜 의미는 &amp;ldquo;창작자들이 더 과격해졌다&amp;rdquo;가 아니다. &lt;b&gt;오브젝트-행동의 조합 공간이 드디어 열렸다&lt;/b&gt;는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀 입장에서는 Prefab을 합리적으로 나누고, 컴포넌트를 절제해서 분리하며, 중앙 관리자 습관을 진짜 전역 위치로만 눌러두는 일을 빨리 시작할수록 좋다. 나중에 더 완전한 Scene Graph 워크플로로 옮겨갈 때 저항이 그만큼 작아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scene Graph와 Verse의 조합이 바꾸는 것은 &amp;ldquo;코드를 몇 줄 덜 쓴다&amp;rdquo; 같은 표면적 효율이 아니다. UEFN 프로젝트에서 &lt;b&gt;오브젝트가 어떻게 정의되는가, 행동은 누구에게 속하는가, 런타임에는 어떻게 생성되는가&lt;/b&gt;라는 세 가지 근본 질문의 기본 답을 바꾸는 것이다.&lt;/p&gt;</description>
      <category>TECH.ART.FLOW.IO</category>
      <category>scene graph</category>
      <category>UEFN</category>
      <category>VERSE</category>
      <category>언리얼엔진</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/789</guid>
      <comments>https://techartnomad.tistory.com/789#entry789comment</comments>
      <pubDate>Wed, 24 Jun 2026 02:38:16 +0900</pubDate>
    </item>
    <item>
      <title>[번역] UE6에서 Verse 동작시키는 방법</title>
      <link>https://techartnomad.tistory.com/788</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;역자의 말: 뭐 이런것 까지 이렇게 해야 하나 싶다가도 웹브라우저에서 제공하는 자동번역 결과는 도무지 이해할 수가 없어서 이렇게 한국어판으로 따로 공유 하게 되었어요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ronaldburns.dev/projects/how-to-verse-in-ue6/?fbclid=IwY2xjawSnm6lleHRuA2FlbQIxMABicmlkETFrUW1OaXVMZFlPaVIweDRLc3J0YwZhcHBfaWQQMjIyMDM5MTc4ODIwMDg5MgABHnY1knQaHjqOQErnZzfGXfziGYUU_qL1EPPkuqnyfanpdyGXVusAjkVF1GIt_aem_YWdncwNAp0CqaQUBxrtFKSZE1zkk&amp;amp;brid=YWdncwHbcEYRYtX7V2FN3ys6bEoy&quot;&gt;How to Get Verse Working in UE6&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782234533377&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;How to Get Verse Working in UE6&quot; data-og-description=&quot;Epic shipped &amp;#96;ue6-main&amp;#96; with Verse in it, but it isn't actually wired up out of the box. Here's how to get it running.&quot; data-og-host=&quot;ronaldburns.dev&quot; data-og-source-url=&quot;https://ronaldburns.dev/projects/how-to-verse-in-ue6/?fbclid=IwY2xjawSnm6lleHRuA2FlbQIxMABicmlkETFrUW1OaXVMZFlPaVIweDRLc3J0YwZhcHBfaWQQMjIyMDM5MTc4ODIwMDg5MgABHnY1knQaHjqOQErnZzfGXfziGYUU_qL1EPPkuqnyfanpdyGXVusAjkVF1GIt_aem_YWdncwNAp0CqaQUBxrtFKSZE1zkk&amp;amp;brid=YWdncwHbcEYRYtX7V2FN3ys6bEoy&quot; data-og-url=&quot;https://ronaldburns.dev/projects/how-to-verse-in-ue6/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dwQkaj/dJMb89ynvBS/FYiCwDBzM9MQNLfcqDRic1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/b2XDdH/dJMb84qisN6/aMkY27lA0qDhsYc4TfKFk0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bwWQ6Y/dJMb86PbDs0/G97j7RSPsvAYoCZThKFVXK/img.png?width=1206&amp;amp;height=840&amp;amp;face=0_0_1206_840&quot;&gt;&lt;a href=&quot;https://ronaldburns.dev/projects/how-to-verse-in-ue6/?fbclid=IwY2xjawSnm6lleHRuA2FlbQIxMABicmlkETFrUW1OaXVMZFlPaVIweDRLc3J0YwZhcHBfaWQQMjIyMDM5MTc4ODIwMDg5MgABHnY1knQaHjqOQErnZzfGXfziGYUU_qL1EPPkuqnyfanpdyGXVusAjkVF1GIt_aem_YWdncwNAp0CqaQUBxrtFKSZE1zkk&amp;amp;brid=YWdncwHbcEYRYtX7V2FN3ys6bEoy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ronaldburns.dev/projects/how-to-verse-in-ue6/?fbclid=IwY2xjawSnm6lleHRuA2FlbQIxMABicmlkETFrUW1OaXVMZFlPaVIweDRLc3J0YwZhcHBfaWQQMjIyMDM5MTc4ODIwMDg5MgABHnY1knQaHjqOQErnZzfGXfziGYUU_qL1EPPkuqnyfanpdyGXVusAjkVF1GIt_aem_YWdncwNAp0CqaQUBxrtFKSZE1zkk&amp;amp;brid=YWdncwHbcEYRYtX7V2FN3ys6bEoy&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dwQkaj/dJMb89ynvBS/FYiCwDBzM9MQNLfcqDRic1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/b2XDdH/dJMb84qisN6/aMkY27lA0qDhsYc4TfKFk0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bwWQ6Y/dJMb86PbDs0/G97j7RSPsvAYoCZThKFVXK/img.png?width=1206&amp;amp;height=840&amp;amp;face=0_0_1206_840');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;How to Get Verse Working in UE6&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Epic shipped `ue6-main` with Verse in it, but it isn't actually wired up out of the box. Here's how to get it running.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ronaldburns.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Epic은 Verse가 포함된 ue6-main을 공개했지만, 기본 상태에서는 실제로 연결되어 있지 않다. 아래는 그것을 실행되게 만드는 방법이다.&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/04iXL/dJMcaiX1mwh/sSX2pdfjjnmvZXrgtppbHK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/04iXL/dJMcaiX1mwh/sSX2pdfjjnmvZXrgtppbHK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/04iXL/dJMcaiX1mwh/sSX2pdfjjnmvZXrgtppbHK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F04iXL%2FdJMcaiX1mwh%2FsSX2pdfjjnmvZXrgtppbHK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Epic이 방금 ue6-main 브랜치를 올렸고, 드디어 Verse도 그 안에 들어왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐&amp;hellip; 어느 정도는 그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔진을 sync하고, .verse 파일을 하나 작성하면 UEFN처럼 동작하리라 기대할 수 있다. 하지만 그렇게 되지 않는다. Verse 스택 대부분은 들어와 있지만, 이것을 실제로 쓸 수 있게 만드는 일반적인 프로젝트 쪽 설정은 아직 연결되어 있지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;느낌상 엔진에는 필요한 부품이 전부 설치되어 있는데, Unreal Fest에 맞추느라 이 릴리스를 꽤 급하게 밀어낸 것처럼 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 직접 배선을 해줘야 한다. 플러그인, 소스, 설정, 그리고 Epic이 원래 Valkyrie가 어려운 부분을 처리해주리라 예상했던 것으로 보이는 몇 군데를 손봐야 한다. 아래 단계를 따라 하면 실제로 동작하게 만들 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시작하기 전에&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라 하기 전에 몇 가지가 준비되어 있어야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Unreal Engine 소스에서 ue6-main 브랜치를 내려받아 둔다.&lt;/li&gt;
&lt;li&gt;엔진이 정상적으로 컴파일되고, 에디터가 오류 없이 열린다.&lt;/li&gt;
&lt;li&gt;작업할 새 UE6 프로젝트를 하나 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 내용은 모두 깨끗하게 컴파일되는 ue6-main 프로젝트에서 시작한다고 가정한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;필요한 플러그인 활성화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름에 &amp;ldquo;Verse&amp;rdquo;가 들어간 플러그인은 모두 켠다. 단, &amp;ldquo;Verse State Tree Editor&amp;rdquo;는 제외한다. 이 플러그인은 아직 공개되지 않은 &amp;ldquo;Verse State Machine&amp;rdquo;이라는 플러그인에 의존한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 플러그인을 활성화한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Verse&lt;/li&gt;
&lt;li&gt;Verse Colors&lt;/li&gt;
&lt;li&gt;Verse Engine&lt;/li&gt;
&lt;li&gt;Verse Experimental&lt;/li&gt;
&lt;li&gt;Verse Gameplay Debug&lt;/li&gt;
&lt;li&gt;Verse Persona Metadata&lt;/li&gt;
&lt;li&gt;Verse Print&lt;/li&gt;
&lt;li&gt;Verse Restricted&lt;/li&gt;
&lt;li&gt;Verse Simulation&lt;/li&gt;
&lt;li&gt;Verse Simulation Metadata&lt;/li&gt;
&lt;li&gt;Verse Spatial Math&lt;/li&gt;
&lt;li&gt;Verse Tags&lt;/li&gt;
&lt;li&gt;Verse Interface&lt;/li&gt;
&lt;li&gt;Verse Modifier&lt;/li&gt;
&lt;li&gt;Verse Module Independence A&lt;/li&gt;
&lt;li&gt;Verse Module Independence B&lt;/li&gt;
&lt;li&gt;Verse VM&lt;/li&gt;
&lt;li&gt;Entity Framework&lt;/li&gt;
&lt;li&gt;Solaris&lt;/li&gt;
&lt;li&gt;Unreal Engine Experimental&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고:&lt;/b&gt; Unreal Engine Experimental도 켜야 한다. 이것을 켜지 않으면 Verse의 Print 함수가 실제로 Unreal 로그에 출력되지 않는다. 왜 이런 식으로 연결해두었는지는 모르겠지만, 현재는 그렇게 되어 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1505&quot; data-origin-height=&quot;899&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r1pEj/dJMcageUnr2/02P2FjC9MUzUIaoLLoqWgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r1pEj/dJMcageUnr2/02P2FjC9MUzUIaoLLoqWgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r1pEj/dJMcageUnr2/02P2FjC9MUzUIaoLLoqWgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr1pEj%2FdJMcageUnr2%2F02P2FjC9MUzUIaoLLoqWgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1505&quot; height=&quot;899&quot; data-origin-width=&quot;1505&quot; data-origin-height=&quot;899&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에디터를 재시작한다. 그러면 최소한 에디터가 Verse의 존재를 인식하기는 한다. 이것만으로 일반 UE6 프로젝트가 UEFN처럼 동작하는 것은 아니지만, 가장 먼저 해야 할 단계다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ConsoleVariables 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플러그인만으로는 충분하지 않다. Verse 툴체인이 깨어나기 전에 몇 가지 ini 설정을 켜야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UEFN에는 이런 설정이 이미 프로젝트 기본값으로 들어가 있으므로, 그쪽에서는 사실 볼 일이 거의 없다. 하지만 새 UE6 프로젝트에서는 직접 설정해야 한다. 이 중 일부는 이것저것 만져보고 테스트하기 위한 성격도 있다. 재미 삼아 켜고 끄면서 무엇이 동작하고 무엇이 멈추는지 확인해봐도 된다. 예를 들어 one-file-per-entity는 시작하고 동작시키는 데 꼭 필요하지 않을 가능성이 높지만, 조금 &lt;b&gt;실험&lt;/b&gt;해봐도 나쁠 것은 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 설정을 넣으면 UEFN에 가까운 느낌으로 동작하기 시작한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// --- Config/DefaultEngine.ini ---

[ConsoleVariables]
; Forces the default outliner to use TEDS.
Valkyrie.UseTedsOutliner=1

TEDS.Enable=1
TEDS.Feature.Folders=1
TEDS.Feature.Folders.TypedElements=1
TEDS.UI.SetOutlinerPurpose=HybridOutliner
TEDS.UI.UseTedsOutlinerFolders=1
TEDS.RevisionControl.AutoPopulateState=1
TEDS.UI.UseNewRevisionControlWidgets=1
TEDS.UI.Outliner.ShowTedsColumnFilters=1
TEDS.UI.UseNewWidgets=1
TEDS.Feature.PickerEnabled=1
TEDS.Feature.UnloadedActors=1
TEDS.UI.EnableTedsContentBrowser=1
TEDS.UI.EnableTestContentSource=1
TEDS.AssetDataStorage=1
TEDS.TedsAssetDataFactory=1
TEDS.AssetDataStorage.Metadata=1
Teds.Feature.Alerts=1
TEDS.Feature.ActorCompatibility.ActorComponents.Enable=1
TEDS.UI.UseDefaultAttributeBindings=1
TEDS.Feature.Layers=1

; Disables using an Actor as a proxy for the prefab/entity and just uses scene graph.
SceneGraph.EntityProxyActors.Enabled=0
;SceneGraph.EnableCardLayout=1
SceneGraph.SelectTransformComponentByDefault=1
Entity.EnablePrefabEditMode=1
DetailsPanel.Overrides.EnableResetToDefault=1
EntityDetailsDisplayManager.LegacyTrimPropertyPathImplementation=1

; One-file-per-entity (external packages per entity). Read-only: startup-only, requires restart.
; OneFilePerEntityEnabled is the master; the other two are no-ops unless it is on.
Entity.OneFilePerEntityEnabled=1
Entity.OneFilePerEntityOnAllInstancesEnabled=1
Entity.OneFilePerPrefabEntityEnabled=1
EntityEditor.EnableAssetComponentSupport=1
EntityPrefabEditor.EnablePrefabThumbnails=1

; Enables thumbnail rendering and many other Prefab/Entity things
IDO.Enable=1
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고:&lt;/b&gt; DefaultEngine.ini를 수정한 뒤에는 에디터를 재시작해야 한다. 이 설정들은 시작 시점에만 읽히므로, 다시 실행하기 전까지는 아무것도 바뀌지 않는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Verse는 아직 Content 폴더 안에 존재할 수 없다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UEFN에서는 Verse 파일을 프로젝트 안에 직접 넣을 수 있고, 자동으로 발견된다. 기술적으로는 GameFeaturePlugin이긴 하지만, 사용자는 보통 그렇게 느낀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 ue6-main에서는 그렇게 동작하지 않는다. 게임용 Verse &amp;ldquo;Project&amp;rdquo;가 생성되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;겉으로 보기에는 게임을 등록해주는 코드가 빠져 있어서 동작하지 않는 것처럼 보인다. 주석을 통해 맞춰보면, 이 경로는 Epic 내부의 Valkyrie 런타임과 연결되어 있는 듯하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UEFN에서는 Valkyrie가 그 일을 대신 해준다. ue6-main에는 그것이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 현재 코드 경로가 없는 Content 폴더를 억지로 쓰려고 하지 말고, Verse 전용 플러그인을 만들어준다. Verse 모듈과 VersePath를 가진 플러그인은 Valkyrie가 관여하지 않아도 Solaris가 이미 mount하는 방법을 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 이것을 GameFeaturePlugin으로 처리했다. UEFN 구성과 가장 비슷하다고 생각했기 때문이다. 첫 테스트라면 같은 방식을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만들려면 Edit 메뉴에서 Plugins 창을 열고, &amp;ldquo;Add&amp;rdquo;를 누른 뒤 &amp;ldquo;Game Feature (Content Only)&amp;rdquo; 템플릿을 선택한다. 이름을 정하고 생성한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;756&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kUKsN/dJMcageUnr1/Xzy3zRxSlTqrLaRqpXxxMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kUKsN/dJMcageUnr1/Xzy3zRxSlTqrLaRqpXxxMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kUKsN/dJMcageUnr1/Xzy3zRxSlTqrLaRqpXxxMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkUKsN%2FdJMcageUnr1%2FXzy3zRxSlTqrLaRqpXxxMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1006&quot; height=&quot;756&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;756&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로 만든 GameFeaturePlugin의 .uplugin 파일에 아래 코드를 추가한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고:&lt;/b&gt; {PLUGIN NAME}은 자신의 GameFeaturePlugin 이름으로 바꾼다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;// START OF .uplugin file...
{
	&quot;FileVersion&quot;: 3,
	&quot;Version&quot;: 1,
	...

	// ADD THE FOLLOWING CODE
	&quot;CanContainVerse&quot;: true,
	&quot;VersePath&quot;: &quot;/localhost/{PLUGIN NAME}&quot;,
	&quot;VerseScope&quot;: &quot;InternalUser&quot;,
	&quot;VerseVersion&quot;: 0,
	&quot;EnableVerseAssetReflection&quot;: true,
	&quot;EnableSceneGraph&quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Content에 코드를 그냥 넣는 것만큼 깔끔하지는 않지만, 이 방식은 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에디터를 재시작한다. VerseExplorer 창을 열면 이제 GameFeaturePlugin용 모듈이 생성된 것을 볼 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4YkLZ/dJMcaiX1mwb/5dE4NZsz85IbXidBujSGVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4YkLZ/dJMcaiX1mwb/5dE4NZsz85IbXidBujSGVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4YkLZ/dJMcaiX1mwb/5dE4NZsz85IbXidBujSGVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4YkLZ%2FdJMcaiX1mwb%2F5dE4NZsz85IbXidBujSGVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;373&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 테스트 플러그인 이름은 &amp;ldquo;ArcadiaCore&amp;rdquo;였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;첫 Verse 파일 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로 생긴 플러그인 모듈을 우클릭하고 &amp;ldquo;Create a new Verse File&amp;rdquo;을 선택한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EmekK/dJMcabY04o0/dwmWuZjjMTejVACKzduri1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EmekK/dJMcabY04o0/dwmWuZjjMTejVACKzduri1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EmekK/dJMcabY04o0/dwmWuZjjMTejVACKzduri1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEmekK%2FdJMcabY04o0%2FdwmWuZjjMTejVACKzduri1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;494&quot; height=&quot;248&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 가자. &amp;ldquo;Scene Graph Component&amp;rdquo;를 만든다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;840&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceCiNR/dJMcabY04oX/kEIm9YCDetmhYk31UsJ4c1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceCiNR/dJMcabY04oX/kEIm9YCDetmhYk31UsJ4c1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceCiNR/dJMcabY04oX/kEIm9YCDetmhYk31UsJ4c1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceCiNR%2FdJMcabY04oX%2FkEIm9YCDetmhYk31UsJ4c1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1206&quot; height=&quot;840&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;840&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 새 Verse 파일을 더블클릭해 VSCode에서 열 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1119&quot; data-origin-height=&quot;837&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/46QqE/dJMcaiX1mwe/od3Eg5EucXLjb1HPtfjwH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/46QqE/dJMcaiX1mwe/od3Eg5EucXLjb1HPtfjwH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/46QqE/dJMcaiX1mwe/od3Eg5EucXLjb1HPtfjwH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F46QqE%2FdJMcaiX1mwe%2Fod3Eg5EucXLjb1HPtfjwH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1119&quot; height=&quot;837&quot; data-origin-width=&quot;1119&quot; data-origin-height=&quot;837&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;VSCode에 Verse 플러그인 추가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 여러분의 VSCode는 내 스크린샷처럼 보이지 않을 것이고, UEFN에서 익숙하게 보던 모습과도 다를 것이다. Epic의 VSCode 플러그인 두 개가 빠져 있기 때문이다. &amp;ldquo;UnrealRevisionControl&amp;rdquo;과, 더 중요하게는 &amp;ldquo;Verse&amp;rdquo;가 필요하다. UEFN에서 프로젝트를 열면 이 플러그인들은 VSCode 인스턴스에 자동 설치된다. ue6-main에서는 이 과정이 실패하지만, 고칠 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔진은 이 플러그인들을 찾아 VSCode에 자동 설치하려고 한다. 우리가 해야 할 일은 올바른 위치에 넣어두는 것뿐이다. UEFN 설치본에서 복사해 우리 엔진에 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬에 UEFN이 설치되어 있는지 확인한다. 거기서 VSCode 플러그인 &amp;ldquo;URC.vsix&amp;rdquo;와 &amp;ldquo;Verse.vsix&amp;rdquo;를 복사한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치는 보통 C:\Program Files\Epic Games\Fortnite\VSCode\... 이다. Fortnite를 다른 위치에 설치했다면 그 위치를 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원한다면 VSCode 설치 파일도 함께 복사해도 된다. 그것도 복사해두면, Verse 코드를 열려고 할 때 VSCode가 설치되어 있지 않은 경우 에디터가 자동으로 VSCode를 설치해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ue6-main 복사본의 루트에 &amp;ldquo;VSCode&amp;rdquo;라는 새 폴더를 만든다. &amp;ldquo;Engine&amp;rdquo;, &amp;ldquo;Samples&amp;rdquo;, &amp;ldquo;Templates&amp;rdquo; 폴더와 나란히 놓이는 위치다. 그 폴더 안에 &amp;ldquo;URC.vsix&amp;rdquo;와 &amp;ldquo;Verse.vsix&amp;rdquo; 복사본을 넣는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CbVQa/dJMcageUnr0/BZ7htdIJjrxKbJwHOZYrpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CbVQa/dJMcageUnr0/BZ7htdIJjrxKbJwHOZYrpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CbVQa/dJMcageUnr0/BZ7htdIJjrxKbJwHOZYrpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCbVQa%2FdJMcageUnr0%2FBZ7htdIJjrxKbJwHOZYrpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;264&quot; height=&quot;361&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1aWi6/dJMcaiX1mwc/1oTTQB4zhUQ1ykGTUxCHtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1aWi6/dJMcaiX1mwc/1oTTQB4zhUQ1ykGTUxCHtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1aWi6/dJMcaiX1mwc/1oTTQB4zhUQ1ykGTUxCHtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1aWi6%2FdJMcaiX1mwc%2F1oTTQB4zhUQ1ykGTUxCHtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;985&quot; height=&quot;176&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 VSCode 인스턴스는 닫는다. 이제 에디터에서 Verse 코드를 열면 플러그인이 자동으로 설치되어야 한다. 안 된다면 .vsix 파일을 VSCode 창에 드래그해서 수동 설치하면 된다.  &lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실제로 동작하는 것을 보고 싶다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 Verse 스크립트가 실제로 돌아가게 해보자. 우리가 만든 컴포넌트를 entity에 붙이고, 그것을 레벨에 끌어다 놓을 것이다. Play-In-Editor를 실행하면 Output Log에 출력이 찍히는 것을 볼 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Content Browser를 열고 GameFeaturePlugin 안에 새 Prefab을 만든다. 이 Prefab이 필요한 entity를 담게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqngl/dJMcaiX1mwd/2VpoqE9T6KQVXD3taSSuA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqngl/dJMcaiX1mwd/2VpoqE9T6KQVXD3taSSuA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqngl/dJMcaiX1mwd/2VpoqE9T6KQVXD3taSSuA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frqngl%2FdJMcaiX1mwd%2F2VpoqE9T6KQVXD3taSSuA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;774&quot; height=&quot;232&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prefab에는 이미 root에 entity가 하나 있다. 여기에 테스트 컴포넌트를 추가한다. 새 컴포넌트가 보이지 않는다면 에디터나 VSCode에서 &amp;ldquo;Compile Verse&amp;rdquo;를 누른다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfBEoE/dJMcaiX1mwg/kGhW7pMqnHjYyOI7bUHMH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfBEoE/dJMcaiX1mwg/kGhW7pMqnHjYyOI7bUHMH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfBEoE/dJMcaiX1mwg/kGhW7pMqnHjYyOI7bUHMH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfBEoE%2FdJMcaiX1mwg%2FkGhW7pMqnHjYyOI7bUHMH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;324&quot; height=&quot;262&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 새 테스트 컴포넌트가 붙은 entity를 담고 있는 Prefab이 생겼다. 이제 이것을 레벨에 추가하기만 하면 된다. Viewport에서는 이런 식으로 보일 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m4hXp/dJMcaiX1mwf/FFsfqozNphQFSQh2G2Zly1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m4hXp/dJMcaiX1mwf/FFsfqozNphQFSQh2G2Zly1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m4hXp/dJMcaiX1mwf/FFsfqozNphQFSQh2G2Zly1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm4hXp%2FdJMcaiX1mwf%2FFFsfqozNphQFSQh2G2Zly1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;68&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Play-In-Editor를 실행한다. 게임 안에서는 아무 일도 일어나지 않을 것이다. 하지만 Output Log에는 출력이 보여야 한다. Output Log에서 LogVerse:가 포함된 항목으로 필터링하면 다음과 같은 로그가 보일 것이다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;LogVerse: OnBeginSimulation
LogVerse: OnSimulate
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;축하한다. Verse 스크립트가 ue6-main에서 컴파일되고 실행되고 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Asset은 어떻게 하나&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 entity는 보이지 않는다. 시각적으로 표현하는 것이 아무것도 없기 때문이다. 여기에 mesh_component를 추가하려고 해도, 추가할 수 있는 옵션이 없다는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Verse가 인식하고 사용할 수 있게 하려면 GameFeaturePlugin에 콘텐츠를 추가해야 한다. 여기서 우리가 .uplugin에 추가한 &quot;EnableSceneGraph&quot;: true가 의미를 갖는다. SceneGraph는 플러그인 안을 스캔해 인식 가능한 asset을 찾고, 해당 asset용 컴포넌트를 자동으로 생성한 뒤 Verse에 노출한다. 이것은 Texture, Material, MaterialInstance, MetaSound, StaticMesh, SkeletalMesh 그리고 몇 가지 기본 타입의 asset에서 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 Cube mesh로 Entity를 표현해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔진의 /Engine/Content/BasicShapes에서 Cube mesh를 복사해 GameFeaturePlugin 안에 붙여넣는다. 플러그인 안에 들어간 뒤 &amp;ldquo;Compile Verse&amp;rdquo; 버튼을 누른다. 그러면 SceneGraph와 Verse가 그 asset을 인식하고, 앞서 만든 entity의 mesh_component로 사용할 수 있게 해줄 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOSyvG/dJMcabY04oY/BOzWWTSDWufr9oxgdgZOdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOSyvG/dJMcabY04oY/BOzWWTSDWufr9oxgdgZOdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOSyvG/dJMcabY04oY/BOzWWTSDWufr9oxgdgZOdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOSyvG%2FdJMcabY04oY%2FBOzWWTSDWufr9oxgdgZOdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;316&quot; height=&quot;187&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pcL6x/dJMcabY04oZ/IZJ3oVvGiz00wwgMSUir0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pcL6x/dJMcabY04oZ/IZJ3oVvGiz00wwgMSUir0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pcL6x/dJMcabY04oZ/IZJ3oVvGiz00wwgMSUir0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpcL6x%2FdJMcabY04oZ%2FIZJ3oVvGiz00wwgMSUir0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;894&quot; height=&quot;264&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1343&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zZXcW/dJMcaiX1mwj/77ETMQdqzZTPCBvGOuDR8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zZXcW/dJMcaiX1mwj/77ETMQdqzZTPCBvGOuDR8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zZXcW/dJMcaiX1mwj/77ETMQdqzZTPCBvGOuDR8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzZXcW%2FdJMcaiX1mwj%2F77ETMQdqzZTPCBvGOuDR8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1343&quot; height=&quot;1004&quot; data-origin-width=&quot;1343&quot; data-origin-height=&quot;1004&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GameFeaturePlugin의 자동 생성 digest 파일을 확인하면, 해당 asset이 Verse에 노출된 것도 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1119&quot; data-origin-height=&quot;837&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0Mj68/dJMcaiX1mwi/DvHGqt0c9aWLmkeRWqA5a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0Mj68/dJMcaiX1mwi/DvHGqt0c9aWLmkeRWqA5a0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0Mj68/dJMcaiX1mwi/DvHGqt0c9aWLmkeRWqA5a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0Mj68%2FdJMcaiX1mwi%2FDvHGqt0c9aWLmkeRWqA5a0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1119&quot; height=&quot;837&quot; data-origin-width=&quot;1119&quot; data-origin-height=&quot;837&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;축하한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋다. 이제 Verse 코드가 컴파일되고 동작하며, asset도 Verse에 노출된다. 이제 멋진 새 아이디어를 만들기 시작할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 아직 이걸로 뭔가를 출시하지는 말자. Epic 입장에서도 모든 것이 극도로 alpha이고 experimental 상태다. API는 바뀔 수 있고, 실제로 바뀔 것이며, 그 과정에서 코드가 깨질 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 작은 재미있는 사실 하나. 성능은 끔찍하다. directional_light, mesh_component, skeletal_mesh_component 같은 많은 컴포넌트에는 실제 &amp;ldquo;SceneGraph representation&amp;rdquo;이 아직 없다. 그러면 백그라운드에서 무엇을 하고 있을까? &lt;b&gt;Actor를 spawn한다.&lt;/b&gt; 그렇다. Epic이 만든 거의 모든 컴포넌트는 그냥 Actor를 spawn한다. 언젠가는 바뀌겠지만, 아직 우리가 기대하는 멋진 SceneGraph 미래는 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재미있게 가지고 놀아보자.&lt;/p&gt;</description>
      <category>TECH.ART.FLOW.IO</category>
      <category>UE6</category>
      <category>VERSE</category>
      <category>개발준비</category>
      <category>스크립트</category>
      <category>언리얼엔진6</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/788</guid>
      <comments>https://techartnomad.tistory.com/788#entry788comment</comments>
      <pubDate>Wed, 24 Jun 2026 02:10:10 +0900</pubDate>
    </item>
    <item>
      <title>[번역] UE6 Verse 첫 탐색 1: 총람과 문법</title>
      <link>https://techartnomad.tistory.com/787</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTdN6h/dJMcabEDa3v/H7LJQ5zi83YONTKKKmaQ51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTdN6h/dJMcabEDa3v/H7LJQ5zi83YONTKKKmaQ51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTdN6h/dJMcabEDa3v/H7LJQ5zi83YONTKKKmaQ51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTdN6h%2FdJMcabEDa3v%2FH7LJQ5zi83YONTKKKmaQ51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;총람과 가이드&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;머리말&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UE6 코드가 며칠 전에 공개되었다. ue6-main 브랜치에 올라와 있다. 내려받고 나서 내가 가장 궁금했던 것은 하나였다. Verse가 UE6 안에서 지금 어떤 상태인가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UE4, UE5를 써온 사람들의 Verse에 대한 인상은 대부분 UEFN(Unreal Editor for Fortnite, 포트나이트 언리얼 에디터) 시절에 머물러 있다. 말하자면 포트나이트 창작 도구 안에 들어 있던 그 스크립트 언어다. 인터넷 자료도 대개 2~3년 전 자료이고, 이야기하는 것도 UEFN 쪽 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 UE6 안에서는 다르다. Claude의 도움을 받아 소스 코드를 훑어보니, Verse는 더 이상 예전처럼 엔진 밖에 독립적으로 놓인 스크립트 레이어가 아니다. 이미 엔진 코어 안으로 통합되어 있다. 다만 현재는 아직 비활성화 상태이고, 기본 경로도 VerseVM이 아니라 여전히 블루프린트 VM을 탄다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;유래&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Verse는 Epic이 처음부터 새로 설계한 언어다. 주도자는 Tim Sweeney다. 언어 설계에는 Simon Peyton Jones와 Lennart Augustsson도 참여했다. 두 사람 모두 함수형 프로그래밍 분야의 베테랑이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 언어는 함수형을 기반으로 하면서, 논리 프로그래밍과 명령형 프로그래밍도 흡수했다. 공식적인 포지셔닝은 &amp;ldquo;함수형 논리 프로그래밍 언어&amp;rdquo;다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;세 가지 핵심 특징&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, 실패를 타입 시스템이 강제로 처리한다. null도 없고 예외도 없다. 어떤 연산이 실패할 수 있다면, 그 사실이 타입에 적히고 컴파일러가 처리하라고 요구한다. 실패하면 그 과정에서 발생한 부작용은 롤백된다. 밑바닥에는 소프트웨어 트랜잭셔널 메모리 지원이 깔려 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 부작용이 함수 시그니처에 적힌다. 함수가 일시 중단될 수 있는지, 전역 상태를 수정하는지, 순수 계산인지, 실패할 수 있는지 같은 것들이 모두 &amp;lt;suspends&amp;gt;, &amp;lt;transacts&amp;gt; 같은 표기로 시그니처에 적힌다. 컴파일러는 이를 바탕으로 정적 검사를 한다. C#이나 Lua에는 이렇게 완전한 메커니즘이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋째, 독립적인 가상 머신 VerseVM과 독립적인 GC 힙을 가진다. 이것이 블루프린트와 본질적으로 다른 점이다. 블루프린트는 UObject 리플렉션 시스템 위의 인터프리터이고, Verse는 독립 런타임을 가진 언어다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;설계 동기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 있는 스크립트 언어도 많은데, Epic은 왜 굳이 처음부터 새로 설계했을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 UE 로직을 작성하는 길은 크게 두 가지다. C++는 성능이 가장 좋지만 컴파일이 느리고, 실수하기 쉽다. 생 포인터, 댕글링 참조, 데이터 레이스는 흔한 문제이고, 기획자가 직접 쓰기도 어렵다. 블루프린트는 시각적이고, 핫 리로드가 빠르고, 상대적으로 안전하며, 기획자도 손댈 수 있다. 하지만 성능이 나쁘다. 노드 하나하나가 리플렉션 조회와 가상 함수 호출이고, 큰 로직은 유지보수하기 어렵다. 버전 관리와 diff에도 잘 맞지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Epic이 마주한 시나리오는 Fortnite, UEFN 같은 플랫폼이다. 수많은 창작자의 코드가 같은 서버 위에서 동시에 돌아간다. 이런 환경에서는 언어가 몇 가지 조건을 동시에 만족해야 한다. 안전해야 한다. 한 창작자의 스크립트 오류가 전체 서버에 영향을 주면 안 된다. 높은 동시성을 지원해야 한다. 장기적으로 진화할 수 있어야 하며, 코드가 배포된 뒤에도 호환성을 유지해야 한다. 소스 안에는 @available{MinUploadedAtFNVersion := 3800} 같은 버전 가드가 많이 있는데, 이미 공개된 프로젝트와의 이름 충돌을 피하기 위한 것이다. 그리고 빨라야 한다. 목표는 C++에 가깝게 가는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루프린트는 이 요구를 만족하지 못하고, C++는 위험이 너무 크다. 다른 스크립트 언어는 엔진과 깊게 맞춤 통합하기 어렵다. 그래서 Epic은 직접 언어를 설계했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;모듈 구성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.verse 소스 코드는 먼저 컴파일 프런트엔드로 들어간다. 프런트엔드는 uLang이라고 부르고, 컴파일러 코드명은 Solaris다. 위치는 Engine/Source/Runtime/Solaris/uLangCore와 Engine/Source/Runtime/VerseCompiler다. 자체 LSP(Language Server Protocol, 언어 서버 프로토콜)와 DAP(Debug Adapter Protocol, 디버그 어댑터 프로토콜)도 가지고 있다. uLangLSP는 에디터 자동완성과 오류 표시를 담당하고, uLangDAP는 중단점 디버깅을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프런트엔드는 소스 코드를 바이트코드로 컴파일하고, VerseVM이 이를 실행한다. VerseVM은 독립 DLL이 아니다. CoreUObject 모듈 안에 있으며, WITH_VERSE_VM 매크로로 조건부 컴파일된다. 코드는 Engine/Source/Runtime/CoreUObject/Public/VerseVM에 있고, 헤더 파일만 200개가 넘는다. CoreUObject 안에 있다는 것은 Verse 타입이 UObject 서브클래스로 직접 리플렉션 시스템에 들어갈 수 있다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 쪽에서 Verse는 UE의 GC를 쓰지 않는다. WebKit의 libpas를 이식했다. 이것은 JavaScript 엔진용 할당자이며, Engine/Source/ThirdParty/libpas에 있다. verse_heap 관련 파일만 30개가 넘는다. Verse는 독립 힙을 관리하고, UObject GC와는 두 시스템이 협력해서 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 AutoRTFM이 있다. 소프트웨어 트랜잭셔널 메모리다. 실패 롤백은 이것이 지원한다. Epic은 이를 위해 Clang과 LLVM 전체를 fork해 Engine/Source/Programs/EpicClang에 두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 VNI(Verse Native Interface, Verse 네이티브 인터페이스)가 있다. Verse가 C++를 호출하는 메커니즘이다. UE6에서는 UHT(UnrealHeaderTool, 언리얼 헤더 툴)의 일부 역할을 대체하고 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;글 구성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시리즈는 총 7편이다. 순서는 &amp;ldquo;먼저 쓸 줄 알고, 그다음 원리를 이해하고, 마지막에 안전성과 성능을 이야기한다&amp;rdquo;는 흐름이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;00 총람.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;01 문법 소개.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;02 구현 원리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;03 타입 안전성.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;04 메모리 관리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;05 메모리 안전성.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;06 성능 관련.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UE6는 아직 정식 출시되지 않았고, Verse도 여전히 개발 중이다. 구현을 설명하는 부분은 현재 버전의 소스 코드를 기준으로 한다. 언어 규격 차원에서는 공식 문서와 《The Verse Calculus》 논문을 함께 참고했다. 정식 버전과 다르다면 공식 문서와 로컬 소스 코드를 기준으로 보면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Verse의 문법&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;머리말&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;먼저 쓸 줄 알고 그다음 원리를 이해한다&amp;rdquo;는 순서에 따라, 이 글에서는 먼저 문법을 이야기한다. 목표는 읽고 나면 기본적인 Verse를 읽고 쓸 수 있게 되는 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Class&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 실제 파일 하나를 보자. 새 클래스를 만들 때의 템플릿이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# Engine/Plugins/Solaris/ScriptTemplates/ClassTemplate.verse
new_class_template := class:
    #TODO: Add members and methods here
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++나 Lua와 다른 점 몇 가지를 먼저 기억해두자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;:= 는 정의다. 타입, 함수, 상수, 클래스 모두 이것을 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입은 콜론 오른쪽에 쓴다. X:int 는 X가 int라는 뜻이다. C++의 int X 와는 반대이고, TypeScript의 x: number 와는 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;들여쓰기는 의미가 있다. class: 뒤에 들여쓴 부분이 클래스 본문이다. Python과 같다. 콜론과 들여쓰기는 Verse가 코드 블록을 구성하는 기본 방식이다. # 는 한 줄 주석이다. @doc(&quot;...&quot;) 는 문서 주석 어노테이션이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;변수와 가변성&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;X := 10            # 불변 바인딩, X는 항상 10
var Y : int = 0    # 가변 변수, var로 선언
set Y = 5          # 가변 변수 수정은 set 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 점은 Lua와 차이가 크다. Lua 변수는 기본적으로 가변이고, 그냥 y = 5 라고 쓰면 바뀐다. Verse는 기본이 불변이다. X := 10 이후 X는 다시 바꿀 수 없다. 가변으로 쓰려면 var 로 선언해야 하고, 값을 바꿀 때는 반드시 set 을 써야 한다. Y = 5 라고 쓰면 안 된다. 그것은 다른 의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준 라이브러리의 실제 예시는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;nimrod&quot;&gt;&lt;code&gt;# Engine/Plugins/Verse/Verse/Source/Verse/Verse/Verse/Array.native.verse
var Result:[]t = array{}    # 가변 배열, 초기값은 빈 배열
var I:int = 0
var SliceBeginIndex:int = 0
# ...
set I += ToReplaceLength    # set으로 수정
set SliceBeginIndex = I
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var Result:[]t = array{} 는 원소 타입이 t인 가변 배열을 선언한다. []t 는 배열 타입 표기이고, array{} 는 빈 배열 리터럴이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기본 타입&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 쓰는 내장 타입은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int 정수, 임의 정밀도다. 고정 32/64비트가 아니며 오버플로하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;float 부동소수점.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;logic 불리언이다. 값은 true 와 false 다. bool이라고 부르지 않는다는 점에 주의하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;char8 / char32 문자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;string 문자열.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[]t 원소 타입이 t인 배열.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[k]v 키가 k이고 값이 v인 map.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;?t option, 값이 있을 수도 없을 수도 있다. null을 대체한다. 뒤에서 이야기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tuple(a, b) 튜플.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;void 반환값 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;type 타입 자체도 하나의 타입이다. 타입이 곧 값이라는 이야기인데, 뒤에서 이야기한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;연산자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;산술 연산자는 + - * / 이고, 단항 음수 -X 도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교는 대부분의 언어와 다르니 따로 기억해야 한다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;=     같음. 대입이 아니다! Verse에서 대입은 := 또는 set이다.
&amp;lt;&amp;gt;    다름. != 가 아니다.
&amp;lt;  &amp;lt;= &amp;gt;  &amp;gt;=   크기 비교
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준 라이브러리의 실제 비교는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;# Array.native.verse
if (ToReplaceLength = 0):        # = 는 같음 판단
    return Input
if (Input[I + J] &amp;lt;&amp;gt; ElementsToReplace[J]):   # &amp;lt;&amp;gt; 는 다름
    set Matches = false
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 특별한 점이 하나 더 있다. 비교를 수학처럼 이어 쓸 수 있다.&lt;/p&gt;
&lt;pre class=&quot;django&quot;&gt;&lt;code&gt;# Array.native.verse, 0 &amp;lt;= StartIndex &amp;lt;= StopIndex &amp;lt;= Length를 한 번에 판단
0&amp;lt;=StartIndex&amp;lt;=StopIndex&amp;lt;=Input.Length
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++나 Lua에서는 이것을 여러 개의 &amp;amp;&amp;amp;로 쪼개야 하지만, Verse에서는 그대로 이어 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리는 and, or, not 을 쓴다. &amp;amp;&amp;amp; || ! 가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;logic 값의 &amp;ldquo;판정&amp;rdquo;에는 물음표를 쓴다. logic 변수 Matches 가 있을 때, Matches? 는 &amp;ldquo;Matches가 true라면&amp;rdquo;이라는 뜻이다. 이것은 실패할 수 있는 표현식이다. false일 때 실패한다.&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;# Array.native.verse
if (Matches?):           # Matches가 true일 때 진입
    # ...
else:
    set I += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제어 흐름: if / else&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if는 if (조건): 형태로 쓰고, 그다음 들여쓴 코드 블록을 둔다. else는 else: 를 쓴다.&lt;/p&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;# Array.native.verse
if (ToReplaceLength &amp;gt; Length - I):
    # 주석
    if (set Result += Input.Slice[SliceBeginIndex, Length]) { }
    return Result
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;else가 붙은 형태는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;if (Matches?):
    set I += ToReplaceLength
    set SliceBeginIndex = I
else:
    set I += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Verse의 if에는 Lua나 C#과 근본적으로 다른 점이 있다. 이것은 &amp;ldquo;참/거짓&amp;rdquo;을 판단하는 것이 아니라 &amp;ldquo;성공/실패&amp;rdquo;를 판단한다. 조건 자리에 들어가는 것은 하나의 표현식이고, 표현식이 성공하면 then으로 가고 실패하면 else로 간다. Matches? 같은 logic 판정, Map[Key] 같은 찾지 못할 수도 있는 조회, X &amp;gt; 0 같은 비교가 모두 &amp;ldquo;실패할 수 있는 표현식&amp;rdquo;이다. 이 메커니즘을 failure라고 부른다. Verse의 핵심이다. 타입 안전성 편에서 따로 이야기할 것이다. 여기서는 일단 이렇게 기억하면 된다. if는 &amp;ldquo;성공할 수 있느냐&amp;rdquo;를 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if는 표현식으로도 쓸 수 있고, 값을 반환할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 의사 코드
Max(A:int, B:int):int =
    if (A &amp;gt; B):
        A
    else:
        B
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제어 흐름: 반복&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Verse의 반복은 주로 두 가지다. loop 와 for 다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loop 는 무한 반복이고, break 로 빠져나온다. C의 while(true) 와 비슷하다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;# Array.native.verse
var J:int = 0
loop:
    if (J &amp;gt;= ToReplaceLength):
        break                       # 반복 탈출
    if (Input[I + J] &amp;lt;&amp;gt; ElementsToReplace[J]):
        set Matches = false
        break
    set J += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for 는 순회할 때 쓴다. 문법은 for (원소 : 컬렉션) 이다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;# 의사 코드
for (Element : MyArray):
    Print(Element)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for 는 인덱스와 원소를 동시에 받을 수도 있다. Index -&amp;gt; Element 를 쓴다. 또한 필터 조건을 붙일 수 있다. 이 점이 Lua의 for보다 강한 부분이다.&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;# Array.native.verse, Input을 순회하되 인덱스가 [StartIndex, StopIndex) 밖에 있는 원소만 보존
for(Index-&amp;gt;Element : Input; Index &amp;lt; StartIndex or Index &amp;gt;= StopIndex) do Element
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 한 줄은 세 가지 일을 한다. Input 을 순회하면서 Index -&amp;gt; Element 를 얻는다. 세미콜론 뒤의 Index &amp;lt; StartIndex or Index &amp;gt;= StopIndex 는 필터 조건이다. 만족하는 것만 들어간다. do Element 는 보존된 각 원소에 대해 계산되는 결과다. 전체 for 표현식은 이 결과들을 모아 새 배열을 만든다. 이런 &amp;ldquo;순회 + 필터 + 매핑&amp;rdquo;을 한 줄로 끝낸다. 다른 언어의 리스트 컴프리헨션과 비슷하고, Lua의 for 루프보다 표현력이 훨씬 강하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 Verse에는 while 키워드가 없다는 것이다. 조건 반복을 하려면 loop 에 if ... break 를 조합하거나, 조건이 붙은 for를 쓰면 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;return과 함수 반환&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수는 := 또는 = 로 정의한다. 대부분의 경우 return 이 필요 없다. 함수 본문의 마지막 표현식 값이 반환값이다. Rust나 함수형 언어와 같다. 다만 중간에 먼저 반환해야 할 때는 return 이 있다.&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;# Array.native.verse
if (ToReplaceLength = 0):
    return Input        # 조기 반환
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완전한 함수 하나의 모습은 다음과 같다. 표준 라이브러리에서 가져왔고, 일부 세부 사항은 제거했다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# Array.native.verse, 배열에서 한 구간 제거
(Input:[]t where t:type).Remove&amp;lt;public&amp;gt;(StartIndex:int, StopIndex:int)&amp;lt;computes&amp;gt;&amp;lt;decides&amp;gt;:[]t =
    0&amp;lt;=StartIndex&amp;lt;=StopIndex&amp;lt;=Input.Length
    for(Index-&amp;gt;Element : Input; Index &amp;lt; StartIndex or Index &amp;gt;= StopIndex) do Element
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시그니처를 뜯어보면 Verse 함수의 특징 몇 가지가 보인다. (Input:[]t where t:type) 는 receiver다. 이것이 배열 타입 위의 확장 메서드라는 뜻이다. where t:type 은 제네릭 제약이다. .Remove 는 메서드 이름이다. &amp;lt;public&amp;gt; 은 가시성이다. (StartIndex:int, StopIndex:int) 는 매개변수다. &amp;lt;computes&amp;gt;&amp;lt;decides&amp;gt; 는 효과다. 순수 계산이고, 실패할 수 있다는 뜻이다. :[]t 는 반환 타입이다. 함수 본문 첫 줄 0&amp;lt;=...&amp;lt;=Length 는 실패할 수 있는 검사다. 범위를 벗어나면 실패한다. 둘째 줄의 for 표현식이 결과를 만든다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;효과 지정자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시그니처 안의 꺾쇠괄호 표기는 Verse의 특징이다. 효과 지정자라고 부르며, 함수에 부작용이 있는지 선언한다. 자주 보는 것은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;computes&amp;gt;   순수 계산, 부작용 없음
&amp;lt;decides&amp;gt;    실패할 수 있음
&amp;lt;transacts&amp;gt;  상태를 수정하며, 트랜잭션 롤백 지원
&amp;lt;suspends&amp;gt;   일시 중단 가능. 병행성에 사용
&amp;lt;reads&amp;gt;      외부 상태 읽기
&amp;lt;native&amp;gt;     C++로 구현됨
&amp;lt;public&amp;gt; &amp;lt;private&amp;gt; &amp;lt;internal&amp;gt;   가시성
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 예시는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;# Math.native.verse
Clamp&amp;lt;native&amp;gt;&amp;lt;public&amp;gt;(Val:int, A:int, B:int)&amp;lt;computes&amp;gt;:int
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lua, C#, TypeScript에는 부작용을 시그니처에 적는 일이 없다. 이것은 Verse만의 특징이고, 타입 안전성 편에서 따로 이야기한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;option: null이 없다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Verse에는 null이 없다. 없을 수도 있는 값은 option으로 표현하고, ?t 라고 쓴다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;# Event.native.verse
var InternalEvent&amp;lt;internal&amp;gt;&amp;lt;native&amp;gt;:?event_base_intrnl   # ?T가 option
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;option은 직접 사용할 수 없다. 실패 컨텍스트 안에서 먼저 &amp;ldquo;열어&amp;rdquo;야 한다. Lua의 nil은 어디에나 들어갈 수 있고 런타임에 터진다. C#의 null도 마찬가지다. 반면 Verse에는 언어 차원에서 빈 포인터가 없다. 자세한 내용은 뒤의 타입 안전성 편에서 말한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;클래스와 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class는 := 로 정의한다. 멤버와 메서드는 그 안에 들여쓴다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;# 의사 코드
my_class := class:
    Health:int = 100              # 필드, 기본값 있음
    var Score:int = 0             # 가변 필드

    TakeDamage(Amount:int):void =  # 메서드
        # ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;interface도 비슷하다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# Result.native.verse
result&amp;lt;public&amp;gt;&amp;lt;native&amp;gt;(success_type:type, error_type:type) := interface&amp;lt;internal&amp;gt;&amp;lt;computes&amp;gt;:
    GetSuccess&amp;lt;public&amp;gt;&amp;lt;native_callable&amp;gt;()&amp;lt;computes&amp;gt;&amp;lt;decides&amp;gt;:success_type
    GetError&amp;lt;public&amp;gt;&amp;lt;native_callable&amp;gt;()&amp;lt;computes&amp;gt;&amp;lt;decides&amp;gt;:error_type
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(success_type:type, error_type:type) 는 타입 매개변수다. 타입 자체가 인자로 들어갈 수 있다. 이것이 Verse의 &amp;ldquo;타입이 곧 값&amp;rdquo;이라는 부분이고, C# 제네릭보다 더 철저하다. 타입 안전성 편에서 자세히 이야기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명명 스타일을 보면 표준 라이브러리는 snake_case를 쓴다. new_class_template, error_type 같은 식이다. UE의 C++ 습관인 PascalCase와는 다르고, Rust나 스크립트 언어에 더 가깝다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;병행성 키워드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Verse는 병행성을 라이브러리가 아니라 언어 키워드로 만든다. 자주 쓰는 것은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;# 몇 가지 일을 동시에 하고, 전부 끝나야 계속 진행
sync:
    LoadModel()
    LoadTexture()

# 먼저 끝난 것을 쓰고, 나머지는 취소
race:
    Button.AwaitClick()
    Sleep(5.0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sync 는 모두 끝나야 계속된다. race 는 첫 번째로 끝난 것이 있으면 계속하고 나머지는 취소한다. rush 는 첫 번째로 끝난 것이 있으면 계속하지만 나머지는 백그라운드에서 계속 돈다. spawn 은 독립 작업을 시작한다. branch 는 기다리지 않는 작업을 시작한다. &amp;lt;suspends&amp;gt; 가 붙은 함수는 일시 중단될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lua에서는 coroutine을 직접 써야 하고, C#에서는 async/await를 쓴다. 진짜 멀티스레드라면 락도 신경 써야 한다. Verse의 병행성은 언어 레벨 표현식이다. 쓰는 느낌은 동기 코드에 가깝고, 밑바닥은 단일 스레드 협력식 스케줄링이다. 구현과 이것이 안전성에 갖는 의미는 뒤의 글에서 이야기한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;키워드 정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에 나온 키워드를 분류해두면 나중에 찾기 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정의와 대입: :=(정의), var(가변 선언), set(수정), =(정의/비교 문맥).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제어 흐름: if, else, loop, for, do, break, return.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리와 비교: and, or, not, =(같음), &amp;lt;&amp;gt;(다름), &amp;lt; &amp;lt;= &amp;gt; &amp;gt;=, ?(logic 판정).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입과 구조: class, interface, enum, type, where(제약).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병행성: sync, race, rush, spawn, branch.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효과 지정자: &amp;lt;computes&amp;gt;, &amp;lt;decides&amp;gt;, &amp;lt;transacts&amp;gt;, &amp;lt;suspends&amp;gt;, &amp;lt;reads&amp;gt;, &amp;lt;native&amp;gt;, &amp;lt;public&amp;gt; 등.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lua처럼 키워드가 열몇 개뿐인 작은 언어와 비교하면, Verse의 키워드와 표기는 많다. 특히 효과 지정자 체계는 다른 곳에 없는 것이다. 하지만 기본 제어 흐름(if/else/loop/for/break/return)은 사실 익숙한 언어들과 크게 다르지 않다. 주된 차이는 문법이 콜론과 들여쓰기로 바뀌었고, 비교 연산자가 = 와 &amp;lt;&amp;gt; 로 바뀌었으며, while이 없고 loop를 쓴다는 정도다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정의에는 := 를 쓰고, 타입은 콜론 오른쪽에 쓴다. 콜론과 들여쓰기로 블록을 나눈다. 기본은 불변이고, 값을 바꾸려면 var와 set을 쓴다. 비교는 =(같음)와 &amp;lt;&amp;gt;(다름)를 쓰며, 이어 쓸 수 있다. 제어 흐름은 if/else, loop(무한 반복 + break), for(필터와 매핑 가능)이고 while은 없다. 함수의 마지막 표현식이 반환값이며, 조기 반환에는 return을 쓴다. option(?t)이 null을 대체한다. 효과 지정자는 부작용을 시그니처에 적는다. 병행성은 sync/race/rush 같은 언어 키워드다. 전체적으로 기본 제어 흐름은 주류 언어와 통하지만, 특징은 기본 불변성, failure 방식의 if, 효과 시스템, 그리고 네이티브 병행성에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 말하면, Verse의 선언&amp;middot;대입&amp;middot;효과 지정자 문법은 꽤 낯설어 보인다. 실제로 쓰면 좀 불편할 것 같은 느낌도 있다.&lt;/p&gt;</description>
      <category>TECH.ART.FLOW.IO</category>
      <category>UE6</category>
      <category>VERSE</category>
      <category>스크립트</category>
      <category>언리얼엔진</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/787</guid>
      <comments>https://techartnomad.tistory.com/787#entry787comment</comments>
      <pubDate>Mon, 22 Jun 2026 19:09:42 +0900</pubDate>
    </item>
    <item>
      <title>[번역] Gdc2024 Open World Rendering Techniques in 'Hogwarts Legacy'</title>
      <link>https://techartnomad.tistory.com/249</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gdcvault.com/play/1034600/Open-World-Rendering-Techniques-in&quot;&gt;GDC Vault - Open World Rendering Techniques in 'Hogwarts Legacy'&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782121663349&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Open World Rendering Techniques in 'Hogwarts Legacy'&quot; data-og-description=&quot;Rendering a game as complex as Hogwarts Legacy required a focus on adapting the Unreal engine for an open world game. This included handling the massive scale of the Hogwarts castle and scaling rendering systems for a seamless indoor and outdoor...&quot; data-og-host=&quot;gdcvault.com&quot; data-og-source-url=&quot;https://gdcvault.com/play/1034600/Open-World-Rendering-Techniques-in&quot; data-og-url=&quot;https://gdcvault.com/play/1034600/Open-World-Rendering-Techniques-in&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pRySS/dJMb8ZvK70c/Last6OGkK97BKVOdSDfypk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=534_154_728_348,https://scrap.kakaocdn.net/dn/iNWqq/dJMb8TCjxd2/K38Ma3iM3JbQY8MiR3r6g0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=534_154_728_348&quot;&gt;&lt;a href=&quot;https://gdcvault.com/play/1034600/Open-World-Rendering-Techniques-in&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gdcvault.com/play/1034600/Open-World-Rendering-Techniques-in&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pRySS/dJMb8ZvK70c/Last6OGkK97BKVOdSDfypk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=534_154_728_348,https://scrap.kakaocdn.net/dn/iNWqq/dJMb8TCjxd2/K38Ma3iM3JbQY8MiR3r6g0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=534_154_728_348');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Open World Rendering Techniques in 'Hogwarts Legacy'&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Rendering a game as complex as Hogwarts Legacy required a focus on adapting the Unreal engine for an open world game. This included handling the massive scale of the Hogwarts castle and scaling rendering systems for a seamless indoor and outdoor...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gdcvault.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제공&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHCAnR/btsIZmMiePJ/U8nlxf1TxAMGocmFU9EHd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHCAnR/btsIZmMiePJ/U8nlxf1TxAMGocmFU9EHd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHCAnR/btsIZmMiePJ/U8nlxf1TxAMGocmFU9EHd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHCAnR%2FbtsIZmMiePJ%2FU8nlxf1TxAMGocmFU9EHd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;322&quot; height=&quot;88&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;88&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #191b1f; text-align: start;&quot;&gt;
&lt;h2 data-first-child=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;프로젝트에 대한 전반적인 정보&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LOD 전환 페이드뿐만 아니라 햇빛 방향에 따라 그림자가 바뀌는 큰 월드도 페이드하는 크로스 페이드에 매우 중점을 둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바인드리스에 많은 노력을 기울여 바인드리스를 지원하지 않는 모든 하드웨어는 완전히 퇴출되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.27 카오스를 사용하는 UE4&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9제곱킬로미터의 거대한 세계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 병목 현상은 UE의 렌더 스레드에 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;날씨/빛/계절 등 렌더링 기능이 많지만 매우 간단하므로 생략하겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;거대한 세상의 크기&lt;/h2&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TvcNs/btsIY0JsXJN/FV93qsjsbQ5lFimdk9j5kK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TvcNs/btsIY0JsXJN/FV93qsjsbQ5lFimdk9j5kK/img.webp&quot; data-alt=&quot;큰 세계 크기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TvcNs/btsIY0JsXJN/FV93qsjsbQ5lFimdk9j5kK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTvcNs%2FbtsIY0JsXJN%2FFV93qsjsbQ5lFimdk9j5kK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;894&quot; height=&quot;496&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;큰 세계 크기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;br /&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YvH1q/btsIXJve2P1/phYAETUoxM8lhnQLGMA9s1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YvH1q/btsIXJve2P1/phYAETUoxM8lhnQLGMA9s1/img.webp&quot; data-alt=&quot;플레이 관련 데이터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YvH1q/btsIXJve2P1/phYAETUoxM8lhnQLGMA9s1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYvH1q%2FbtsIXJve2P1%2FphYAETUoxM8lhnQLGMA9s1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;913&quot; height=&quot;505&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;플레이 관련 데이터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;br /&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;921&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/db2duN/btsIXGyrQRv/xJeu8soBhNURKFOr4K52D1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/db2duN/btsIXGyrQRv/xJeu8soBhNURKFOr4K52D1/img.webp&quot; data-alt=&quot;촌락&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/db2duN/btsIXGyrQRv/xJeu8soBhNURKFOr4K52D1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdb2duN%2FbtsIXGyrQRv%2FxJeu8soBhNURKFOr4K52D1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;921&quot; height=&quot;517&quot; data-origin-width=&quot;921&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;촌락&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;br /&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zKiwM/btsIX3G1bdm/WlcYZEC8lZVrQMgzz4x1W1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zKiwM/btsIX3G1bdm/WlcYZEC8lZVrQMgzz4x1W1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zKiwM/btsIX3G1bdm/WlcYZEC8lZVrQMgzz4x1W1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzKiwM%2FbtsIX3G1bdm%2FWlcYZEC8lZVrQMgzz4x1W1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;919&quot; height=&quot;510&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;510&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
호그와트 성
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;bindless resouce&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 게임의 CPU 병목 현상은 렌더링 스레드에 있기 때문에 가능한 한 인스턴스화를 하고 싶습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQXHzu/btsIYxHyZXC/z4pfz7yRrrub5kXZs33szk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQXHzu/btsIYxHyZXC/z4pfz7yRrrub5kXZs33szk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQXHzu/btsIYxHyZXC/z4pfz7yRrrub5kXZs33szk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQXHzu%2FbtsIYxHyZXC%2Fz4pfz7yRrrub5kXZs33szk%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;795&quot; height=&quot;445&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 바인드리스 리소스는 더 많은 인스턴싱 가능성을 열어주는 열쇠입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바인드리스란 버퍼/텍스처 바인딩을 특수 셰이더 파라미터(텍스처/버퍼)에서 셰이더의 간단한 정수 인덱스로 변경하여 디스크립터 테이블을 인덱싱하고 해당 리소스를 가져올 수 있음을 의미합니다.이렇게 하면 텍스처/버퍼는 다르지만 PSO가 동일한 드로잉을 인스턴스화할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 바인드리스의 사용은 gbuffer에만 국한되지 않습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lToLm/btsIZpaYNEj/9FTPV613w6Od6INz3cgk00/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lToLm/btsIZpaYNEj/9FTPV613w6Od6INz3cgk00/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lToLm/btsIZpaYNEj/9FTPV613w6Od6INz3cgk00/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlToLm%2FbtsIZpaYNEj%2F9FTPV613w6Od6INz3cgk00%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;794&quot; height=&quot;453&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;323&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원칙은 간단하지만 프로젝트의 구현은 주로 UE 버전이 지원하지 않고 폴백이 좋지 않기 때문에 많은 작업을 수행해야 합니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pCknD/btsIYAxyjA9/Y1s7gMK2SqZEtHCoSKrF71/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pCknD/btsIYAxyjA9/Y1s7gMK2SqZEtHCoSKrF71/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pCknD/btsIYAxyjA9/Y1s7gMK2SqZEtHCoSKrF71/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpCknD%2FbtsIYAxyjA9%2FY1s7gMK2SqZEtHCoSKrF71%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;772&quot; height=&quot;435&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;볼류메트릭을 위한 거리 분할 전략&lt;/h2&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAfq4h/btsIZLLyCkz/CKGGkfWlAIjtY8mcORMNq1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAfq4h/btsIZLLyCkz/CKGGkfWlAIjtY8mcORMNq1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAfq4h/btsIZLLyCkz/CKGGkfWlAIjtY8mcORMNq1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAfq4h%2FbtsIZLLyCkz%2FCKGGkfWlAIjtY8mcORMNq1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;899&quot; height=&quot;498&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;probe volume&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UE 볼류메트릭 라이트맵처럼 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바인드리스를 사용하면 바인딩을 더 쉽게 처리할 수 있으며 셰이더는 모든 글로벌 프로브 볼륨에 한 번에 액세스할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흥미로운 점은 성의 원통형 씬 케이스에 실린더 볼륨이 추가되었다는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바인드리스를 사용하면 셰이더가 로드된 모든 볼륨에 액세스할 수 있지만 메모리 제어를 위해서는 스트리밍이 필요합니다.이를 수행하는 방법은 프러스텀 컬을 사용하는 것입니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;895&quot; data-origin-height=&quot;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPUGBz/btsIZRdL6zx/LgKJSkgqFzHZQsQCli1p51/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPUGBz/btsIZRdL6zx/LgKJSkgqFzHZQsQCli1p51/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPUGBz/btsIZRdL6zx/LgKJSkgqFzHZQsQCli1p51/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPUGBz%2FbtsIZRdL6zx%2FLgKJSkgqFzHZQsQCli1p51%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;895&quot; height=&quot;497&quot; data-origin-width=&quot;895&quot; data-origin-height=&quot;497&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;probe shadow&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흥미로운 기능은 프로브 볼륨에 저장된 우세한 방향에 따라 스크린 스페이스 레이트레이스를 수행하여 접촉 그림자를 얻는 것으로, 기본적으로 방향이 있는 SSAO 효과를 볼 수 있습니다. ( SSDO 와 결과가 유사? )&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;907&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baCnVv/btsIYUJizBf/lhhi9caMJ6N9SJU704nwHK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baCnVv/btsIYUJizBf/lhhi9caMJ6N9SJU704nwHK/img.webp&quot; data-alt=&quot;발밑의&amp;amp;nbsp;간접&amp;amp;nbsp;조명&amp;amp;nbsp;그림자에&amp;amp;nbsp;주목하세요.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baCnVv/btsIYUJizBf/lhhi9caMJ6N9SJU704nwHK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaCnVv%2FbtsIYUJizBf%2Flhhi9caMJ6N9SJU704nwHK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;907&quot; height=&quot;505&quot; data-origin-width=&quot;907&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;발밑의&amp;nbsp;간접&amp;nbsp;조명&amp;nbsp;그림자에&amp;nbsp;주목하세요.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;point-blank shadow&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적 그림자와 정적 그림자뿐만 아니라 접촉 그림자(Contact Shadow)와 캡슐 그림자도 있습니다. 많은 빛에는 정적 그림자가 있지만 소량의 빛만 동적 그림자를 드리우며, 동적 그림자가 없는 빛을 선택하여 캐릭터에 캡슐 그림자를 줄 수 있습니다. 그림자 맵 캐시에도 크기 버킷이 있습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c93445/btsIYYZbErl/chrYkTutAT9VVKx07DnKQK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c93445/btsIYYZbErl/chrYkTutAT9VVKx07DnKQK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c93445/btsIYYZbErl/chrYkTutAT9VVKx07DnKQK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc93445%2FbtsIYYZbErl%2FchrYkTutAT9VVKx07DnKQK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;903&quot; height=&quot;502&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이내믹 섀도에는 빈/비어 있는 검은색 부분의 샘플링을 건너뛰는 데 사용되는 저해상도 UAV가 2019년에 도입됩니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;905&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCMAKd/btsIXHK0QTP/VKDe39bM0gbG51ZKeRWrK1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCMAKd/btsIXHK0QTP/VKDe39bM0gbG51ZKeRWrK1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCMAKd/btsIXHK0QTP/VKDe39bM0gbG51ZKeRWrK1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCMAKd%2FbtsIXHK0QTP%2FVKDe39bM0gbG51ZKeRWrK1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;905&quot; height=&quot;504&quot; data-origin-width=&quot;905&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UE의 자체 캡슐 섀도를 최적화한 것 중 하나는 캡슐 섀도 계산 범위를 제한하는 것이었습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDDVfn/btsIXJhDxOI/aTrAi87jJVckJDvpjHuuN0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDDVfn/btsIXJhDxOI/aTrAi87jJVckJDvpjHuuN0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDDVfn/btsIXJhDxOI/aTrAi87jJVckJDvpjHuuN0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDDVfn%2FbtsIXJhDxOI%2FaTrAi87jJVckJDvpjHuuN0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;900&quot; height=&quot;503&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #191b1f; text-align: left;&quot;&gt;Lumos shadow&lt;/span&gt; (지팡이 끝 포인트 라이트)는 사실 포인트 라이트 그림자가 캐시할 수 없는(움직이는 사람을 따라가기 때문에) 문제가 있습니다. 최적화는 큐브맵을 사용하여 한 번에 6 개의 그림자를 그리는 것 외에도 캐릭터의 그림자에만 로우 프로파일 (스위치)이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;태양 그림자 집중 최적화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전략.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접촉 그림자(Contact Shadow)는 매우 효과적이므로 가까운 거리에 있는 작은 물체나 풀과 같은 번거로운 사물을 그리는 것을 건너뛰고 먼 거리에 그림자를 만들 수 있습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L0nVc/btsIY0o9S3h/GpJVemUOQfEVJFix3Djvv0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L0nVc/btsIY0o9S3h/GpJVemUOQfEVJFix3Djvv0/img.webp&quot; data-alt=&quot;잔디 그림자에 주목하세요.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L0nVc/btsIY0o9S3h/GpJVemUOQfEVJFix3Djvv0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL0nVc%2FbtsIY0o9S3h%2FGpJVemUOQfEVJFix3Djvv0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;826&quot; height=&quot;463&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;잔디 그림자에 주목하세요.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;br /&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/od4m7/btsIYSLq7iZ/JTnAOTMeTQ3W0OREyJLGsk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/od4m7/btsIYSLq7iZ/JTnAOTMeTQ3W0OREyJLGsk/img.webp&quot; data-alt=&quot;잔디 그림자에 주목하세요.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/od4m7/btsIYSLq7iZ/JTnAOTMeTQ3W0OREyJLGsk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fod4m7%2FbtsIYSLq7iZ%2FJTnAOTMeTQ3W0OREyJLGsk%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;822&quot; height=&quot;462&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;잔디 그림자에 주목하세요.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;tile based directional shadow cache&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 아이디어는 카메라가 움직일 때 시야에 들어오는 부분의 그림자만 업데이트하면 되는 스크롤된 그림자 캐시와 비슷합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조명 공간을 타일로 분할하여 각 타일을 개별적으로 업데이트할 수 있으며, 카메라가 작은 영역에서 앞뒤로 움직일 때 캐시를 전혀 업데이트하지 않을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타일 분할의 또 다른 장점은 각 타일이 필요한지 여부와 시야각과 같은 오클루전 정보를 확인할 수 있다는 점입니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P0jPg/btsIZmS0r2u/eMHNZMgdl5Ah2toQrgWFD1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P0jPg/btsIZmS0r2u/eMHNZMgdl5Ah2toQrgWFD1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P0jPg/btsIZmS0r2u/eMHNZMgdl5Ah2toQrgWFD1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP0jPg%2FbtsIZmS0r2u%2FeMHNZMgdl5Ah2toQrgWFD1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;758&quot; height=&quot;428&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;429&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s8DPn/btsIYXeVtdE/d5QskQpKuCIXbV9NvdeiY1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s8DPn/btsIYXeVtdE/d5QskQpKuCIXbV9NvdeiY1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s8DPn/btsIYXeVtdE/d5QskQpKuCIXbV9NvdeiY1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs8DPn%2FbtsIYXeVtdE%2Fd5QskQpKuCIXbV9NvdeiY1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;758&quot; height=&quot;429&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;429&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 타일 디퍼드의 분류 패스에서 각 화면 타일에 대해 샘플링할 그림자 유형도 고려해야 한다고 언급했습니다.이 두 가지를 사용하면 모든 픽셀이 동적 참조 또는 캐시된 섀도 케이스만 선택하도록 하여 분기를 사용하지 않는 &lt;span style=&quot;background-color: #ffffff; color: #191b1f; text-align: left;&quot;&gt;gpu program variant&lt;/span&gt; 를 완전히 삭제하여 VGPR 사용을 줄일 수 있습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;431&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NUy41/btsIZ5JD3PN/jWbWTLNKGIrxGp2saP8DXk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NUy41/btsIZ5JD3PN/jWbWTLNKGIrxGp2saP8DXk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NUy41/btsIZ5JD3PN/jWbWTLNKGIrxGp2saP8DXk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNUy41%2FbtsIZ5JD3PN%2FjWbWTLNKGIrxGp2saP8DXk%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;761&quot; height=&quot;431&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;431&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1351&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRNLmt/btsIZsyIiT5/2SUmkeW9I5SBeebvc6hOR0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRNLmt/btsIZsyIiT5/2SUmkeW9I5SBeebvc6hOR0/img.webp&quot; data-alt=&quot;타일은 여러 가지가 아닌 하나의 음영만 선택합니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRNLmt/btsIZsyIiT5/2SUmkeW9I5SBeebvc6hOR0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRNLmt%2FbtsIZsyIiT5%2F2SUmkeW9I5SBeebvc6hOR0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1351&quot; height=&quot;748&quot; data-origin-width=&quot;1351&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;타일은 여러 가지가 아닌 하나의 음영만 선택합니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;캐시 관리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 타일은 128x128m로 결코 작지 않습니다.&amp;nbsp;타일을 업데이트하려면 컬링 등의 작업이 필요하기 때문에 프레임당 하나의 타일을 사용하는 것이 전략입니다.하지만 시점이 빠르게 움직일 때는 타일 하나로는 충분하지 않기 때문에 전환할 때 카메라가 넓어집니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/354cT/btsIYCWmGms/ZShl3kWr3SbVBmjszpvRY1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/354cT/btsIYCWmGms/ZShl3kWr3SbVBmjszpvRY1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/354cT/btsIYCWmGms/ZShl3kWr3SbVBmjszpvRY1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F354cT%2FbtsIYCWmGms%2FZShl3kWr3SbVBmjszpvRY1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;844&quot; height=&quot;476&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시를&amp;nbsp;새로&amp;nbsp;고칠&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;다른&amp;nbsp;많은&amp;nbsp;요인이&amp;nbsp;있습니다.&lt;br /&gt;나무와&amp;nbsp;같은&amp;nbsp;동적&amp;nbsp;물체는&amp;nbsp;무시하세요.&lt;br /&gt;시간,&amp;nbsp;크로스&amp;nbsp;페이드가&amp;nbsp;필요하므로&amp;nbsp;실제로&amp;nbsp;각&amp;nbsp;프레임은&amp;nbsp;기본적으로&amp;nbsp;사용되는&amp;nbsp;메모리&amp;nbsp;양의&amp;nbsp;2&amp;nbsp;배,&amp;nbsp;마지막&amp;nbsp;햇빛&amp;nbsp;각도와&amp;nbsp;현재&amp;nbsp;각도는&amp;nbsp;크로스&amp;nbsp;페이드가&amp;nbsp;필요합니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rPFl4/btsIZnxsqUW/53qEsIvrwab28EMxLtAy81/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rPFl4/btsIZnxsqUW/53qEsIvrwab28EMxLtAy81/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rPFl4/btsIZnxsqUW/53qEsIvrwab28EMxLtAy81/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrPFl4%2FbtsIZnxsqUW%2F53qEsIvrwab28EMxLtAy81%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;803&quot; height=&quot;451&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;477&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레벨&amp;nbsp;스트리밍으로&amp;nbsp;인한&amp;nbsp;업데이트,&amp;nbsp;가장&amp;nbsp;낮은&amp;nbsp;우선순위로&amp;nbsp;설정&amp;nbsp;로드&amp;nbsp;전환으로&amp;nbsp;인한&amp;nbsp;섀도&amp;nbsp;깊이&amp;nbsp;불일치,&amp;nbsp;장거리에서만&amp;nbsp;처리합니다.&amp;nbsp;특수&amp;nbsp;섀도&amp;nbsp;프록시&amp;nbsp;메시를&amp;nbsp;사용하면&amp;nbsp;실제로는&amp;nbsp;문제가&amp;nbsp;되지&amp;nbsp;않는&amp;nbsp;것으로&amp;nbsp;보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;햇빛이 땅과 거의 평행할 때 일출과 일몰과 같은 경우 드로우콜은 매우 높아집니다. 평행한 조명을 직접 끄십시오...&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJdcUQ/btsIYenX8ZG/kKhBLthVtc8RKVe4hDfkO0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJdcUQ/btsIYenX8ZG/kKhBLthVtc8RKVe4hDfkO0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJdcUQ/btsIYenX8ZG/kKhBLthVtc8RKVe4hDfkO0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJdcUQ%2FbtsIYenX8ZG%2FkKhBLthVtc8RKVe4hDfkO0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;812&quot; height=&quot;457&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;의류용 멀티 레이어 소재&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 나이브 한 구현에서 16 개의 레이어 머티리얼 블렌드. 실제로 한 사람에게 총 16 개의 머티리얼 만 있으면 대부분의 지점은 1 개의 머티리얼이고 과도한 지점의 가장자리는 실제로 2 개의 머티리얼 전환을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근 방식의 최적화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 마이크로와 매크로 디테일을 구별하기 위해 옷 주름은 매크로 디테일이며, 이것과 다층 재료는 아무 관련이 없으며, 마이크로 디테일 재료는 실제로 각 재료가 초기 핸드 헬드 지형 블렌드와 유사하게 (다른베이스 / 일반 / 메탈릭 러프니스 맵) 2 개의 재료 색인과 메탈릭 러프니스 맵, 저장 2 개의 재료 색인과 초기 휴대용 지형 혼합을 절약 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로 디테리얼 머티리얼은 초기 지형 블렌드와 유사하게 각 머티리얼마다 다른(베이스/일반/메탈릭 러프니스 맵이 다른) 머티리얼 인덱스 2개와 블렌드 웨이트 1개로 구성되어 있습니다. 16개의 레이어에 달하는 거친 머티리얼 블렌드에 비해 많은 시간을 절약할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 필터 후에도 인덱스가 올바른 값을 얻을 수 있도록 머티리얼 인덱스 맵이 경계에 있어야 한다는 것인데, 이 방법은 경계에서 인덱스 맵을 두 개로 몇 번 펼쳐서 이중 선형 필터가 정상인지 확인하는 것입니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1013&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LD4SI/btsIYaTz3xW/I2GXRjKKY6t8BLKkZ9br90/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LD4SI/btsIYaTz3xW/I2GXRjKKY6t8BLKkZ9br90/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LD4SI/btsIYaTz3xW/I2GXRjKKY6t8BLKkZ9br90/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLD4SI%2FbtsIYaTz3xW%2FI2GXRjKKY6t8BLKkZ9br90%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1013&quot; height=&quot;579&quot; data-origin-width=&quot;1013&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;자동화된 테스트 사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능 모니터링 시나리오&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWFto3/btsIZyldQYO/lBWldM7IUGbyuMxAgi55TK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWFto3/btsIZyldQYO/lBWldM7IUGbyuMxAgi55TK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWFto3/btsIZyldQYO/lBWldM7IUGbyuMxAgi55TK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWFto3%2FbtsIZyldQYO%2FlBWldM7IUGbyuMxAgi55TK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1023&quot; height=&quot;572&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특수 효과가 갑자기 문제의 프레임을 고착시키는 데 일조했습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;563&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvtebW/btsIZJfUJ4F/dccRBHGDvezGS3c5bPyns0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvtebW/btsIZJfUJ4F/dccRBHGDvezGS3c5bPyns0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvtebW/btsIZJfUJ4F/dccRBHGDvezGS3c5bPyns0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvtebW%2FbtsIZJfUJ4F%2FdccRBHGDvezGS3c5bPyns0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1008&quot; height=&quot;563&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;563&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;적응형 밝기 제어&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특수 효과, 게임 내 일부 조명의 밝기를 적응형으로 제어해야 합니다.여러 가지 방법이 있습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;563&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nt3U1/btsIZ6u0Uyb/9mn6t3edAcbXax0b0esK7K/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nt3U1/btsIZ6u0Uyb/9mn6t3edAcbXax0b0esK7K/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nt3U1/btsIZ6u0Uyb/9mn6t3edAcbXax0b0esK7K/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnt3U1%2FbtsIZ6u0Uyb%2F9mn6t3edAcbXax0b0esK7K%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1011&quot; height=&quot;563&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;563&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 노출을 사용하면 특수 효과와 조명 마법을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 렌더링된 프레임의 평균 밝기를 기준으로 사용하면 많은 문제가 발생할 수 있습니다. 예를 들어 카메라가 시야각 조명을 차단할 때, 전후 두 프레임의 밝기가 너무 많이 변하는 경우 등이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카메라 주변의 프로브를 읽고 연평균 밝기, 고스트 반투명 사용, 애니메이션의 아트도 부드러움 때문에 사용하기를 좋아합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 수동 조정 옵션이 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;live painting&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학교에 그려져 있는 살아있는 그림이에요.제가 생각할 수 있는 유일한 방법은 동영상에 올리거나비디오에 넣거나 별도의 카메라를 사용하여 각 프레임을 RT로 그리는 것입니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NbPIx/btsIZM4Ol23/KSVjVCDmJwiJWJ9HH2ITm1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NbPIx/btsIZM4Ol23/KSVjVCDmJwiJWJ9HH2ITm1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NbPIx/btsIZM4Ol23/KSVjVCDmJwiJWJ9HH2ITm1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNbPIx%2FbtsIZM4Ol23%2FKSVjVCDmJwiJWJ9HH2ITm1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;912&quot; height=&quot;494&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 그들이 생각해낸 방법은 VS에서 변경을 수행하고, 메인 카메라 뷰에서 직접 3D 모델을 그린 다음을 메인 카메라 뷰에서 직접 그리고 VS 변경 사항을 캔버스에 평평하게 배치하는 것이었습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xx1jW/btsIZJ1ieRm/LIKqBbFFKPcCyiTMmK4eRk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xx1jW/btsIZJ1ieRm/LIKqBbFFKPcCyiTMmK4eRk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xx1jW/btsIZJ1ieRm/LIKqBbFFKPcCyiTMmK4eRk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXx1jW%2FbtsIZJ1ieRm%2FLIKqBbFFKPcCyiTMmK4eRk%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;818&quot; height=&quot;456&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8KLYI/btsIX4lA4NF/xnlzxq0bQ6G1vNVxnLWOeK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8KLYI/btsIX4lA4NF/xnlzxq0bQ6G1vNVxnLWOeK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8KLYI/btsIX4lA4NF/xnlzxq0bQ6G1vNVxnLWOeK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8KLYI%2FbtsIX4lA4NF%2Fxnlzxq0bQ6G1vNVxnLWOeK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;894&quot; height=&quot;502&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능과 결과물 측면에서 더 좋습니다. RT 크기가 실제로 메인 카메라 뷰에 붙여넣을 픽셀 수와 일치하는지 확인하기가 어렵기 때문에 별도의 RT에 그리는 것보다 낫습니다. 새로운 패스를 사용하지 않고 일반 드로우콜만 사용하기 때문에 성능이 더 좋습니다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;363&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSZyKb/btsIZKeOPpB/GCpBT43TtCZw8QE3B8BpsK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSZyKb/btsIZKeOPpB/GCpBT43TtCZw8QE3B8BpsK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSZyKb/btsIZKeOPpB/GCpBT43TtCZw8QE3B8BpsK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSZyKb%2FbtsIZKeOPpB%2FGCpBT43TtCZw8QE3B8BpsK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;782&quot; height=&quot;448&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;363&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/703657480?utm_psn=1804512244769366017&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://zhuanlan.zhihu.com/p/703657480?utm_psn=1804512244769366017&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723129308785&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;https://zhuanlan.zhihu.com/p/703657480?utm_psn=1804512244769366017&quot; data-og-description=&quot;&quot; data-og-host=&quot;zhuanlan.zhihu.com&quot; data-og-source-url=&quot;https://zhuanlan.zhihu.com/p/703657480?utm_psn=1804512244769366017&quot; data-og-url=&quot;https://zhuanlan.zhihu.com/p/703657480?utm_psn=1804512244769366017&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/703657480?utm_psn=1804512244769366017&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://zhuanlan.zhihu.com/p/703657480?utm_psn=1804512244769366017&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;https://zhuanlan.zhihu.com/p/703657480?utm_psn=1804512244769366017&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;zhuanlan.zhihu.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TECH.ART.FLOW.IO</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/249</guid>
      <comments>https://techartnomad.tistory.com/249#entry249comment</comments>
      <pubDate>Mon, 22 Jun 2026 18:47:51 +0900</pubDate>
    </item>
    <item>
      <title>[UFSH2025] 《록왕국 세계》 모바일 파이프라인 설계와 최적화 &amp;mdash; 주곡재, 텐센트 게임 모어펀 스튜디오 클라이언트 개발, 영상 요약</title>
      <link>https://techartnomad.tistory.com/786</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;역자의 말: 2019년 겨울 모어펀 스튜디오 테크니컬 아트 디렉터(홍콩사람)가 보직해임 되어 그 후보자에 제가 추천을 받아 인터뷰 진행 하고 합격했었던 스튜디오입니다. 보직 해임된 모어펀 스튜디오 테크니컬 아트 디렉터가 소후에 홍콩 민주화 시위에 대한 자신의 생각을 올렸는데 그 사건으로 바로 보직 해임된 사건이 있었죠. 중국은 역시 중국이네요. 텐센트가 아무리 큰 회사라고 해도 중국 정부에게는 그냥 까라면 까는 그런 회사일 수 밖에 없더군요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모어펀 스튜디오 소개.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텐센트 모어펀 스튜디오 그룹(MoreFun Studios)은 2010년 12월 설립된 텐센트 인터랙티브 엔터테인먼트(IEG) 산하의 게임 개발 스튜디오입니다. 액션, 슈팅, RPG, 캐주얼 등 다양한 장르를 아우르며, 심천&amp;middot;베이징&amp;middot;상하이에 거점을 두고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표작으로는 10년 이상 서비스 중인 &lt;b&gt;나루토 모바일&lt;/b&gt;, 높은 자유도의 전술 슈팅 게임 &lt;b&gt;암구돌파(Escape from Tarkov류)&lt;/b&gt; 등이 있으며, 현재는 UE5 기반의 신작 &lt;b&gt;이인지하(異人之下)&lt;/b&gt; 와 멀티플레이 액션 &lt;b&gt;수(狩)&lt;/b&gt; 를 개발 중입니다. 특히 AI 기술을 게임 개발에 적극 접목하고 있다는 점도 주목할 만합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 게임으로 출발해 모바일로의 전환이라는 어려운 과도기를 거쳤지만, 꾸준한 투자와 도전으로 현재는 텐센트 자체 개발 라인업의 핵심 축을 담당하고 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자: 电话微波炉&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제 1 부&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm431L/dJMcai4L279/ihQQyPsMnx0Y1K4LkcNNT1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm431L/dJMcai4L279/ihQQyPsMnx0Y1K4LkcNNT1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm431L/dJMcai4L279/ihQQyPsMnx0Y1K4LkcNNT1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm431L%2FdJMcai4L279%2FihQQyPsMnx0Y1K4LkcNNT1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhm7iW/dJMcai4L28a/fbhGIxVYKYklCCn7v2ptvK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhm7iW/dJMcai4L28a/fbhGIxVYKYklCCn7v2ptvK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhm7iW/dJMcai4L28a/fbhGIxVYKYklCCn7v2ptvK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhm7iW%2FdJMcai4L28a%2FfbhGIxVYKYklCCn7v2ptvK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eikMKP/dJMcai4L28b/0AYaPA7KTHkv45vYScaPc1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eikMKP/dJMcai4L28b/0AYaPA7KTHkv45vYScaPc1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eikMKP/dJMcai4L28b/0AYaPA7KTHkv45vYScaPc1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeikMKP%2FdJMcai4L28b%2F0AYaPA7KTHkv45vYScaPc1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;록왕국 세계 모바일 렌더링 파이프라인 설계 및 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;一、 렌더링 파이프라인 총람 (Rendering Pipeline Overview)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 프로젝트 배경과 기술 선정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;게임 타입&lt;/b&gt;: 오픈월드, 정령 수집 육성, 스타일화된 아트.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;엔진 버전&lt;/b&gt;: Unreal Engine 4.26.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본 파이프라인&lt;/b&gt;: &lt;b&gt;모바일 전방향 렌더링 파이프라인 (Mobile Forward Rendering Pipeline)&lt;/b&gt; 기반으로 깊이 커스터마이징 및 최적화.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 핵심 아트와 렌더링 요구사항&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스타일화된 표현&lt;/b&gt;: 캐릭터와 이펙트의 렌더링은 씬과 독립되어야 하며, 특정 아트 효과(스킬 발동 시 씬 암 처리, 후처리 단계별 분리 처리 등)를 실현해야 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고성능 동시 화면&lt;/b&gt;: 모바일에서 &lt;b&gt;50개 이상&lt;/b&gt;의 캐릭터와 정령 동시 렌더링 지원.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 환경&lt;/b&gt;: 완전한 &lt;b&gt;주야 변환 (Time of Day - TOD)&lt;/b&gt; 및 복잡하고 다양한 &lt;b&gt;날씨 시스템&lt;/b&gt; 실현.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조명과 디테일&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;씬의 &lt;b&gt;암부 디테일&lt;/b&gt; 표현 향상.&lt;/li&gt;
&lt;li&gt;동적 점광원, 수면 반사 등 고급 효과 지원.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 전방향 파이프라인 개조와 도전 과제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;신규 렌더링 특성&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;화면 공간 환경광 차폐 (&lt;b&gt;SSAO&lt;/b&gt;).&lt;/li&gt;
&lt;li&gt;화면 공간 반사 (&lt;b&gt;SSR&lt;/b&gt;).&lt;/li&gt;
&lt;li&gt;색 보정 (&lt;b&gt;Color Grading&lt;/b&gt;).&lt;/li&gt;
&lt;li&gt;완전한 동적 &lt;b&gt;TOD 시스템&lt;/b&gt; (실시간 동적 조명과 그림자).&lt;/li&gt;
&lt;li&gt;모바일 동적 점광원.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 도전 과제&lt;/b&gt;: &lt;b&gt;&quot;~도 만족시키면서 ~도 만족시켜야 하는&quot;&lt;/b&gt; 모순.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;만족시켜야 할 것&lt;/b&gt;: 위의 고품질&amp;middot;고비용 아트 요구사항.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동시에 보장해야 할 것&lt;/b&gt;: 파이프라인이 주류 모바일 기기에서 원활하게 동작 (목표 30FPS, 고급 기기 60+ FPS).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nom44/dJMcaftvj3I/y2u2gt6lilbUonFGKCg2P1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nom44/dJMcaftvj3I/y2u2gt6lilbUonFGKCg2P1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nom44/dJMcaftvj3I/y2u2gt6lilbUonFGKCg2P1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNom44%2FdJMcaftvj3I%2Fy2u2gt6lilbUonFGKCg2P1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brlDIY/dJMcaftvj3G/CIt1lmhTiwtIhN067pjhHK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brlDIY/dJMcaftvj3G/CIt1lmhTiwtIhN067pjhHK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brlDIY/dJMcaftvj3G/CIt1lmhTiwtIhN067pjhHK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrlDIY%2FdJMcaftvj3G%2FCIt1lmhTiwtIhN067pjhHK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bixC2z/dJMcaaloMIJ/2Y7QJml44af0pRBlOalkRK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bixC2z/dJMcaaloMIJ/2Y7QJml44af0pRBlOalkRK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bixC2z/dJMcaaloMIJ/2Y7QJml44af0pRBlOalkRK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbixC2z%2FdJMcaaloMIJ%2F2Y7QJml44af0pRBlOalkRK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRFvkQ/dJMb991aO04/SaAlRLz9JFS5i3VFiChqTK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRFvkQ/dJMb991aO04/SaAlRLz9JFS5i3VFiChqTK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRFvkQ/dJMb991aO04/SaAlRLz9JFS5i3VFiChqTK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRFvkQ%2FdJMb991aO04%2FSaAlRLz9JFS5i3VFiChqTK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edQ7ZC/dJMcaaFNPwq/SZ6NsAE6Xc3tcxgyDVgpKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edQ7ZC/dJMcaaFNPwq/SZ6NsAE6Xc3tcxgyDVgpKk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edQ7ZC/dJMcaaFNPwq/SZ6NsAE6Xc3tcxgyDVgpKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedQ7ZC%2FdJMcaaFNPwq%2FSZ6NsAE6Xc3tcxgyDVgpKk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqPqwM/dJMcacwOaCC/Fodv1fBXgdbL9Yo6YnZgk1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqPqwM/dJMcacwOaCC/Fodv1fBXgdbL9Yo6YnZgk1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqPqwM/dJMcacwOaCC/Fodv1fBXgdbL9Yo6YnZgk1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqPqwM%2FdJMcacwOaCC%2FFodv1fBXgdbL9Yo6YnZgk1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;二、 Scene Color 방안: 픽셀 레벨에서 캐릭터와 씬 구분&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 요구사항과 페인 포인트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 요구사항&lt;/b&gt;: 후처리 등 단계에서 하나의 픽셀이 &lt;b&gt;씬&lt;/b&gt;에 속하는지 &lt;b&gt;캐릭터/정령&lt;/b&gt;에 속하는지 정확히 구분.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;활용 시나리오 1&lt;/b&gt;: 스킬 발동 시 절차적으로 씬을 암 처리하면서 캐릭터/정령 밝기는 유지.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활용 시나리오 2&lt;/b&gt;: 씬에 초해상도 샤프닝을 적용하되 캐릭터는 제외하여 캐릭터 외곽에 부자연스러운 샤프닝 아티팩트를 방지.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 병목&lt;/b&gt;: &lt;b&gt;50+ 캐릭터&lt;/b&gt; 동시 렌더링이라는 엄격한 조건 하에서 이 기능을 실현해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 일반적 방안: Custom Depth / Stencil&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;구현 원리&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;추가 Render Pass를 열어 구분이 필요한 모든 오브젝트(예: 캐릭터)를 독립된 &lt;b&gt;Custom Depth&lt;/b&gt; 맵에 렌더링.&lt;/li&gt;
&lt;li&gt;동시에 &lt;b&gt;Custom Stencil&lt;/b&gt; 버퍼에 특정값을 기록.&lt;/li&gt;
&lt;li&gt;후속 Pass(예: 후처리)에서 Custom Depth/Stencil 맵을 샘플링하여 픽셀 소속을 판단.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모바일에서의 성능 문제&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;추가 Pass 오버헤드&lt;/b&gt;: Custom Depth Pass 자체가 상당한 성능 소모를 발생시키며, 모바일에서는 아무것도 그리지 않아도 &lt;b&gt;0.5ms&lt;/b&gt; 이상 소모 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대역폭과 메모리&lt;/b&gt;: 화면 크기의 맵 두 장(Depth + Stencil)이 필요하며 720P 기준 대역폭은 약 &lt;b&gt;3.35MB&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Draw Call 급증 (가장 심각한 문제)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 내 캐릭터와 정령은 정밀한 다파트 스켈레톤 모델이며 외곽선 효과를 포함해本身就 Draw Call 수가 많음 (단일 캐릭터당 9개 DC 가능).&lt;/li&gt;
&lt;li&gt;다인 동시 화면에서 Custom Depth Pass로 인해 Draw Call 수가 폭발적으로 증가 (100-200+ 도달 가능), 모바일 CPU에 막대한 부하.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 록왕국의 해결 방안: Alpha 채널 인코딩 활용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 아이디어&lt;/b&gt;: 추가 Pass와 Buffer를 피하고 구분 정보를 메인 렌더 타깃(&lt;b&gt;Scene Color Buffer&lt;/b&gt;)에 직접 인코딩.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기술 선정&lt;/b&gt;: Scene Color 포맷을 일반 RGBA8에서 **RGB10A2**로 변경.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;RGB (각 10 bit)&lt;/b&gt;: HDR 색상 정보 저장, 정밀도 충분.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;A (2 bit)&lt;/b&gt;: 원래 잘 쓰이지 않던 Alpha 채널을 &lt;b&gt;2-bit ID 저장 영역&lt;/b&gt;으로 활용. 2비트면 여러 카테고리를 구분하기에 충분(예: 00=씬, 01=캐릭터, 10=이펙트 등)하며 추가 비용은 거의 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;추가 Pass 제로&lt;/b&gt;: Custom Depth Pass가 불필요하여 고정 오버헤드와 Draw Call 두 배 문제를 근본적으로 제거.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;추가 대역폭 없음&lt;/b&gt;: 데이터가 Scene Color 맵에 통합되어 추가 메모리 및 대역폭 점유 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제 2 부&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxRaYE/dJMcadbjDm1/1onTtHBueV5aNaTpkuDtE0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxRaYE/dJMcadbjDm1/1onTtHBueV5aNaTpkuDtE0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxRaYE/dJMcadbjDm1/1onTtHBueV5aNaTpkuDtE0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxRaYE%2FdJMcadbjDm1%2F1onTtHBueV5aNaTpkuDtE0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxTQl/dJMcacwOaCD/k10JERjhrVCyOS0NzIbBW0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxTQl/dJMcacwOaCD/k10JERjhrVCyOS0NzIbBW0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxTQl/dJMcacwOaCD/k10JERjhrVCyOS0NzIbBW0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkxTQl%2FdJMcacwOaCD%2Fk10JERjhrVCyOS0NzIbBW0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RGB10A2를 활용한 캐릭터와 씬 구분 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 문제 배경: 높은 외곽선 렌더링 비용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 내 캐릭터와 정령(Sprite)은 정밀한 다파트 스켈레톤 모델이며 모두 &lt;b&gt;외곽선 효과&lt;/b&gt;를 포함.&lt;/li&gt;
&lt;li&gt;전통적인 외곽선 방법(예: Custom Depth Buffer 사용)은 외곽선이 필요한 오브젝트마다 깊이 맵에 한 번 더 렌더링해야 하여 &lt;b&gt;Draw Call&lt;/b&gt; 수가 급증.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 병목&lt;/b&gt;: 캐릭터와 정령이 많은 씬에서 Draw Call 수가 단일 캐릭터 9개에서 수백 개까지 폭발적으로 증가, 모바일 기기에 막대한 부하.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 해결 방안: Alpha 채널을 마스크(Mask)로 활용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 아이디어&lt;/b&gt;: Custom Depth를 포기하고 메인 컬러 버퍼(Scene Color Buffer)의 Alpha 채널을 활용해 캐릭터와 비캐릭터 픽셀을 구분.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구체적 구현&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;메인 컬러 버퍼 포맷을 **RGB10A2**로 설정. 10비트 RGB와 2비트 Alpha를 가진 포맷.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Base Pass&lt;/b&gt; 렌더링 시 캐릭터/정령 머티리얼이 특정 Alpha 값 출력(예: a=1.0).&lt;/li&gt;
&lt;li&gt;씬 내 다른 오브젝트는 기본 Alpha 값 출력(예: a=0.0).&lt;/li&gt;
&lt;li&gt;렌더링 완료 후 Scene Color 버퍼의 Alpha 채널이 &lt;b&gt;무료 캐릭터 마스크&lt;/b&gt;가 되며, 후속 외곽선&amp;middot;후처리 등 효과는 이 Alpha 채널을 샘플링하여 픽셀이 캐릭터인지 판별.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;추가 비용 제로&lt;/b&gt;: 거의 무료로 캐릭터와 씬 픽셀 구분 능력을 획득.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;추가 Render Pass 불필요&lt;/b&gt;: Custom Depth를 위한 추가 렌더링 과정을 완전히 제거.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대역폭 절약&lt;/b&gt;: 추가 깊이 텍스처 읽기/쓰기 불필요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Draw Call 감소&lt;/b&gt;: 외곽선으로 인한 Draw Call 증가 문제를 근본적으로 해결.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cskFMj/dJMcaaFNPwt/MpjKVxMMbvxRa9QH9hTXD0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cskFMj/dJMcaaFNPwt/MpjKVxMMbvxRa9QH9hTXD0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cskFMj/dJMcaaFNPwt/MpjKVxMMbvxRa9QH9hTXD0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcskFMj%2FdJMcaaFNPwt%2FMpjKVxMMbvxRa9QH9hTXD0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVSqYF/dJMcab5IXLJ/X0zihZtGI7shJCR0kZkkk0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVSqYF/dJMcab5IXLJ/X0zihZtGI7shJCR0kZkkk0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVSqYF/dJMcab5IXLJ/X0zihZtGI7shJCR0kZkkk0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVSqYF%2FdJMcab5IXLJ%2FX0zihZtGI7shJCR0kZkkk0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RGB10A2의 한계 해결&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 고동적 범위(HDR) 색상 클램핑 문제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;문제 설명&lt;/b&gt;: RGB10A2는 UNORM (Unsigned Normalized) 포맷으로 색상 채널이 [0, 1] 범위 값만 표현 가능. 씬에 하이라이트나 자발광 오브젝트(색상 값 &amp;gt; 1.0)가 존재하면 밝기가 **강제로 1.0에 클램프(Clamp)**됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부정적 영향&lt;/b&gt;: 이로 인해 &lt;b&gt;Bloom&lt;/b&gt; 등 하이라이트 정보에 의존하는 후처리 효과가 완전히 무효화되거나 잘못된 결과를 출력.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해결 방안: 고정소수점 인코딩/디코딩 (Fixed-Point Encoding/Decoding)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;색상을 RGB10A2 텍스처에 기록하기 전에 먼저 인코딩하여 더 큰 범위(예: [0, ColorRange])를 [0, 1]로 압축.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인코딩 공식&lt;/b&gt;:&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디코딩 공식&lt;/b&gt;: 후속 읽기 단계에서 다시 원래 범위로 디코딩.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 소수 정밀도와 색 단계(Banding) 문제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;문제 설명&lt;/b&gt;: 위 고정소수점 방안은 색상 범위를 확장했지만 정밀도를 희생. 제한된 10비트에서 표현 범위가 넓어질수록 소수 부분의 정밀도가 낮아짐. 이는 색 그라데이션이 완만한 영역(예: 스카이박스)에서 특히 영(0)에 가까운 암부 영역에서 뚜렷한 &lt;b&gt;색 단계(Color Banding)&lt;/b&gt; 현상을 발생시킴.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해결 방안: 비선형 인코딩 (제곱근)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 사상&lt;/b&gt;: 비선형 함수(예: 제곱근)로 색상을 인코딩하여 암부 영역에 더 많은 정밀도 비트를 할당하면서 하이라이트 영역의 범위를 유지. 감마 보정과 원리가 유사.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인코딩 공식&lt;/b&gt; (기록 시):&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디코딩 공식&lt;/b&gt; (읽기 시):&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효과&lt;/b&gt;: 이 방식을 통해 하늘 등 영역의 색 단계 문제가 효과적으로 수정되어 화면 전환이 더 부드러워짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6JUgf/dJMcacwOaCz/AnvgzvOeFfn5NsTQVBKT6k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6JUgf/dJMcacwOaCz/AnvgzvOeFfn5NsTQVBKT6k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6JUgf/dJMcacwOaCz/AnvgzvOeFfn5NsTQVBKT6k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6JUgf%2FdJMcacwOaCz%2FAnvgzvOeFfn5NsTQVBKT6k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWnEaT/dJMcab5IXLL/cN9rOH0tyG96nDptLrCem1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWnEaT/dJMcab5IXLL/cN9rOH0tyG96nDptLrCem1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWnEaT/dJMcab5IXLL/cN9rOH0tyG96nDptLrCem1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWnEaT%2FdJMcab5IXLL%2FcN9rOH0tyG96nDptLrCem1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WyN6F/dJMcaaFNPwp/JWdUknEtsvlnBhkyttKSb1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WyN6F/dJMcaaFNPwp/JWdUknEtsvlnBhkyttKSb1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WyN6F/dJMcaaFNPwp/JWdUknEtsvlnBhkyttKSb1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWyN6F%2FdJMcaaFNPwp%2FJWdUknEtsvlnBhkyttKSb1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/comW4q/dJMcaaeHOTz/DRe1LguhLmqKbLMIhiT1g0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/comW4q/dJMcaaeHOTz/DRe1LguhLmqKbLMIhiT1g0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/comW4q/dJMcaaeHOTz/DRe1LguhLmqKbLMIhiT1g0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcomW4q%2FdJMcaaeHOTz%2FDRe1LguhLmqKbLMIhiT1g0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스크린 공간 안개 방식 (Post-Process Fog)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 문제: SSAO와 전통적인 버텍스 안개의 렌더링 충돌&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;배경&lt;/b&gt;: 씬의 암부 디테일을 강화하기 위해 &lt;b&gt;포워드 렌더링 파이프라인(Forward Pipeline)&lt;/b&gt; 에 &lt;b&gt;스크린 공간 주변광 차폐(SSAO)&lt;/b&gt; 를 도입했다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;렌더링 순서 충돌&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;전통적인 &lt;b&gt;버텍스 안개(Vertex Fog)&lt;/b&gt; 는 &lt;b&gt;Base Pass&lt;/b&gt; 의 버텍스 셰이더에서 계산되며, 멀리 있는 오브젝트 색상을 안개 색과 섞는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SSAO&lt;/b&gt; 는 후처리 효과이므로 Base Pass 렌더링이 끝나 전체 씬 깊이를 얻은 뒤에 계산할 수 있다.&lt;/li&gt;
&lt;li&gt;SSAO가 안개 효과 이후에 적용되면, 이미 안개 색으로 덮인 픽셀을 &lt;b&gt;다시 어둡게&lt;/b&gt; 만들어 먼 거리의 안개 영역에 부자연스러운 어두운 얼룩이 생긴다. 이는 시각적으로 잘못된 결과다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 해결책: 후처리 안개 (Post-Process Fog)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 아이디어&lt;/b&gt;: 안개 계산을 버텍스 셰이더 단계에서 &lt;b&gt;후처리 단계&lt;/b&gt; 로 옮겨, SSAO 이후에 실행되도록 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새 렌더링 흐름&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Base Pass&lt;/b&gt;: 씬을 정상 렌더링하되 &lt;b&gt;버텍스 안개를 계산하지 않는다&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후처리&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 SSAO를 계산하고 적용한다.&lt;/li&gt;
&lt;li&gt;이후 같은 Pass 또는 다음 Pass에서 씬 깊이 맵을 이용해 픽셀의 월드 위치를 재구성하고, 카메라와의 거리를 계산해 &lt;b&gt;안개 색&lt;/b&gt; 을 구한 뒤 씬 색상과 섞는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시각적 정확성&lt;/b&gt;: SSAO가 안개 자체의 색상에 영향을 주지 않아 올바른 렌더링 결과를 보장한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 최적화&lt;/b&gt;: 정점 수가 매우 많은 장면(다수 캐릭터와 정령이 동시에 등장하는 경우)에서는 안개 계산을 per-vertex에서 per-pixel(풀스크린 후처리)로 옮겨 버텍스 셰이더 부담을 크게 줄일 수 있다. 부하가 큰 장면에서 &lt;b&gt;Base Pass Vertex Stage 비용을 약 10% 최적화&lt;/b&gt; 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 버텍스 안개의 유지와 확장&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;버텍스 안개를 유지하는 예외&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스카이박스(Skybox)&lt;/b&gt;: 스카이박스는 SSAO의 영향을 받지 않으며, 정점 수가 픽셀 수보다 훨씬 적다. 따라서 풀스크린 후처리보다 버텍스 안개 비용이 더 낮아 계속 유지한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후처리 이후 렌더링되는 오브젝트&lt;/b&gt;: 후처리 안개가 합성된 뒤 렌더링되는 반투명 오브젝트나 이펙트는 자체적으로 버텍스 안개를 계산해야 한다. 보통 이런 오브젝트는 모델이 단순해 비용이 관리 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커스텀 버텍스 안개 (Custom Vertex Fog)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진의 머티리얼 에디터를 확장해 아티스트가 &lt;b&gt;버텍스 안개를 커스터마이즈&lt;/b&gt; 할 수 있도록 했다.&lt;/li&gt;
&lt;li&gt;이를 통해 아티스트는 더 풍부한 아트 효과를 만들 수 있다. 예를 들어 뇌우 구름의 하단과 상단에 서로 다른 안개 색과 전환을 설정해 씬과 더 자연스럽게 섞이도록 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5LEK7/dJMcafG5V1J/kbhSYLFKohpzmTo92NvDj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5LEK7/dJMcafG5V1J/kbhSYLFKohpzmTo92NvDj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5LEK7/dJMcafG5V1J/kbhSYLFKohpzmTo92NvDj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5LEK7%2FdJMcafG5V1J%2FkbhSYLFKohpzmTo92NvDj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;렌더링 흐름 연결 최적화 (Subpass Chaining)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 목표&lt;/b&gt;: 모바일에서는 &lt;b&gt;Tile-Based Rendering&lt;/b&gt; 구조의 장점(예: 온칩 메모리)을 최대한 활용하기 위해, 가능한 한 많은 렌더링 작업을 &lt;b&gt;하나의 Render Pass 안에서 완료&lt;/b&gt; 해야 한다. 비싼 메모리 읽기/쓰기를 피하기 위해서다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;렌더링 작업 체인 예시&lt;/b&gt;: 하나의 Pass 안에서 여러 후처리 단계를 순서대로 실행한다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Base Pass의 출력(인코딩된 색상)을 읽는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;색상 디코딩&lt;/b&gt; (Decode).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SSAO&lt;/b&gt; 합성.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후처리 안개(Post-Process Fog)&lt;/b&gt; 합성.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컬러 그레이딩(Color Grading)&lt;/b&gt; 수행.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;투명 오브젝트&lt;/b&gt; 렌더링(예: 수면).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;독립 반투명 오브젝트(Separate Translucency)&lt;/b&gt; 렌더링. 보통 후처리 영향을 받지 않는 이펙트다.&lt;/li&gt;
&lt;li&gt;최종적으로 &lt;b&gt;Bloom&lt;/b&gt; 과 &lt;b&gt;Distortion&lt;/b&gt; 이 포함된 이미지를 출력한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제 3 부분&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCv9Hk/dJMcadCl1DF/z2Pse5IM4LMdoaPhFa0Znk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCv9Hk/dJMcadCl1DF/z2Pse5IM4LMdoaPhFa0Znk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCv9Hk/dJMcadCl1DF/z2Pse5IM4LMdoaPhFa0Znk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCv9Hk%2FdJMcadCl1DF%2Fz2Pse5IM4LMdoaPhFa0Znk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLpTI3/dJMcadCl1DH/UImkHYvT6HNPdPNYBtR7B1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLpTI3/dJMcadCl1DH/UImkHYvT6HNPdPNYBtR7B1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLpTI3/dJMcadCl1DH/UImkHYvT6HNPdPNYBtR7B1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLpTI3%2FdJMcadCl1DH%2FUImkHYvT6HNPdPNYBtR7B1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp4NdU/dJMcadCl1DG/9GSy0NCBJHs6R6eUo8cHJ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp4NdU/dJMcadCl1DG/9GSy0NCBJHs6R6eUo8cHJ0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp4NdU/dJMcadCl1DG/9GSy0NCBJHs6R6eUo8cHJ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp4NdU%2FdJMcadCl1DG%2F9GSy0NCBJHs6R6eUo8cHJ0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모바일 렌더링 파이프라인의 성능 병목과 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 전통적인 멀티 Pass 렌더링 흐름의 과제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;표준 렌더링 흐름 개요&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Base Pass&lt;/b&gt;: 씬의 기본 색상을 출력한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후처리 단계&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;색상 디코딩(Color Decode).&lt;/li&gt;
&lt;li&gt;스크린 공간 주변광 차폐(&lt;b&gt;SSAO&lt;/b&gt;) 합성.&lt;/li&gt;
&lt;li&gt;후처리 안개(Post-Process Fog).&lt;/li&gt;
&lt;li&gt;컬러 그레이딩(&lt;b&gt;Color Grading&lt;/b&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;투명 오브젝트 렌더링&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수면, 반투명 이펙트 등을 렌더링.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Separate Translucency&lt;/b&gt; 큐의 오브젝트 렌더링. 보통 후처리 영향을 받지 않게 하려는 이펙트다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최종 합성&lt;/b&gt;: &lt;b&gt;Bloom&lt;/b&gt;, &lt;b&gt;Distortion&lt;/b&gt;(왜곡), &lt;b&gt;Tone Mapping&lt;/b&gt; 결과를 합성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 성능 문제&lt;/b&gt;: &lt;b&gt;잦은 Render Pass 전환&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모바일에서는 &lt;b&gt;Render Pass&lt;/b&gt; 를 전환할 때마다 중간 결과를 &lt;b&gt;시스템 메모리(그래픽 메모리)에 다시 기록(Write back)&lt;/b&gt; 해야 하며, 이 과정에서 큰 대역폭과 시간 비용이 발생한다.&lt;/li&gt;
&lt;li&gt;복잡한 장면에서는 이로 인해 기기 발열, 프레임 저하, 전력 소모 증가가 발생한다.&lt;/li&gt;
&lt;li&gt;초기 파이프라인은 1차 병합을 거친 뒤에도 여전히 &lt;b&gt;5개의 Render Pass&lt;/b&gt; 와 &lt;b&gt;4번의 중간 결과 메모리 write back&lt;/b&gt; 이 필요했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문제의 근본 원인: Pass를 끊는 요소&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;후처리 머티리얼(Post-Process Material)&lt;/b&gt;: 이전 단계의 렌더링 결과를 샘플링해야 하므로 현재 Pass를 강제로 중단하고 결과를 메모리에 쓴 뒤, 새 Pass를 열어 처리하게 만든다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;왜곡 효과(Distortion)&lt;/b&gt;: 합성 단계에서 역시 씬 색상을 샘플링해야 하므로 Pass가 끊긴다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhEWu/dJMcah5ZyS0/QhhxAPYtSnR2tzmn4t1w6k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhEWu/dJMcah5ZyS0/QhhxAPYtSnR2tzmn4t1w6k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhEWu/dJMcah5ZyS0/QhhxAPYtSnR2tzmn4t1w6k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhEWu%2FdJMcah5ZyS0%2FQhhxAPYtSnR2tzmn4t1w6k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kOjAL/dJMcadbjFTq/RWuPuCaADojdoCsrRtvloK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kOjAL/dJMcadbjFTq/RWuPuCaADojdoCsrRtvloK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kOjAL/dJMcadbjFTq/RWuPuCaADojdoCsrRtvloK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkOjAL%2FdJMcadbjFTq%2FRWuPuCaADojdoCsrRtvloK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN5xdC/dJMcah5ZySY/sBdzg6X7GBYmakWgvpru20/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN5xdC/dJMcah5ZySY/sBdzg6X7GBYmakWgvpru20/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN5xdC/dJMcah5ZySY/sBdzg6X7GBYmakWgvpru20/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN5xdC%2FdJMcah5ZySY%2FsBdzg6X7GBYmakWgvpru20%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crxfr7/dJMcah5ZySX/1ZJLsBAq9175wrDyY8o8qK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crxfr7/dJMcah5ZySX/1ZJLsBAq9175wrDyY8o8qK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crxfr7/dJMcah5ZySX/1ZJLsBAq9175wrDyY8o8qK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcrxfr7%2FdJMcah5ZySX%2F1ZJLsBAq9175wrDyY8o8qK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 최적화 방안 1: Subpass 후처리 머티리얼&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;문제 분석&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전통적인 후처리 머티리얼은 PostProcessInput0(이전 Pass의 렌더링 결과)을 샘플링해야 한다. 이 때문에 자연스럽게 세 개의 독립적인 Pass로 나뉜다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Pass 1: 씬 렌더링.&lt;/li&gt;
&lt;li&gt;Pass 2: Pass 1의 결과를 메모리에 기록.&lt;/li&gt;
&lt;li&gt;Pass 3: 후처리 머티리얼이 메모리에 있는 결과를 읽어 계산.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 아이디어와 통찰&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 통찰&lt;/b&gt;: 프로젝트의 대부분 후처리 머티리얼은 &lt;b&gt;현재 픽셀의 색상만 샘플링&lt;/b&gt; 하면 되며, 주변 픽셀을 샘플링할 필요가 없다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해결책&lt;/b&gt;: 모바일 GPU의 &lt;b&gt;Framebuffer Fetch&lt;/b&gt; (&lt;b&gt;FBF&lt;/b&gt;) 기능을 활용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Framebuffer Fetch&lt;/b&gt; 는 셰이더 실행 중 &lt;b&gt;Tile Memory(온칩 메모리)&lt;/b&gt; 에 이미 존재하는 현재 픽셀 위치의 데이터(예: 색상)를 직접 읽을 수 있게 해준다. 따라서 현재 Render Pass를 끝낼 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구현과 효과&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Subpass 후처리 머티리얼 개발&lt;/b&gt;: 전통적인 텍스처 샘플링 대신 &lt;b&gt;Framebuffer Fetch&lt;/b&gt; 로 이전 계산 색상을 가져오는 새로운 머티리얼 타입을 제공했다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적화 결과&lt;/b&gt;: Color Grading, 반투명 렌더링, 후처리 머티리얼 같은 여러 렌더링 단계를 하나의 Render Pass 안으로 병합했다. 모든 계산은 효율적인 &lt;b&gt;Tile Memory&lt;/b&gt; 안에서 수행되고, 마지막에 최종 결과만 한 번 시스템 메모리에 기록한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 이득 (iPhone X)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;테스트 장면&lt;/b&gt;: 쓰기 대역폭 &lt;b&gt;23%&lt;/b&gt; 최적화, GPU 시간 &lt;b&gt;31.6%&lt;/b&gt; 최적화.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실제 게임 장면&lt;/b&gt;: GPU 시간 &lt;b&gt;5.5%&lt;/b&gt; 최적화, 쓰기 대역폭 &lt;b&gt;14.8%&lt;/b&gt; 최적화, 읽기 대역폭 &lt;b&gt;16.5%&lt;/b&gt; 최적화.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FGUje/dJMcah5ZyS2/lS0gPPKEXBbfTH1uBmjgAK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FGUje/dJMcah5ZyS2/lS0gPPKEXBbfTH1uBmjgAK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FGUje/dJMcah5ZyS2/lS0gPPKEXBbfTH1uBmjgAK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFGUje%2FdJMcah5ZyS2%2FlS0gPPKEXBbfTH1uBmjgAK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN26HF/dJMcah5ZyS1/yFp9UJqBGIPpWqo3DPvCq1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN26HF/dJMcah5ZyS1/yFp9UJqBGIPpWqo3DPvCq1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN26HF/dJMcah5ZyS1/yFp9UJqBGIPpWqo3DPvCq1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN26HF%2FdJMcah5ZyS1%2FyFp9UJqBGIPpWqo3DPvCq1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/es4nti/dJMcaaZ195C/kuYkpjfn1zVQ14Hgy7Ontk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/es4nti/dJMcaaZ195C/kuYkpjfn1zVQ14Hgy7Ontk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/es4nti/dJMcaaZ195C/kuYkpjfn1zVQ14Hgy7Ontk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fes4nti%2FdJMcaaZ195C%2FkuYkpjfn1zVQ14Hgy7Ontk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 최적화 방안 2: Distortion 계산 병합&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;문제 분석&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전통적인 &lt;b&gt;Distortion&lt;/b&gt; 은 두 단계로 나뉜다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;누적(Accumulation)&lt;/b&gt;: 모든 왜곡 효과의 오프셋 값을 하나의 RT에 렌더링한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;합성(Merge)&lt;/b&gt;: 새 Pass를 열고 누적된 오프셋으로 씬 색상을 샘플링해 왜곡 효과를 구현한다. 이 샘플링 작업이 렌더링 흐름을 끊는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 아이디어&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;합성 계산을 뒤로 미루기&lt;/b&gt;: Distortion의 합성 계산 로직을 이후 단계 중 원래부터 씬 색상을 샘플링해야 하는 Pass로 옮긴다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대상 Pass&lt;/b&gt;: &lt;b&gt;Bloom&lt;/b&gt; 과 &lt;b&gt;Tone Mapping&lt;/b&gt;. 두 Pass는 원래 씬 색상을 읽어야 하므로, 읽을 때 Distortion의 UV 오프셋을 추가 적용하는 비용은 낮다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구현과 트레이드오프&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;구현 방식&lt;/b&gt;: Bloom 과 Tone Mapping 셰이더에서 씬 색상을 샘플링하는 UV 좌표에 Distortion 텍스처의 오프셋 값을 적용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과&lt;/b&gt;: 독립적인 Distortion 합성 Pass를 제거해 메인 렌더링 흐름이 더 이상 끊기지 않게 했다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;표현상의 트레이드오프&lt;/b&gt;: 합성 시점이 뒤로 밀리면서, 원래는 왜곡의 영향을 받지 않던 이펙트(예: Separate Translucency)도 이제 왜곡된다. 프로젝트에서는 이 시각적 결과를 허용 가능한 것으로 판단했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 이득 (iPhone X)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GPU 시간 &lt;b&gt;13.8%&lt;/b&gt; 최적화.&lt;/li&gt;
&lt;li&gt;읽기&amp;middot;쓰기 대역폭 약 &lt;b&gt;30%&lt;/b&gt; 최적화.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ydmvB/dJMcaaZ195B/tB7jgNwUbiZ6zndpD53n6k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ydmvB/dJMcaaZ195B/tB7jgNwUbiZ6zndpD53n6k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ydmvB/dJMcaaZ195B/tB7jgNwUbiZ6zndpD53n6k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FydmvB%2FdJMcaaZ195B%2FtB7jgNwUbiZ6zndpD53n6k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nLCJd/dJMcadbjFTp/8NXY4xUocaDb0JHmczUDLK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nLCJd/dJMcadbjFTp/8NXY4xUocaDb0JHmczUDLK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nLCJd/dJMcadbjFTp/8NXY4xUocaDb0JHmczUDLK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnLCJd%2FdJMcadbjFTp%2F8NXY4xUocaDb0JHmczUDLK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGva4l/dJMcaaZ195D/81sAsaycKDJ1ThWUAiVw51/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGva4l/dJMcaaZ195D/81sAsaycKDJ1ThWUAiVw51/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGva4l/dJMcaaZ195D/81sAsaycKDJ1ThWUAiVw51/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGva4l%2FdJMcaaZ195D%2F81sAsaycKDJ1ThWUAiVw51%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 궁극적 최적화: 단일 Pass 기반 저사양 HDR 파이프라인&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;최적화 성과 정리&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 두 최적화를 통해 렌더링 흐름을 &lt;b&gt;5개의 Render Pass / 4번의 메모리 write back&lt;/b&gt; 에서 &lt;b&gt;2개의 Render Pass / 1번의 메모리 write back&lt;/b&gt; 으로 줄였다.&lt;/li&gt;
&lt;li&gt;Color Grading 부터 Separate Translucency 까지 대부분의 작업을 &lt;b&gt;하나의 Render Pass&lt;/b&gt; 안에서 완료했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;추가 병합 아이디어&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pass 병합 효과가 이렇게 크다면, 더 앞 단계인 &lt;b&gt;Pre-Pass&lt;/b&gt;, &lt;b&gt;Base Pass&lt;/b&gt; 와 이후 &lt;b&gt;Tone Mapping&lt;/b&gt; 등도 모두 하나의 Render Pass로 합칠 수 있지 않을까?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;ldquo;저사양 버전&amp;rdquo; 단일 Pass 파이프라인 구현&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 기술&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Framebuffer Fetch&lt;/b&gt;: 이후 계산에서 현재 픽셀의 색상 정보를 가져오는 데 사용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Depth Stencil Fetch&lt;/b&gt;: 이후 계산에서 현재 픽셀의 깊이 정보를 가져오는 데 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구현 원리&lt;/b&gt;: 두 Fetch 기술을 활용해 Pre-Pass부터 Tone Mapping까지 모든 계산을 &lt;b&gt;Tile Memory&lt;/b&gt; 안에서 이어서 수행한다. 중간 결과를 메인 메모리에 write back 하지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기술적 희생(Trade-offs)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 방식은 &lt;b&gt;주변 픽셀 샘플링이 필요한 후처리 효과&lt;/b&gt; 를 구현할 수 없다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SSAO&lt;/b&gt;, &lt;b&gt;스크린 공간 반사(SSR)&lt;/b&gt;, &lt;b&gt;Bloom&lt;/b&gt; 같은 효과를 비활성화하거나 제거해야 한다.&lt;/li&gt;
&lt;li&gt;일부 고급 효과를 희생하지만, 화면에 큰 영향을 주는 핵심 후처리(예: 컬러 그레이딩, 안개 효과 등)는 유지해 극한 성능을 위한 렌더링 파이프라인을 구현했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제 4 부분&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W8f01/dJMcaaZ195F/UfIje18lWinrjktK4eB0lK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W8f01/dJMcaaZ195F/UfIje18lWinrjktK4eB0lK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W8f01/dJMcaaZ195F/UfIje18lWinrjktK4eB0lK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW8f01%2FdJMcaaZ195F%2FUfIje18lWinrjktK4eB0lK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kyNjh/dJMcah5ZySZ/8NkW9FDWtcyKRVNXKDaPM1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kyNjh/dJMcah5ZySZ/8NkW9FDWtcyKRVNXKDaPM1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kyNjh/dJMcah5ZySZ/8NkW9FDWtcyKRVNXKDaPM1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkyNjh%2FdJMcah5ZySZ%2F8NkW9FDWtcyKRVNXKDaPM1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;810&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크린샷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;저사양 HDR 렌더링 파이프라인 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 아이디어와 목표&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;목표&lt;/b&gt;: 저사양 기기를 대상으로 HDR 렌더링 파이프라인을 최적화한다. 핵심 비주얼 스타일은 유지하면서 성능 비용, 특히 메모리 대역폭 비용을 크게 낮추는 것이 목표다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 전략&lt;/b&gt;: &lt;b&gt;렌더링 패스 병합(Pass Consolidation)&lt;/b&gt; 을 통해 여러 후처리 단계를 하나의 Render Pass 로 통합하고, 모바일 GPU(TBDR 구조)의 특성을 활용해 &lt;b&gt;Tile Memory(온칩 메모리)&lt;/b&gt; 안에서 계산을 완료한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구체적 최적화 전략&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;비용이 큰 후처리 효과 제거&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 Pass 통합을 실현하기 위해, 멀티 Pass 나 복잡한 계산에 의존하는 후처리 효과를 선택적으로 제거했다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요 제거 효과&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스크린 공간 주변광 차폐(SSAO)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스크린 공간 반사(SSR)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;블룸(Bloom)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TBDR 특성을 활용한 계산 병합&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Framebuffer Fetch / Subpass Load&lt;/b&gt;: 같은 Render Pass 의 프래그먼트 셰이더 안에서, 현재 픽셀 위치에 이미 프레임버퍼에 기록된 색상 데이터를 직접 읽을 수 있게 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Depth/Stencil Fetch&lt;/b&gt;: 마찬가지로 현재 픽셀의 깊이와 스텐실 값을 직접 읽을 수 있게 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구현 방식&lt;/b&gt;: 위 기능을 사용해, 원래는 여러 Pass가 필요했던 계산(예: 씬을 먼저 렌더링한 뒤 G-Buffer/Color Buffer를 다시 읽어 후처리)을 모두 하나의 Pass 안으로 집중시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 비주얼 표현 유지&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일부 효과를 제거했지만, 화면 스타일에 큰 영향을 주는 핵심 후처리 단계는 유지했다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유지한 효과&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;후처리 안개(Post-Processing Fog)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컬러 그레이딩(Color Grading)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;톤 매핑(Tonemapping)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과&lt;/b&gt;: 최적화된 파이프라인에서도 원래의 화면 분위기와 아트 스타일을 잘 유지할 수 있었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;성능 이득과 분석&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;중간 결과 write back 감소 (Reduced Write Bandwidth)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 큰 성능 향상 요인이다. 계산이 Tile Memory 안에서 닫힌 루프로 완료되므로, 중간 결과(예: 씬 색상, 깊이)를 시스템 메모리에 쓴 뒤 이후 Pass가 다시 읽는 과정을 피할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;깊이 버퍼 최적화&lt;/b&gt;: 깊이 정보를 위한 별도 Render Target 을 만들고 시스템 메모리에 저장할 필요가 없다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Memoryless Depth/Stencil&lt;/b&gt;: 깊이/스텐실 첨부(Depth/Stencil Attachment)를 &lt;b&gt;Memoryless&lt;/b&gt; 로 설정할 수 있다. 이렇게 하면 해당 내용은 렌더링 중에만 Tile Memory에 존재하고 렌더링 종료 후 폐기되므로 write back 대역폭 비용을 완전히 제거할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 테스트 데이터 (Remix 2 기준)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;렌더링 시간(Render Time)&lt;/b&gt;: &lt;b&gt;3%&lt;/b&gt; 최적화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;읽기 대역폭(Read Bandwidth)&lt;/b&gt;: &lt;b&gt;15.1%&lt;/b&gt; 최적화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쓰기 대역폭(Write Bandwidth)&lt;/b&gt;: &lt;b&gt;30%&lt;/b&gt; 최적화(가장 큰 이득)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>TECH.ART.FLOW.IO</category>
      <category>그래픽스 프로그래밍</category>
      <category>모어펀 스튜디오</category>
      <category>중국</category>
      <category>테크니컬 아트</category>
      <category>텐센트</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/786</guid>
      <comments>https://techartnomad.tistory.com/786#entry786comment</comments>
      <pubDate>Mon, 22 Jun 2026 18:37:39 +0900</pubDate>
    </item>
    <item>
      <title>[번역] RenderDoc For VSCode: 에디터를 떠나지 않고 GPU Debug</title>
      <link>https://techartnomad.tistory.com/785</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;역자의 말: 요즘은 컨설팅 고객사들 역시 시장 상황의 여파로 인해 신작 프로젝트 진행을 홀드 하는 형편이라 저로서는 여유로운 시간을 보내게 되었습니다. 게임프로토타입도 만들고 로컬 LLM 을 공부하면서 출시할 앱을 개발하고 있습니다. 최근엔 그래도 언리얼6 브렌치가 공개 되어서 이래저래 살펴봐야 할 것들도 늘었기도 하고 말이죠. 조만간 Verse 언어에 대한 글들을 깊게 써 보기도 해야겠습니다만 그 전에 렌더독 관련 토픽이 하나 또 올라와서 간단히 전파 해 보려 합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자: Kirk&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSgoCe/dJMcahLCDcC/tb05kdKSyCs8Tp7ScjPBi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSgoCe/dJMcahLCDcC/tb05kdKSyCs8Tp7ScjPBi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSgoCe/dJMcahLCDcC/tb05kdKSyCs8Tp7ScjPBi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSgoCe%2FdJMcahLCDcC%2Ftb05kdKSyCs8Tp7ScjPBi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;207&quot; height=&quot;207&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개발 배경&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vibe Coding에 익숙해지면서, GPU 캡처 분석을 할 때도 AI의 도움을 받고 싶었습니다. RenderDoc은 기본적으로 AI 연동을 지원하지 않아, MCP를 통해서만 접근할 수 있었습니다. 하지만 RenderDoc MCP를 사용할 때, RenderDoc을 열고 다시 MCP를 실행해서 AI와 상호작용해야 하는데, 두 창이 분리되어 있어 다소 불편했습니다. 게다가 MCP는 현재 클릭한 draw의 정보를 알지 못해 사용성이 자연스럽지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 VSCode 안에서 RenderDoc과 AI를 함께 사용할 수 있다면, 프로젝트를 열고 캡처를 열면 AI가 더 많은 유용한 정보와 상호작용을 볼 수 있고, 현재 프레임의 성능 병목을 직접 분석한 다음 프로젝트 디렉토리로 돌아가 해당 구현을 찾아 최적화할 수 있을 것이라고 생각했습니다. 우리는 AI가 작업하는 모습을 지켜보기만 하면 됩니다. (플러그인 자체도 AI로 작성했고, 이 글의 내용도 거의 AI가 작성했습니다 hhhh)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;제품 소개&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RenderDoc For VSCode는 GPU 디버깅 및 렌더링 분석 시나리오를 위해 구성된 에디터 내 워크스테이션을 제공하며, 현재 다음 기능을 지원합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VS Code에서 직접 .rdc 파일을 열고, 로컬 및 실제 기기에서 실행, 캡처, 프로세스 연결, 실제 기기 재생 등의 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;Draw Call과 API 호출 정보를 탐색하고, RenderDoc과 유사한 Pipeline, Shader, Texture, Mesh 등의 창 인터페이스를 구현했습니다.&lt;/li&gt;
&lt;li&gt;Shader 섹션에서 Mali Offline Compiler 분석 기능을 통합하여 AI 성능 분석에 추가 데이터를 제공합니다.&lt;/li&gt;
&lt;li&gt;GitHub Copilot과 외부 MCP 클라이언트를 통해 현재 capture 컨텍스트에 접근할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것의 목표는 단순한 capture 뷰어가 아니라, 캡처, 분석, 문제 파악 및 협업을 최대한 동일한 워크플로우로 통합하는 것입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;핵심 기능&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. VS Code에서 직접 RenderDoc Capture 열기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.rdc 파일을 열면 사이드바에 다음과 같은 capture 관련 뷰가 제공됩니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Capture Info&lt;/li&gt;
&lt;li&gt;Event Browser&lt;/li&gt;
&lt;li&gt;API Inspector&lt;/li&gt;
&lt;li&gt;Capture Target&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 이벤트 트리에서 빠르게 지정된 Draw Call로 이동하고, Inspector를 바로 열어 계속 분석할 수 있습니다. 이를 통해 capture 탐색이 별도의 창 전환 없이 자연스럽게 에디터 작업 공간에 통합됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rDVK6/dJMcag6Z2wE/3nnR95DsQfJjNaCD0vXJN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rDVK6/dJMcag6Z2wE/3nnR95DsQfJjNaCD0vXJN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rDVK6/dJMcag6Z2wE/3nnR95DsQfJjNaCD0vXJN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrDVK6%2FdJMcag6Z2wE%2F3nnR95DsQfJjNaCD0vXJN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Inspector가 간소화된 뷰가 아닌 완전한 분석 패널 제공&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Inspector는 그래픽 디버깅에서 가장 핵심적인 관찰 영역을 이미 커버하고 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Overview&lt;/li&gt;
&lt;li&gt;Pipeline&lt;/li&gt;
&lt;li&gt;Shaders&lt;/li&gt;
&lt;li&gt;Textures&lt;/li&gt;
&lt;li&gt;Mesh&lt;/li&gt;
&lt;li&gt;Events&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 탭들에서 다음을 직접 확인할 수 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 draw의 pipeline state&lt;/li&gt;
&lt;li&gt;각 shader stage의 소스 코드와 디스어셈블리 결과&lt;/li&gt;
&lt;li&gt;현재 draw가 샘플링하는 텍스처와 리소스 정보&lt;/li&gt;
&lt;li&gt;mesh, vertex 및 index 데이터&lt;/li&gt;
&lt;li&gt;이벤트 체인과 GPU timing&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 기존에 RenderDoc 네이티브 창에서만 수행할 수 있었던 많은 분석 작업을 이제 VS Code 내에서 직접 수행할 수 있으며, 프로젝트 코드와 동일한 컨텍스트를 유지할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nxpTl/dJMcadbi0lY/wwaDKkCmwoTFnzeIhU3o21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nxpTl/dJMcadbi0lY/wwaDKkCmwoTFnzeIhU3o21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nxpTl/dJMcadbi0lY/wwaDKkCmwoTFnzeIhU3o21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnxpTl%2FdJMcadbi0lY%2FwwaDKkCmwoTFnzeIhU3o21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OverView&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5Lw3L/dJMcah5YO2i/sefypNk3vkG4fT8o4FCC8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5Lw3L/dJMcah5YO2i/sefypNk3vkG4fT8o4FCC8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5Lw3L/dJMcah5YO2i/sefypNk3vkG4fT8o4FCC8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5Lw3L%2FdJMcah5YO2i%2FsefypNk3vkG4fT8o4FCC8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PipelineView&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FZ5Lr/dJMcagTu66D/aNbWI2RiMg6C6HXG3hgoX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FZ5Lr/dJMcagTu66D/aNbWI2RiMg6C6HXG3hgoX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FZ5Lr/dJMcagTu66D/aNbWI2RiMg6C6HXG3hgoX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFZ5Lr%2FdJMcagTu66D%2FaNbWI2RiMg6C6HXG3hgoX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Shaders&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/571l7/dJMcacQ2QQl/YI5BO7hSEpeFkuv1k1LkX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/571l7/dJMcacQ2QQl/YI5BO7hSEpeFkuv1k1LkX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/571l7/dJMcacQ2QQl/YI5BO7hSEpeFkuv1k1LkX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F571l7%2FdJMcacQ2QQl%2FYI5BO7hSEpeFkuv1k1LkX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MeshView&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cq8srB/dJMcadibKDH/guB3C5ncVWesKTORhGwfKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cq8srB/dJMcadibKDH/guB3C5ncVWesKTORhGwfKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cq8srB/dJMcadibKDH/guB3C5ncVWesKTORhGwfKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcq8srB%2FdJMcadibKDH%2FguB3C5ncVWesKTORhGwfKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TextureView&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 에디터에서 실행, 연결 및 캡처 완료&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RenderDoc For VSCode의 포지셔닝은 capture 보기에만 국한되지 않고, capture 워크플로우의 시작 단계까지 확장됩니다. 현재 다음을 지원합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 프로그램 실행 및 캡처&lt;/li&gt;
&lt;li&gt;로컬 또는 원격 Capture Target 선택&lt;/li&gt;
&lt;li&gt;실행 중인 프로세스에 연결&lt;/li&gt;
&lt;li&gt;원격 기기와 협력하여 캡처 완료&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기능의 가치는 &quot;캡처&quot;와 &quot;프레임 분석&quot;을 동일한 작업 컨텍스트에 배치하여, 도구 전환과 상태 이동으로 인한 추가 비용을 줄이는 데 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjl0nV/dJMcaglCMui/h0bIFEUBOE1lSz0cGP3oFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjl0nV/dJMcaglCMui/h0bIFEUBOE1lSz0cGP3oFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjl0nV/dJMcaglCMui/h0bIFEUBOE1lSz0cGP3oFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjl0nV%2FdJMcaglCMui%2Fh0bIFEUBOE1lSz0cGP3oFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. Mali Offline Compiler를 Shader 분석 워크플로우에 통합&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모바일 그래픽 최적화 시나리오에서는 단순히 shader 소스 코드를 읽는 것만으로는 충분하지 않은 경우가 많습니다. 이를 위해 플러그인은 Mali Offline Compiler를 Inspector의 Shaders 탭에 통합했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 지원되는 워크플로우:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Shader 패널에서 직접 Mali 분석 시작&lt;/li&gt;
&lt;li&gt;대상 Mali 기기 프로필 선택&lt;/li&gt;
&lt;li&gt;분석 출력 결과 확인&lt;/li&gt;
&lt;li&gt;분석 결과를 바탕으로 AI 설명 및 최적화 논의 계속 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 shader 소스 코드, 하드웨어 분석 결과 및 후속 최적화 결정을 동일한 인터페이스 내에서 완료할 수 있어, 모바일 shader 튜닝의 컨텍스트 비용을 줄일 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdrLsM/dJMb997SJCA/LqQOafFu9IbNJ90dRgVYhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdrLsM/dJMb997SJCA/LqQOafFu9IbNJ90dRgVYhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdrLsM/dJMb997SJCA/LqQOafFu9IbNJ90dRgVYhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdrLsM%2FdJMb997SJCA%2FLqQOafFu9IbNJ90dRgVYhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. AI가 현재 Capture 컨텍스트를 직접 읽을 수 있도록&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RenderDoc For VSCode의 또 다른 중요한 방향은, AI를 &quot;현장과 분리된 채팅 도구&quot;에서 &quot;현재 capture 상태를 이해하는 분석 도우미&quot;로 전환하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub Copilot을 사용하는 경우, 현재 저장소에서 추가 MCP 구성 없이 로컬 renderdoc_* 도구를 직접 사용하여 capture 정보를 읽을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Roo, Zoo, Claude Code, Codex 등 MCP 클라이언트를 사용하는 경우, 플러그인이 노출하는 로컬 MCP 서비스를 통해 현재 VS Code 창의 RenderDoc 컨텍스트에 접근할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 현재 capture에 대해 다음과 같은 질문을 직접 할 수 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 프레임에 어떤 pass들이 포함되어 있나요?&lt;/li&gt;
&lt;li&gt;현재 선택된 draw에 어떤 텍스처가 바인딩되어 있나요?&lt;/li&gt;
&lt;li&gt;특정 EID의 fragment shader가 왜 비용이 높은가요?&lt;/li&gt;
&lt;li&gt;특정 shader가 프로젝트 내 어디에 구현되어 있나요?&lt;/li&gt;
&lt;li&gt;특정 ResourceId에 해당하는 buffer의 첫 256바이트 내용은 무엇인가요?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 핵심은 &quot;질문할 수 있다&quot;는 것뿐만 아니라, AI가 인간이 전달한 단편적인 정보가 아닌 현재 Inspector의 실제 선택 상태를 직접 얻는다는 점입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IKdJc/dJMcahLCC87/5FKhML6y6ZQik8VK50bT81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IKdJc/dJMcahLCC87/5FKhML6y6ZQik8VK50bT81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IKdJc/dJMcahLCC87/5FKhML6y6ZQik8VK50bT81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIKdJc%2FdJMcahLCC87%2F5FKhML6y6ZQik8VK50bT81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;외부 MCP 클라이언트 접근 장벽 낮추기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 MCP 클라이언트의 경우, 실제 도입 효율성에 영향을 미치는 것은 종종 프로토콜 자체가 아니라 접근 과정에서의 사소한 세부 사항들입니다. 예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 MCP 서비스가 이미 시작되었는지 여부&lt;/li&gt;
&lt;li&gt;현재 실제 포트 번호와 endpoint가 무엇인지&lt;/li&gt;
&lt;li&gt;어떤 워크스페이스 구성 파일을 수정해야 하는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해, 플러그인은 사이드바의 Capture Target 뷰에 독립적인 Local MCP 카드를 추가하여 다음을 중앙에서 표시합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MCP 활성화 여부&lt;/li&gt;
&lt;li&gt;MCP가 현재 성공적으로 실행 중인지&lt;/li&gt;
&lt;li&gt;현재 실제 포트 번호&lt;/li&gt;
&lt;li&gt;현재 endpoint&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 플러그인은 One-Click Configure 버튼을 제공하여 다음 작업을 자동으로 완료합니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;MCP 기능 활성화&lt;/li&gt;
&lt;li&gt;로컬 MCP 서비스 시작&lt;/li&gt;
&lt;li&gt;현재 실제 endpoint를 워크스페이스 MCP 구성에 기록&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 팀 내 접근 프로세스가 &quot;상태를 수동으로 확인하고 여러 JSON 파일을 유지 관리하는 것&quot;에서 한 번의 명시적이고 가시적이며 반복 가능한 구성 작업으로 축소되어, 일상적인 협업과 보급에 더 적합합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baMkxw/dJMcageSGSs/kemVsdGwpScSSzbIixqLk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baMkxw/dJMcageSGSs/kemVsdGwpScSSzbIixqLk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baMkxw/dJMcageSGSs/kemVsdGwpScSSzbIixqLk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaMkxw%2FdJMcageSGSs%2FkemVsdGwpScSSzbIixqLk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;788&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;설치 및 사용 가이드&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1단계: 플러그인 설치&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;릴리스 버전 VSIX를 직접 설치하는 것을 권장합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VS Code의 확장 패널에서 RenderDoc For VSCode를 검색하여 설치&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;797&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FEkwt/dJMcafUBRFh/KMvDHp8Wkj8jvRswi0aV5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FEkwt/dJMcafUBRFh/KMvDHp8Wkj8jvRswi0aV5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FEkwt/dJMcafUBRFh/KMvDHp8Wkj8jvRswi0aV5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFEkwt%2FdJMcafUBRFh%2FKMvDHp8Wkj8jvRswi0aV5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;797&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;797&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Visual Studio Marketplace에서 RenderDoc For VSCode를 검색하여 다운로드 및 설치&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;903&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cl0zPz/dJMb997SJC5/DLAwPl6krW10zIGrp0IP60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cl0zPz/dJMb997SJC5/DLAwPl6krW10zIGrp0IP60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cl0zPz/dJMb997SJC5/DLAwPl6krW10zIGrp0IP60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcl0zPz%2FdJMb997SJC5%2FDLAwPl6krW10zIGrp0IP60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;903&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;903&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=Kirkice.renderdoc-for-vscode&quot;&gt;RenderDoc for VS Code - Visual Studio Marketplace&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782053963309&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;RenderDoc for VS Code - Visual Studio Marketplace&quot; data-og-description=&quot;Extension for Visual Studio Code - View and analyze RenderDoc capture (.rdc) files in VS Code&quot; data-og-host=&quot;marketplace.visualstudio.com&quot; data-og-source-url=&quot;https://marketplace.visualstudio.com/items?itemName=Kirkice.renderdoc-for-vscode&quot; data-og-url=&quot;https://marketplace.visualstudio.com/items?itemName=Kirkice.renderdoc-for-vscode&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sEd39/dJMb9jOwpoc/oC0KFykvKrFlRchiFM6nCk/img.png?width=4267&amp;amp;height=4267&amp;amp;face=0_0_4267_4267,https://scrap.kakaocdn.net/dn/vNR7J/dJMb9cBRvKp/gnuQ3F4YaAlWJlMOZk3dkk/img.png?width=4267&amp;amp;height=4267&amp;amp;face=0_0_4267_4267,https://scrap.kakaocdn.net/dn/dX5osG/dJMb83SsAjO/0sgYM3kLSl7xk3ja5ORaK1/img.jpg?width=2560&amp;amp;height=1400&amp;amp;face=0_0_2560_1400&quot;&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=Kirkice.renderdoc-for-vscode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://marketplace.visualstudio.com/items?itemName=Kirkice.renderdoc-for-vscode&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sEd39/dJMb9jOwpoc/oC0KFykvKrFlRchiFM6nCk/img.png?width=4267&amp;amp;height=4267&amp;amp;face=0_0_4267_4267,https://scrap.kakaocdn.net/dn/vNR7J/dJMb9cBRvKp/gnuQ3F4YaAlWJlMOZk3dkk/img.png?width=4267&amp;amp;height=4267&amp;amp;face=0_0_4267_4267,https://scrap.kakaocdn.net/dn/dX5osG/dJMb83SsAjO/0sgYM3kLSl7xk3ja5ORaK1/img.jpg?width=2560&amp;amp;height=1400&amp;amp;face=0_0_2560_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;RenderDoc for VS Code - Visual Studio Marketplace&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Extension for Visual Studio Code - View and analyze RenderDoc capture (.rdc) files in VS Code&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;marketplace.visualstudio.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2단계: Capture 준비 및 열기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 후, 가장 짧은 학습 경로이므로 기존 .rdc 파일로 먼저 경험하는 것을 권장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 방법으로 capture에 진입할 수 있습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;VS Code에서 .rdc 파일을 직접 엽니다.&lt;/li&gt;
&lt;li&gt;명령 팔레트에서 &lt;b&gt;RenderDoc: Open RDC Capture&lt;/b&gt;를 실행합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RenderDoc: Open Launch Panel&lt;/b&gt;을 통해 로컬 프로그램을 구성하고 직접 캡처합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Capture Target&lt;/b&gt; 뷰에서 로컬 또는 원격 대상을 선택한 후, 연결 또는 캡처 작업을 실행합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;capture가 열리면 사이드바에 Capture Info, Event Browser, API Inspector, Capture Target과 같은 분석 관련 핵심 뷰가 나타납니다. 이 단계에서 기본 작업 환경이 구축된 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;887&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1O2s6/dJMcajimGgp/ckKvxlCYAUskoI8AYdhibK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1O2s6/dJMcajimGgp/ckKvxlCYAUskoI8AYdhibK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1O2s6/dJMcajimGgp/ckKvxlCYAUskoI8AYdhibK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1O2s6%2FdJMcajimGgp%2FckKvxlCYAUskoI8AYdhibK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;887&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;887&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJNvXX/dJMcacwNvwF/EOKUSCf4V7QuOTRE39q6m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJNvXX/dJMcacwNvwF/EOKUSCf4V7QuOTRE39q6m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJNvXX/dJMcacwNvwF/EOKUSCf4V7QuOTRE39q6m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJNvXX%2FdJMcacwNvwF%2FEOKUSCf4V7QuOTRE39q6m0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;724&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3단계: Draw Call에서 Inspector로 진입&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 프레임을 연 후, 이벤트 트리에서 직접 Draw Call을 선택하여 Inspector로 진입하는 것을 권장합니다. 이것이 플러그인의 가장 핵심적인 분석 진입점이기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Inspector를 연 후, 다음 순서로 인터페이스를 이해하는 것이 좋습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Overview&lt;/b&gt;에서 capture 기본 정보, API, 드라이버 및 프레임 요약을 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pipeline&lt;/b&gt;에서 현재 draw의 그래픽 파이프라인 상태와 바인딩 단계를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Shaders&lt;/b&gt;에서 각 stage의 소스 코드와 디스어셈블리를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Textures&lt;/b&gt;에서 현재 draw가 실제로 사용하는 입력 텍스처와 대상 리소스를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Mesh&lt;/b&gt;에서 vertex, index 및 입력 어셈블리 정보를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Events&lt;/b&gt;에서 이벤트 체인을 따라 컨텍스트를 계속 파악합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능 분석을 하려면, Draw Calls 뷰에서 먼저 &lt;b&gt;Fetch GPU Timings&lt;/b&gt;를 실행하는 것이 좋습니다. 그러면 이벤트 목록에 durationUs가 표시되어, 이후 수동으로 보든 AI에게 분석을 맡기든 더 효율적입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;681&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nEPn2/dJMcadPVAku/YI6ZPGiZkPr2uuWrkup531/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nEPn2/dJMcadPVAku/YI6ZPGiZkPr2uuWrkup531/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nEPn2/dJMcadPVAku/YI6ZPGiZkPr2uuWrkup531/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnEPn2%2FdJMcadPVAku%2FYI6ZPGiZkPr2uuWrkup531%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;681&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;681&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4단계: 필요에 따라 Mali Offline Compiler 활성화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 중점에 모바일 shader 최적화가 포함되어 있다면, 다음 단계로 Mali Offline Compiler를 연결할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준 절차는 다음과 같습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;먼저 Arm에서 제공하는 Mali Offline Compiler를 설치합니다.&lt;/li&gt;
&lt;li&gt;VS Code 설정에서 renderdoc.maliOfflineCompilerPath를 구성하여 malioc.exe를 가리킵니다.&lt;/li&gt;
&lt;li&gt;Inspector의 &lt;b&gt;Shaders&lt;/b&gt; 탭으로 돌아가 &lt;b&gt;Analyze with Mali Offline Compiler&lt;/b&gt;를 클릭합니다.&lt;/li&gt;
&lt;li&gt;대상 Mali 기기 프로필을 선택하고 분석 출력을 확인합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 shader 소스 코드, 정적 하드웨어 분석 결과 및 후속 최적화 논의가 동일한 작업 인터페이스에 나타나며, 특히 모바일 그래픽 개발 시나리오에 적합합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;627&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/71rRR/dJMcagzagRd/YhmREaU3oUPO83kywCujvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/71rRR/dJMcagzagRd/YhmREaU3oUPO83kywCujvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/71rRR/dJMcagzagRd/YhmREaU3oUPO83kywCujvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F71rRR%2FdJMcagzagRd%2FYhmREaU3oUPO83kywCujvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;627&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;627&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5단계: VS Code에서 AI로 현재 Capture 직접 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀에서 이미 GitHub Copilot을 사용 중이라면, 이 단계가 일반적으로 가장 간단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 저장소에서 Copilot은 로컬 renderdoc_* 도구를 직접 사용할 수 있으므로, 추가 MCP 구성이 필요하지 않습니다. VS Code Chat을 연 후, @renderdoc을 직접 사용하거나 기본 Copilot 대화에서 현재 capture에 대해 질문할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 경험으로 적합한 질문은 다음과 같습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이 프레임에는 대략 어떤 pass들이 있나요?&lt;/li&gt;
&lt;li&gt;현재 선택된 draw에 어떤 텍스처가 바인딩되어 있나요?&lt;/li&gt;
&lt;li&gt;이 draw의 fragment shader가 왜 비용이 높은지 분석해 주세요.&lt;/li&gt;
&lt;li&gt;이 shader는 프로젝트 내 어떤 구현에 해당하나요?&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계의 핵심은 AI가 현재 Inspector의 실제 선택 상태를 읽기 때문에 &quot;현재 draw&quot;, &quot;이 event&quot;, &quot;이 텍스처&quot;와 같은 자연스러운 표현이 그대로 성립된다는 점입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6단계: Roo, Claude Code, Codex 등 클라이언트를 위한 MCP 구성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀에서 다른 MCP 클라이언트도 사용 중이라면, 구성 파일을 수동으로 유지 관리하는 대신 플러그인 내장 그래픽 인터페이스 구성 절차를 직접 사용하는 것을 권장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 권장하는 방법은:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;동일한 VS Code 창에서 먼저 대상 .rdc capture를 엽니다.&lt;/li&gt;
&lt;li&gt;사이드바의 &lt;b&gt;Capture Target&lt;/b&gt; 뷰를 엽니다.&lt;/li&gt;
&lt;li&gt;그 안의 &lt;b&gt;Local MCP&lt;/b&gt; 카드를 찾습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;One-Click Configure&lt;/b&gt;를 클릭합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 버튼은 자동으로 세 가지 작업을 완료합니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;MCP 활성화&lt;/li&gt;
&lt;li&gt;로컬 MCP 서비스 시작&lt;/li&gt;
&lt;li&gt;현재 실제 endpoint를 워크스페이스 구성에 기록&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;980&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cl3IxP/dJMcadvBh5Z/HJ2i7yPcjYbwtnciBT8Gn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cl3IxP/dJMcadvBh5Z/HJ2i7yPcjYbwtnciBT8Gn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cl3IxP/dJMcadvBh5Z/HJ2i7yPcjYbwtnciBT8Gn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcl3IxP%2FdJMcadvBh5Z%2FHJ2i7yPcjYbwtnciBT8Gn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1294&quot; height=&quot;980&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;980&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구성 완료 후, 사용자는 인터페이스에서 MCP가 실행 중인지, 현재 포트 번호가 무엇인지, 최종 endpoint가 무엇인지 직접 확인할 수 있습니다. 여기서 매우 중요한 세부 사항이 있습니다: 포트 번호는 고정된 값으로 가정해서는 안 되며, 실제 연결 시 인터페이스에 표시된 현재 URL을 기준으로 해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수동으로 구성을 복사해야 하는 경우, 동일한 위치의 &lt;b&gt;MCP Info&lt;/b&gt;를 클릭할 수 있습니다. 그러나 실제 보급 및 팀 사용 관점에서는 One-Click Configure를 우선 권장합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;저장소 주소&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Kirkice/renderdoc-for-vscode&quot;&gt;Kirkice/renderdoc-for-vscode: renderdoc-for-vscode&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782054065243&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Kirkice/renderdoc-for-vscode: renderdoc-for-vscode&quot; data-og-description=&quot;renderdoc-for-vscode. Contribute to Kirkice/renderdoc-for-vscode development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Kirkice/renderdoc-for-vscode&quot; data-og-url=&quot;https://github.com/Kirkice/renderdoc-for-vscode&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/AMy80/dJMb81f2c34/l2SI91hleVEC9D9lgKq7c1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/OkewW/dJMb82eWAcS/MRs5UtH804KVJ4TruwLUA1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/IIwpP/dJMb88GeB45/5kV2mXY7WK0PZitM2P3ze1/img.jpg?width=2560&amp;amp;height=1400&amp;amp;face=0_0_2560_1400&quot;&gt;&lt;a href=&quot;https://github.com/Kirkice/renderdoc-for-vscode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Kirkice/renderdoc-for-vscode&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/AMy80/dJMb81f2c34/l2SI91hleVEC9D9lgKq7c1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/OkewW/dJMb82eWAcS/MRs5UtH804KVJ4TruwLUA1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/IIwpP/dJMb88GeB45/5kV2mXY7WK0PZitM2P3ze1/img.jpg?width=2560&amp;amp;height=1400&amp;amp;face=0_0_2560_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - Kirkice/renderdoc-for-vscode: renderdoc-for-vscode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;renderdoc-for-vscode. Contribute to Kirkice/renderdoc-for-vscode development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/2041134174560581346&quot;&gt;(73 封私信 / 61 条消息) RenderDoc For VSCode：不离开你的Editor就可以GPU debug - 知乎&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TECH.ART.FLOW.IO</category>
      <category>renderdoc</category>
      <category>technical art</category>
      <category>렌더독</category>
      <category>분석</category>
      <category>테크니컬 아트</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/785</guid>
      <comments>https://techartnomad.tistory.com/785#entry785comment</comments>
      <pubDate>Mon, 22 Jun 2026 00:02:14 +0900</pubDate>
    </item>
    <item>
      <title>차세대 VCS &amp;ldquo;LORE&amp;rdquo; 에 대한 간단한 서머리</title>
      <link>https://techartnomad.tistory.com/784</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmIV2d/dJMcahx5z7d/m8YLxJY7jSOaeyaxk8Sph1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmIV2d/dJMcahx5z7d/m8YLxJY7jSOaeyaxk8Sph1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmIV2d/dJMcahx5z7d/m8YLxJY7jSOaeyaxk8Sph1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmIV2d%2FdJMcahx5z7d%2Fm8YLxJY7jSOaeyaxk8Sph1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;436&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;State of Unreal 2026 Unreal Fest Chicago 영상 후반부에 언급된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/xXGSvLH9zAs?si=CMPOoM_CJ9jzZHcz&quot;&gt;https://youtu.be/xXGSvLH9zAs?si=CMPOoM_CJ9jzZHcz&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/xXGSvLH9zAs&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;상상해 보세요.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;상상, 상상.&lt;br /&gt;바로 그거예요.&lt;br /&gt;안녕하세요, 여러분. 언리얼 페스트에 오신 것을 환영합니다. 준비되셨나요?&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f6f2ea;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6f2ea; color: #575451;&quot;&gt;시작합시다. 시카고에 와주신 모든 분들께, 그리고 라이브 스트리밍으로 지켜봐 주시는 모든 분들께 정말 감사드립니다.&lt;/span&gt;&lt;span style=&quot;color: #575451;&quot;&gt;&lt;br /&gt;다시 한번, 저희는 AAA 게임 스튜디오의 거장들, 인디 팀, 포트나이트 크리에이터, 영화 제작자 등 엔터테인먼트의 미래를 만들어가고 있는 분들과 함께했습니다. 또한 로봇 공학, 건축, 자동차 등 수많은 산업 분야의 혁신가들이 언리얼의 힘을 새로운 영역으로 이끌고 있습니다.&lt;br /&gt;선택할 수 있는 100개가 넘는 세션과 실습실이 있습니다. 아직 이벤트 앱이 없다면, 이 QR 코드를 찍어 다운로드하고 앞으로 이틀간의 계획을 세워보세요.&lt;br /&gt;전시장에 있는 모든 데모와 게임들을 꼭 둘러보시고, 기술적인 도움이 필요할 때 개발 라운지 옆에 있는 학습 극장도 들러보세요.&lt;br /&gt;저희는 여러분의 성공을 축하하고 우리가 미래에 어디로 나아갈지 엿볼 수 있는 기회를 드리고자 이 자리에 섰습니다. 보여드릴 멋진 것들이 많지만, 미리 말씀드리자면 올해는 무대에서 라이브 기술 데모는 진행하지 않습니다. 팀이 멋진 새로운 엔진 버전을 만들고 언리얼 엔진 6의 기반을 다지는 데 정말 열심히 노력해 왔으며, 이에 대해서는 나중에 더 자세히 말씀드리겠습니다.&lt;br /&gt;새로운 기능에 대해 이야기하기 전에, 몇 가지 획기적인 프로젝트들을 소개해 드리고 싶습니다.&lt;br /&gt;작년 언리얼 페스트 직전에 Sandfall Interactive에서 클레어 옵스큐어 익스페디션 33을 출시했는데, 이것이 2025년의 대히트작이 되었습니다.&lt;br /&gt;그리고 1년이 지난 지금, 이 게임은 500개 이상의 상을 받았으며, 역사상 가장 많은 상을 받은 게임이 되었습니다.&lt;br /&gt;팀의 모든 성과에 축하드리며, 다음 것이 무엇일지 기대가 큽니다.&lt;br /&gt;아크 레이더스는 또 다른 엄청난 성공 사례입니다. 10월부터 2월까지 이 추출 슈터 게임은 1,400만 장 이상 판매되었습니다. Embark는 UE5를 활용하여 게임의 거대한 오픈 월드를 구축하고 에픽 온라인 서비스의 음성 채팅 기능을 통해 최대 동시 접속자 96만 명 규모로 수백만 플레이어에게 멋진 소셜 경험을 선사했습니다.&lt;br /&gt;K-pop 데몬 헌터스는 넷플릭스 역사상 가장 많이 시청된 영화가 되어 두 개의 아카데미상을 수상하며 애니메이션 산업의 기념비적인 순간을 만들었습니다. 소니 픽처스 애니메이션과 이미지 워크스는 언리얼 엔진을 사용하여 실시간 프리비즈 및 레이아웃으로 파이프라인을 전환함으로써 제작 시간을 추정치로 25% 단축했습니다.&lt;br /&gt;이것은 몇 달의 작업 시간을 절약한 것입니다. 그리고 팀이 제작 과정에서 실시간 사용 가능한 에셋을 사용했기 때문에, 기록적인 시간 안에 포트나이트 콜라보레이션을 성공시킬 수 있었습니다. 이는 데몬 러시 한정 시간 모드로 시작되어 블리츠 리로드와 아이템 상점의 코스메틱을 거치며 전체 생태계가 움직인 순간이었습니다. 저희는 이 모든 것을 2개월 만에 해내고 UFN 개발자 도구를 출시했습니다.&lt;br /&gt;언리얼은 엔터테인먼트 분야를 넘어 계속해서 모멘텀을 얻고 있습니다.&lt;br /&gt;SAS는 엔터프라이즈 분석, AI 및 데이터 관리 분야의 선두 주자입니다. 이들은 산업 제조, 작업자 안전, 생명 과학 등 다양한 산업 분야에 걸쳐 매우 복잡한 언리얼 엔진 디지털 트윈 시뮬레이션을 개발하고 있습니다. 이제 이러한 디지털 트윈은 비즈니스가 단 하나의 기계가 움직이거나, 단 하나의 작업자가 위험에 처하거나, 단 하나의 돈이 잘못된 구성에 쓰이기 전에 시뮬레이션으로 운영 결정을 내리도록 돕습니다.&lt;br /&gt;이 모든 게임, 애니메이션, 그리고 엔터프라이즈 솔루션은 언리얼 엔진 5를 기반으로 구축되었습니다.&lt;br /&gt;저희는 몇 년 전에 UE5를 공개했습니다. 그 이후로 버전별로, 놀라운 고화질 오픈 월드를 초당 60프레임으로 구동하는 데 필요한 수많은 기능을 출시해 왔습니다. 또한 여러분이 더 빠르고 효율적으로 작업할 수 있도록 실제 워크플로우 개선에 힘써 왔습니다.&lt;br /&gt;나나이트는 수동 LOD 파이프라인을 최소화했습니다.&lt;br /&gt;루멘은 라이트 베이킹을 거의 없앴습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;메타휴먼은 멋진 캐릭터를 만드는 시간을 몇 달에서 며칠, 심지어 몇 분으로 단축했습니다. 시퀀서와 컨트롤 위그는 에디터를 벗어나지 않고도 엔진에서 매우 복잡한 캐릭터 연기를 애니메이션화할 수 있게 했습니다. 월드 파티션은 핵심 엔지니어링 리소스에 의존하지 않고도 방대한 오픈 월드 스트리밍을 가능하게 했습니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;UE5 출시가 6년이 되었다는 것이 믿기지 않지만, 여러분이 이룬 성과를 보니 영감을 받습니다.&lt;br /&gt;최신 릴리스에 포함된 내용을 공유하기 위해 모나미 사이먼 토론을 소개합니다.&lt;br /&gt;감사합니다, 빌. 좋은 아침입니다. 언리얼 엔진의 최신 소식을 전하게 되어 기쁩니다. 지난 몇 번의 릴리스 동안 스튜디오들로부터 가장 많이 들은 피드백은 '빨라지게, 안정적으로'였습니다. 그래서 저희는 바로 그 부분, 성능에 집중해 왔습니다.&lt;br /&gt;테스트 57에서는 GPU에서 최대 25%, CPU에서 최대 35%까지 성능을 개선하여 더 부드러운 프레임 속도를 제공했습니다.&lt;br /&gt;오늘 저희는 이러한 모멘텀을 바탕으로 더 많은 여유 공간, 적은 끊김, 그리고 아이디어와 실제로 출시할 수 있는 것 사이의 마찰을 줄여주는 언리얼 엔진 5.8을 출시합니다.&lt;br /&gt;5.8의 큰 부분은 성숙도입니다.&lt;br /&gt;이전 릴리스에서 실험적이거나 더 나았던 시스템들이 이제 프로덕션 준비 단계로 진입하고 있습니다.&lt;br /&gt;주요 기능은 메가 라이트입니다. 장면 내 수천 개의 동적 그림자 투사 라이트와 영역 라이트를 고정된 비용으로 사용할 수 있습니다.&lt;br /&gt;과거에는 성능 향상으로 여겨졌던 것이 이제 창의적인 도구가 되었습니다. 아티스트들은 타협 없이 조명을 비출 수 있고, 팀들은 주변의 모든 동적 라이트를 예산 책정하는 데 드는 시간을 줄일 수 있습니다. 라이트 링크 허브, 영화 렌더 그래프, 카오스 클록, 데이터 흐름 오디오 인사이트, 아이리스 또한 프로덕션 준비가 되었습니다.&lt;br /&gt;또한 다양한 플랫폼으로 확장하는 것도 더 간단해졌습니다. 우리의 동적 전역 조명 시스템인 루멘은 루멘 라이트라는 경량 모드를 갖추게 되어 GPU 비용을 상당히 낮추면서 시각적 영향력의 대부분을 유지하도록 설계되었습니다.&lt;br /&gt;이로 인해 루멘이 이전에 불가능했던 곳, 스위치 2를 포함하여 사용 가능해졌습니다.&lt;br /&gt;그리고 그 작업은 이미 플랫폼에 대한 추가적인 나나이트 최적화 노력을 이끌고 있습니다.&lt;br /&gt;이제 이 방에 있는 모든 개발자가 느꼈을 무언가에 대해 이야기해 보겠습니다.&lt;br /&gt;네. 끊김, 프레임 스파이크, 긴 셰이더 컴파일. 게임이 멈추고 그 시간이 어디로 갔는지 궁금해하는 순간 말입니다.&lt;br /&gt;그 문제의 큰 부분은 셰이더입니다. 그래서 저희는 컴파일러를 다듬고 중복 작업을 제거하기 위해 중복을 개선했습니다. 컴파일할 것이 적고, 로드할 것이 적고, 방해받는 것이 적습니다.&lt;br /&gt;포트나이트에서는 이 작업이 콘텐츠 변경과 결합하여 셰이더 수를 68% 줄이는 데 기여했습니다. 더 빠른 쿠킹, 더 빠른 로딩, 더 가벼운 메모리입니다.&lt;br /&gt;제이슨과 존의 내일 발표에서는 어떻게 그 지점에 도달했는지 깊이 있게 다룰 예정입니다.&lt;br /&gt;하지만 셰이더는 이야기의 절반일 뿐입니다. 나머지 절반은 파이프라인 상태 객체(PSO)입니다.&lt;br /&gt;PSO는 GPU가 효과를 렌더링하는 데 필요한 번들입니다. 셰이더, 블렌드 모드, 렌더 상태 등 모든 것입니다. 런타임에 하나라도 놓치면 드라이버가 즉석에서 조립하고 컴파일해야 합니다. 그것이 바로 끊김입니다.&lt;br /&gt;그리고 그것들은 찾기가 악명 높을 정도로 어려운 버그들입니다. 다행히도, 이를 처리할 사람이 있습니다.&lt;br /&gt;그래서 5.8에서는 PSO 사전 캐싱을 개선했습니다. PSO가 여전히 컴파일되는 동안 폴백 렌더링이 훨씬 덜 눈에 띕니다. 그리고 전체 시스템이 조정하고 디버깅하고 프로파일링하기가 더 쉬워졌습니다.&lt;br /&gt;이것들은 화려한 변경 사항은 아니지만, 끊김을 쫓아온 적이 있다면 첫 부팅 시 차이를 느낄 것입니다.&lt;br /&gt;그리고 저희는 아직 끝나지 않았습니다. 마이크로소프트 및 하드웨어 파트너와 협력하여 고급 셰이더 전송, 즉 DirectX 12 이니셔티브를 진행하고 있습니다. 이를 통해 플레이어에게 사전 컴파일된 셰이더를 전송하여 셰이더 작업을 플레이어의 런타임 경험에서 더 많이 제거할 수 있습니다. 배포가 증가하고 있으며 곧 이 부분에 대해 더 알려드리겠습니다.&lt;br /&gt;자, 여기 5.8에서 출시하는 완전히 새로운 실험적 기능인 메시 지형이 있습니다.&lt;br /&gt;우리는 모든 지점이 한 방향으로만 움직일 수 있고 고정된 그리드 때문에 디테일을 추가하거나 영역을 최적화하기 위해 해상도를 조정할 수 없는 높이 맵 기반 지형의 한계를 넘어서고 싶었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;메시 배열은 높이 필드에 얽매이지 않고 복잡한 지형을 제작하는 새로운 방식입니다. 그리고 단순한 메시 그 이상입니다. 협업 워크플로우를 위해 분할되었고, 월드 파티션 스트리밍을 지원하며, 사용 가능한 경우 나나이트를 사용하여 각 플랫폼에 맞는 런타임 표현을 조정하면서 동일한 소스 에셋으로 다양한 플랫폼에서 확장하도록 설계되었습니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;메싱을 사용하면 완전한 3D 조작 기능을 갖게 됩니다. 오버행, 터널, 떠다니는 섬, 이전에는 만들 수 없었던 모양까지 가능합니다.&lt;br /&gt;그리고 메시 기반이기 때문에 삼각형 수준에서 테셀레이션을 제어할 수도 있습니다. 이는 필요한 곳에만 디테일을 추가하면서 디테일하지 않은 곳의 메모리와 성능을 절약할 수 있다는 의미입니다.&lt;br /&gt;예상하셨겠지만, 재질 레이어는 물론 추가 속성도 페인팅할 수 있습니다.&lt;br /&gt;또한 자동 UV 생성을 통해 가상 텍스처를 지원합니다.&lt;br /&gt;메셔는 비파괴 수정자와 절차적 도구를 사용하여 반복 작업을 극적으로 쉽게 만듭니다. 모든 것을 계층화하고, 재배열하고, 결합하고, 어느 시점에서든 조정할 수 있습니다. 말 그대로 산을 옮길 수 있습니다.&lt;br /&gt;또한 PCG와 네이티브로 작동하며 확장된 모델링 도구 세트를 제공합니다. 하지만 가장 좋은 점은, 진행 중인 포트나이트 최적화 노력에서 메시 지형이 랜드스케이프보다 메모리 사용량이 적고 더 빠르게 실행된다는 것입니다. 더 높은 품질, 더 낮은 비용, 더 많은 창의적이고 기술적인 자유. 이것이 메시 지형입니다.&lt;br /&gt;58의 또 다른 큰 초점은 아이디어를 결과물로 더 빨리 전환하는 것을 돕는 것입니다.&lt;br /&gt;퍼포먼스 캡처는 책상에 앉은 한 명의 오퍼레이터부터 현장의 모든 녹화 장치(비디오 포함)를 제어하는 전체 모션 캡처 스튜디오까지 확장되었습니다.&lt;br /&gt;그리고 우리는 여기서 더 나아가고 있습니다.&lt;br /&gt;올해 초, Meshcapade가 에픽에 합류하여 비디오를 이용한 마커리스 모션 캡처 분야에서 세계 최고의 기술을 가져왔습니다.&lt;br /&gt;이미 생태계에 통합하기 시작했으며, 오늘 Fab에서 메타휴먼 애니메이터 마커리스 모션 캡처 플러그인을 출시합니다. 일반 비디오만으로 캐릭터의 몸, 얼굴, 손을 구동할 수 있습니다. 슈트도, 마커도 필요 없습니다. 비디오 입력, 애니메이션 출력입니다.&lt;br /&gt;피처급 작업을 추구하는 애니메이터들에게 이것은 우리가 지금까지 발표한 애니메이션 기능 중 가장 중요한 것입니다. 우리는 고급 애니메이션 워크플로우를 더욱 상호작용적이고, 더욱 직관적이며, 창작 과정과 더 밀접하게 연결되도록 만들었습니다.&lt;br /&gt;스타일화된 리그에서 직접 조각하는 것부터 캐릭터 자체에 존재하는 컨트롤까지, 그리고 퍼포먼스에 집중할 수 있게 해주는 간소화된 타임라인까지.&lt;br /&gt;이것들은 우리 애니메이션 팀이 매일 사용하는 도구들입니다. 그리고 이제 모두가 사용할 수 있게 되었습니다. 그리고 58과 함께 샘플을 출시합니다.&lt;br /&gt;시네마틱 측면에서는 오프라인 심도(depth of field)가 대대적으로 업그레이드됩니다. 이제 렌즈의 여러 지점에서 장면을 샘플링하여 실제 카메라가 만드는 방식으로 블러를 렌더링합니다. 따라서 반투명하거나 얇은 지오메트리에서도 물리적으로 정확한 초점 흐림 효과를 얻을 수 있습니다.&lt;br /&gt;초고해상도 미디어로 작업하는 프로덕션의 경우, 새로운 타일 맵 비디오 형식은 규모에 맞게 유지되는 압축 비디오를 제공합니다. 뷰포트가 실제로 필요로 하는 타일과 Mip 레벨만 디코드합니다. 따라서 아무도 보지 않는 픽셀을 처리하는 비용을 지불하지 않습니다.&lt;br /&gt;이것이 플라이바이였습니다. 이 내용 중 흥미로운 것이 있다면 언리얼 페스트 앱에서 심층 세션을 찾아볼 수 있습니다. 그리고 58이 엔진 전반의 마찰을 줄이는 것이라면, 우리가 또 하나 시작하고 있는 곳이 있습니다. 바로 에디터 자체와 사용자가 상호작용하는 방식입니다. 더 자세한 내용은 여기 마이클이 설명해 드리겠습니다. 감사합니다.&lt;br /&gt;고맙습니다, 사이먼. 때때로 게임을 만드는 것은 어렵고, 비싸고, 느릴 수 있습니다. 상상하는 것과 만들 수 있는 것 사이의 간극이 기술적인 오버헤드로 인해 막힐 때가 있습니다.&lt;br /&gt;저는 모르겠지만, 단지 한 가지를 변경하기 위해 노드 그래프에서 몇 시간 동안 헤매고 이해하려고 애쓰는 것은 제가 생각하는 창의성이 아닙니다.&lt;br /&gt;더 나은 방법이 있어야 합니다.&lt;br /&gt;그래서 우리가 노력해 온 것이 바로 그것입니다.&lt;br /&gt;더 빠르게 구축하고 더 많이 반복할 수 있도록 하는 도구들입니다.&lt;br /&gt;언리얼은 단순한 아이디어 위에 구축되었습니다. 당신의 소스, 당신의 파이프라인, 당신의 워크플로우.&lt;br /&gt;개발자에게 도구에 대한 완전한 제어권을 주고, 방해받지 않도록 하는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;그 철학은 변하지 않았습니다. 단지 대규모 언어 모델에 적용하고 있을 뿐입니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;이제 58 버전에서는 언리얼과 원하는 모든 모델을 연결하는 다리 역할을 하는 MCP 서버를 구현했습니다. 이번 발표에서는 클라우드 코드를 사용하겠지만, 제미나이나 자체 사용자 지정 모델 등 원하는 것을 사용하셔도 됩니다.&lt;br /&gt;언리얼 MCP를 활성화하는 것은 플러그인을 켜고, 약간의 설정을 하고, 원하는 모델에 연결하는 것만큼 간단합니다.&lt;br /&gt;그리고 오늘 여러분이 보게 될 모든 것은 그 설정을 기반으로 작동합니다.&lt;br /&gt;지금은 아직 초기 단계이며 모델들이 여전히 매우 예측 불가능한 행동을 할 수 있습니다.&lt;br /&gt;하지만 이 접근 방식을 통해 여러분이 어떤 언리얼 씬을 편집하듯이 개입하여 수정할 수 있는 능력을 유지합니다.&lt;br /&gt;자, 실제로 작동하는 것을 보겠습니다.&lt;br /&gt;왼쪽에는 언리얼 엔진이 있고, 오른쪽에는 클라우드 코드가 실행되는 터미널이 있습니다. 주고받는 모든 메시지를 볼 수 있습니다. 클라우드 코드가 MCP 서버를 통해 언리얼과 통신하며 씬을 읽고 엔진 내부에서 직접 작업을 수행합니다.&lt;br /&gt;그래서 작은 것부터 시작해 보겠습니다. 현대적인 거실입니다. 모델에게 무엇을 만들고 싶은지, 그리고 레벨의 어느 부분에 배치할지에 대한 컨텍스트를 먼저 제공합니다.&lt;br /&gt;모두가 따라올 수 있도록 진행하면서 각 프롬프트의 요약 버전을 보여드리겠습니다. 하지만 전체 세부 정보는 터미널 창에서 여전히 확인하실 수 있습니다.&lt;br /&gt;발표 목적으로 속도를 높이겠지만, 보이는 모든 것은 엔진 내부에서 실제로 일어나는 작업입니다. 그래서 소파, 러그, 커피 테이블 같은 기본 요소부터 요청할 수 있습니다. 그런 다음 의자, 램프, 사이드 테이블로 채워 넣습니다.&lt;br /&gt;58 릴리스의 일부인 시맨틱 검색은 설명에 맞는 에셋을 라이브러리에서 가져옵니다. 그리고 이것이 언리얼이기 때문에 의자를 수동으로 추가하고 '독서 공간'이라고 설명하면 모델이 그에 맞게 방을 꾸며줍니다.&lt;br /&gt;여기 모든 단계는 여러분이 내리는 창의적인 결정입니다. 모델은 광범위한 반복 작업에 능숙합니다. 여러분은 정확히 무엇을 원하는지 아는 데 능숙합니다.&lt;br /&gt;이러한 원칙은 방을 꾸미든, 아니면 도시 전체를 건설할 정도로 규모를 확장하든 동일하게 적용됩니다.&lt;br /&gt;자, 같은 접근 방식으로 도시를 건설해 보겠습니다.&lt;br /&gt;경계선을 그리는 것부터 시작합니다.&lt;br /&gt;그 다음으로 구역이 어디에 위치할지, 그리고 각 구역이 어떤 특징을 가질지 결정할 수 있습니다.&lt;br /&gt;고속도로가 방향을 따라 가로지릅니다.&lt;br /&gt;그리고 거기서부터 도로망이 채워지기 시작합니다.&lt;br /&gt;건물들이 생겨납니다. 여기서 모델은 시맨틱 검색을 사용하여 라이브러리에서 적절한 에셋을 찾아 레벨에 배치합니다. 가장자리에 숲을 요청하면 그것을 채워 넣을 수 있습니다.&lt;br /&gt;모든 단계에서 여러분이 호출을 합니다.&lt;br /&gt;그리고 결과물은 무엇일까요? 렌더링된 이미지가 아닙니다. 열고, 편집하고, 수정할 수 있는 실제 지오메트리, 실제 절차적 콘텐츠 생성 그래프입니다.&lt;br /&gt;그리고 이것은 전체 팀에게도 작동합니다.&lt;br /&gt;다른 개발자들이 각자의 세션에서 작업하며 에셋을 만들고 도시에 바로 드롭할 수 있습니다. 도로망이 조정되고, 블록이 업데이트되며, 도시가 그것을 흡수합니다. 다른 사람, 다른 세션, 그리고 모든 것이 함께 작동합니다.&lt;br /&gt;그렇다면 이 모든 것이 실제로 어떻게 작동할까요?&lt;br /&gt;MCP 서버가 언리얼과 모델 사이의 다리 역할을 하여, 모델에게 씬을 읽고, 에셋을 이해하고, 엔진 내에서 직접 변경할 수 있는 능력을 부여합니다. 그리고 이것이 개방형이기 때문에 특정 모델이나 워크플로우에 갇히지 않습니다.&lt;br /&gt;대규모 언어 모델은 언어와 추론에는 훌륭하지만, 자연스럽게 공간적으로 생각하지는 못합니다. 언리얼은 할 수 있습니다.&lt;br /&gt;이 둘을 연결하는 데 도움을 주기 위해, 80가지가 넘는 기본 절차적 콘텐츠 생성 빌딩 블록, 예시 라이브러리, 그리고 특정 언리얼 워크플로우를 인코딩한 기술을 제공합니다.&lt;br /&gt;지금은 실험적인 단계이며 계속 개선될 것입니다. 여기에 여러분이 필요한 부분입니다. 무엇이 작동하는지, 무엇이 작동하지 않는지 알려주세요. 그렇게 우리가 이것을 더 좋게 만들 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;도시가 지어졌으니, 이제 불을 밝히고 싶습니다. 언리얼 엔진에서 조명을 제대로 구현하는 것은 수십 개의 파라미터를 만져야 하는 기술이며, 이 모든 것이 함께 작동해야 합니다. 조명 밸런스, 구름 재질, 하늘, 대기, 포스트 프로세싱 등이 그것입니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;알아야 할 것이 너무 많습니다. 하지만 전용 조명 스킬을 생성하면 원하는 것만 설명하면 모델이 이 모든 것을 자동으로 처리합니다.&lt;br /&gt;보라색 황혼을 요청해 보세요.&lt;br /&gt;그리고 여기 있습니다.&lt;br /&gt;내부적으로는 이 모든 설정을 조화롭게 조정하고 있습니다.&lt;br /&gt;그러면 흐린 하늘을 요청할 수 있습니다. 그리고 이것은 모델이 잘못하는 좋은 예입니다. 하늘을 잘못 읽고 구름 재질을 잘못 수정했습니다. 하지만 무슨 일이 일어났는지 정확히 볼 수 있고, 다음 프롬프트에서 수정하여 원하는 지점으로 바로 돌아갈 수 있습니다.&lt;br /&gt;모델은 실제 세계 지식도 가지고 있습니다. 아침 9시 30분 보고타라고 말하기만 하면, 그 시간에 실제로 맞는 태양의 위치, 방향, 온도, 대기를 알아내서 적용합니다.&lt;br /&gt;특정 것을 맞추고 싶다면 이미지를 가져올 수 있습니다. 그래서 여기서는 밴쿠버의 이미지를 사용해서 그 분위기를 재현하도록 요청했습니다.&lt;br /&gt;스크린샷을 사용하여 평가하고 반복하여 원하는 결과에 도달합니다.&lt;br /&gt;그리고 모든 것이 여전히 편집 가능합니다. 도로를 잡고 움직여 보세요. 도시가 그 주변에 맞춰 조정됩니다. 건물을 더 높거나 눈에 띄게 만들라고 요청하면 그렇게 합니다. 하지만 그 후에는 개별 에셋을 수정하여 원하는 대로 만들 수 있습니다.&lt;br /&gt;이것은 붙잡혀 있는 생성된 이미지가 아닙니다. 언리얼 엔진의 실제 장면이며, 모든 부분을 제어할 수 있습니다.&lt;br /&gt;이제 하나의 교차로를 살펴보겠습니다. 위험 구역을 추가하고 싶었습니다. 깜박이는 램프, 증기, 그리고 플레이어가 가까이 다가올 때의 위험한 느낌 같은 것입니다. 이것은 보통 여러 분야에 걸쳐 며칠 동안 오가며 작업해야 하는 것을 의미합니다. 그래서 대신 이렇게 했습니다.&lt;br /&gt;경고 램프에는 이미 재질이 있지만, 여기에 무언가를 추가하고 싶다고 가정해 봅시다. 모델에게 기존 그래프를 읽고, 새로운 로직을 구축하여 필요한 곳에 삽입하도록 요청합니다.&lt;br /&gt;그런 다음 머티리얼 인스턴스 에디터로 이동하여 최종 값을 수동으로 조정할 수 있습니다.&lt;br /&gt;그런 다음 나그라 템플릿을 가져와 확장하여, 여러 방출기를 한 번에 구동하는 단일 파라미터를 추가함으로써 한 곳에서 전체 효과를 제어할 수 있습니다.&lt;br /&gt;프롬프팅과 UMG 상태 표시, 위험 게이지, 경고 상태를 통해 HUD를 구축합니다. 그런 다음 블루프린트 로직이 이 모든 것을 연결합니다. 근접 트리거가 재질, 나그라 시스템, HUD에 연결됩니다. 걸어 들어가면 모든 것이 한 번에 작동합니다.&lt;br /&gt;좋습니다. 그럼 실행해 보겠습니다. 램프가 꺼져 있고 조용합니다. 그녀가 현장으로 걸어갑니다. 램프가 켜집니다. 증기가 피어오르기 시작합니다. 그녀가 안으로 들어서자 램프가 깜박이고, 증기가 쏟아져 나오고, 현장이 폭발합니다.&lt;br /&gt;오늘 보여드린 것은 수작업으로 만들려면 몇 달이 걸릴 작업입니다. 하지만 MCP 서버와 언리얼을 사용하면서 저희 아티스트들은 며칠 만에 이 모든 것을 만들 수 있었습니다. 기술적 마찰을 낮추면 더 많이 반복하고 더 나은 게임을 만들 수 있습니다.&lt;br /&gt;이것이 우리가 만든 것입니다. 이것은 정말 시작점일 뿐입니다. 자신만의 기본 요소, 자신만의 예시, 자신만의 파이프라인을 기반으로 구축한 자신만의 기술을 가져오세요. 팀이 시간이 지남에 따라 많이 투입할수록 프로젝트의 모든 사람에게 더 유용해집니다.&lt;br /&gt;저희는 MCP 서버, PCG 기본 요소 플러그인, 그리고 오늘 개발한 기술들을 58의 일부로 출시합니다. 이것은 공개되어 있으며 여러분이 확장할 수 있습니다. 다운로드해서 모델을 연결하고 무엇을 할 수 있는지 확인해 보세요.&lt;br /&gt;더 깊이 들어가고 싶다면, 여기 페스트에서 기술 발표회가 두 번 있습니다. 저희를 찾아주세요.&lt;br /&gt;이제 제가 패트에게 제가 보여드린 내용 중 일부가 엔진에서 선형 콘텐츠 제작에 어떻게 영향을 미치는지에 대해 이야기하도록 넘기겠습니다.&lt;br /&gt;고마워요, 마이클.&lt;br /&gt;안녕하세요, 여러분. 제 이름은 패트 터백입니다. 저는 영화와 텔레비전 분야의 배경을 가지고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;미디어 및 엔터테인먼트 분야에서 마이클이 방금 보여준 MCP 플러그인은 LLM뿐만 아니라 나노 바나나, GTP, GPT 이미지, Gro imagine, Luma, Seed Dance 등 이미지 및 비디오 모델과 연결되는 광범위한 새로운 연결을 열어줍니다. 마이클은 현재 사용 가능한 도구들에 대해 이야기하고 있었고, 저는 내년 초에 출시되어 이러한 모델들을 제어할 수 있는 선형 콘텐츠 제작 도구들에 대해 다룰 예정입니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;이미지 모델을 사용하는 표준적인 접근 방식은 텍스트 프롬프트를 작성하는 것부터 시작하는 것입니다. 이 경우에는 에픽 모터스라는 1950년대 주유소의 가상의 장면을 묘사하는 소설을 작성했습니다. 하지만 스토리 포인트를 맞춰야 하고, 정확한 연속성을 유지해야 하며, 크리에이티브 디렉터가 원하는 것을 전달해야 하는 전문적인 상황에서는 일반적으로 스케치와 프리비주얼을 통해 시각적으로 소통하게 됩니다. 언리얼이 그런 데 아주 좋습니다.&lt;br /&gt;언리얼에서 시작하기 위해, 저는 Fab에서 사용할 수 있는 퀴클의 황폐한 복도 장면을 찾아냈고, 제가 필요로 하는 주유소 배치처럼 보이도록 빠르게 수정했습니다. 이 단계에서는 단순히 구도를 잡기 위해 사용했기 때문에 디테일 라이팅 모드에서 작업했습니다. 그 맵에서 적절한 에셋들, 선반, 프로판 탱크, 캐비닛 몇 개를 가져다 놓았고, 제가 가지고 있지 않은 에셋들을 위한 프록시 모양도 만들었습니다. 긴 카운터, 더 많은 선반, 계산대, 그리고 아이스박스 같은 것들이요. 그런 다음 뒤로 물러나 카메라 뷰를 잡고, 나중에 샷에 사용할 붐 다운과 푸싱 애니메이션을 만들었습니다.&lt;br /&gt;하지만 전체 비디오 제작에 착수하기 전에, 저는 단일 스타일 프레임, 즉 장면의 시각적 레퍼런스를 만들어야 했습니다.&lt;br /&gt;이를 위해 저는 모델을 사용하여 깊이 패스와 이전에 작성했던 소설 프롬프트를 결합했습니다. 깊이 정보는 모델이 레이아웃과 구도를 이해하도록 조건화합니다. 작동 방식은 이렇습니다. 언리얼의 새로운 도구들을 사용하여, 저는 Claude Code에게 MCP 플러그인을 통해 연결하여 언리얼의 영화 렌더 그래프를 사용해 4K 이미지와 나머지를 만들도록 요청했습니다. 언리얼 렌더를 사용하여 이미지를 생성하도록 요청하는 것은, 제가 모델에게 깊이 패스를 제공하고 싶지만, 프롬프트에 설명된 창의적인 느낌을 사용하라는 신호였습니다. 그런 다음 그 요청을 날렸고, 생성되는 동안 그 작업에 대해 만든 그래프를 검사했습니다. 이미지 모델들은 도움이 되는 데이터와 조건화에 목말라합니다. 그래서 저는 언리얼 장면에서 가치 있는 시각적 데이터를 추출하여 이미지 모델로 전달하는 프로세스를 준비했습니다. 이 경우, 구글의 나노 바나나 프로를 사용했습니다. 이제 이 이미지를 더 자세히 살펴보겠습니다.&lt;br /&gt;제가 요청한 시각적 디테일을 잘 맞추었지만, 가장 중요한 것은 무작위로 물건을 배치하지 않았다는 것입니다. 제 언리얼 뷰포트의 구도를 정확하게 맞추었습니다. 거기서부터 저는 반복 작업을 시작할 수 있었습니다.&lt;br /&gt;예를 들어, 바닥에 타이어가 하나 더 필요했지만, 그것은 이미지 모델로 생성하는 것이었기 때문에 그 특정 에셋이 없었습니다. 에디터의 새로운 이미지 분할 도구를 사용하여 타이어를 마스킹하고, 마스크와 이미지를 모두 선택했습니다. 그리고 미리 정의된 워크플로우를 사용하여 Claude Code에게 이를 추출하고, 복구하고, Tripo 3.1을 사용하여 메시화하도록 요청했습니다.&lt;br /&gt;그리고 나서 저는 그 그래프를 다시 확인하고 작업을 감독했습니다. 물론 이것은 실시간 과정은 아닙니다. 그래서 몇 분 후에 질감이 있는 타이어 메시를 얻었습니다. 저는 그것을 콘텐츠 브라우저에 저장한 다음, 타이어를 가져와 3D 공간에 배치했습니다. 마지막으로, Claude Code에게 이 타이어를 이미지에 추가하도록 요청했습니다. 그 결과를 살펴보겠습니다.&lt;br /&gt;따라서 제 UE 패스와 그 안의 타이어를 비교해 보면, 제가 요청한 곳에 새 타이어를 배치했고, 정확한 복제본이 아니라 생성된 타이어의 변형처럼 보이게 만들었다는 것을 알 수 있습니다.&lt;br /&gt;좋습니다. 이제 뷰포트로 돌아가서 3D로 또 한 번 작업하면서 장면에 완전히 새로운 것을 추가해 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;패브에서 구경하다가 폐차장에서 가져온 메가 스캔용 자동차 부품을 발견했어요. 제가 원하는 특정 펜더 조각을 골랐는데, 1950년대 느낌이 모델링되어 있어서 이미지 모델의 상상력을 덜 빌리게 할 수 있었어요. 클로드 코드에게 이 부품을 제 이미지에 추가하고 새로 페인트칠한 것처럼 보이게 해달라고 요청했어요. 그리고 나나 바나나에서 또 다른 이미지 처리 단계를 거치니 완성되었죠.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;자, 이제 스타일 프레임을 만들었으니, 우리 새 언리얼 툴로 장면 영상을 생성할 준비가 되었어요. 여기 제 샷 카메라 무브를 다시 보여드릴게요. 처음에 만들었던 그 움직임이에요. 오른쪽에서는 전체 범위에 걸친 깊이(depth)를 나타내는 시퀀스 렌더 노드를 실행했어요. 제가 스틸 이미지에 했던 것과 같은 깊이 스타일링 프로세스를 비디오에도 적용할 거예요. 방금 생성한 스타일 프레임을 비디오 모델에 첫 프레임 참조로 공급합니다.&lt;br /&gt;그리고 생기를 좀 불어넣으려고 고양이 한 마리를 추가했어요. 그리고 비디오 생성 노드를 시드 댄스 2.0을 사용하도록 설정하고, 해상도를 설정하고, 오디오를 추가한 다음, 끝! 몇 분 동안 그 과정이 돌아가자 이런 비디오가 나왔어요.&lt;br /&gt;분명히 카메라를 제어할 수 있다는 걸 보여주지만, 고양이는 아무도 제어할 수 없다는 것도 보여주죠.&lt;br /&gt;좋아요, 차고와 고양이는 두고 아파트로 넘어가 볼게요.&lt;br /&gt;이건 확산 모델과 뷰포트를 나란히 두고 더 빠르게 콘셉트를 잡을 수 있도록 병행 구축해 온 다른 워크플로우입니다. 이 비디오에서 보시는 것은 왼쪽의 UEI 뷰포트가 오른쪽의 로컬 플럭스 클라이언트 이미지 모델로 스트리밍되는 모습이에요. 로컬 모델 결과는 시간적으로 일관성이 없어요. 매 프레임마다 새로운 이미지를 찍어내고 초당 몇 프레임만 작동하기 때문에 오른쪽이 더 느려 보이는 거예요. 하지만 얼마나 직관적인지 보여드릴게요. 처음에는 일몰 조명으로 프롬프트를 입력했다가, 이 아파트에 방금 불이 났다면 어떨지 보고 싶어졌어요.&lt;br /&gt;그리고 더 극단적인 것을 시도해 봤어요. 탁한 연못 바닷속에 있는 것처럼요.&lt;br /&gt;여기서 얻는 진짜 이점은 UEI 뷰포트로 돌아가서 에셋과 상호작용하고, 이 새로운 확산 렌즈를 통해 재배치되는 것을 볼 수 있다는 거예요. 그뿐만 아니라, 숯 드로잉이나 수채화 같은 더 일러스트레이션 같은 모습도 시도해 볼 수 있어요.&lt;br /&gt;모델들이 더 능숙해지고 하드웨어가 개선됨에 따라, 이 워크플로우를 확산 모델이 실시간으로 작동하고 시간적으로 일관성을 갖는 시점까지 예측하는 것은 어렵지 않을 거예요.&lt;br /&gt;좋아요, 아티스트들이 엔진 내에서 다양한 소스를 사용하여 리스타일링한 언리얼 엔진 장면의 다른 예시들을 살펴보겠습니다. 일부는 친구인 키트 배시 3D의 프리미엄 환경 팩이고, 일부는 시티 샘플을 포함한 자체 내부 에셋입니다. 품질 좋은 소스 에셋에서 시작하면 모델의 해석할 여지가 줄어듭니다.&lt;br /&gt;저희는 이 새로운 UEIE 툴들이 아티스트들이 언리얼 엔진에서 의지해 온 실시간 애니메이션, 모델링, 텍스처링 및 버추얼 프로덕션 툴과 함께 작업하는 창의적인 반복 기회를 더 많이 제공하는 '강력한 승수'가 될 것이라고 생각합니다.&lt;br /&gt;이것이 우리가 나아갈 방향입니다. 이 모든 것을 가능하게 하는 MCP 서버는 실험적이며, 이미지 및 비디오 생성에 대해 보시는 것은 내년 초에 제공될 예정입니다. 우리는 이 여정을 함께하고 있으며, 이러한 모델들이 진정으로 유용하려면 기술적 복잡성을 낮추는 것뿐만 아니라 무엇을 만들지에 대한 완전한 창의적 통제권을 제공하는 데 집중해야 한다는 것을 알고 있습니다. 감사합니다.&lt;br /&gt;감사합니다, 팻. 정말 멋졌어요.&lt;br /&gt;자, 이제 멋진 게임과 콘텐츠를 만드는 데 도움이 될 모든 기능, 워크플로우 개선 사항들을 더 많이 보셨습니다. 이제 배포에 대해 이야기해 봅시다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;2025년은 에픽게임즈 스토어에게 성장하는 한 해였으며, 2026년도도 순조롭게 시작하고 있습니다. 연간 회고에서 12월 월간 활성 사용자 수가 7,800만 명에 달하며 에픽게임즈 스토어 역대 최고 기록을 경신했다고 보고했습니다. 또한 플레이어들은 서드파티 및 퍼스트파티 타이틀 전반에 걸쳐 스토어에서 11억 6천만 달러를 지출했습니다. 이는 전년 대비 6% 증가한 수치입니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;서드파티 타이틀만 놓고 보더라도 플레이어 지출액은 4억 달러에 달했습니다. 이는 전년 대비 57% 증가한 수치입니다. 현재 3,000개 이상의 파트너사로부터 6,000개가 넘는 게임을 카탈로그에 보유하고 있습니다.&lt;br /&gt;저희는 비즈니스를 성장시킬 수 있는 여러 가지 방법을 제공합니다. 2025년 6월, 개발사들이 제품당 첫 100만 달러 순수익에 대해서는 100%를 유지하고, 그 이후부터는 업계 최고 수준인 88/12의 수익 분배율이 적용될 것이라고 발표했습니다. 개발사들이 다른 스토어에 출시하기 전 처음 6개월 동안 순수익의 100%를 유지할 수 있는 에픽 퍼스트 런(Epic First Run)도 있습니다.&lt;br /&gt;또한, UEE 개발사들이 에픽게임즈 스토어에 타이틀을 출시할 경우 엔진 로열티 비율이 5%에서 3.5%로 낮아지는 '에픽과 함께 어디서든 출시(launch everywhere with Epic)'도 제공합니다.&lt;br /&gt;마지막으로, 에픽 리워드(Epic Rewards)를 지속적으로 추진하여 에픽을 통해 처리되는 모든 서드파티 콘텐츠 구매에 대해 플레이어들에게 5%를 돌려주고 있습니다. 실제로 작년에는 하반기 동안 20%의 리워드 부스트가 있었으며, 플레이어들은 이 프로모션 기간 동안 적립하고 얻은 리워드를 사용하여 높은 수준의 지출을 계속하고 있는 것을 확인할 수 있습니다. 실제로 서드파티 게임의 올해 첫 4개월간의 지출액은 전년 대비 40% 이상 증가했습니다.&lt;br /&gt;따라서 이러한 훌륭한 인센티브 프로그램 외에도, 저희는 에픽게임즈 스토어를 포트나이트 생태계와 더욱 긴밀하게 연결하기 위해 노력하고 있으며, 이는 개발사들에게 훨씬 더 큰 플레이어 기반에 대한 접근성을 제공할 것입니다. 호이버스(Hoyverse)와의 협업을 예로 들어보겠습니다. 플레이어들이 에픽게임즈 스토어에서 홍키 스타 레일(Hongkey Star Rail)의 적격 아이템을 구매하면, 배틀로얄 또는 수천 개의 UFN 게임 전반에서 사용할 수 있는 스텔라론 헌터 블레이드 의상을 받았습니다. 이제 일부 플레이어들은 포트나이트에서 한카이 스타(Hankai Star)를 처음 발견했습니다. 그런 다음 에픽게임즈 스토어에서 게임에 지출했고, 그 지출로 포트나이트로 가져간 새로운 의상을 잠금 해제했습니다. 이는 개발사와 플레이어 모두에게 선순환 구조입니다. 저희는 3,000개에 달하는 유사한 콜라보레이션을 2026년에 준비했으며, 2027년에는 더 많은 콜라보레이션이 예정되어 있습니다.&lt;br /&gt;따라서 저희는 개발사와 플레이어 모두에게 훌륭한 인센티브를 제공하고 있지만, 스토어 경험 자체를 개선해야 합니다. 지난 몇 달 동안 팀은 런처를 재구축하는 데 힘써왔습니다. 여기서 목표는 콜드 스타트 시간을 줄이고 탐색 속도를 훨씬 빠르게 하여 성능을 극적으로 개선하는 것입니다.&lt;br /&gt;또한 스토어의 백엔드 아키텍처를 재설계하여, 새로운 플레이어 대면 기능을 더 빠르고 자주 출시할 수 있도록 할 것입니다.&lt;br /&gt;검색 및 발견 기능을 개선하고, 오랫동안 기다려온 커뮤니티 기능을 많이 추가하며, 전반적으로 더 나은 플레이어 경험을 제공하는 데 집중할 것입니다.&lt;br /&gt;저희는 에픽게임즈 스토어의 성장에 전념하고 있으며, 업계에서 가장 유리한 조건으로 개발사들에게 높은 가치의 글로벌 플레이어 기반에 접근할 수 있도록 하는 사명에 결코 타협하지 않을 것입니다. 에픽게임즈 스토어의 향후 계획에 대해서는 내일 세션에서 더 자세히 알아보실 수 있습니다. 자, 이제 저희 생태계에서 일어나고 있는 일들에 대해 어느 정도 다루었으니, 이 모든 것을 실제로 구현하고 있는 몇몇 팀들의 이야기를 들어보겠습니다.&lt;br /&gt;먼저, 에머전스 데이(Emergence Day)로부터 20년이 지난 지금, 더 코얼리션(The Coalition)이 마침내 그들이 항상 이야기하고 싶었던 이야기를 들려줍니다.&lt;br /&gt;더 어둡고, 더 생동감 넘치며, 수백 개의 그림자 투사 조명으로 초당 60프레임으로 구동됩니다. 다음으로, 라이엇 게임즈(Riot Games)는 대부분의 스튜디오가 시도하지 않을 일을 합니다. 3억 명의 플레이어가 있는 라이브 PC 및 모바일 게임을 새로운 엔진으로 재구축하면서도 라이브 서비스를 유지하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;마지막으로, 네온 자이언트의 작은 팀은 상상할 수 있는 가장 밀도 높고 살아있는 도시를 건설하기 위해 나섰습니다. 모든 프레임에 이야기가 담겨 있고, 당신이 내리는 모든 선택이 그 이야기의 일부가 되는 도시입니다. 세 개의 게임, 세 개의 매우 다른 세계, 하나의 엔진. 먼저, 코얼리션의 케이트 레너를 소개합니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;안녕하세요, 저는 케이트 레너입니다. 오늘 여러분과 함께하게 되어 기쁩니다. 기어스 오브 워가 올해로 20주년을 맞이하며, 언리얼 엔진은 이 시리즈가 2006년에 처음 출시된 이래 모든 게임의 기반이 되어 왔습니다.&lt;br /&gt;기어스 오브 워 에데이의 경우, 우리는 언리얼 엔진 5에 투자하여 빈 하드 드라이브에서 시작해 모든 것을 처음부터 다시 구축함으로써 혼돈 속 세계의 믿을 수 있는 느낌을 구현하기로 결정했습니다.&lt;br /&gt;에머전스 데이는 우리 우주에서 가장 어두운 날입니다. 괴물 같은 로커스 군단이 땅에서 솟아나 인류를 황폐화시킨 날입니다. 그리고 그 상실의 감정적 영향을 진정으로 느끼기 위해, 우리는 어둡고 거친 비주얼 스타일로 돌아가야 했습니다.&lt;br /&gt;빛과 그림자는 단순히 분위기를 조성하는 것 이상의 역할을 합니다. 그리고 언리얼 엔진 5를 통해 우리는 시그니처 기어스 스타일을 한 단계 끌어올렸습니다. 자, 우리가 만든 것의 일부를 보여드리겠습니다.&lt;br /&gt;콜로나 시내의 페인 세이브 슈퍼스토어에 오신 것을 환영합니다. 이전 게임에서는 이런 공간이 보이는 그림자 생성기가 세 개로 제한적이었습니다. 메갈라이트를 사용하면서, 우리는 이제 수백 개의 광원을 가지며, 이 모든 광원이 Xbox Series X에서 초당 60프레임으로 그림자를 드리웁니다.&lt;br /&gt;이 TV 디스플레이 벽은 비디오 자체에 의해 구동되는 애니메이션 영역 조명과 빛 기능을 활용합니다.&lt;br /&gt;각각은 장면 전체에 부드러운 반그림자를 가진 섬뜩하고 불안한 동적 그림자를 드리웁니다.&lt;br /&gt;페인 세이브는 이 타일 기둥과 같은 지오메트리 컬렉션 파괴 가능한 에셋으로 환경을 만든 방법을 보여주는 훌륭한 예입니다.&lt;br /&gt;이러한 동적 오브젝트들은 빛을 올바르게 드리우고 받기 때문에, 파괴가 실제 세계에서 기대하는 것과 정확하게 시각적으로 근거를 갖게 됩니다.&lt;br /&gt;냉동고 구역을 살펴보겠습니다.&lt;br /&gt;이 모든 냉동고에는 지역 식료품점의 냉동 식품 구역에서 볼 수 있는 사실적인 조명 효과를 시뮬레이션하기 위한 여러 영역 조명이 있습니다.&lt;br /&gt;전투 중에는 총알이 유리창에 동적 파손점을 만듭니다. 깨지면, 모든 조각들이 물리적으로 정확한 반투명 반사를 사용하여 하드웨어 레이 트레이스 충돌과 함께 환경과 충돌합니다.&lt;br /&gt;여기에 얼마나 많은 광원이 있는지 보는 것은 놀랍습니다. 수백 개가 있습니다. 마커스의 갑옷에 있는 작은 조명부터 천장의 큰 스포트라이트에 이르기까지, 메갈라이트 없이는 현재 세대 하드웨어에서 이 효과나 이 많은 레이 트레이스 영역 조명을 구현하는 것은 불가능했을 것입니다.&lt;br /&gt;기어스 프랜차이즈의 주춧돌입니다. E-홀이 기어스 오브 워 에데이로 돌아왔습니다. 자, 몇 개 열어보겠습니다.&lt;br /&gt;모든 괴물들이 길을 막지 않으니, 모든 볼루트릭과 연기가 완벽하게 보입니다.&lt;br /&gt;과거에는 상상할 수 없었던 우리가 매우 기대하는 것 중 하나는 모든 총구 섬광에 그림자가 있다는 것입니다.&lt;br /&gt;이것은 기어스의 역동적인 전투에 더 믿을 수 있는 발사 경험을 더하여, 이전에 경험하지 못했던 것처럼 당신을 액션 한가운데에 놓는 정말 훌륭한 개선점입니다.&lt;br /&gt;저희 게임은 단일 공간에 국한되지 않습니다. 수만 개의 그림자를 드리우는 조명으로 콜로나 전체 도시를 탐험할 수 있습니다.&lt;br /&gt;이 수준의 시각적 충실도로 에데이를 구현하는 것은 쉽지 않았지만, 과거에 사용했던 베이킹 조명에 비해 하드웨어 레이 트레이스 루멘을 사용함으로써 훨씬 더 빠르게 반복할 수 있었습니다.&lt;br /&gt;메갈라이트를 사용하면서, 우리의 조명은 더 이상 실시간 그림자 생성기의 수에 구애받지 않아, 현실 세계와 동일한 복잡성으로 게임을 비출 자유를 얻었습니다.&lt;br /&gt;그리고 나나이트의 마이크로 폴리곤 렌더링 덕분에 에셋의 기하학적 디테일이 100배 증가했습니다.&lt;br /&gt;이 모든 시스템은 함께 작동하여 Xbox와 PC 전반에 걸쳐 시각적 쇼케이스를 일관되게 제공할 수 있는 매우 확장 가능한 엔진을 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;개발자로서 우리 중 많은 이들이 인상적인 데모와 60프레임으로 구현된 완전한 비전을 전달하는 것 사이의 차이를 알고 있습니다. 이 연합은 언리얼 엔진 5와 이 엔진이 구동되는 하드웨어를 극한까지 밀어붙여 전례 없는 수준의 디테일로 게어스 세계를 재창조하고 있습니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;10월 6일에 Eday가 출시될 때 여러분이 직접 확인하시기를 고대합니다.&lt;br /&gt;감사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f6f2ea;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6f2ea; color: #575451;&quot;&gt;우리 모두 참여했습니다. 제가 여기에서 빠져나올 수 있도록 기다려 주세요.&lt;/span&gt;&lt;span style=&quot;color: #575451;&quot;&gt;&lt;br /&gt;아직 끝난 게 아닙니다. 온다, 이 자식아.&lt;br /&gt;시야를 잃었습니다. 누가 봤나요?&lt;br /&gt;아닙니다. 제가 놓쳤습니다.&lt;br /&gt;내 새.&lt;br /&gt;조심해.&lt;br /&gt;안녕하세요, 저는 라이엇의 팀 파이트 전술(TFT) 기술 책임자 지나입니다. 저희가 부르는 대로 TFT라고 합니다. TFT는 저희가 리그 오브 레전드와 동일한 엔진으로 게임 모드로 처음 만든 오토 배틀러입니다. 아이디어 구상부터 출시까지 약 18주 만에 빠르게 만들었고, 그 후 예상했던 것 이상으로 성장했습니다. TFT는 생태계 전반에 걸쳐 3억 명이 넘는 플레이어를 보유한 선도적인 전략 게임이 되었는데, 이걸 입으로 말하기엔 좀 놀라운 일입니다.&lt;br /&gt;저희는 TFT가 다음 세트인 '마법의 황무지(Enchanted Wilds)'와 함께 언리얼 엔진으로 이전한다고 발표했습니다.&lt;br /&gt;실행 중인 라이브 게임을 새로운 엔진으로 재구축하는 것은 대부분의 게임이 선택하는 일이 아닙니다. 이는 엔지니어링, 아트, 디자인, 프로덕션 전반에 걸친 수년간의 작업입니다. 게다가 게임이 여전히 새로운 세트, 이벤트 등 모든 것을 플레이어들에게 정기적으로 출시하고 있다면 그 난이도는 더욱 높아집니다. 하지만 저희는 그렇게 하기로 결정했습니다. 저는 TFT 작업을 위해 라이엇에 합류했고, 약 6주 만에 게임을 언리얼로 이전하기로 결정했습니다. 그리고 금세 깨달았습니다. 이것은 단순히 엔진을 옮기는 문제가 아니었습니다.&lt;br /&gt;무엇이 가능해지는가에 관한 것이었습니다.&lt;br /&gt;공유 기술을 기반으로 하고, 우리가 만든 것을 더 재사용하며, 기반을 재구축하는 데 쓰는 시간을 줄이고, TFT를 만드는 데 더 많은 시간을 쓰는 것이었습니다.&lt;br /&gt;한 가지 예가 게임 플레이 능력 시스템입니다. 이는 게임이 성장함에 따라 게임 플레이를 구축하는 보다 구조적이고 유연한 방식을 제공합니다. 그리고 모든 세트가 새로운 메커니즘, 콘텐츠, 플레이 방식을 가져오는 TFT와 같은 게임에게는 그러한 공통 기반이 매우 중요합니다. 이는 매우 다른 부분의 게임에서도 재사용할 수 있는 공유 빌딩 블록, 능력, 속성 및 효과를 제공합니다. 그리고 이것이 시간이 지남에 따라 우리가 더 빠르게 움직일 수 있게 해줍니다. 언리얼을 사용하면서 우리는 게임이 어떻게 구축되었는지에 대해 다시 생각해야 했습니다.&lt;br /&gt;아키텍처, 네트워킹, 게임 플레이, 심지어 게임 데이터가 구조화되는 방식까지도 바뀌어야 했습니다. 언리얼의 초기 버전에서는 그저 느낌이 좋지 않았습니다.&lt;br /&gt;성능이 좋지 않았습니다. 8인 게임에서 초당 약 12프레임으로 빌드가 실행되는 경우가 있었는데, 여러분 모두가 이것이 목표가 아니었음을 상상하실 수 있을 겁니다. 따라서 저희의 첫 번째 목표는 혁신이 아니었습니다. 그것은 '동등함'이었습니다. 우리는 TFT를 되찾아야 했습니다. 그리고 그것은 언리얼 내부의 많은 시스템을 재작업하는 것을 의미했습니다. 어떤 것들은 강력한 출발점을 제공했고, 어떤 것들은 상당한 맞춤화가 필요했으며, 어떤 것들은 처음부터 다시 구축해야 했습니다.&lt;br /&gt;예를 들어, 네트워킹이 그렇습니다. 게임을 더 많이 구축하고 콘텐츠를 추가하면서 한계에 부딪히기 시작했습니다. 매치에 엄청나게 많은 게임 플레이 액터가 있을 때, 기본 복제 방식으로는 서버 및 대역폭 성능 목표를 충족하기에 충분하지 않았습니다. 그래서 에픽의 도움을 받아, 필요한 성능을 얻기 위해 푸시 기반 복제와 빠른 배열을 사용하는 아이리스 네트워킹을 채택하며 접근 방식을 발전시켰습니다. 어려운 점은 무언가를 작동시키는 것이 아니라, 그것을 규모에 맞게 작동시키는 것이었습니다.&lt;br /&gt;게임 플레이도 또 다른 큰 부분이었습니다. 저희는 게임 플레이 능력 시스템에 크게 의존했습니다. 이것은 강력하며 우리가 빠르게 무언가를 작동시키는 데 도움을 주었고, 많은 분들이 아시다시피 초기에는 이것이 매우 중요합니다. 하지만 TFT는 세트, 모드, 게임 플레이 콘텐츠가 항상 같은 일정으로 출시되는 것은 아닙니다. 그리고 금세 우리는 이 모든 것을 정리할 더 나은 방법이 필요하다는 것을 깨달았습니다. 그래서 우리는 게임 기능 플러그인을 사용하여 그 콘텐츠에 더 명확한 경계를 부여하고 시스템을 공유하는 보다 확장 가능한 방법을 제공하게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;그리고 그것은 팀들에게 더 많은 자유를 주어 구축할 수 있게 했습니다. 그리고 모바일도 있습니다. TFT의 큰 부분은 저사양 모바일 하드웨어를 포함한 광범위한 기기에서 실행된다는 것입니다. 엔진을 이전했다고 해서 이것이 변한 것은 아닙니다. 이것이 마이그레이션 과정에서 가장 어려웠던 부분 중 하나였지만, 동시에 우리가 이전을 하게 된 이유 중 하나이기도 합니다. 모바일은 저를 포함하여 사람들이 TFT를 플레이하는 방식의 큰 부분입니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;그래서 우리는 커스텀 렌더링, 메모리 관리, 그리고 기기 전반에 걸쳐 게임을 확장하는 데 깊이 투자했으며, TFT가 필요한 곳에서 실행될 수 있도록 에픽과 긴밀하게 협력했습니다. 하지만 우리는 여전히 그 여정의 초기 단계에 있습니다. 이미 PC와 모바일 간에 이전보다 훨씬 더 많은 것을 공유하고 있으며, 모바일 플레이어들을 위해 할 수 있는 것이 훨씬 더 많습니다.&lt;br /&gt;콘텐츠 마이그레이션. 여러분 중 많은 분들은 이미 이것이 어디로 가고 있는지 알고 계실 것이라고 생각합니다.&lt;br /&gt;TFT에는 아트, 애니메이션, VFX, 오디오에 걸쳐 수천 개의 에셋이 있었고, 이 모든 것을 마이그레이션해야 했습니다. 그리고 모든 종류의 콘텐츠는 가져올 때 다르게 깨졌습니다. VFX만 해도 엄청난 작업량이었습니다. 우리는 단순히 에셋을 변환하는 것이 아니라 근본적으로 다른 시스템 간을 이동하고 있었습니다. 수천 개의 에셋을 엔진에 넣는 것이 하나의 과제였습니다. 그것들을 플레이어가 기대하는 품질 수준으로 되돌리는 것이 또 다른 과제였습니다. 그리고 우리는 이것이 얼마나 많은 시간이 걸릴지 정말 과소평가했습니다. 그래서 노력의 큰 부분은 모든 콘텐츠를 대규모로 수정, 변환 및 검증하기 위한 툴링과 파이프라인을 구축하는 것이 되었습니다.&lt;br /&gt;그리고 바로 그 지점에서 언리얼의 확장성이 정말 중요했습니다. 우리가 이것을 가능하게 하기 위해 필요한 시스템을 구축할 수 있었기 때문입니다. 우리가 모든 것을 손으로 재구축해야 하는 세상은 없었기 때문입니다. 그리고 우리는 모든 곳에서 같은 패턴에 계속 부딪혔습니다. 언리얼은 많은 것을 제공하지만, 언리얼에서 TFT로 가는 과정은 여전히 엄청난 양의 작업을 필요로 했습니다. 우리는 이미 TFT 전반에 걸쳐 언리얼의 영향을 보고 있습니다.&lt;br /&gt;게임의 더 많은 부분이 공유된 기반 위에 구축되었습니다. 모바일과 PC는 훨씬 더 많은 동일한 UI와 기본 시스템을 공유하며, 우리는 라이엇 전반에 걸쳐 존재하는 기술과 기능을 기반으로 구축할 수 있습니다. 그리고 그것이 언리얼이 우리에게 준 가장 큰 것, 기능이 아니라 레버리지입니다.&lt;br /&gt;하지만 이 이전은 모두를 위한 것은 아닙니다. TFT에게 이것은 우리가 더 빠르게 움직이고, 더 큰 도전을 하고, 플레이어들이 기대하는 경험을 계속 제공할 수 있게 해줄 것입니다. 왜냐하면 우리에게 이것은 플레이어들이 계속 돌아올 수 있는 영원한 게임으로 TFT를 만드는 것에 관한 것이기 때문입니다. 그리고 플레이어들은 몇 주 안에 언리얼에서 TFT를 플레이할 첫 기회를 얻게 될 것입니다. 그리고 솔직히 말해서, 플레이어들이 그것을 사용해보고 &quot;네, 이건 TFT 같아요&quot;라고 말해주기를 바랍니다. 왜냐하면 우리가 일을 잘했다면, 그들은 엔진에 대해 전혀 생각하지 않을 것이기 때문입니다. 그들은 그저 TFT를 플레이할 것입니다. 정말 감사합니다. 모두 즐거운 언리얼 페스트가 되기를 바랍니다.&lt;br /&gt;저는 네온 자이언트의 크리에이티브 디렉터인 토리이며, 저희 스튜디오의 다음 게임인 노라에 대해 이야기하기 위해 왔습니다. 저희의 첫 번째 게임인 어센트에서는 저희의 작은 팀이 아웃 오브 더 박스 U4 기술을 극한까지 밀어붙여 매우 상세한 생활형 사이버펑크 세계를 만들었습니다. 저희의 새 게임인 노 로는 규제가 없는 도시 포트 디자이에 배경으로 하는 고화질 몰입형 1인칭 슈팅 게임입니다. 저희는 최고의 출발점이 언리얼 5의 핵심 기능 세트를 중심으로 게임을 구축하는 것이 될 것이라는 것을 알았습니다. 왜냐하면 저희와 같은 작은 팀은 엔진에 맞서 싸우는 것이 아니라 엔진을 활용해야 하기 때문입니다. 저희는 초기에 아웃 오브 더 박스만으로는 충분하지 않다는 것을 깨달았습니다. 저희가 원하는 세계를 만들기 위해 기본 설정을 넘어서 자체 워크플로우를 U5 내에 구축해야 했습니다. 저희는 어센트와 노 로를 통해 무엇을 했는지 자랑스럽게 생각하며, 노 로는 같은 접근 방식의 다음 단계입니다.&lt;br /&gt;저희의 제약 조건은 구체적이었습니다. 저희는 가장 큰 세계를 원한 것이 아니라 가장 밀도 높은 세계를 원했습니다.&lt;br /&gt;모든 규모에서 살아 숨 쉬는 듯한 느낌을 주는 도시. 모든 구석에 역사가 담겨 있고 모든 표면이 이야기를 들려주는 곳.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;포트 디자이어는 인간의 잡동사니, 좁은 시장 골목, 여러 겹의 그래피티, 전기 상자에 붙은 낡은 스티커, 그리고 그곳에 사는 사람들의 손길이 닿고 수정된 공간들로 채워져 있습니다. 저희의 목표는 캐릭터들이 일상을 보내는 어수선한 아파트의 모든 프레임부터 도시의 스카이라인까지 이야기를 담아내는 것이었습니다. 비교적 소규모 팀이었기에, 그 야심찬 목표는 현실적인 어려움을 동반했습니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;저희는 모든 곳에서 극도의 디테일을 원했습니다. 하지만 각 장소를 수동으로 최적화하지 않으면서 안정성과 성능도 필요했습니다.&lt;br /&gt;저희에게 해답은 단일 시스템이 아니라, 세계를 구축하는 방식의 전환이었습니다. 저희는 규모보다 밀도를 우선시했고, 아티스트들이 세부 사항을 계속 제거할 필요 없이, 그리고 절차적 생성에 의존하지 않으면서 공간을 직접 만들 수 있는 파이프라인을 구축했습니다.&lt;br /&gt;나나이트(Nanite)가 이러한 접근 방식을 실현 가능하게 만들었습니다. 모든 에셋을 충실도와 성능 사이의 트레이드오프처럼 취급하지 않으면서도 표면 전반에 걸쳐 높은 수준의 디테일을 유지할 수 있게 해줍니다.&lt;br /&gt;빠른 지오(geo)에 대한 저희의 맞춤형 구현과 월드 파티션 시스템의 결합은 끊김 없는 경험을 가능하게 합니다. 모든 구석구마다 디테일을 담고 수백만 가지의 작은 이야기를 들려줄 수 있게 합니다. 사실, 특정 프레임에 포함된 오브젝트의 수는 에센트(ascent) 전체보다 많습니다.&lt;br /&gt;이 워크플로우를 통해 저희는 화물선에 달린 가장 작은 볼트부터 도시 전체에 이르기까지 모든 구석에서 디테일과 밀도를 보존할 수 있습니다. 보이지 않는 벽이나 로딩 없이, 언리얼 내부 도구를 사용하여 아티스트들이 골목마다, 건물마다, 블록마다 도시 전체를 직접 만들 수 있도록 돕습니다.&lt;br /&gt;포트 디자이어가 식물로 뒤덮인 도시로서 가진 전체적인 범위를 보여주기 위해, 저희는 동적 조명이 필요했습니다. 아늑하고 무성한 한낮의 태양부터, 밝은 네온 불빛조차 닿지 않는 가장 어둡고 위험한 골목까지 말입니다. 어려움은 예측 불가능한 프레임 시간 없이 완전히 동적인 일광 및 날씨 시스템을 유지하는 것이었습니다. 루멘(Lumen)은 아티스트들이 모든 개별 광원을 조정하는 대신 공간의 사실성에 집중할 수 있도록 완전히 동적인 조명과 메가 라이트의 기반을 제공합니다. 모든 사실적인 공간은 카메라의 가장 작은 깜빡이는 전자 경고등부터 시장 위의 큰 네온사인까지 수십 개에서 수백 개의 개별 광원을 필요로 합니다.&lt;br /&gt;메가 라이트는 성능 고려 사항을 낮게 유지하면서 우리가 목표하는 시각적 충실도 수준을 유지할 수 있게 해줍니다.&lt;br /&gt;모든 것이 동적이게 되면, 이는 게임플레이에 더 직접적인 영향을 미치기 시작합니다.&lt;br /&gt;플레이어는 가로등을 쏘거나, 손전등으로 공간을 비출 수 있고, 아니면 어두운 지역을 벗어나 AI가 빛과 그림자에 반응하도록 하거나, 빛을 피해 숨거나, 어둠 속을 수색하거나, 무언가 이상하다고 느껴질 때 고조되도록 할 수 있습니다.&lt;br /&gt;누가 더 큰 총을 가지고 있는지 봅시다. 도시를 살아있게 느끼게 하기 위해, 저희는 군중을 구동하기 위해 매스(Mass) 프레임워크에 의존했습니다. NPC의 밀도와 유형은 시간대, 지역, 날씨에 따라 변합니다. 빈민가에서는 폭풍우가 거리를 쓸어내리지만, 포트 디자이어의 더 죄악스러운 부분에서는 폭우조차 상황을 늦추지 못합니다. 매스는 한 번에 수천 명의 캐릭터를 시뮬레이션할 수 있게 해주며, 어느 시점에도 3,000명을 넘기므로, 플레이어가 어디에 있든 도시는 항상 활기차게 느껴집니다.&lt;br /&gt;또한 저희는 메타휴먼(Metahuman)을 자체 캐릭터 무작위화 시스템과 함께 사용하고 있습니다. 메타휴먼 애니메이터(Metahuman Animator)와 결합하여, 주요 캐릭터와 배경의 엑스트라 모두 독특하도록 수천 가지의 캐릭터 변형을 생성하고 생명을 불어넣을 수 있습니다.&lt;br /&gt;저희는 효과와 파괴를 수동으로 배치할 필요 없이 플레이어에게 시스템적으로 반응하는 세계를 원했습니다. 이 정도의 밀도와 규모를 가진 세계를 맥락적인 효과로 채우면서 성능과 상호작용성을 유지하는 것은 저희의 주요 과제 중 하나였습니다. PCG와 나이아가라(Niagra) 데이터 채널을 결합하여, 환경 효과는 적절한 곳에 절차적으로 채워집니다. 아티스트가 쓰레기나 낙엽을 놓는 곳이라면, 바람, 날씨, 플레이어 행동에 따라 입자가 동적으로 생성됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;총알을 쏘거나 수류탄을 던지면 입자들이 비켜갑니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;우리는 혼돈 물리와 자체 GPU 구동 솔루션을 결합하여 수만 개의 움직이는 객체를 동시에 지원합니다.&lt;br /&gt;그 결과, 연기가 남아 있고, 불씨가 떠다니며, 깨진 유리가 떨어진 곳에 그대로 있는 반응형 환경이 만들어집니다.&lt;br /&gt;놀라(Nola)를 만드는 과정은 엔진이 끝나는 지점과 우리가 만든 도구가 시작되는 지점을 찾는 과정이었습니다. 이 정도의 밀도, 조명 복잡성, 시스템적 반응성을 달성하는 것은 이전에는 우리 규모의 스튜디오에게 불가능했습니다. UFI의 최신 기술을 활용하여 기존 개발 병목 현상을 우회함으로써, 우리는 마침내 수년 동안 만들고 싶었던 세상의 타협 없는 버전을 구축할 수 있게 되었습니다.&lt;br /&gt;여러분들이 경험하시기를 고대합니다.&lt;br /&gt;감사합니다.&lt;br /&gt;여러분 안녕하세요. 저는 에픽게임즈의 포트나이트 개발자 관계팀을 이끌고 있으며, 포트나이트 생태계에서 일어나고 있는 일에 대해 말씀드리려고 합니다.&lt;br /&gt;제 뒤 스크린에 있는 모든 게임은 독립 개발자가 만들었습니다. 소규모 팀, 때로는 단 두세 명의 사람들이 UEFn을 사용하여 수백만 명의 플레이어가 이용하는 생태계에 게시했습니다.&lt;br /&gt;UEFn과 함께 해오신 분들, 심지어 처음부터 함께 해주신 분들께 감사드립니다.&lt;br /&gt;여러분의 피드백은 도구를 형성하는 데 정말 큰 도움이 되었고, 여러분의 창의성은 7,500만 명 이상의 월간 활성 사용자가 포트나이트를 경험하는 방식을 변화시켰습니다.&lt;br /&gt;여러분의 게임이 포트나이트 플레이타임에서 차지하는 비중이 커지고 있습니다. 5월에는 전체 플레이 시간의 47%를 차지하며, 이는 작년의 38%에서 증가한 수치입니다. 그리고 UEFn 출시 이후 개발자들에게 지급된 10억 달러 이상의 금액과, 1섬 거래를 통해 이 팀들은 참여 보상 및 1섬 거래를 통해 이곳에서 비즈니스를 구축하고 있습니다.&lt;br /&gt;이는 수익화할 수 있는 방법을 더 많이 열어주었습니다.&lt;br /&gt;새로운 장르를 개척하고 개발자들이 더 작은 참여 커뮤니티를 가지고도 번성할 수 있도록 도왔습니다. 3,000개가 넘는 섬이 이제 참여 보상보다 1섬 거래에서 더 많은 수익을 올리고 있습니다.&lt;br /&gt;그리고 우리는 전체 지급액 중 1섬 거래에서 나오는 비중이 계속해서 증가하는 것을 보고 있습니다.&lt;br /&gt;이는 배틀로얄이나 슈팅 장르가 아닌 장르에 활력을 불어넣고 있습니다. 그리고 이 게임들이 이제 모든 1섬 거래 수익의 75% 이상을 차지합니다.&lt;br /&gt;저희는 아직 성숙 단계에 있는 플랫폼에서 구축하는 것이 신뢰가 필요하다는 것을 알고 있습니다. 그리고 올해는 안정성과 개발자 효율성이 저희의 최우선 과제입니다.&lt;br /&gt;지난 3월, 저희는 반복 시간을 단축하겠다는 목표를 밝혔습니다. 그리고 평균적으로 변경 사항을 배포하는 데 걸리는 시간을 약 40%가량 줄이는 실질적인 진전을 이루고 있습니다. 이는 대규모 프로젝트의 경우 더욱 높은 수치이며, 최대 70%까지 감소한 것을 확인했습니다.&lt;br /&gt;게다가, 확장된 라이브 에디트 지원 기능은 반복 작업을 더 빠르고 원활하게 만듭니다.&lt;br /&gt;라이브 에디트는 이제 게임 모드 내에서 직접 적용되며, 새로운 에디트 목록은 작업하는 동안 변경 사항을 명확하게 보여줍니다. 통합된 UI는 세션 제어를 단순화하고 게임을 일시 중지하는 기능을 추가하여, 분리된 카메라로 에디트를 탐색하거나 장면을 편집할 수 있게 합니다.&lt;br /&gt;그리고 여기서 끝이 아닙니다. 저희는 계속해서 반복 시간을 단축하고, 출시할 때마다 UFN을 더 나은 제작 도구로 만들고 있습니다.&lt;br /&gt;도구를 강화하는 것과 더불어, 더 많은 게임플레이 기능을 개방하고 있습니다.&lt;br /&gt;곧 UE6의 기반이 될 장면 그래프(Scene graph)가 UEFn에서 빠르게 성숙하고 있으며, 포트나이트 개발자들에게 그 어느 때보다 더 많은 제어력과 사용자 정의 기능을 제공하고 있습니다. 이는 사용자 지정 아이템, 인벤토리와 같은 새로운 시스템의 기반이 되며, 최신 릴리스에서는 장면 그래프를 이용한 사용자 지정 무기 및 애니메이션을 만드는 초기 워크플로우 세트를 제공합니다. 그리고 게임플레이 속성, 게임플레이 능력, 장면 그래프 UI를 포함하여 훨씬 더 많은 것이 준비되어 있습니다.&lt;br /&gt;저희는 더 많은 주요 엔진 시스템을 첫 번째 스크립터블 컴포넌트로 도입하여, 여러분이 UFN에서 게임플레이를 작성하는 데 더 많은 시간을 보내고 설정하는 데 덜 시간을 보내도록 할 것입니다.&lt;br /&gt;또한, 타겟팅된 기능 세트를 통해 새로운 유형의 게임플레이도 열어주고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;크리처 기반 게임 플레이 도구가 올여름 출시되는 게임들과 함께 출시되었습니다. 포트나이트 사이드키크는 개발자들이 이미 자신의 동반자들과 쌓아온 애정을 활용할 수 있게 해줍니다. 개발자들은 이제 펫 배틀러, 아늑한 농장 시뮬레이션 등 다양한 게임을 만들 수 있습니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;또한, 이러한 게임들이 구현되는 영역도 확장되고 있습니다. 포트나이트가 전 세계 구글 플레이와 앱스토어에 다시 돌아왔으며, UFN 게임의 모바일 플레이 시간은 지난 한 해 동안 두 배 이상 증가했습니다.&lt;br /&gt;모바일 최적화가 쉽지 않았다는 것을 알고 있습니다. 네이티브 제스처 지원, 터치스크린 레이아웃 사용자 지정, HUD에 대한 더 세밀한 제어와 같은 최근 기능 출시들이 더 모바일 친화적인 게임을 만드는 데 도움이 되기를 바랍니다.&lt;br /&gt;이러한 모바일 기능들은 8월에 실험 모드를 벗어나, 모바일에서 더 자연스럽게 느껴지는 경험과 장르를 가능하게 할 것입니다.&lt;br /&gt;최근의 디스커버 변경 사항들은 이미 성과를 보이고 있습니다. 스팸과 중복 콘텐츠를 단속하고, 아일랜드를 명확한 장르로 분류했으며, 디스커버를 개인화하여 게임이 더 빨리 잠재 고객을 찾도록 도왔습니다. 그리고 연말에는 전면적인 재설계를 할 예정입니다. 모든 곳에 비디오, 모든 행에 걸친 개인화, 그리고 타일 위에 좋아요 비율을 포함한 소셜 신호가 추가될 것입니다.&lt;br /&gt;큰 변화로, 포트나이트에 접속했을 때 플레이어가 가장 먼저 보는 것이 로비가 아닌 디스커버가 됩니다.&lt;br /&gt;앞으로 며칠 동안 디스커버 로드와 UEFM 생태계의 나머지 부분에 대해 더 깊이 다룰 예정입니다.&lt;br /&gt;저희 IP 파트너 프로그램은 모든 포트나이트 개발자가 레고, 스타워즈, 오징어 게임 등 주요 IP의 공식 라이선스 콘텐츠를 활용하여 게임을 만들 수 있도록 합니다. 각 파트너십은 개발자들이 다른 곳에서는 만들 수 없는 게임을 만들 수 있도록 독점적인 캐릭터, 환경 및 템플릿을 제공합니다.&lt;br /&gt;오리지널 UFN 개발자 중 한 명인 퓨처 트래시는 자신들의 FOD IP를 포트나이트에 성공적으로 가져와 아주 먼 은하계 배경의 히트작 게임을 출시했습니다.&lt;br /&gt;그의 창립자인 케빈이 그들이 무엇을 해왔는지 더 많이 공유하기 위해 여기에 왔습니다. 그러니 따뜻한 환영 부탁드립니다.&lt;br /&gt;해나, 감사합니다. 안녕하세요, 여러분. 저는 FOD의 개발 스튜디오인 퓨처 트래시의 공동 창립자이자 CEO인 케빈 마르시아노입니다.&lt;br /&gt;2022년에 공동 창립자인 네이트, 스콧, 에릭과 저는 직장을 그만두고 다음 대박 파티 게임을 만들고 싶었습니다. 우리는 하나의 아이디어와 많은 열정으로 무장한 인디 스튜디오에 모든 것을 걸었습니다. 우리는 그 길이 얼마나 가혹한지 빠르게 배웠습니다. 백엔드 인프라, 발견 가능성, 배포. 벽이 사방에 있었습니다. 2023년 초가 되자 우리에게 남은 자금은 몇 주밖에 남지 않았습니다. 저는 GDC에 스팀 덱을 들고 날아가, 우리가 만든 것에 관심을 가져줄 사람의 주의를 끌려고 노력했습니다. 그때 UFN이 발표되었고, 우리는 '우리 게임을 포트나이트로 가져가면 어떨까?'라고 생각했습니다. 우리는 UGC에 익숙하지 않았기 때문에 엄청나게 위험하게 느껴졌습니다. 도구들을 가지고 실험하고 번창하는 크리에이터 이코노미에 대해 더 많이 배우면서, 우리는 잠재력을 볼 수 있었습니다.&lt;br /&gt;우리는 팔을 걷어붙이고 3주도 안 되어 첫 게임을 출시했습니다. 출시하고 거의 즉시 플레이어 피드백을 받았습니다.&lt;br /&gt;그리고 그것이 정착되었습니다. 이것이 우리의 앞으로의 길이 될 것이었습니다.&lt;br /&gt;그리고 그 대담한 방향 전환은 우리 회사를 구했을 뿐만 아니라 게임 산업의 미래에 대한 우리의 관점까지 바꾸어 놓았습니다. UFN이 우리에게 준 것은 단순한 플랫폼이 아니었습니다. 그것은 우리 오디언스에 대한 직접적인 접근성이었습니다. 게이트키퍼도, 퍼블리셔 승인도 없습니다. 아이디어만 있으면, 만들고, 플레이어들이 플레이하게 하는 것입니다. 우리는 이제 작은 스튜디오로서 진정으로 불가능하다고 생각했던 규모의 플레이어에 도달했습니다. 포트나이트 오디언스에게 완전히 맞지 않았던 모아부터 우리의 첫 대박작인 붐 타이쿤까지, 우리는 광범위한 장르를 실험하고 플랫폼에서 우리의 창의적인 감성에 맞는 것이 무엇인지 발견할 기회를 가졌습니다. 그리고 월드 빌딩, 캐릭터 중심 경험, 오리지널 IP 구축에 집착하는 스튜디오로서, UEFN은 우리에게 창의적인 샌드박스이자 배포 계층이 되었습니다.&lt;br /&gt;스타워즈는 어린 시절부터 우리 팀원 모두에게 창의적인 영감의 원천이었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;우리 중 누구도 상징적인 지적 재산(IP)을 활용하여 창의적인 통제권을 거의 완전히 가지고 우리만의 게임을 만들 수 있을 것이라고는 꿈도 꾸지 못했습니다. 스타워즈의 안드로이드들이요. 그들이 가장 힘든 일을 합니다. 그들은 최악의 역경을 이겨내고 가장 적은 공로를 인정받습니다. 그리고 우리는 '이들을 주제로 게임을 만들자'고 생각했습니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;드로이드 타이쿤은 이 스타워즈 세계관의 알려지지 않은 영웅들에게 바치는 우리의 사랑의 편지였습니다. 이 게임이 다른 곳에서 존재할 수 있었을 것이라고는 믿기 어렵습니다.&lt;br /&gt;그리고 이것이 우리가 레거시 IP가 UGC 네이티브 크리에이터를 포용하여 콘텐츠 세계관을 무한히 확장해 나갈 미래를 보는 방식입니다. 가장 흥미로운 이야기가 펼쳐질 곳이 바로 그곳입니다. 그리고 여러분은 그것을 증명하기 위해 나타났습니다. 맵을 출시한 이후로 드로이드 타이쿤은 포트나이트에서 가장 많이 플레이된 UFN 게임이 되었습니다. 첫 주 동안 모든 포트나이트에서 두 번째로 많이 플레이된 게임이 되었습니다. 그리고 이달 초에는 2시간 동안의 동시 접속자 수 최고 기록을 세웠는데, 이는 포트나이트에서 IP 경험이 달성한 가장 강력한 기록입니다. 앞으로도 저희의 목표는 시각적 품질과 스토리텔링 측면에서 플랫폼에서 가능한 것의 경계를 계속해서 넓히는 것입니다. 저희는 계속해서 자체 오리지널 IP를 구축하는 동시에, 저희에게 가장 영감을 주는 프랜차이즈를 위한 몰입감 넘치는 경험도 만들 것입니다.&lt;br /&gt;감사합니다.&lt;br /&gt;케빈, 당신의 이야기와 창의적인 과정, 그리고 특히 스타워즈 IP를 팬들과 깊이 공감할 수 있는 방식으로 드로이드 타이쿤에 생명력을 불어넣어 주셔서 감사합니다.&lt;br /&gt;드로이드 타이쿤은 올해 디즈니와 포트나이트에서 있었던 주요 하이라이트 중 하나를 대표하는 작품입니다.&lt;br /&gt;한번 살펴보겠습니다.&lt;br /&gt;열정. 열정.&lt;br /&gt;무한히 그리고 저 너머로.&lt;br /&gt;하늘에서 떨어진 거대한 음식들을 보라.&lt;br /&gt;이 파트너십은 하나의 신념에 기반을 두고 있습니다. 디즈니 이야기는 팬들이 이미 있는 곳에 도달해야 한다는 것입니다. 그리고 그곳은 점점 게임 속으로 들어오고 있습니다. 그리고 이것은 에픽과 디즈니를 넘어섭니다. 개발자 여러분도 마찬가지입니다. 여러분이 알고 사랑하는 IP를 사용하여 자신만의 경험을 만들고 자신만의 이야기를 할 수 있는 권한을 가지고 있습니다.&lt;br /&gt;제 게임 개발 초기에 제 꿈은 스타워즈 세계관에서 게임을 만드는 것이었습니다.&lt;br /&gt;저는 그것을 할 수 있는 행운을 누렸고, 개발자들이 자신만의 스타워즈 게임을 만드는 스릴을 처음으로 경험하는 것을 보는 것은 저 개인적으로 큰 원점으로 돌아온 순간이었습니다. 이 IP 프로그램을 출시한 이후로 일어난 일들은 우리가 예상했던 모든 것을 뛰어넘었습니다.&lt;br /&gt;스타워즈가 UFN에 왔고 개발자들이 이를 활용했습니다. 갤럭시 시즈, 이스케이프 베이더, 드로이드 타이쿤 등 모두 이 방에 있는 모든 사람에게 제공된 도구로 만들어졌습니다. 72시간 동안 총 8백만 명의 플레이어가 참여했습니다.&lt;br /&gt;갤럭시 시즈는 단 6일 만에 650만 명의 플레이어를 기록했고, 이스케이프 베이더는 340만 명의 플레이어를 기록했습니다.&lt;br /&gt;그리고 드로이드 타이쿤은 일주일 만에 포트나이트에서 두 번째로 많이 플레이된 섬이 되었습니다.&lt;br /&gt;디즈니의 모든 사람이 드로이드 타이쿤과 함께 뛰어난 섬 출시를 통해 기여한 비욘드 크리에이티브와 주에게 축하와 감사를 전하고 싶습니다.&lt;br /&gt;만달로리안과 그루 워치 파티 섬에서는 팬들이 영화가 극장에 개봉하기 전 처음 10분을 볼 수 있었습니다.&lt;br /&gt;이것은 스튜디오 IP와 창의적 파이프라인이 가질 수 있는 새로운 모델입니다.&lt;br /&gt;단순한 IP 접근을 넘어, 현실처럼 느껴지는 세계에서의 창의적 연속성과 몰입으로 나아가는 것입니다.&lt;br /&gt;하지만 스타워즈는 게임이 우리의 스토리텔링을 의미 있게 확장한 한 해의 한 장에 불과했습니다. 퍼시 잭슨이 시즌 2를 위해 디즈니 플러스로 돌아오면서, 우리 친구들인 가운틀렛이 만든 '괴물들의 포위 공격'은 그 세계를 경험하는 새로운 방식을 제공했습니다. 저희 자체 디즈니랜드 게임 러시는 애너헤와 디즈니랜드 70주년의 에너지를 플레이 가능한 형태로 옮겼습니다. 그리고 저희 디즈니, 픽사, 루카스필름, 20세기, 마블의 콜라보레이션은 포트나이트에서 가장 인기 있는 것들로 남아 있습니다.&lt;br /&gt;이것은 전통적인 IP 계약을 넘어서는 것입니다. 더 많은 크리에이터의 손에 있는 상징적인 디즈니 이야기들이 그 어느 때보다 더 많은 팬들에게 도달하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;그리고 작년에 정신없는 한 달간의 시즌을 보낸 우리가 가장 좋아하는 스프링필드의 애니메이션 가족을 잊을 수 없습니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;이번 시즌에는 8천만 명이 넘는 고유 플레이어와 7억 5천만 시간이 넘는 플레이 시간이 기록되었습니다. 이 도달률만으로도 알 수 있습니다.&lt;br /&gt;플레이어들이 스프링필드로 오는 것을 보는 것이 정말 기대되었지만, 시민들이 스프링필드에서 UFN의 일부로 넘어가는 것도 좋아했습니다.&lt;br /&gt;가장 좋아하는 스트리머 중 한 명의 하이라이트를 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f6f2ea;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6f2ea; color: #575451;&quot;&gt;여러분, 제 채널에 오신 것을 환영합니다.&lt;/span&gt;&lt;span style=&quot;color: #575451;&quot;&gt;&lt;br /&gt;바드가 포트나이트를 하는 바보에게 반응하다. 호머가 매일 우리를 학교에 데려가는 방법. 이 수의사는 이 부분에 강합니다.&lt;br /&gt;이봐, 저것 좀 봐. 공룡 나라잖아. 아, 여기 아빠가 선생님인 Kbapple 선생님과 회의를 하는 모습이네.&lt;br /&gt;자, 간다. 호흡기 질환을 앓는 두 노인 사이의 타이타닉 전투.&lt;br /&gt;좋아, 공룡과 스톰트루퍼는 아빠에게 힘들지만, 그가 자신의 스프링필드 섬이라는 본거지에 있으면 아마도 자신이 만든 도넛 대포에 질식할 거예요.&lt;br /&gt;36년이 지났지만, 심슨 가족은 여전히 모두의 가족처럼 느껴지지만, 오늘은 새로운 보금자리를 찾고 있습니다.&lt;br /&gt;올해 말에 심슨 가족이 IP 파트너 프로그램에 합류한다는 것을 발표하게 되어 매우 기쁩니다.&lt;br /&gt;스프링필드는 당신의 것입니다. 캐릭터, 장소, 방사성 폐기물, 모든 것이 UFN 준비 완료입니다.&lt;br /&gt;하지만 플랜더스에게 친절하게 대해주세요.&lt;br /&gt;하지만 우리가 본 바로는, 스프링필드는 좋은 손에 있습니다. 이 커뮤니티의 모든 멋진 개발자 여러분께 감사드립니다. 여러분이 다음에 무엇을 창조할지 기대하겠습니다. 이제 에픽으로 돌아가겠습니다.&lt;br /&gt;슈퍼 소닉으로 처음 갔던 때부터 바로 여기, 지금 이 순간까지, 전 세계 최고의 팬들 앞에서 우리 게임의 가장 큰 축제를 열게 된 것은 적절합니다. 우리는 그 역사를 기념합니다.&lt;br /&gt;파리에 있는 친구들과 전 세계 시청자 여러분 모두에게, 이것이 미래이고 이것이입니다.&lt;br /&gt;아.&lt;br /&gt;네, 우와.&lt;br /&gt;좋습니다. 파리에서 열린 로켓 리그 경쟁 시리즈에서 우리는 언리얼 엔진 6의 첫인상을 전 세계에 공개했습니다. 그리고 이것은 훌륭한 게임과 도구를 만들고 여러분과 공유하여 여러분이 아이디어를 실현할 수 있도록 하는 우리의 사명에 있어 다음 단계입니다. 그리고 저는 우리가 미래를 위해 무엇을 구축하고 있는지 말씀드리려고 합니다. 오늘 상황이 다소 어색합니다. 언리얼에서 무언가를 구축하는 방법이 실제로 두 가지가 있습니다. 하나는 대규모 AAA 기능을 갖춘 독립형 배포용 언리얼 엔진 5 게임을 구축하는 것이고, 다른 하나는 포트나이트용 언리얼 에디터 기능 세트와 도구 세트로, 한 번 게임을 구축하면 8천만 명의 월간 활성 사용자가 있는 포트나이트의 모든 플랫폼에 라이브로 배포할 수 있게 해줍니다.&lt;br /&gt;각각이 정말 멋지고 독특한 기능들을 가지고 있지만, 다른 쪽의 기능이 부족합니다. 그래서 이 두 가지를 하나로 통합하려는 우리의 큰 계획이 언리얼 엔진 6 노력의 핵심입니다. UE5에 UFN을 더하면 UE6이 되고, 여기에 더 멋진 것들이 추가될 예정입니다. 비전은 언리얼 엔진 6 방식으로 한 번 구축하면, 콘솔 스토어, PC 스토어, 모바일 스토어는 물론, 포트나이트 생태계나 다른 개발자가 만든 다른 언리얼 엔진 6 기반 게임 생태계에까지 배포할 수 있는 게임을 가질 수 있다는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;이전 세대에서는 그래픽을 최우선으로 하여 기술을 선보이고 발표했습니다. 하지만 언리얼 엔진 6 세대에서는 차세대 게임 개발과 게이밍을 준비하기 위해 엔진의 기반에 가장 중점을 두고 있습니다. 그리고 여기서 가장 중요한 변화는 저수준 C++ 엔진과 더불어 게임플레이 개발을 위한 다양한 프로그래밍 언어로의 전환입니다. 그 이유는 게임 전반에 걸쳐 대규모 코드 및 콘텐츠 상호 운용성을 구현하기 위함입니다. 오늘날 우리는 많은 콘텐츠 상호 운용성 기능을 가지고 있습니다. 팹 콘텐츠 마켓플레이스에 가서 멋진 오브젝트들을 다운로드하여 게임에 배치하지만, 그 다음에는 직접 연결하고 작동하도록 만들어야 합니다. 언리얼 엔진 6 세대에서는 모든 곳에서 작동하는 통일된 API 세트와 통일된 언어를 갖춤으로써, 게임 간, 프로젝트 간에 완전히 이식 가능한 스마트 에셋을 구축할 수 있으며, 수백만 명의 개발자가 협업하여 누구나 사용할 수 있는 공유된 작업물에 어떠한 규모로든 공유될 잠재력을 가질 수 있습니다. 언리얼 엔진 6 세대의 또 다른 주요 목표는 훨씬 더 큰 게임 시뮬레이션을 가능하게 하는 것입니다. 아시다시피, 1999년 배틀 로얄 장르의 게임에 영감을 준 오리지널 영화가 있었습니다. 다행히도 그 영화는 100명이 섬에 낙하하는 장면이 있었습니다. 그리고 이것은 사실 우리 코드베이스가 단일 스레드 서버에서 지원할 수 있는 최대 플레이어 수와 일치하는 좋은 우연의 일치입니다. 만약 플레이어가 천 명이었다면 우리는 그것을 할 수 없었을 것입니다. 하지만 언리얼 엔진 6의 목표는 커티스 슈미트가 나중에 더 자세히 설명할 소프트웨어 및 트랜잭션 메모리 기술을 도입하여, 데이터 센터에 들어갈 수 있는 모든 컴퓨터, 미래에는 수십만, 어쩌면 수백만 대의 컴퓨터로 게임의 확장을 가능하게 하는 것입니다. 그리고 이것은 연구실에 있는 기술이며, 팀은 이를 실용적인 출시 시스템으로 만들기 위해 매우 빠르게 작업하고 있습니다. 언리얼 엔진 6의 또 다른 주요 목표는 제가 2016년 시그라프 컴퓨터 그래픽 쇼에서 처음 이야기했던 것입니다. 그곳에서 저는 웹처럼 개방된 시스템으로서의 게임의 잠재적인 미래에 대해 이야기했습니다. 즉, 어떤 개발자든 서버를 운영하고, 게임을 만들고, 자체 콘텐츠를 호스팅할 수 있으며, 사용자는 원하는 곳 어디든 이동하면서 모든 것을 가지고 다닐 수 있는 것입니다. 그리고 게임들 사이에 존재하는 벽과 장벽을 허물어 완전히 상호 운용 가능한 생태계를 만드는 것입니다. 그리고 로켓 리그의 언리얼 엔진 6 프리뷰를 보시면, 가장 마지막 프레임에 상단에 작은 URL 표시줄이 있었습니다. URL은 versetleague.com이었고, 우리는 현재 이 개방형 게임 생태계의 아이디어를 완전히 실현하는 데 아주 가까워졌습니다. 게임 간 이동 능력과 개발자가 원하는 모든 것을 어디서든 구축할 수 있는 자유가 있습니다. 에픽의 목표는 업계의 모든 개발자들과 함께 이 시스템을 동료로서 함께 구축하는 것입니다. 우리는 지배자가 없는 시스템을 원했습니다. 아시다시피, 우리는 업계에서 지배자들과 맞서 싸우는 데 어느 정도 성공을 거두었습니다. 그리고 우리는 다음 주자가 되고 싶지 않습니다. 오히려 우리는 모든 게임 개발자뿐만 아니라 기술 및 서비스를 만드는 다른 제작자들을 포함하여 업계의 모든 회사들의 파트너가 되어 최고의 결과물을 만들고 모든 것을 연결하고 싶습니다. 따라서 이 노력의 큰 부분은 에픽이 픽사 USD 파일 형식과 GOTF와 같은 개방 표준을 채택하고, 표준화 기구들과 협력하여 부족하고 필요한 곳에 새로운 표준을 도입하기 위해 사양을 발표하는 것입니다. 그리고 제가 나중에 더 자세히 이야기하겠습니다. 하지만 지금은 마커스 위즈머를 소개하며 언리얼 엔진 6의 아키텍처에 대해 이야기하도록 하겠습니다. 감사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;좋습니다, 팀. 음, 그럼 언리얼 엔진의 최근 역사를 다시 한번 살펴보겠습니다. 언리얼 엔진 4는 도구를 무료로 사용하고 소스 코드를 GitHub에서 접근 가능하게 함으로써 엔진을 모두에게 개방했습니다. 그리고 UE5는 월드를 구축하는 방식을 재창조하여, 이전보다 더 크고, 밀도 높고, 역동적인 디테일을 더하며, 더 빠르게 할 수 있도록 도와줍니다. U6는 다른 제안을 가지고 있습니다. 그것은 우리가 게임을 배포하고 운영하는 방식의 진화에 관한 것입니다. 그렇다고 해도, U6는 여러분이 언리얼 엔진에 바라는 모든 것을 계속해서 할 것입니다. 렌더링은 계속 좋아질 것이고, 컴파일 시간은 단축될 것입니다. 반복 작업 주기는 더 짧아질 것입니다. 모바일도 점점 더 강력해질 것입니다. 하지만 우리는 UE6에 있어 게임 개발에 있어 동시에 변화해야 할 세 가지가 있다고 믿습니다. 첫째, 지속적인 대규모 라이브 월드를 만들기 위해 게임플레이 프로그래밍이 더 단순해져야 합니다. 그리고 Verse는 에픽의 미래 프로그래밍 모델의 기반입니다. 이는 글로벌 상태가 작동하고 트랜잭션적으로 정확한 동시성이 런타임에 처리되는 대규모 지속적인 게임 월드를 구동하기 위해 특별히 설계된 차세대 언어입니다. 우리는 Verse를 기반으로 현대적이고 높은 게임플레이 프레임워크를 구축하여, 게임과 경험을 쉽게 구축하고 그 상호 운용 가능한 구성 요소를 게임 간에 공유할 수 있는 진정한 기반을 제공합니다. 이 프로그래밍 모델에 대한 목표와 아키텍처는 몇 분 후에 프로젝트의 기술 디렉터가 말씀드릴 것입니다. 하지만 지금은 UE6의 두 번째 핵심 원칙에 대해 이야기해 보겠습니다. 콘텐츠와 코드는 게임과 심지어 엔진 전반에 걸쳐 이식 가능해야 합니다. 우리의 목표는 게임 산업에 상호 프로모션 가능한 플레이어 가치와 함께 생태계를 성장시킬 완전히 새로운 방법을 제공하는 것이며, 메타버스 법칙이 예측하는 경험과 소셜 그래프 연결의 모든 긍정적 합의 역학을 적극적으로 활용하는 것입니다. 그리고 우리는 UE를 단순한 확장성을 넘어 상호 운용을 위한 개방형 사양으로 이동시키려는 확고한 노력으로 이를 수행할 것입니다. glTF나 USD와 같은 기존 표준이 우리의 요구를 충족할 수 있는 경우에는, 이를 엔진 내의 최고 등급 형식으로 만들 것입니다. 그리고 게임 생태계의 요구를 충족하는 표준이 아직 존재하지 않는 경우에는, Verse API, 정의된 에셋 조건, 그리고 어떤 엔진, 도구 또는 스튜디오라도 구현할 수 있는 문서를 통해 언리얼 자체 시스템을 개방형 사양으로 공개할 것입니다. 포트나이트 코스메틱이 포터빌리티의 첫 번째 실제 증거점이 될 것입니다. 우리는 기본 시스템을 모든 게임에서 사용할 수 있는 개방형 UE6 모듈로 이동하는 것부터 시작할 것입니다. 이것은 여러분이 자신의 게임에서 플레이어가 소유한 포트나이트 의상을 사용할 수 있는 옵션을 갖게 된다는 것을 의미합니다. 그리고 포트나이트 안에서 작동하는 자신만의 게임 의상을 구축할 도구를 얻게 됩니다. 그리고 우리는 이 문제를 가장 먼저 다루는 이유는, 이 아이디어의 의미 있는 존재 증명이 될 만큼 복잡하고, 상호 연결된 게임 생태계 전반에 걸쳐 그들의 구매를 존중함으로써 본질적으로 많은 플레이어 가치를 수반하는 시스템으로 증명하고 싶기 때문입니다. 우리는 이것을 스마트 자산, 즉 게임 전반에서 작동하는 로직과 기능이 있는 기능적 자산에 대한 공유 경제를 구축하는 첫걸음으로 봅니다. 궁극적으로 이것은 정말 포트나이트 이야기가 아닙니다. 단지 그렇게 성숙하고 복잡한 시스템이 대규모로 작동할 수 있다는 것과, 이 시스템을 사용하는 모든 게임이 즉시 그 혜택을 받을 것이라는 것을 증명하는 것입니다. 다행히도, 우리는 지금 바로 그러한 개방형 생태계 시스템을 향한 첫 번째 구체적인 발걸음을 내딛고 있습니다. 메타휴먼은 세계에서 가장 성공적인 게임들 중 일부에 채택되었으며, 디지털 캐릭터의 표준이 되고 있습니다. 그래서 오늘 우리는 메타휴먼 개발 키트를 발표하며, 우리의 리그 로직과 메타휴먼 DNA 도구 세트를 MIT 라이선스로 공개하여 여러분이 어떤 게임, 어떤 엔진, 어떤 플랫폼에서도 메타휴먼을 구현할 수 있도록 합니다. 더 자세한 내용은 감사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;네. 더 자세히 알아보려면 이어서 진행되는 저희 발표에 와주세요. 자, 다음으로 넘어가겠습니다. 기술 발표라면 당연히 AI에 대한 논의가 빠질 수 없죠. 재미있는 이야기거리 중 하나로, 게임 엔진이 프롬프트 가능한 월드 모델로 대체될 것이라는 추측이 돌고 있습니다. 하지만 저희는 실제로 그렇게 될 것이라고 생각하지 않습니다. 저희가 훨씬 더 흥미롭다고 생각하는 부분은 AI 지원 게임 제작이 반복 주기를 단축하고, 레벨, 캐릭터 리깅, 파티클 시스템, 본 가중치 설정, 조명 조정 등 시간이 많이 걸리는 수동 설정을 줄여준다는 것입니다. 즉, 전문적인 창의적 의도를 성능이 뛰어나고 다양한 플랫폼에서 작동하는 게임으로 구현하는 데 필요한 모든 수동 작업을 줄여준다는 것이죠. 그리고 결정적으로, 언리얼 엔진은 전 세계 최고의 게임들이 구동되는 기반이 될 효율적인 크로스 플랫폼 고화질 런타임으로 자리매김할 수 있는 독보적인 위치에 있습니다. 따라서 UE6에서는 LLM, 생성형 AI 모델, 그리고 Claude, Gemini와 같은 도구들이 창의적인 통제력을 유지하면서 콘텐츠를 더 빠르게 구축하는 데 핵심적인 역할을 할 것이라고 봅니다. 그리고 아까 보신 것처럼, 이러한 워크플로우의 미래는 자연어 의도와 제작 파이프라인 사이의 원활한 번역 계층입니다. UE6의 목표는 콘텐츠 제작의 지루한 작업을 크게 줄여 창의적인 탐구에 더 많은 시간을 할애하고 팀이 콘텐츠를 다듬을 수 있는 반복 횟수를 늘리는 것입니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;UE6는 이러한 워크플로우를 내부 개발 및 UEFN에서 테스트하여 출시할 예정입니다.&lt;br /&gt;저희가 주로 콘텐츠 제작에 대해 보여주고 이야기했지만, 코딩과 엔지니어링 역시 중요합니다. 에픽 내부에서는 무엇이 효과가 있고 무엇이 효과가 없는지 알아보기 위해 많은 조사를 진행해 왔습니다. 그리고 최근에는 백엔드 엔진 및 게임 개발 엔지니어링 팀 전반에 걸쳐 코드 생성 및 AI 분석에 대한 상당히 폭넓은 사용을 허용했습니다. 저희는 많은 성공 사례를 경험했습니다. 특히 사람들이 자신의 작업을 위한 맞춤형 도구를 작성하는 경우, LLM이 UEIE와 같은 대규모 코드베이스를 다룰 수 있도록 돕는 빠른 코드 인덱싱 도구, 빠른 장애 대응 분석, 충돌에 대한 자동 근본 원인 분석, 자동 테스트 생성, 그리고 물론 백엔드 서비스 개발에서 기대할 수 있는 이점들이 큰 성공을 거두었습니다. 하지만 흥미로운 점은 이러한 사례들 대부분이 아직 메인 언리얼 엔진 코드를 생성하는 단계는 아니라는 것입니다. 물론 그 부분도 나올 것입니다. 따라서 언리얼 엔진 6는 콘텐츠 워크플로우와 함께 엔지니어링에 AI를 사용하는 데 필요한 모든 핵심 학습 내용을 포함할 것으로 예상할 수 있습니다.&lt;br /&gt;좋습니다. U5에서 UE6로의 전환에 대해 궁금한 점이 많으실 것이라는 것을 알고 있습니다. 그러니 잠시 그 부분에 대해 이야기해 보겠습니다. UE6는 저희가 병렬로 진행해 온 두 가지 개발 흐름을 통합합니다. 하나는 고사양 독립형 게임 및 콘텐츠 개발을 위한 U5이고, 다른 하나는 새로운 프로그래밍 모델이 테스트되고 있는 라이브 환경인 포트나이트 에디터(Unreal Editor for Fortnite)입니다. UEIE6는 이 두 제품을 하나의 에디터로 결합할 것입니다. UE5와 UEFN이 하나의 에디터로 합쳐지면서, 오늘날처럼 전통적인 게임과 프로젝트를 출시할 수 있게 됩니다. 포트나이트 내에서 직접 출시하거나, 자체 생태계를 출시하고 선택적으로 저희 생태계와 호환되도록 만들 수도 있습니다. 한쪽에서 다른 쪽으로 이동하는 경로가 쉬워질 것입니다. 액터와 블루프린트는 UE6의 초기 버전에서 제공될 예정입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;결국 이 기능들은 새로운 프레임워크가 충분히 성숙해지면 사용되지 않게 될 것이며, 프로젝트를 한 프레임워크에서 다른 프레임워크로 옮길 수 있는 변환 도구도 갖게 될 것입니다. 또한, 오늘 늦게 GitHub에 새로운 UE6 메인 스트림이 공개될 예정이며, 이는 UE5 스트림이 항상 그랬던 것처럼 공개적으로 볼 수 있을 것입니다. 남아 있는 UE5 변경 사항들은 손실되지 않도록 UE6으로 병합되겠지만, 그 반대는 그렇지 않습니다. 게다가 포트나이트 개발은 UE6 스트림에 연결될 것이므로, 진행 중인 모든 작업을 실시간으로 확인하고 필요에 따라 변경 사항을 가져올 수 있습니다. 하지만 이 스트림은 일종의 알파 버전으로 만들어진 것이 아니며, 우리가 어디로 가고 있는지 투명하게 보여주기 위한 것입니다. 현재 58 버전 이후의 공식 UE5 릴리스는 계획하고 있지 않지만, 필요하다면 59 버전을 출시할 권리는 유보하고 있습니다. 예측할 수 없습니다. 그래서 UEIE6는 언제 사용할 수 있나요? 2027년 말경에 얼리 액세스로 출시할 계획입니다. 저희는 게임 개발이 어떻게 돌아가는지 알고 있습니다. 하지만 에픽은 얼리 액세스 출시보다 앞서 기술 스택 관련 사항들을 출시할 예정입니다. 제대로 작동하는지 확인하기 위함입니다. 6.0은 얼리 액세스 출시 후 12개월에서 18개월 후에 출시될 예정입니다. 그리고 거의 모든 사람이 프로젝트를 6.0으로 옮길 수 있을 것으로 예상하는데, 그 이유는 여전히 메인라인 UE5의 모든 기술을 가지고 있지만 Cascade만 제외하기 때문입니다. 그건 없애버립니다. 그건 살아남지 못할 겁니다. 그러니 나이아가라로 넘어가세요. 그렇긴 하지만, 우리는 포인트 릴리스에서는 보통 하지 않을 큰 아키텍처 및 기타 변경 사항을 적용할 기회를 가질 것입니다. 따라서 UE5에서 6으로 업그레이드하는 과정은 4에서 5로 할 때와 유사할 것으로 예상할 수 있습니다. 개발이 계속됨에 따라 진행 상황을 계속 알려드리겠습니다. 이제 커티스가 나와서 게임플레이 아키텍처에 대해 더 자세히 설명해 주겠습니다. 감사합니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;감사합니다, 마커스. 그리고 모두 좋은 아침입니다.&lt;br /&gt;저는 커티스입니다. 언리얼 엔진의 게임플레이 아키텍처를 담당하고 있으며, 오늘 UE6의 새로운 게임플레이 프레임워크에 대해 이야기하게 되어 기쁩니다. 이 프레임워크는 Verse로 시작됩니다. Verse는 대규모의 지속적인 게임 월드를 구동하기 위해 특별히 설계된 차세대 프로그래밍 언어입니다. 저희는 3년 전에 UFN에서 처음 출시했으며, 이곳에서 UE6의 기반이 될 수 있도록 성장시켰습니다. Verse는 함수형 논리와 명령형 언어에서 아이디어를 가져왔기 때문에 C나 Python 같은 언어에 익숙했던 사람이라면 즉시 친숙하게 느껴져야 합니다. 하지만 또한 현대 게임 개발의 복잡성과 확장성 문제를 해결하기 위한 독특한 기능들도 가지고 있습니다. 가장 먼저 이 독특한 소프트웨어 트랜잭션 메모리 모델(STM)부터 말씀드리겠습니다. Verse의 모든 함수는 원자적 트랜잭션의 일부로 실행되며, 필요에 따라 롤백 및 재실행될 수 있습니다. 그리고 이것은 게임 코드에서 많은 흥미로운 작업을 할 수 있게 해줍니다. 예를 들어, 객체가 월드에서 성공적으로 이동할 수 있는지 확인하려면, 단순히 위치를 설정한 다음 공간 쿼리를 수행하여 무언가와 충돌하는지 확인할 수 있습니다. 만약 충돌한다면, 전체 트랜잭션을 포기하고 전체 작업을 되돌려 코드가 전혀 실행되지 않은 것처럼 처리할 수 있습니다. Verse의 트랜잭션 메모리 모델은 게임 개발의 또 다른 큰 문제에 대처하는 데 도움을 줄 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;더 많은 플레이어 수를 가진 거대한 세계를 구축하는 것. 그리고 오늘, 더 큰 게임을 구축하는 데 있어 큰 제약 요소 중 하나는 서버 기술에 달려 있습니다. 게임을 여러 게임 서버에서 실행하도록 확장하려면 게임 전체 아키텍처를 근본적으로 재고해야 합니다. UE6에서는 이를 해결하기 위해 완전한 분산 소프트웨어 트랜잭션 메모리 시스템을 구축하고 있습니다. 아이디어는 이렇습니다. 기존의 단일 스레드 방식의 버스 게임 코드를 여러 서버에 분산합니다. 한 서버에서 필요한 객체가 있으면, 버스 런타임은 현재 트랜잭션을 롤백하고, 객체를 서버로 마이그레이션한 다음, 객체가 존재하는 상태로 트랜잭션을 다시 실행합니다. 그리고 이 모든 과정은 원래 프로그램의 트랜잭션 일관성을 유지하는 방식으로 이루어집니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;마지막으로, 버스에서는 게임 데이터를 저장하는 것을 훨씬 간단하게 만들고 싶었습니다. 그래서 버스 런타임은 프로그램의 모든 전역 상태를 자동으로 동기화하고 저장하여, 실행 중인 게임 인스턴스 또는 에코시스템 전체에 공유할 수 있습니다. 프로그래머에게 이것이 의미하는 바는 플레이어의 저장 상태와 같은 것을 설정하는 것이 단일 전역 맵에 플레이어와 저장 상태를 매핑하는 것만큼 간단하다는 것입니다. 데이터베이스를 설정하거나 게임과 다른 백엔드 서비스 간의 스키마를 조정할 필요가 없습니다. 버스를 벗어나지 않고 이 모든 것을 할 수 있습니다.&lt;br /&gt;이제 버스가 더 큰 UE6 게임플레이 아키텍처에 어떻게 들어맞는지 살펴보겠습니다. 근본적인 수준에서, 우리는 버스 런타임과 렌더링, 카오스 물리, 메타 사운드와 같은 오늘날 존재하는 모든 UEI 시스템을 갖추고 있습니다. 버스에서는 버스 씬 그래프 프레임워크도 도입합니다. 이것은 프리팹 스타일 워크플로우와 런타임 컴포지션에 대한 완벽한 지원을 갖춘 최신 게임 컴포넌트 프레임워크입니다. 씬 그래프는 프리팹 데이터 모델 전체를 버스 타입 시스템을 통해 모델링하는 것을 포함하여 버스 언어의 모든 기능을 활용하도록 설계되었습니다. 그 위로, 엔진의 모든 핵심 시스템은 구체적인 버스 객체로 노출됩니다. 작가님이 만든 모든 머티리얼, 메시, 나이아가라 시스템은 정적으로 검증 가능한 API를 가진 버스 클래스 유형이 됩니다. 이를 통해 버스 컴파일러를 사용하여 엔진 전체에서 모든 데이터를 통합적으로 검증할 수 있습니다. 예를 들어, 파티클 시스템의 매개변수를 변경하면, 코드에서 일치시키기 위해 어디를 업데이트해야 하는지 즉시 알 수 있습니다. 마지막으로, 캐릭터, 무기, 차량과 같은 일반적인 게임 시스템을 위한 하이레(highle) 프레임워크를 도입할 예정입니다. 이제 이러한 프레임워크로 구축하는 것은 개발 속도를 높이는 데 도움이 되지만, 게임과 에코시스템 전반에 걸쳐 광범위하게 공유될 수 있는 콘텐츠도 만듭니다. 예를 들어, Fab에서 자동차를 가져와서 오늘날처럼 단순히 스켈레탈 메시와 애니메이션만 얻는 것이 아니라, 모든 게임에서 작동하는 완전히 작동하는 자동차 버스 모듈을 얻는 것을 상상해 보세요. UE6 게임플레이 프레임워크를 통해, 우리는 방대한 양의 코드와 콘텐츠가 이러한 프로젝트들 사이에서 구축되고 공유되는 세상을 구상하고 있으며, 버스는 에코시스템이 지속 가능하게 성장하도록 돕는 강력한 하위 호환성 보장을 제공합니다.&lt;br /&gt;물론, 이 모든 코드와 데이터를 저장할 장소가 필요합니다. 그리고 이 점에 대해 이야기할 사람이 마티아스입니다.&lt;br /&gt;커티스, 감사합니다.&lt;br /&gt;저는 마티아스 얀센입니다. 개발자 도구를 담당하고 있으며, 저희 버전 관리 시스템인 로어(lower)에 대해 이야기할 것입니다.&lt;br /&gt;플랫폼과 서비스를 계속 확장함에 따라, 데이터 저장 및 버전 관리와 관련하여 많은 어려움에 직면합니다. 대용량 바이너리 데이터 세트를 처리하고, 전 세계적으로 쉽게 확장할 수 있으며, 공유 멀티 테넌트 환경에서 안전한 데이터 격리를 제공하는 것이 필요합니다.&lt;br /&gt;또한 프로그래머뿐만 아니라 모든 사람에게 사용하기 쉽도록 만들어야 합니다.&lt;br /&gt;저희는 사용 가능한 도구들을 살펴보고, 어떤 것도 우리가 필요로 하는 모든 것을 갖추고 있지 않다는 결론에 도달했습니다. 예를 들어 Git은 자신이 만들어진 목적, 즉 소스 코드의 분산 개발에는 탁월합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;하지만 게임 개발에는 방대한 양의 바이너리 데이터와 콘텐츠가 포함되어 있으며, 로컬 머신에 모든 것을 필요로 하는 경우는 드뭅니다. Git은 이러한 요구 사항 하에서 제대로 작동하지 않습니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;다른 상용 및 독점 시스템들도 고려되었지만, 우리의 기반 도구는 반드시 공개 사양, 공개 프로토콜, 공개 형식을 갖추어야 합니다. 그보다 못한 것은 의존하는 사람들이 확장하거나 감사하거나 신뢰할 수 없기 때문입니다. 그래서 우리는 처음부터 로어(Lore)를 구축하기로 결정했고, 우리의 요구 사항을 충족하도록 데이터 모델을 처음부터 설계했습니다. 우리는 확장성과 성능을 첫날부터 핵심 원칙으로 삼았습니다.&lt;br /&gt;그리고 여기에 로어의 대부분의 기술적 혁신이 담겨 있습니다. 효율적인 대규모 에셋 처리를 자유로운 브랜칭 모델과 결합하여 팀이 워크플로우 유연성이나 저장 효율성을 희생하지 않고 빠르게 반복 작업을 할 수 있도록 합니다.&lt;br /&gt;로어는 소규모 팀을 위한 제로 설정 단일 서비스 구성부터 UFM과 같은 다중 리전, 수백만 사용자 배포까지 여러분과 함께 성장할 것입니다. 로어의 핵심은 효율적인 콘텐츠 주소 지정 데이터 저장소입니다. 모든 파일, 모든 디렉토리, 모든 개정본은 그것이 어디에 있느냐가 아니라 그것이 무엇으로 구성되어 있느냐에 의해 식별됩니다. 동일한 데이터 조각은 한 번만 저장됩니다.&lt;br /&gt;로어는 이 스토리지 플랫폼에 직접 접근할 수 있게 하여, 그 위에 자신만의 애플리케이션과 파이프라인을 구축할 수 있도록 합니다. 로어의 버전 제어는 이 스토리지 플랫폼을 사용하여 여러 작업을 병렬로 수행하고, 자유롭게 전환하며, 확장성에 대해 걱정할 필요 없이 안전하고 격리된 공간에서 협업할 수 있도록 합니다.&lt;br /&gt;로어의 희소 바이너리 우선 스토리지 아키텍처는 작업하는 개정본과 브랜치에 필요한 데이터만 가져와서 모든 크기의 프로젝트를 지원합니다.&lt;br /&gt;대용량 바이너리 데이터는 더 작은 조각으로 저장되어 부분 중복 및 모든 파일에 대한 매우 효율적인 병렬 데이터 전송이 가능합니다.&lt;br /&gt;바로 그 데이터 모델이 로어가 인프라 전반에 걸쳐 확장할 수 있게 하는 것입니다.&lt;br /&gt;성장함에 따라 로어는 로컬 머신부터 엣지 및 리전 캐시를 거쳐 지속적인 글로벌 스토어에 이르기까지 추가 서버 계층을 투명하게 추가할 수 있게 합니다. 그리고 접근이 모든 계층에서 인증되고 권한 부여되기 때문에, 이러한 확장은 통제력을 희생하는 대가를 치르지 않습니다. 모든 서버는 전역적으로 분산된 팀을 위해 동일한 접근 정책을 시행합니다. 이는 다른 지역의 사용자가 가장 가까운 캐시에 접근할 수 있으며, 글로벌 단일 진실 공급원이 병목 현상이 되지 않음을 의미합니다.&lt;br /&gt;로어가 하는 모든 것, 데이터 저장, 버전 제어는 단일하고 완전한 API를 통해 노출됩니다. 그리고 그 API 위에, 우리는 예상할 수 있는 도구들, 즉 명령줄 인터페이스, 데스크톱 애플리케이션, 그리고 가까운 미래에는 언리얼 에디터 통합 기능을 구축했습니다.&lt;br /&gt;그리고 이 도구들은 모두 동일한 API와 라이브러리를 기반으로 구축되었습니다. 이러한 API 우선 설계는 로어를 쉽게 확장하고 모든 개발 파이프라인에 통합할 수 있게 합니다.&lt;br /&gt;여러분의 도구와 애플리케이션은 원하는 언어로 API를 통해 로어를 쉽게 사용할 수 있습니다. 비록 우리가 여기서 긁어모은 것에 불과하지만요. 이것이 로어의 강력함과 잠재력을 느끼게 해드리길 바랍니다. 그리고 이미 프로덕션 환경에서 사용되고 있습니다. 현재까지 언리얼 버전 제어로 알려져 있던 UFN 생태계를 구동하며, 모든 콘텐츠 파이프라인에 버전 제어와 데이터 스토리지를 제공하고 있습니다.&lt;br /&gt;우리는 이미 에픽 내부 개발의 주요 버전 제어 시스템으로 로어를 사용하도록 전환하기 시작했으며, UE6 출시까지 로어를 완전히 사용할 계획입니다.&lt;br /&gt;우리는 에픽에서 겪고 있는 확장성 및 효율성 문제를 해결하기 위해 로어를 구축했습니다.&lt;br /&gt;그리고 여러분 중 많은 분들과 이야기하면서, 업계 전반에 걸쳐 유사한 어려움이 공명하고 있음을 들었습니다.&lt;br /&gt;그리고 그것은 더 큰 깨달음으로 이어졌습니다. 만약 우리가 모두가 함께 구축하는 진정으로 개방된 생태계를 육성하려고 한다면, 문을 닫고 만든 시스템은 부족할 것이라는 것입니다. 그래서 오늘 로어를 오픈 소스로 발표합니다.&lt;br /&gt;모든 소스 코드까지요.&lt;br /&gt;감사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;모든 소스 코드와 데이터 형식 및 프로토콜에 대한 문서는 이제 MIT 라이선스 하에 배포되어 자유롭게 사용할 수 있습니다. 이 릴리스를 완벽하거나 완전한 패키지로 간주해서는 안 되며, 오히려 여러분이 이를 확장하고, 도전하고, 함께 더 강력한 무언가로 만들어 나갈 수 있는 초대장으로 받아들여 주시기 바랍니다.&lt;/span&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;&lt;br /&gt;더 알고 싶으시다면 lore.org로 오셔서 나중에 진행될 쇼에서 로어의 아키텍처에 대한 심층적인 논의 세션에 참석해 주세요.&lt;br /&gt;이상으로 제가 팀에게 마이크를 넘기겠습니다.&lt;br /&gt;멋지네요. 이것이 저희 차세대 배포 가능한 오픈 소스 릴리스 중 첫 번째 두 가지이며, 게임 상호 운용성을 위한 표준을 점점 더 많이 구축함에 따라 계속될 많은 릴리스 중 첫 번째입니다. 이제 저는 게임 비즈니스에 대해 이야기하고 싶습니다. 이 분야는 위기와 기회가 공존하는 시기입니다.&lt;br /&gt;긍정적인 측면에서 보면, 새로운 세대의 게이머들이 유입되고 있으며, 그들은 새로운 취향으로 게임을 즐기고 있으며, 이전 세대보다 더 높은 비율로 게임을 플레이하고 있습니다. 그리고 포트나이트와 같은 대형 게임들은 다시 한번 성장하고 번창하고 있습니다. 하지만 그 이면에는 AAA 개발사들에게 심각한 도전 과제가 있습니다. 바로 대형 게임의 신규 출시작 중 상당수가 실패하고 있다는 것입니다.&lt;br /&gt;우리는 종종 수억 달러의 개발 비용이 수천만 달러의 수익으로 이어지는 것을 목격하고 있으며, 개발 비용은 계속 증가하고 있습니다. 많은 사람들에게는 마치 AAA 게임 비즈니스를 휩쓰는 물결이 몰아치는 것처럼 느껴집니다. 저는 여러분 모두가 왜 이런 일이 일어나고 있는지에 대한 이론을 가지고 있다는 것을 알고 있지만, 저는 이 현상의 근본적인 세대 변화와 추세를 파악하는 데 초점을 맞추고 싶습니다. 왜냐하면 우리가 정직한 해결책을 제시하려면 문제를 정확하게 파악해야 하기 때문입니다.&lt;br /&gt;핵심 트렌드 중 하나는 게이밍이 점점 더 사회적인 활동이 되고 있다는 것입니다. 예전에는 게임을 하려고 결정하고, 다운로드하고, 혼자 하거나, 아니면 우연히 만나는 낯선 사람들과 멀티플레이를 하곤 했습니다.&lt;br /&gt;요즘은 친구들과 모여서 온라인에서 무엇을 함께 할지 결정하는 것이 훨씬 더 중요합니다. 게임을 하든, 경험을 하든 말이죠. 그리고 이러한 게이밍의 사회적 측면 증가는 대형 게임과 거대한 생태계에 엄청난 이점을 제공하고 있습니다. 왜냐하면 플레이어가 많은 게임은 친구들을 많이 포함하고 있을 가능성이 훨씬 높기 때문입니다.&lt;br /&gt;그리고 거대한 플레이어 기반을 가진 오랫동안 자리 잡은 게임은 신규 플레이어를 유치하는 것보다 플레이어를 유지하는 것이 훨씬 쉽습니다. 따라서 과거에는 그랬을지 몰라도, 많은 대형 신규 멀티플레이어 게임들이 충분한 커뮤니티와 모멘텀을 얻지 못하고 있습니다.&lt;br /&gt;게이밍에 영향을 미치는 또 다른 큰 변화는 경제가 게임을 '구매하는 것'에서 게임 내 '아이템을 구매하는 것'으로 이동하고 있다는 것입니다. 여러분이 이것을 좋아하든 싫어하든, 그 산술적인 사실은 부인할 수 없습니다. 그리고 이것은 게임 내의 매우 큰 기존 생태계의 성공을 더욱 강화하는 또 다른 요인입니다. 새로운 진입자가 들어오기 점점 더 어려워지고 있습니다.&lt;br /&gt;그리고 만약 여러분이 오랫동안 게임을 해왔고 거대한 플레이어 기반을 가진 게임이라면, 구매한 아이템이 며칠, 몇 주, 심지어 몇 년 후에 여전히 유용할 것이라는 확신을 가지고 구매할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;새로운 게임이 출시될 때는 돈을 쓰는 것이 훨씬 더 어려운 결정입니다. 다음 날, 다음 주, 다음 달에 플레이할지 확신할 수 없기 때문에 돈을 쓸 가능성이 훨씬 적습니다. 게이밍에 영향을 미치는 마지막 추세는 플레이어의 관심에 대한 시장이 비정상적으로 경쟁적이 되었다는 것입니다. 제가 살면서 본 적이 있는 것보다 더 경쟁적입니다. 예전에 저희가 촌스러운 TV나 다른 것들과 경쟁할 때보다도요. 요즘은 온갖 종류의 소셜 미디어 플랫폼은 물론이고, 사람들의 시간을 매우 효과적으로 놓고 경쟁하는 예측 시장 같은 것들도 있습니다. 그래서, 이러한 추세를 극복하기 위해 게임 산업은 우리가 좋아하든 싫어하든 스스로 재편하고 있습니다. 그리고 이러한 문제들이 업계 전반에 걸쳐 반향을 일으키면서 미래에 대한 두 가지 큰 예측이 있습니다. 미래에 대한 한 가지 관점은 로블록스가 성장하여 게임을 잠식한다는 것입니다. 그리고 많은 사람들이 온라인에서 이런 말을 하고 있습니다. 하지만 여기에는 모든 콘텐츠를 상품화하고, 수익의 70% 이상을 가져가며, 4억 5천만 명의 사용자를 확보한 단일 게이트키퍼가 있는 중앙 집중식 플랫폼이 있습니다. 이는 게임 개발자들에게 정말 큰 도전입니다. 하지만 우리는 매우 다른, 훨씬 더 밝은 미래를 믿고 있으며, 그것은 고품질 게임이 도전에 응답하고, 우리의 콘텐츠를 연결하고, 우리의 커뮤니티를 연결하고, 우리의 경제를 연결하여 이전에 해본 적 없는 방식으로 재미를 제공하고 게이머들에게 훌륭한 게임을 제공하는 미래입니다. 그리고 그것을 성취하기 위해 우리는 모든 것을 만드는 방식을 바꿔야 할 것입니다. 우리는 더 나은 게임을 만들어야 할 것입니다. 우리는 그것들을 더 효율적으로 만들어야 할 것입니다. 우리는 처음부터 설계하고 연결된 게임을 위해 만들어야 할 것입니다. 모든 플레이어 기반이 사회적으로 연결되고, 우리의 경제가 연결되어 있어서, 플레이어들이 이것들을 고립된 제품으로 보는 대신, 모든 게임 개발자가 함께 참여하는 글로벌 생태계의 일부로 보도록 해야 합니다. 저희는 여러분 모두와 업계의 모든 게임 개발자들과 협력하여 이것을 함께 성취하고 싶습니다. 언리얼 엔진 6으로 만든 것들이 우리의 기술적 기반입니다. 그리고 우리는 이것이 우리 모두가 맞서야 할 큰 도전이라고 믿습니다. 우리는 다른 게임뿐만 아니라 유튜브나 틱톡, 그리고 사람들이 온라인에서 하는 모든 것들과의 플레이어 시간 경쟁에서 승리해야 합니다. 그리고 이것은 우리가 언리얼 엔진 6을 구축할 때 마음속에 있던 것이었습니다. 이것은 디즈니나 레고와 같은 매우 가까운 파트너들, 그리고 다른 AAA 게임 개발자들의 마음속에도 있던 것이었습니다. 우리가 함께 이것을 구축하기 위해 그들과 점점 더 긴밀한 파트너십을 맺어왔습니다. 그리고 포트나이트의 월간 활성 사용자 수 8천만 명은 꽤 많은 수이지만, 이것만으로는 에픽이 혼자서 미래의 생태계를 구축하기에 충분하지 않다는 것을 깨달았습니다. 우리는 함께 구축해야 합니다. 그리고 저는 그에 대한 논지가 매우 낙관적이라고 생각합니다. 우리 모두가, 세계 최고의 게임들, 많은 분들이 언리얼 엔진을 사용하는 분들, 그리고 많은 개발자들이 언리얼 엔진을 사용하는 프로젝트들 사이에서, 우리는 수십억 명의 활성 사용자를 보유하고 있습니다. 따라서 우리는 '팀 오픈'을 구성하고 게임의 미래를 함께 정의할 기회를 갖게 되었습니다. 그리고 그것이 바로 우리가 여러분과 함께 이번 세기에 함께 성취하고 싶은 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1410;&quot;&gt;그래서, 저희가 하는 게 바로 이거예요. 음, 그리고 언리얼 페스트에 와주셔서 정말 감사합니다. 그리고 기억하세요, 전 세계 어디에서 포트나이트 크리에이터들이 AAA 게임 개발자, 영화 제작자, 건축가, 자동차 디자이너, 그리고 여기서는 심지어 이야기할 수도 없는 것들을 설계하는 록히드 마틴 사람들과 함께 모여서, 그리고 실제로 같은 언어, 즉 언리얼과 콘텐츠, 코드, 개발의 언어를 이야기할 수 있는 곳이 또 있을까요? 음, 그러니 즐거운 시간 보내시고 많은 사람들을 만날 좋은 기회가 되기를 바랍니다. 정말 감사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상 전문 번역글&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/EpicGames/lore&quot;&gt;https://github.com/EpicGames/lore&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781861562766&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - EpicGames/lore: Lore is a next-generation, open source version control system&quot; data-og-description=&quot;Lore is a next-generation, open source version control system - EpicGames/lore&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/EpicGames/lore&quot; data-og-url=&quot;https://github.com/EpicGames/lore&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cqe21P/dJMb9aKOj0d/jqrjkHp4k3GZFo5PxCWtzK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/6ozLv/dJMb87N55bm/SjozErswk0jzD2g98iHxC0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/EpicGames/lore&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/EpicGames/lore&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cqe21P/dJMb9aKOj0d/jqrjkHp4k3GZFo5PxCWtzK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/6ozLv/dJMb87N55bm/SjozErswk0jzD2g98iHxC0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - EpicGames/lore: Lore is a next-generation, open source version control system&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Lore is a next-generation, open source version control system - EpicGames/lore&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLI 와 데스크탑 애플리케이션 지원.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/EpicGames/lore/releases&quot;&gt;https://github.com/EpicGames/lore/releases&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781861563949&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Releases &amp;middot; EpicGames/lore&quot; data-og-description=&quot;Lore is a next-generation, open source version control system - EpicGames/lore&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/EpicGames/lore/releases&quot; data-og-url=&quot;https://github.com/EpicGames/lore/releases&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UlDxT/dJMb9lMkIro/oTZJlAk1sNMHy5DCPzzi7k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/NIMd1/dJMb81G6M5D/5pTwMb0XIxk2K3I5PQnQvk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/EpicGames/lore/releases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/EpicGames/lore/releases&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UlDxT/dJMb9lMkIro/oTZJlAk1sNMHy5DCPzzi7k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/NIMd1/dJMb81G6M5D/5pTwMb0XIxk2K3I5PQnQvk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Releases &amp;middot; EpicGames/lore&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Lore is a next-generation, open source version control system - EpicGames/lore&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1894&quot; data-origin-height=&quot;1180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4ni2x/dJMcabduPTa/zQmNC8yCJfCEUulohOcKWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4ni2x/dJMcabduPTa/zQmNC8yCJfCEUulohOcKWk/img.png&quot; data-alt=&quot;게임테일즈 리모트 서버 설치 후 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4ni2x/dJMcabduPTa/zQmNC8yCJfCEUulohOcKWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4ni2x%2FdJMcabduPTa%2FzQmNC8yCJfCEUulohOcKWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1894&quot; height=&quot;1180&quot; data-origin-width=&quot;1894&quot; data-origin-height=&quot;1180&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;게임테일즈 리모트 서버 설치 후 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1900&quot; data-origin-height=&quot;1144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLkt9Y/dJMcadPUOG0/xups4tZ1Ek2Z9kFUPXm0HK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLkt9Y/dJMcadPUOG0/xups4tZ1Ek2Z9kFUPXm0HK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLkt9Y/dJMcadPUOG0/xups4tZ1Ek2Z9kFUPXm0HK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLkt9Y%2FdJMcadPUOG0%2Fxups4tZ1Ek2Z9kFUPXm0HK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1900&quot; height=&quot;1144&quot; data-origin-width=&quot;1900&quot; data-origin-height=&quot;1144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 설정 문서를 만들고 커밋 후 동기화 해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도의 계정 관리(인증)은 작업을 좀 해 줘야하는 것으로 보인다. User 개념으로 커밋을 하는 방식이다. Lore CLI 에서 stage 할 때 User 입력을 할 수 있으나 Lore Desktop 에는 아직 별도 기능이 없어보인다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;LORE &amp;mdash; 게임과 크리에이티브 워크플로를 위한 차세대 버전 관리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2026년, Epic Games는 &lt;b&gt;LORE&lt;/b&gt;(Lore)를 MIT 라이선스로 공개했습니다. 과거 내부에서는 &lt;i&gt;Unreal Revision Control&lt;/i&gt;이라는 이름으로 불리던 이 시스템은, UEFN(Unreal Editor for Fortnite)의 기본 버전 관리로 이미 수많은 크리에이터에게 검증을 받아 왔습니다. 이제 그 설계 철학과 프로토콜 전체가 오픈소스로 열리면서, 대규모 바이너리 에셋과 분산 팀을 다루는 프로젝트에 새로운 선택지가 생겼습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 LORE가 &lt;b&gt;왜&lt;/b&gt; 만들어졌는지, &lt;b&gt;무엇이&lt;/b&gt; 다른지, 그리고 &lt;b&gt;언리얼 엔진 6&lt;/b&gt; 생태계와 맞닿아 있는 지점을 정리합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LORE란 무엇인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LORE는 &lt;b&gt;중앙집중형(centralized)&lt;/b&gt; 이지만 &lt;b&gt;콘텐츠 주소 지정(content-addressed)&lt;/b&gt; 방식을 취하는 차세대 버전 관리 시스템입니다. 저장소 상태는 &lt;b&gt;Merkle 트리&lt;/b&gt;와 &lt;b&gt;불변(immutable) 리비전 체인&lt;/b&gt;으로 표현되며, 바이너리 우선(binary-first) 저장, 중복 제거(deduplication), 희소(sparse) 워크스페이스, 온디맨드 하이드레이션(on-demand hydration)에 최적화되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 줄로 요약하면 이렇습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드와 수 기가바이트짜리 에셋이 한 저장소에 공존하는, 수백~수천 명 규모의 게임&amp;middot;엔터테인먼트 프로젝트를 전제로 설계된 VCS.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rust로 구현된 코어 라이브러리, 서버, CLI가 공개되어 있고, C/C++, Rust, C#, Python, Go, JavaScript용 SDK도 함께 제공됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LORE의 철학 &amp;mdash; 왜 새로운 VCS가 필요했는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LORE 공식 문서는 기존 VCS를 &quot;나쁘다&quot;고 말하지 않습니다. Git, Perforce, Mercurial/Sapling은 각자의 영역에서 훌륭합니다. 다만 &lt;b&gt;대규모 게임&amp;middot;크리에이티브 워크플로가 동시에 요구하는 제약의 교집합&lt;/b&gt;을 아무 시스템도 처음부터 설계하지 않았다는 것이 LORE의 출발점입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 열린 생태계는 한 회사만으로 완성되지 않는다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LORE는 MIT 라이선스로 전면 공개되었습니다. 포맷, 프로토콜, 설계 결정까지 검토&amp;middot;도전&amp;middot;개선할 수 있어야 한다는 믿음이 핵심입니다. Epic 엔지니어와 외부 기여자가 &lt;b&gt;동등한 접근권&lt;/b&gt;을 가져야 하며, 숨겨진 기능이나 페이월도 없다는 원칙이 FAQ에 명시되어 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 바이너리 우선(Binary-first)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LORE의 핫 패스에서는 모든 콘텐츠가 &lt;b&gt;불투명한 바이트 스트림&lt;/b&gt;으로 처리됩니다. 텍스트 인식 기능은 그 위에 얹히는 레이어일 뿐, 저장&amp;middot;전송 계층의 전제가 아닙니다. &lt;code&gt;.uasset&lt;/code&gt;, &lt;code&gt;.fbx&lt;/code&gt;, &lt;code&gt;.png&lt;/code&gt;, 쿡 결과물, 빌드 아티팩트가 &lt;code&gt;.cpp&lt;/code&gt;와 &lt;b&gt;동일한 저장 원시 타입&lt;/b&gt;으로 다뤄집니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 중앙집중이지만 오프라인에서도 일한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원격 서버는 내구성, 접근 제어, 충돌 해결의 &lt;b&gt;단일 진실 공급원(source of truth)&lt;/b&gt; 입니다. 그러나 스테이징, 커밋, 브랜치 전환, diff 같은 일상 작업은 &lt;b&gt;네트워크 왕복 없이&lt;/b&gt; 로컬에서 수행됩니다. Perforce가 일상 작업마다 서버 왕복을 요구하는 패턴과, Git이 분산 모델에 최적화된 패턴 사이의 균형점을 노립니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 희소성(Sparseness)은 옵션이 아니라 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;워크스페이스는 사용자가 요청한 부분만 물질화(materialize)합니다. 수 테라바이트 프로젝트라도 &lt;b&gt;필요한 프래그먼트만&lt;/b&gt; 가져옵니다. 작업 비용은 저장소 전체 크기가 아니라 &lt;b&gt;작업 집합(working set)&lt;/b&gt; 에 비례합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 암호학적으로 검증 가능한 이력&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 프래그먼트는 BLAKE3 해시로 식별되고, 리비전 그래프는 해시 체인으로 연결됩니다. 서버는 push를 끝까지 검증한 뒤에야 브랜치 포인터를 갱신합니다. 변조와 손상을 탐지할 수 있는 &lt;b&gt;신뢰할 수 있는 이력&lt;/b&gt;이 목표입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. API 우선(API-first)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLI나 특정 언어 바인딩에만 숨겨진 기능이 없습니다. C 라이브러리와 공개 헤더가 LORE의 1차 산출물이며, 저장 서브시스템과 버전 관리 서브시스템이 각각 독립적인 공개 API로 노출됩니다. 파이프라인, DCC 툴, 커스텀 에디터가 LORE 위에 직접 올라설 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기존 VCS와 비교했을 때 LORE의 장점&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;관점&lt;/th&gt;
&lt;th&gt;Git (+ LFS)&lt;/th&gt;
&lt;th&gt;Perforce 계열&lt;/th&gt;
&lt;th&gt;LORE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;대용량 바이너리&lt;/td&gt;
&lt;td&gt;LFS는 볼트-온&lt;/td&gt;
&lt;td&gt;전체 파일 단위&lt;/td&gt;
&lt;td&gt;&lt;b&gt;프래그먼트 단위 청킹&amp;middot;중복 제거&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;희소 워크스페이스&lt;/td&gt;
&lt;td&gt;실험적, 오프라인에서 날카로운 모서리&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설계 중심의 lazy fetch&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일상 작업 네트워크 의존&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;td&gt;&lt;b&gt;낮음 (로컬 커밋&amp;middot;브랜치)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;멀티 테넌트 격리&lt;/td&gt;
&lt;td&gt;인프라에 위임&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;td&gt;&lt;b&gt;파티션 기반 설계&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스펙 공개 범위&lt;/td&gt;
&lt;td&gt;프로토콜은 공개, 일부 포맷은 구현 종속&lt;/td&gt;
&lt;td&gt;독점 프로토콜&lt;/td&gt;
&lt;td&gt;&lt;b&gt;온디스크&amp;middot;와이어&amp;middot;스토리지 전체 공개&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;라이선스&lt;/td&gt;
&lt;td&gt;GPL 등&lt;/td&gt;
&lt;td&gt;상용&lt;/td&gt;
&lt;td&gt;&lt;b&gt;MIT&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;대용량 파일에서 진짜 차이가 나는 지점: 청킹과 중복 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수 GB짜리 에셋에서 한 부분만 수정해도, LORE는 &lt;b&gt;변경된 청크와 그 상위 Merkle 노드만&lt;/b&gt; 다시 업로드합니다. FastCDC 기반 콘텐츠 정의 청킹(content-defined chunking)을 사용하므로, 파일 중간의 작은 편집이 전체 파일 재전송으로 이어지지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 텍스처 변형이 브랜치마다 반복되어도, 동일 프래그먼트는 &lt;b&gt;한 번만&lt;/b&gt; 저장됩니다. Git의 pack delta 휴리스틱에 의존하는 방식과 달리, 바이너리에서도 예측 가능한 중복 제거가 목표입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;브랜치는 가볍고, 이력은 무겁지 않다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브랜치는 가변 포인터일 뿐, 기저 데이터를 복제하지 않습니다. 실험 브랜치를 마음껏 만들고 버려도 저장 비용이 선형으로 폭증하지 않습니다. &quot;브랜치를 부담 없이&quot; 쓰는 문화는 대규모 아트&amp;middot;레벨 디자인 팀에 특히 중요합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로컬 모드에서 10분 안에 시작&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도 인증&amp;middot;클라우드 설정 없이 단일 실행 파일로 로컬 서버를 띄울 수 있습니다. 팀 규모가 커지면 AWS S3(불변 저장) + DynamoDB(가변 메타데이터) 백엔드를 연결하고, Docker나 수평 확장 캐시 티어로 스케일아웃합니다. 백엔드는 문서화된 인터페이스 뒤에 있어 &lt;b&gt;서드파티 구현도 가능&lt;/b&gt;합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;0.x라도 커밋한 데이터는 낡지 않는다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LORE는 아직 pre-1.0입니다. API와 프로토콜은 1.0 전까지 변할 수 있습니다. 그러나 &lt;b&gt;이미 커밋된 콘텐츠는 미래 버전에서도 읽을 수 있도록&lt;/b&gt; 설계되었다는 점이 강조됩니다. VCS에서 신뢰는 하루아침에 얻는 것이 아니라는 현실을 Epic도 인정하고, 당장 기존 도구를 교체하라고 요구하지 않습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;언리얼 엔진 6와 LORE &amp;mdash; 어디까지 왔고, 어디로 가는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼 엔진 사용자에게 LORE는 &quot;먼 미래의 이야기&quot;가 아닙니다. 이미 Epic 생태계 안에서 &lt;b&gt;실전 검증&lt;/b&gt;이 진행 중이고, 로드맵은 UE 본체 통합을 명시하고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지금: UEFN에서의 실사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LORE(구 Unreal Revision Control)는 &lt;b&gt;UEFN의 기본 VCS&lt;/b&gt;입니다. 포트나이트 크리에이터들이 아일랜드를 버전 관리하는 데 쓰고 있으며, Epic 내부 팀으로도 점진적 도입이 이어지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 주목할 만한 사례는 &lt;b&gt;쿡(cook) 파이프라인&lt;/b&gt;입니다. LORE가 중간 저장 계층을 대체하면서, 불필요한 파일 전송을 줄이고 &lt;b&gt;퍼블리시 후 플레이 가능해지기까지의 시간&lt;/b&gt;을 단축하고 있습니다. 엔진 파이프라인과 VCS가 한 저장 추상화 위에서 맞물린다는 점은, 단순히 &quot;에셋만 버전 관리&quot;하는 도구와 근본적으로 다른 방향입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2026: OSS와 UEFN 구현의 수렴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스 LORE는 Zstandard 압축을 사용하지만, 기존 UEFN 프로젝트는 Oodle을 썼기 때문에 &lt;b&gt;아직 바로 호환되지 않습니다&lt;/b&gt;. Epic은 UEFN을 Zstandard로 마이그레이션해 OSS 툴체인과 UEFN 호스팅 LORE가 직접 대화할 수 있게 하는 작업을 진행 중입니다(로드맵 2026).&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2027: 언리얼 에디터 네이티브 플러그인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드맵의 핵심 항목 중 하나가 &lt;b&gt;Unreal Editor plugin&lt;/b&gt;(2027, In progress)입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UEFN에 이미 있는 LORE 플러그인 경험을 &lt;b&gt;본편 언리얼 엔진 코드베이스&lt;/b&gt;로 가져옵니다.&lt;/li&gt;
&lt;li&gt;별도 LORE 프로젝트가 아니라 &lt;b&gt;엔진에 포함되어 배포&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;터미널을 쓰지 않는 아티스트도 에디터 안에서 체크아웃&amp;middot;커밋&amp;middot;히스토리를 다룰 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UE6 시대의 언리얼 프로젝트에서 LORE가 강점을 발휘할 수 있는 이유를 정리하면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 에셋 중심 워크플로와 철학이 맞닿는다&lt;/b&gt;&lt;br /&gt;언리얼 프로젝트는 소스 코드보다 &lt;code&gt;.uasset&lt;/code&gt;, &lt;code&gt;.umap&lt;/code&gt;, 나노이트 메시, 텍스처, 시퀀서 데이터가 저장소 용량의 대부분을 차지합니다. LORE의 바이너리 우선&amp;middot;프래그먼트 dedup 모델은 이 워크로드를 1급 시민으로 취급합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 아티스트와 프로그래머가 같은 저장소를 공유한다&lt;/b&gt;&lt;br /&gt;개발자는 CLI/API로, 아티스트는(곧) 에디터 UI로 같은 리비전 그래프를 봅니다. 파일 잠금(locking) 로드맵은 수백만 파일&amp;middot;수천 동시 사용자 규모의 &lt;b&gt;강제 잠금(enforcement)&lt;/b&gt; 을 목표로 하며, 머지 불가능한 바이너리 에셋 협업에 필수적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. VFS로 멀티 테라바이트 프로젝트의 디스크 부담을 줄인다&lt;/b&gt;&lt;br /&gt;2026 로드맵의 Virtual File System(VFS)은 클론 직후에도 거대 프로젝트에서 바로 작업을 시작하고, &lt;b&gt;디스크에는 한 번만&lt;/b&gt; 콘텐츠를 두도록 합니다. 브랜치마다 전체 복사본을 쌓는 비용을 줄이는 것은 UE 대형 프로젝트에 직결되는 이야기입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Links와 Layers로 멀티 레포 구성&lt;/b&gt;&lt;br /&gt;공유 플러그인, 공통 콘텐츠, 게임별 모듈을 각각 독립 저장소(파티션)로 두고, 작업 트리에서는 하나처럼 조합할 수 있습니다. 접근 권한은 파티션 단위로 유지됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 파이프라인 통합 여지&lt;/b&gt;&lt;br /&gt;저수준 리비전 API(버퍼 기반 리비전 구성&amp;middot;커밋) 같은 제안이 논의되고 있어, 쿡 출력&amp;middot;빌드 아티팩트를 워킹 트리에 억지로 materialize하지 않고 LORE에 등록하는 경로도 열리고 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;아키텍처 한눈에 보기&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│  CLI &amp;middot; Desktop &amp;middot; (UE Editor) &amp;middot; VS Code &amp;middot; Custom Tools   │
└──────────────────────────┬──────────────────────────────┘
                           │ Public API (C / bindings)
┌──────────────────────────▼──────────────────────────────┐
│           Version Control Subsystem                      │
│  Revisions &amp;middot; Branches &amp;middot; Merge &amp;middot; Stage &amp;middot; Sync &amp;middot; Diff     │
└──────────────────────────┬──────────────────────────────┘
                           │
┌──────────────────────────▼──────────────────────────────┐
│              Storage Subsystem                           │
│  Immutable Store (BLAKE3, chunks)  +  Mutable KV Store   │
└──────────────────────────┬──────────────────────────────┘
                           │
┌──────────────────────────▼──────────────────────────────┐
│  Lore Server &amp;middot; Edge Cache &amp;middot; Read Replicas &amp;middot; S3 / etc.   │
└─────────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장 서브시스템과 버전 관리 서브시스템은 &lt;b&gt;독립 API&lt;/b&gt;로도 쓸 수 있습니다. &quot;버전 관리 없이 콘텐츠 주소 저장소만&quot; 필요한 도구도 같은 스택 위에 올릴 수 있다는 점이 확장성의 핵심입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;지금 당장 시도해 볼 수 있는 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows, macOS(ARM64), Linux(x86-64/ARM64)용 바이너리가 제공됩니다. PowerShell에서 데모 모드로 로컬 서버를 띄우는 방법은 다음과 같습니다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;$env:LORE_DEMO=1; irm https://raw.githubusercontent.com/EpicGames/lore/main/scripts/install.ps1 | iex&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 &lt;a href=&quot;https://epicgames.github.io/lore/tutorials/quickstart/&quot;&gt;Quickstart&lt;/a&gt; 가이드를 따라 저장소 생성, 커밋, 브랜치, 동기화까지 10분 안에 체험할 수 있습니다. 질문과 피드백은 &lt;a href=&quot;https://discord.gg/E4SFJKRPbg&quot;&gt;Discord&lt;/a&gt;와 &lt;a href=&quot;https://github.com/EpicGames/lore/issues&quot;&gt;GitHub Issues&lt;/a&gt;로 이어집니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리 &amp;mdash; LORE가 의미하는 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LORE는 &quot;Git을 대체한다&quot;는 단순한 슬로건이 아닙니다. &lt;b&gt;임의의 콘텐츠 타입, 다축 스케일, 멀티 테넌트 안전, 완전 공개 스펙, MIT 라이선스&lt;/b&gt; &amp;mdash; 이 다섯 가지를 동시에 만족하려는 시도입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼 엔진 6 세대에는 이미 UEFN과 쿡 파이프라인에서 LORE의 실전 데이터가 쌓이고 있고, 2027년경 &lt;b&gt;에디터 네이티브 통합&lt;/b&gt;으로 일반 UE 프로젝트까지 영역이 넓어질 예정입니다. 아직 0.x이므로 프로덕션 전면 교체를 서두를 필요는 없지만, 워크플로 프로토타이핑과 커뮤니티 피드백 참여를 통해 &lt;b&gt;차세대 VCS가 어디로 갈지&lt;/b&gt; 함께 그려 갈 시점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 바이너리와 분산 팀을 다루는 스튜디오라면, LORE는 단순한 새 도구가 아니라 &lt;b&gt;엔진&amp;middot;파이프라인&amp;middot;협업 모델을 한 축으로 정렬할 수 있는 인프라&lt;/b&gt;에 가깝습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 링크&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/EpicGames/lore&quot;&gt;LORE GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://epicgames.github.io/lore/&quot;&gt;공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://epicgames.github.io/lore/explanation/system-design/&quot;&gt;시스템 설계 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://epicgames.github.io/lore/faq/&quot;&gt;FAQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://epicgames.github.io/lore/roadmap/&quot;&gt;로드맵&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>UNREAL ENGINE</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/784</guid>
      <comments>https://techartnomad.tistory.com/784#entry784comment</comments>
      <pubDate>Fri, 19 Jun 2026 18:31:57 +0900</pubDate>
    </item>
    <item>
      <title>[번역] RecaNoMaho 처음부터 시작하는 체적광 렌더링</title>
      <link>https://techartnomad.tistory.com/783</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저자: 유클리드 노름&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;【RecaNoMaho】처음부터 시작하는 체적광 렌더링&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bu1bGT/dJMcabxOzi5/EC5ZVrkQ95MMKZxaNCwCq0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bu1bGT/dJMcabxOzi5/EC5ZVrkQ95MMKZxaNCwCq0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bu1bGT/dJMcabxOzi5/EC5ZVrkQ95MMKZxaNCwCq0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbu1bGT%2FdJMcabxOzi5%2FEC5ZVrkQ95MMKZxaNCwCq0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;804&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0 시작하기 전에&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RecaNoMaho는 내가 만들고 있는 오픈소스 Unity URP 프로젝트다. 이 프로젝트 안에는 흔히 볼 수 있는 렌더링 효과, 조금은 별난 효과, 그리고 재미있는 렌더링 기술들을 계속 수록해 나갈 생각이다. 단순히 결과만 보여주는 것이 아니라, 소스 구현과 원리 해설까지 함께 정리해서 이 시리즈가 어느 정도 학습 가치와 참고 의미를 갖도록 하는 것이 목표다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 정도의 이식성, 반복 개발 가능성, 그리고 가벼움을 보장하기 위해, 이 렌더링 효과와 기술을 구현할 때의 첫 번째 원칙은 이렇다. RenderFeature로 쓸 수 있는 것은 최대한 RenderFeature로 쓴다. 그 대가는 있다. 원래 URP 코드를 직접 고치면 아주 편하게 할 수 있는 일도 조금 돌아가야 할 수 있고, 파이프라인 레벨에서 가능한 일부 최적화 포인트를 잃을 수도 있다. 이런 최적화는 실제 프로젝트 실천 과정에서 다시 구현하면 된다. 개인 능력에는 한계가 있으니, 글 안에 틀린 부분이 있거나 더 좋은 생각이 있다면 함께 토론해 주면 좋겠다~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RecaNoMaho 프로젝트 저장소:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/recaeee/RecaNoMaho_P&quot;&gt;https://github.com/recaeee/RecaNoMaho_P&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 사용 중인 Unity 버전: 2022.3.17f1c1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 사용 중인 URP 버전: 14.0.9&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GqNkm/dJMcaiXX0K8/DuV2VS5DjNTYbExsYXMAZ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GqNkm/dJMcaiXX0K8/DuV2VS5DjNTYbExsYXMAZ0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GqNkm/dJMcaiXX0K8/DuV2VS5DjNTYbExsYXMAZ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGqNkm%2FdJMcaiXX0K8%2FDuV2VS5DjNTYbExsYXMAZ0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;804&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지는 현재 RecaNoMaho 안에서 구현한 체적광 렌더링 효과다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1 체적광이란 무엇인가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실 환경에서 우리는 가끔 구름 사이로 빛줄기가 쏟아지는 것을 볼 수 있다. 또 약간의 연무가 있는 무대에서는 스포트라이트 아래에서 마치 &amp;ldquo;부피&amp;rdquo;를 가진 듯한 빛을 볼 수 있다. 이런 현상을 &lt;b&gt;틴들 효과, Tyndall effect&lt;/b&gt;라고 부른다. 틴들 현상, 틴들 효과라고도 하며, 인터넷에서는 온갖 XXX 효과 같은 밈으로도 자주 불린다. 그 원리는 &lt;b&gt;빛이 떠다니는 콜로이드 입자에 의해 산란되는 것&lt;/b&gt;이다. 아래 이미지에서 독일 궁정 주교좌성당 내부에 보이는 빛의 경로는 틴들 효과의 전형적인 예시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;2014&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDVDwE/dJMcabxOzje/JyeGxlkzLiVlAsjSC5SjMk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDVDwE/dJMcabxOzje/JyeGxlkzLiVlAsjSC5SjMk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDVDwE/dJMcabxOzje/JyeGxlkzLiVlAsjSC5SjMk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDVDwE%2FdJMcabxOzje%2FJyeGxlkzLiVlAsjSC5SjMk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;2014&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;2014&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 체적광은 무엇인가? &lt;b&gt;체적광은 3D 컴퓨터 그래픽스에서 렌더링된 장면에 조명 효과를 추가하기 위한 기술&lt;/b&gt;이다. 이 기술을 사용하면 우리는 &amp;ldquo;공간 속의 빛줄기&amp;rdquo;를 볼 수 있다. 렌더링과 게임 분야에서 널리 사용되며, 아래 이미지는 CG 기술 안에서의 체적광 렌더링 효과다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDS5Wh/dJMcaiqbW5T/CvWkk7RbdESoP6usoObYV0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDS5Wh/dJMcaiqbW5T/CvWkk7RbdESoP6usoObYV0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDS5Wh/dJMcaiqbW5T/CvWkk7RbdESoP6usoObYV0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDS5Wh%2FdJMcaiqbW5T%2FCvWkk7RbdESoP6usoObYV0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1366&quot; height=&quot;768&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이렇게 말할 수 있다. &lt;b&gt;체적광은 현실 환경의 틴들 효과를 시뮬레이션하기 위한 CG 기술, 혹은 미세 입자가 빛을 산란시키는 현상을 시뮬레이션하기 위한 기술&lt;/b&gt;이다. 따라서 체적광을 구현하려면 먼저 현실 환경에서 틴들 효과가 왜 생기는지 간단히 이해할 필요가 있다. 아래 설명은 《Real-Time Rendering, Fourth Edition》 14장의 내용을 참고해 최대한 쉽게 풀어쓴 것이다. 관심 있는 사람은 원서를 직접 보는 편이 더 좋다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1.1 틴들 효과의 원인&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 생각해 보자. 틴들 효과에서 우리가 보는 &lt;b&gt;&amp;ldquo;부피&amp;rdquo;를 가진 빛은 대체 무엇인가?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 현실의 여러 물체 표면을 볼 수 있는 이유는, 빛이 물체 표면을 거치거나 물체 표면에서 출발해, 즉 자체 발광해, 반사와 굴절 같은 과정을 거쳐 눈에 들어오기 때문이다. 틴들 효과도 원리는 같다. 다만 차이가 있다면, 빛이 거치는 것이 &amp;ldquo;물체 표면&amp;rdquo;이 아니라 &lt;b&gt;미세 입자로 가득 찬 어떤 매질&lt;/b&gt;, 즉 어떤 영역 혹은 공간이라는 점이다. 이것을 &lt;b&gt;참여 매질, Participating Media&lt;/b&gt;라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빛이 물체 표면을 지날 때 반사와 굴절이 일어나듯이, &lt;b&gt;빛이 참여 매질을 지날 때는 산란과 흡수라는 두 가지 현상이 일어난다&lt;/b&gt;. 더 엄밀하게 말하면 반사와 굴절도 산란의 한 종류라고 볼 수 있다. 우리가 보는 &amp;ldquo;부피 있는 빛&amp;rdquo;의 원인은 바로 이것이다. &lt;b&gt;빛이 참여 매질을 지난 뒤 산란되어 사람 눈에 들어온다.&lt;/b&gt; 이것이 틴들 효과의 원인이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1.2 참여 매질&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;참여 매질&lt;/b&gt;에 대해 이야기해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참여 매질, Participating Media는 입자로 가득 찬 체적을 설명하는 개념이다. 이 매질은 빛의 전달 과정에 참여하며, 다시 말해 산란이나 흡수를 통해 자신을 통과하는 빛에 영향을 준다.&lt;/b&gt; 사실 돌이나 나무 같은 물체 표면도 참여 매질이라고 볼 수 있다. 다만 그것들은 &lt;b&gt;밀도가 매우 높은 참여 매질&lt;/b&gt;이다. 대부분의 빛은 그런 표면을 지날 때 &lt;b&gt;참여 매질 속 입자와 접촉하고 산란&lt;/b&gt;된다. 산란 정도가 매우 높고, 주로 기하 산란에 가깝다. 사람 눈에 보이는 것은 바로 이렇게 대량으로 산란되어 들어오는 빛이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 물, 안개, 수증기 같은 &lt;b&gt;밀도가 낮은 참여 매질&lt;/b&gt;은 전체 입자 수가 적다. 그래서 &lt;b&gt;대부분의 빛&lt;/b&gt;은 매질을 지나도 입자의 영향을 받지 않고 원래 방향으로 계속 나아간다. 오직 &lt;b&gt;일부 빛만 입자의 영향을 받아 산란&lt;/b&gt;된다. 만약 우리가 빛이 오는 방향을 직접 바라보지 않는다면, 대부분의 빛은 거의 눈에 들어오지 않으므로 볼 수 없다. 하지만 &lt;b&gt;분명히 일부 빛은 참여 매질 속 입자에 의해 산란&lt;/b&gt;되고, 이 산란광이 눈에 들어오면 우리는 물, 안개, 수증기 같은 낮은 밀도의 참여 매질 속 빛을 보게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비유하자면 아래 그림과 같다. 왼쪽의 밀도가 큰 참여 매질, 예를 들어 돌이 &lt;b&gt;100%의 빛&lt;/b&gt;을 받는다면, 그중 &lt;b&gt;99.999%의 빛&lt;/b&gt;은 주변 모든 방향으로 산란되고, 아마 &lt;b&gt;0.001%의 빛&lt;/b&gt;만 원래 방향으로 투과될 것이다. 반면 오른쪽의 밀도가 작은 참여 매질, 예를 들어 구름이나 안개가 &lt;b&gt;100%의 빛&lt;/b&gt;을 받는다면, 그중 &lt;b&gt;70%의 빛&lt;/b&gt;은 원래 방향으로 투과되고, 동시에 &lt;b&gt;30%의 빛&lt;/b&gt;이 다른 방향으로 산란된다. 이 산란된 빛이 눈에 들어오면, 우리는 구름이나 안개 속의 &lt;b&gt;틴들 효과&lt;/b&gt;를 보게 된다. 여기서 좌우 그림의 산란광 편향량 차이에 너무 신경 쓸 필요는 없다. 지금 단계에서는 빛의 투과와 산란 비율만 생각하면 된다. 그림에서 매질에 따라 산란광의 편향량을 다르게 그린 것은, 뒤에서 매질 입자가 산란 방향에 어떤 영향을 주는지 직관적으로 설명하기 위한 밑밥 정도라고 보면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zwCZL/dJMcaf1hbH5/RV6i9eS0LvWviueUzIYtNK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zwCZL/dJMcaf1hbH5/RV6i9eS0LvWviueUzIYtNK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zwCZL/dJMcaf1hbH5/RV6i9eS0LvWviueUzIYtNK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzwCZL%2FdJMcaf1hbH5%2FRV6i9eS0LvWviueUzIYtNK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;642&quot; height=&quot;300&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 우리는 참여 매질이 무엇인지, 그리고 밀도가 다른 참여 매질이 빛을 서로 다른 정도로 산란시킨다는 것을 알았다. 여기에 한 가지를 더 덧붙이자. 사람이 일반적으로 보는 틴들 효과는 두 종류의 빛을 포함한다고 볼 수 있다. 하나는 위에서 말한 &lt;b&gt;광원이 낮은 밀도의 참여 매질을 지나며 산란된 빛&lt;/b&gt;이다. 우리가 예쁘다고 느끼는 바로 그 빛줄기다. 다른 하나는 &lt;b&gt;시선 뒤쪽에 있는 다른 참여 매질 혹은 물체 표면에서 나온 빛이 참여 매질을 투과해 들어온 것&lt;/b&gt;이다. 즉 틴들 효과 너머로 보이는 물체 표면, 예를 들어 구름 뒤의 산 같은 것이다. 아래 그림이 이 관계를 보여준다. 낮은 밀도 참여 매질은 입자 수가 적기 때문에 산란되는 빛의 총량이 적고, 그래서 우리는 그 뒤의 물체도 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;261&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCXWQ6/dJMcaiqbW5L/BeLRYEebj1jC1IqfwOPv9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCXWQ6/dJMcaiqbW5L/BeLRYEebj1jC1IqfwOPv9k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCXWQ6/dJMcaiqbW5L/BeLRYEebj1jC1IqfwOPv9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCXWQ6%2FdJMcaiqbW5L%2FBeLRYEebj1jC1IqfwOPv9k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;502&quot; height=&quot;261&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;261&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1.3 빛의 산란과 흡수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋다. 참여 매질 이야기를 했으니 이제 &lt;b&gt;빛의 산란과 흡수&lt;/b&gt;를 이야기해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빛이 매질을 통과하다가 매질 속 입자에 의해 반사되는 사건을 보통 Light Scattering, 즉 빛의 산란이라고 부른다.&lt;/b&gt; 여기서 말하는 반사는 출사 방향과 입사 방향 사이의 각도가 반드시 커야 한다는 뜻은 아니다. 어떤 각도로든 출사될 수 있고, 그것을 반사 혹은 산란으로 볼 수 있다. &lt;b&gt;모든 것은 산란을 일으킨다.&lt;/b&gt; 일반적인 의미의 표면 반사와 굴절도 모두 빛의 산란에 속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빛의 산란 원리를 자세히 이야기하려면 사실 매우 복잡하다. 하지만 체적광 렌더링에서는 그렇게까지 많이 알 필요는 없다. 우리는 이것만 알면 된다. &lt;b&gt;빛이 참여 매질 안의 아주 작은 영역을 지날 때, 일정 확률로 원래 방향과 다른 방향으로 산란된다.&lt;/b&gt; 이것이 바로 &lt;b&gt;체적광을 지탱하는 이론적 기반&lt;/b&gt;이다. 정량 모델, 즉 각 방향으로 얼마나 많은 빛이 산란되는지를 어떻게 정의하는지, 어떤 파라미터가 영향을 주는지는 2장에서 다시 이야기하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참여 매질 속 입자가 대체 어떤 방식으로 빛을 꺾는지까지는 깊게 알 필요가 없다. 물론 관심 있는 사람은 RTR4의 9장을 따로 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 우리는 이것도 알아야 한다. &lt;b&gt;빛, 혹은 광자는 참여 매질을 지날 때 일부가 흡수되어 열이나 다른 형태의 에너지로 전환된다.&lt;/b&gt; 이것 역시 체적광 렌더링에서 &lt;b&gt;고려해야 하는 요소&lt;/b&gt;다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1.4 산란에 영향을 주는 요소&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 우리는 현실에서 틴들 효과를 가끔, 혹은 특정 환경에서만 볼 수 있을까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 어떤 상황에서 틴들 효과를 보기 쉬운지 생각해 보자. 먼지가 가득한 교회, 아침 안개가 낀 숲, 비가 막 그친 뒤 맑아진 하늘. 이런 환경의 공통점은 &lt;b&gt;참여 매질의 밀도가 어느 정도에 도달했다는 것&lt;/b&gt;이다. 즉 &lt;b&gt;참여 매질의 밀도가 클수록 그 안의 입자가 많고, 입자가 많을수록 더 많은 산란이 일어난다. 산란 정도가 더 강해진다고 말할 수도 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 &lt;b&gt;참여 매질 속 단일 입자의 크기도 산란에 영향을 준다.&lt;/b&gt; 빛이 참여 매질 속 단일 입자를 지날 때, &lt;b&gt;각 방향으로 산란될 확률은 입자 반경과 관련이 있다.&lt;/b&gt; 이것이 뒤에서 말할 Phase Function이다. 직관적으로는 이해하기 조금 어려운 부분이지만, 실제로 체적광 렌더링에서 중요한 파라미터다. 현실의 틴들 효과는 물, 구름, 안개, 먼지 낀 방 등 여러 참여 매질에서 생길 수 있다. 모두 틴들 효과라고 부르지만, 실제 현상은 조금씩 다르다. 그 이유 중 하나가 바로 &lt;b&gt;각 장면의 참여 매질 입자가 다르고, 따라서 입자 반경도 다르기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 하나, &lt;b&gt;입사광의 파장도 산란에 영향을 준다.&lt;/b&gt; 파장이 짧은 빛일수록 더 쉽게 산란된다. 파란색 빛은 파장이 짧기 때문에 더 쉽게 산란되며, 이것이 하늘이 파란 이유 중 하나다. 하지만 실시간 렌더링 분야에서는 &lt;b&gt;이 요소를 거의 고려하지 않는 편&lt;/b&gt;이다. 물리 시뮬레이션을 매우 엄밀하게 해야 하는 경우, 예를 들어 대기 렌더링의 Rayleigh Scattering 같은 경우가 아니라면 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면, &lt;b&gt;체적광 렌더링에 반드시 필요한 산란 영향 요소는 주로 두 가지&lt;/b&gt;다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;참여 매질 밀도&lt;/b&gt;: 밀도가 클수록 산란을 일으키는 입자가 많고, 산란 정도가 강해진다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참여 매질을 구성하는 입자의 반경&lt;/b&gt;: 입자 반경이 다르면 각 방향으로 산란될 확률도 달라진다. 이를 통해 물속 체적광, 연기 속 체적광 같은 서로 다른 환경을 구분할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은, &lt;b&gt;빛의 파장이 산란에 미치는 영향은 여기서는 무시한다&lt;/b&gt;는 것이다. 실시간 렌더링 환경에서 이 요소까지 고려하면 복잡도가 꽤 높아진다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2 체적광의 정량 모델&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.1 빛의 전파와 매질 통과에 영향을 주는 4가지 사건&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1절에서 우리는 틴들 효과의 원인이, 빛이 참여 매질을 지난 뒤 &lt;b&gt;산란&lt;/b&gt;되어 눈에 들어오는 것임을 알았다. 그리고 &lt;b&gt;정성적으로&lt;/b&gt; 참여 매질이 빛의 산란에 어떤 영향을 주는지도 설명했다. 이제는 &lt;b&gt;체적광의 정량 모델&lt;/b&gt; 차례다. 말하자면 &lt;b&gt;물리 법칙을 수학 공식으로 바꾸고&lt;/b&gt;, 이후 렌더링 실천에서는 그 수학 공식을 다시 코드로 바꾸는 단계다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 절 역시 《Real-Time Rendering, Fourth Edition》을 참고한다. 먼저 우리는 실시간 렌더링에서 3D 모델을 렌더링할 때, 예를 들어 PBR에서는 보통 빛이 광원에서 출발해 물체 표면에 닿고, 반사되어 카메라의 각 픽셀에 들어오는 RGB 값을 계산한다. 원서 표현을 빌리면 더 엄밀하게는 &lt;b&gt;표면 셰이딩 지점에서 카메라 위치까지의 radiance를 계산&lt;/b&gt;하는 것이다. 체적광 렌더링도 비슷하다. 우리는 &lt;b&gt;빛이 광원에서 출발해 참여 매질에 닿고, 그 뒤 산란되어 카메라의 각 픽셀로 들어오는 RGB 값&lt;/b&gt;을 계산해야 한다. 더 엄밀하게 말하면 &lt;b&gt;빛이 참여 매질을 통과해 카메라 위치까지 전파되는 경로상의 radiance&lt;/b&gt;를 계산해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 문제는 이 radiance를 어떻게 계산하느냐다. 답은 원서를 참고하면 된다. 여기서는 &lt;b&gt;단일 산란만 고려&lt;/b&gt;한다. 관심 있는 사람은 원서 14.1.1절을 직접 보면 좋다. 지면 관계상 여기서는 개괄 위주로 설명한다. 원서가 훨씬 더 자세하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;매질을 따라 전파되는 radiance에 영향을 줄 수 있는 사건은 4종류가 있다.&lt;/b&gt; 아래 그림은 이 함수들의 도식적 설명이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxGSPq/dJMcabxOzi6/FDcW8tSoTvZ3cGrYOxCZKK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxGSPq/dJMcabxOzi6/FDcW8tSoTvZ3cGrYOxCZKK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxGSPq/dJMcabxOzi6/FDcW8tSoTvZ3cGrYOxCZKK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxGSPq%2FdJMcabxOzi6%2FFDcW8tSoTvZ3cGrYOxCZKK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1036&quot; height=&quot;315&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약하면 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;흡수 Absorption&lt;/b&gt; &amp;mdash; 광자가 매질에 흡수되어 열이나 다른 형태의 에너지로 전환된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외산란 Out-scattering&lt;/b&gt; &amp;mdash; 광자가 매질 속 입자에 의해 튕겨 나가 현재 경로 밖으로 산란된다. 이 사건이 일어날 확률은 빛의 반사 방향 분포를 설명하는 Phase Function에 의해 결정된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;발광 Emission&lt;/b&gt; &amp;mdash; 매질이 높은 온도에 도달했을 때, 예를 들어 화염의 흑체 복사처럼 매질에서 빛을 방출할 수 있다. 보통 렌더링에서는 이 부분을 고려하지 않아도 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내산란 In-scattering&lt;/b&gt; &amp;mdash; 어떤 방향에서 온 광자든, 매질 입자에 의해 튕긴 뒤 현재 광로 안으로 산란되어 최종 radiance에 기여할 수 있다. 주어진 방향으로 얼마나 많은 빛이 내산란되는지도 해당 빛 방향의 Phase Function에 의해 결정된다. 외산란과 대응되는 개념이라고 보면 어렵지 않다. 현재 경로에서 빛이 밖으로 산란될 수 있다면, 당연히 다른 경로의 빛도 현재 경로 안으로 산란될 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 네 가지 사건을 기준으로 보면, 어떤 경로에 광자를 더하는 것은 &lt;b&gt;내산란과 발광, 보통은 무시 가능, 의 함수&lt;/b&gt;다. 즉 광로상의 RGB 값을 증가시키는 항이다. 반대로 광자를 제거하는 것은 &lt;b&gt;Extinction, 소광 계수의 함수&lt;/b&gt;이며, 이는 흡수와 외산란을 대표한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.2 최종 RGB 값을 어떻게 계산할 것인가&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체적광 렌더링에서 &lt;b&gt;최종 radiance&lt;/b&gt;, 즉 카메라의 한 픽셀 RGB 값은 두 부분으로 이루어진다. 하나는 &lt;b&gt;물체 표면에서 반사된 빛이 매질을 지나 카메라 위치까지 도달한 radiance&lt;/b&gt;이고, 다른 하나는 &lt;b&gt;정확한 광원에서 온 산란광이 매질을 지나 카메라 위치까지 도달한 radiance&lt;/b&gt;다. 공식은 아래와 같다. 보기에는 복잡하지만, 사실 이해 자체는 그렇게 어렵지 않다. 수학 공식이라는 게 정말 간결하고 추상적이라 감탄이 나올 정도다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d433ea/dJMcaf1hbH7/zAEEjg7hXMhVDJmVeRS0t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d433ea/dJMcaf1hbH7/zAEEjg7hXMhVDJmVeRS0t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d433ea/dJMcaf1hbH7/zAEEjg7hXMhVDJmVeRS0t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd433ea%2FdJMcaf1hbH7%2FzAEEjg7hXMhVDJmVeRS0t1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;162&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 말했듯이, 앞의 항은 관찰 방향의 반대 방향에서 물체 표면이 반사한 빛이 매질을 지나 카메라 위치까지 도달한 radiance다. 뒤의 항은 관찰 방향의 반대 방향에서 정확한 광원으로부터 산란된 빛이 매질을 지나 카메라 위치까지 도달한 radiance다. 여기서 T는 주어진 점과 카메라 위치 사이의 &lt;b&gt;투과율&lt;/b&gt;이고, Lscat은 &lt;b&gt;관찰 광선을 따라 주어진 점 x에서 산란된 빛&lt;/b&gt;이다. 공식의 각 계산 부분은 아래 그림처럼 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;587&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/defcNr/dJMcaiqbW5Q/8sMaNwk5XpYrfTnmDyvh10/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/defcNr/dJMcaiqbW5Q/8sMaNwk5XpYrfTnmDyvh10/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/defcNr/dJMcaiqbW5Q/8sMaNwk5XpYrfTnmDyvh10/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdefcNr%2FdJMcaiqbW5Q%2F8sMaNwk5XpYrfTnmDyvh10%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1060&quot; height=&quot;587&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;587&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 공식에 들어가는 관련 개념을 간단히 이야기하겠다. 이 개념들은 코드 구현에서도 중요한 파라미터다. 지면도 제한되어 있고, 나 자신의 이해도 제한되어 있으며, 내용 자체도 꽤 난해해서 설명하기 쉽지 않다. 부족한 부분은 양해 바란다. 더 자세한 내용은 원서를 참고하면 좋다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.3 투과율&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;투과율은 빛이 일정 거리 안에서 매질을 통과할 수 있는 비율&lt;/b&gt;을 의미한다. 쉽게 말하면, 빛은 매질을 지날 때 거리에 따라 감쇠한다. 수학적 정의는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;489&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x2DZV/dJMcaiXX0K1/lfXmdbosoXEiykJMFENBS0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x2DZV/dJMcaiXX0K1/lfXmdbosoXEiykJMFENBS0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x2DZV/dJMcaiXX0K1/lfXmdbosoXEiykJMFENBS0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx2DZV%2FdJMcaiXX0K1%2FlfXmdbosoXEiykJMFENBS0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;489&quot; height=&quot;89&quot; data-origin-width=&quot;489&quot; data-origin-height=&quot;89&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 관계는 &lt;b&gt;Beer-Lambert 법칙&lt;/b&gt;이라고도 부른다. 식 안의 Optical Depth, 광학 깊이는 단위가 없으며 빛의 감쇠량을 나타낸다. &lt;b&gt;Extinction, 소광 계수&lt;/b&gt;나 전파 &lt;b&gt;거리&lt;/b&gt;가 커질수록 광학 깊이도 커진다. 이는 매질을 통과하는 빛이 줄어든다는 뜻이다. 앞에서 말했듯이, &lt;b&gt;투과율은 흡수와 외산란의 영향을 동시에 받는다&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTmYCt/dJMcabxOzi9/8Ua6RL4NO799FfK4DsF3G1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTmYCt/dJMcabxOzi9/8Ua6RL4NO799FfK4DsF3G1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTmYCt/dJMcabxOzi9/8Ua6RL4NO799FfK4DsF3G1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTmYCt%2FdJMcabxOzi9%2F8Ua6RL4NO799FfK4DsF3G1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;832&quot; height=&quot;453&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;453&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.4 산란 사건&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장면 안의 &lt;b&gt;주어진 위치 x, 즉 Ray Marching 샘플 지점과 방향 v, 즉 관찰 방향의 반대 방향&lt;/b&gt;에 대해, 정확한 광원의 내산란 사건은 다음과 같이 적분할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WNsBI/dJMcaiXX0K2/6H1p6kHwguOnsAW0dwGWX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WNsBI/dJMcaiXX0K2/6H1p6kHwguOnsAW0dwGWX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WNsBI/dJMcaiXX0K2/6H1p6kHwguOnsAW0dwGWX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWNsBI%2FdJMcaiXX0K2%2F6H1p6kHwguOnsAW0dwGWX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;666&quot; height=&quot;89&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;89&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식에서 l은 광원의 수, p는 Phase Function, V는 Visibility Function, wi는 i번째 광원의 방향 벡터, pi는 i번째 광원의 위치다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보기에는 복잡하지만 사실 간단하다. 단일 광원만 고려한다면, &lt;b&gt;공간의 한 점에서의 내산란 강도는 Phase Function, 즉 특정 방향으로 산란될 확률, 광원이 그 점에서 보이는지 여부, 즉 그림자와 매질 체적 감쇠, 그리고 광원에서 그 점까지 오는 radiance의 거리 감쇠와 관련 있다&lt;/b&gt;고 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Visibility Function은 광원 위치에서 나온 빛이 최종적으로 위치 x에 도달하는 비율&lt;/b&gt;을 나타낸다. 수학적 형태는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;56&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zP33w/dJMcabxOzi4/YLKbjDRWosfFeRwfY8InjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zP33w/dJMcabxOzi4/YLKbjDRWosfFeRwfY8InjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zP33w/dJMcabxOzi4/YLKbjDRWosfFeRwfY8InjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzP33w%2FdJMcabxOzi4%2FYLKbjDRWosfFeRwfY8InjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;665&quot; height=&quot;56&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;56&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ShadowMap은 이해하기 쉽다. 해당 점이 그림자 안에 있는지 아닌지를 뜻한다. &lt;b&gt;volShad, 체적 그림자 항&lt;/b&gt;은 광원 위치에서 샘플 지점까지의 &lt;b&gt;투과율&lt;/b&gt;을 의미한다. 2.3절에서 이야기한 흡수와 외산란 사건에 해당한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.5 Phase Function&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 마지막 이론 부분이다. 힘내자!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.4절에서 말했듯이, 참여 매질 속 단일 입자의 크기도 산란에 영향을 준다. 빛이 참여 매질 속 단일 입자를 지날 때, &lt;b&gt;서로 다른 방향으로 산란될 확률은 입자 반경과 관련이 있다.&lt;/b&gt; 즉 &lt;b&gt;입자 크기는 주어진 방향으로 빛이 산란될 확률에 영향을 준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내산란 사건을 평가할 때는 Phase Function을 사용할 수 있다. 이는 거시적인 관점에서 산란 방향의 확률 분포를 설명하는 함수다. 다시 말해, &lt;b&gt;하나의 입자에 대해 입사 방향이 주어졌을 때, 출사 방향이 모든 방향에 대해 어떤 확률 분포를 갖는지 정의하는 함수&lt;/b&gt;다. 이 함수는 단위 구 위에서 적분했을 때 반드시 1이 되어야 한다. 아래 그림은 이 개념을 보여준다. 이해하기 쉽다. 여기서 &amp;theta;는 빛의 전방 진행 경로, 파란색과 외산란 방향, 초록색 사이의 각도를 뜻한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buRfBu/dJMcabxOzjb/dcuY14SejKeiLfgLg6e4Q1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buRfBu/dJMcabxOzjb/dcuY14SejKeiLfgLg6e4Q1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buRfBu/dJMcabxOzjb/dcuY14SejKeiLfgLg6e4Q1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuRfBu%2FdJMcabxOzjb%2FdcuY14SejKeiLfgLg6e4Q1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1060&quot; height=&quot;252&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물리적인 이유 때문에, &lt;b&gt;서로 다른 크기 스케일&lt;/b&gt;의 입자 반경에 따라 Phase Function은 크게 달라진다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;빛의 파장에 비해 매우 작은 입자는 &lt;b&gt;Rayleigh Scattering&lt;/b&gt;을 일으킨다. 예를 들면 공기다.&lt;/li&gt;
&lt;li&gt;상대 크기가 1에 가까운 입자는 &lt;b&gt;Mie Scattering&lt;/b&gt;을 일으킨다. 흔한 예로 안개 속 스포트라이트, 태양 방향의 구름 등이 있다. 이것이 바로 &lt;b&gt;체적광에 대응하는 Phase Function&lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;입자 크기가 빛의 파장보다 명확히 크면 &lt;b&gt;기하 산란&lt;/b&gt;이 일어난다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체적광 렌더링에서는 Mie Scattering의 Phase Function이 필요하다. 물리학자들의 연구 덕분에, &lt;b&gt;Mie Scattering을 설명하는 데 자주 쓰이는 Phase Function 중 하나가 Henyey-Greenstein, HG Phase Function&lt;/b&gt;이다. 연기, 안개, 먼지 같은 참여 매질을 표현하는 데 사용할 수 있다. HG 함수의 수학적 형태는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;483&quot; data-origin-height=&quot;129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0YZGd/dJMcab5GrS0/bGULEFbD0b7Wr9fDkRQd0k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0YZGd/dJMcab5GrS0/bGULEFbD0b7Wr9fDkRQd0k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0YZGd/dJMcab5GrS0/bGULEFbD0b7Wr9fDkRQd0k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0YZGd%2FdJMcab5GrS0%2FbGULEFbD0b7Wr9fDkRQd0k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;483&quot; height=&quot;129&quot; data-origin-width=&quot;483&quot; data-origin-height=&quot;129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &amp;theta;는 입사광과 출사광 사이의 각도다. 파라미터 g는 [-1, 1] 범위의 값이며, 전방 산란과 후방 산란의 비율을 제어한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수의 그래프는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edXHdz/dJMcabxOzi7/D6pgL43BuzARkNX0MehlW0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edXHdz/dJMcabxOzi7/D6pgL43BuzARkNX0MehlW0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edXHdz/dJMcabxOzi7/D6pgL43BuzARkNX0MehlW0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedXHdz%2FdJMcabxOzi7%2FD6pgL43BuzARkNX0MehlW0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;692&quot; height=&quot;362&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 HG 함수와 비슷한 결과를 내지만 더 빠른 근사 Phase Function인 Schlick Phase Function도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;123&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvsvv7/dJMcaiXX0K5/hiZVa2vDzBJgUo4Lwf9km1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvsvv7/dJMcaiXX0K5/hiZVa2vDzBJgUo4Lwf9km1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvsvv7/dJMcaiXX0K5/hiZVa2vDzBJgUo4Lwf9km1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbvsvv7%2FdJMcaiXX0K5%2FhiZVa2vDzBJgUo4Lwf9km1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;664&quot; height=&quot;123&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;123&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OK, 이론 부분이 드디어 끝났다. 사실 복잡하다고 하면 복잡하고, 안 복잡하다고 하면 또 안 복잡하다. 이 부분은 설명하기 꽤 어려운 구간이고, 간결함과 자세함 사이의 균형을 맞춰야 한다. 설명이 부족했다면 양해 바란다. 시간이 더 있다면 RTR4 14장을 읽어보는 것을 추천한다. 이제 실전으로 들어가자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3 RecaNoMaho 체적광 실전&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용을 읽었거나 《Real-Time Rendering, Fourth Edition》 14장 &amp;ldquo;Volume and Translucency Rendering&amp;rdquo;의 Light Scattering 이론 부분을 읽었다면, 이제 틴들 효과의 원인, 체적광의 정성적 모델과 정량적 모델, 즉 &lt;b&gt;체적광의 이론 부분&lt;/b&gt;을 대략 이해했을 것이다. 이제 Unity URP에서 체적광을 어떻게 구현하는지 실천해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실패 확률을 줄이고, 렌더링 효과가 빠르게 나오는 즐거움을 얻기 위해, 일단 머릿속에서 꿈틀거리는 여러 아이디어는 잠시 접어두자. 먼저 인터넷에 이미 공개된 고수들의 성공 사례를 참고하는 편이 좋다. 이론 모델을 알고 있다면 처음부터 체적광을 직접 구현하는 것도 대체로 가능하긴 하다. 하지만 분명 많은坑을 밟을 것이다. 물론 한 번 직접 해 보면 체적광에 대한 이해는 훨씬 깊어지겠지만, 그 대가는 더 많은 시간과 에너지, 그리고 벽에 부딪힌 뒤 포기할 가능성이다. 그래서 개인적으로는 10일 동안 처음부터 혼자 들이받기보다는, 잠깐 바보가 된 셈 치고 고수들이 공유한 실천을 먼저 참고하는 편이 낫다고 생각한다. 현자가 걸어간 길을 따라 걷는 것이다. 게다가 남의 실천을 참고한 뒤에도, 우리는 얼마든지 자기 아이디어를 계속 열어갈 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RecaNoMaho에서는 &lt;b&gt;URP&lt;/b&gt;를 렌더링 파이프라인으로 사용하며, RenderFeature 형태로 체적광 렌더링을 구현했다. 덕분에 쉽게 이식하고 사용할 수 있다. 이번 실전의 대부분 코드는 SardineFish 님의 글 《Unity에서 체적광 렌더링 구현하기》를 참고했다. 아낌없이 공유해 주신 것에 감사드린다. 해당 작성자는 《Real-Time Rendering, Fourth Edition》 14장과 GDC 2016의 《Low Complexity, High Fidelity - INSIDE Rendering》 발표를 주로 참고해 체적광 구현을 완성했다. 또한 그 코드는 작성자가 직접 SRP 기반으로 구현한 파이프라인 안에 들어 있다. 그래서 현재 내 코드의 상당 부분은 그 내용을 URP 파이프라인으로 이식한 것에 가깝다. 다시 한 번 공유에 감사드리며, 앞으로도 더 많은 자료를 참고해 RecaNoMaho의 체적광을 계속 보완하고 개선할 생각이다. 원 작성자의 효과 이미지는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t1mPj/dJMcabxOzja/5zgYIc6o7kF4eYZiWFq9G0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t1mPj/dJMcabxOzja/5zgYIc6o7kF4eYZiWFq9G0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t1mPj/dJMcabxOzja/5zgYIc6o7kF4eYZiWFq9G0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft1mPj%2FdJMcabxOzja%2F5zgYIc6o7kF4eYZiWFq9G0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;745&quot; height=&quot;420&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RecaNoMaho에서 체적광을 초보적으로 구현한 뒤의 효과는 아래와 같다. 4회 샘플링이고, 후처리 같은 추가 최적화는 없다. 개인적으로 이런 입자감이 꽤 마음에 들어서 노이즈를 일부 제거하긴 했지만, 여전히 일부는 남겨 두었다. 그래야 네가 렌더링하고 있는 게 체적광이라는 걸 알 수 있으니까, bushi.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Iak8Q/dJMcaiXX0K6/ELEo2mtS7ReKy4bRPf2Bs0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Iak8Q/dJMcaiXX0K6/ELEo2mtS7ReKy4bRPf2Bs0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Iak8Q/dJMcaiXX0K6/ELEo2mtS7ReKy4bRPf2Bs0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIak8Q%2FdJMcaiXX0K6%2FELEo2mtS7ReKy4bRPf2Bs0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;744&quot; height=&quot;416&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샘플 횟수를 늘리면 아래와 같은 렌더링 결과가 나온다. 물론 따라오는 대가는 성능이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhQUn0/dJMcaiqbW5O/1lN3J4QUzezaqGTcGGpxt1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhQUn0/dJMcaiqbW5O/1lN3J4QUzezaqGTcGGpxt1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhQUn0/dJMcaiqbW5O/1lN3J4QUzezaqGTcGGpxt1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhQUn0%2FdJMcaiqbW5O%2F1lN3J4QUzezaqGTcGGpxt1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;800&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실전에서 중요한 몇 가지 포인트를 이야기하겠다. 자세한 내용은 RecaNoMaho 소스 코드를 직접 참고하면 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.1 Ray Marching 기반 체적광 렌더링&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체적광의 실시간 렌더링은 현재 업계에 이미 &lt;b&gt;다양한 구현 방식&lt;/b&gt;이 있다. 예를 들면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현은 매우 간단하고 성능도 매우 좋지만, 효과가 많이 제한되는 &lt;b&gt;Billboard 기반 &amp;ldquo;가짜&amp;rdquo; 체적광&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbzZfI/dJMcaiqbW5N/NXxt4nwpwsGBe5rFyQXKcK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbzZfI/dJMcaiqbW5N/NXxt4nwpwsGBe5rFyQXKcK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbzZfI/dJMcaiqbW5N/NXxt4nwpwsGBe5rFyQXKcK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbzZfI%2FdJMcaiqbW5N%2FNXxt4nwpwsGBe5rFyQXKcK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;557&quot; height=&quot;554&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 성능은 좋지만 적용 범위가 좁은 &lt;b&gt;후처리 기반 Radial Blur 체적광&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzNiMS/dJMcaiXX0K4/C7NnzwuKrDRRlzGfY26MKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzNiMS/dJMcaiXX0K4/C7NnzwuKrDRRlzGfY26MKk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzNiMS/dJMcaiXX0K4/C7NnzwuKrDRRlzGfY26MKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzNiMS%2FdJMcaiXX0K4%2FC7NnzwuKrDRRlzGfY26MKk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;358&quot; height=&quot;270&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;Volume Rendering 기반 체적광&lt;/b&gt;도 있다. 예를 들어 Voxel Volume 기반 체적 안개 같은 구현이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 이번 절의 주인공인 &lt;b&gt;Ray Marching 기반 체적광&lt;/b&gt;이 있다. 효과가 비교적 좋고, 적용 범위도 넓은 체적광 구현 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실시간 렌더링에서는 보통 &lt;b&gt;Ray Marching, 즉 광선步进&lt;/b&gt; 방식으로 체적광을 구현한다. &lt;b&gt;광로 위의 여러步进 샘플 지점을 샘플링함으로써 산란광과 올바른 투과율을 적분&lt;/b&gt;하는 것이다. 이는 2.2, 2.3, 2.4절에서 설명한 계산식에 해당한다. Ray Marching 기반 체적광 렌더링의 도식은 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FlcTO/dJMcaf1hbH6/1KRzkwqBlXPrQg70NxGkwK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FlcTO/dJMcaf1hbH6/1KRzkwqBlXPrQg70NxGkwK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FlcTO/dJMcaf1hbH6/1KRzkwqBlXPrQg70NxGkwK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFlcTO%2FdJMcaf1hbH6%2F1KRzkwqBlXPrQg70NxGkwK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;342&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;《Unity에서 체적광 렌더링 구현하기》에서는 실시간 Ray Marching의 비용이 매우 크기 때문에 &lt;b&gt;모델을 단순화할 수 있다&lt;/b&gt;고 말한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;광원에서 매질로 입사하는 경로의 Transmittance 적분을 생략한다.&lt;/li&gt;
&lt;li&gt;입사광이 지나간 거리와 매질의 평균 감쇠율을 추정한다. 즉 균일 매질을 가정한다.&lt;/li&gt;
&lt;li&gt;효과 필요에 따라 그림자를 고려할지 결정한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체적광에서 &lt;b&gt;광로상의 산란광을 적분하는 과정&lt;/b&gt;은 기본적으로 아래 코드처럼 표현할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 관찰 방향 ray. near에서 far까지 Ray Marching으로 산란광을 샘플링하고 적분한다.
float3 scattering(float3 ray, float near, float far, out float3 transmittance)
{
    transmittance = 1;
    float3 totalLight = 0;
    float stepSize = (far - near) / _Steps;

    // [UNITY_LOOP]
    for (int i = 1; i &amp;lt;= _Steps; i++)
    {
        float3 pos = _WorldSpaceCameraPos + ray * (near + stepSize * i);

        // 시점에서 매질 내부 x 지점까지의 투과율.
        // 여러 번 적분하는 대신 누적으로 곱해 계산한다.
        transmittance *= exp(-stepSize * extinctionAt(pos));

        float3 lightDir;

        // 산란광 = 매질 내부 x에서 시점까지의 투과율
        //        * 광원에서 매질 내부 x까지 도달한 산란광
        //        * step 가중치
        //        * 매질 내부 x에서 시점 방향으로의 Phase Function
        //          (입자 지름이 산란 방향에 주는 영향)
        totalLight += transmittance * lightAt(pos, lightDir) * stepSize * Phase(lightDir, -ray);
    }

    return totalLight;
}

// 매질 내부 x 지점에서 받은 빛 RGB와, x에서 광원으로 향하는 방향을 반환한다.
float3 lightAt(float3 pos, out float3 lightDir)
{
    // _LightPosition.w = 1이면 SpotLight
    lightDir = normalize(_LightPosition.xyz - pos * _LightPosition.w);
    float lightDistance = lerp(_DirLightDistance, distance(_LightPosition.xyz, pos), _LightPosition.w);

    // 매질 내부 x 지점에서 시점까지의 소광 계수.
    // 여러 번 적분하는 대신 누적으로 곱해 계산한다.
    float transmittance = lerp(1, exp(-lightDistance * extinctionAt(pos)), _IncomingLoss);

    float3 lightColor = _LightColor.rgb;

    // 광원 방향과 픽셀에서 광원으로 향하는 방향 사이의 각도에 따른 에너지 손실을 고려한다.
    lightColor *= step(_LightCosHalfAngle, dot(lightDir, _LightDirection.xyz));

    // 그림자를 고려한다.
    lightColor *= shadowAt(pos);

    // 투과율에 의한 감쇠.
    lightColor *= transmittance;

    // 산란 계수 = 소광 계수 - 흡수 계수.
    // 여기서는 파라미터를 비율로 단순화하여, 산란 계수 = 소광 계수 * (1 - _Absorption)으로 둔다.
    lightColor *= extinctionAt(pos, _BrightIntensity) * (1 - _Absorption);

    return lightColor;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;extinctionAt&lt;/b&gt;은 2.1절에서 말한 소광 계수다. 즉 &lt;b&gt;흡수와 외산란 사건이 현재 광로상의 산란광에 주는 손실&lt;/b&gt;을 의미한다. 이것은 균일 매질이라면 상수값으로 표현할 수 있고, 아니면 3D Texture를 샘플링할 수도 있다. &lt;b&gt;Phase Function&lt;/b&gt;은 2.5절에 대응하며, HG 함수나 Schlick 함수 같은 서로 다른 모델을 사용할 수 있다. &lt;b&gt;shadowAt&lt;/b&gt;은 ShadowMap을 샘플링해 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원 글에서는 시점에서 매질 내부 x 지점까지의 투과율 계산을 &lt;b&gt;누적 곱 방식으로 처리해 여러 번의 적분 계산을 피할 수 있다&lt;/b&gt;고 설명한다. 즉 지수 부분을 곱셈 항으로 쪼개는 방식이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.2 Ray Marching의 시작점과 끝점 정하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면, 우리는 &lt;b&gt;관찰 광선의 near 깊이부터 Ray Marching을 시작해 far 깊이까지 계산&lt;/b&gt;한다. 실제 장면을 생각해 보자. 예를 들어 스포트라이트가 비추는 장면에서, 스포트라이트가 비추는 범위 자체는 하나의 원뿔이다. 만약 카메라부터 바로 샘플링을 시작하면, 샘플 지점이 스포트라이트 원뿔 밖에 놓이기 쉽다. 그러면 해당 샘플 지점의 조명 결과는 당연히 0이다. 광원에서 그 지점으로 들어오는 빛이 처음부터 0이기 때문이다. 이렇게 되면 많은 샘플 지점이 무효가 되고, 성능만 낭비하며 최종 효과도 좋지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 첫 번째로 흔한 최적화 포인트는 &lt;b&gt;더 정확한 Ray Marching 시작점과 끝점, 즉 코드의 near와 far를 정하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스포트라이트의 원뿔 범위를 예로 들면, 우리는 &lt;b&gt;관찰 광선이 원뿔 범위에 들어가는 시작점과, 원뿔 범위를 빠져나가는 끝점&lt;/b&gt;만 계산하면 된다. 이 구간에서만 Ray Marching하면 충분하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원 글에서는 &lt;b&gt;투영 행렬을 기반으로 투영 평두체 6개 평면을 빠르게 얻는 방법&lt;/b&gt;을 소개한다. 이를 사용하면 &lt;b&gt;스포트라이트의 조사 범위 평두체&lt;/b&gt;, 주의할 점은 원뿔이 아니라 평두체라는 것, 를 빠르게 계산할 수 있다. 참고 문헌은 《Fast Extraction of Viewing Frustum Planes from the WorldView-Projection Matrix》다. 구체 원리는 여기서 펼치지 않겠다. SardineFish 님의 글에서 이 방법의 사고방식을 간단히 소개하고 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.3 노이즈 적용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ray Marching 기반 체적광 렌더링에서 &lt;b&gt;노이즈, 즉 jitter sampling을 적용하는 것은 정말 정말 정말 중요하다.&lt;/b&gt; 왜 이렇게 중요한지는 그냥 그림으로 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 &lt;b&gt;노이즈를 적용하지 않고 16회 샘플링&lt;/b&gt;한 결과다. 그림자 영역이 덩어리져 보이고, 결함도 많으며, 효과가 제대로 나오지 않는 부분도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;809&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5uVLN/dJMcabxOzjd/U6wRMwm9abk7SGUGsK5Tz0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5uVLN/dJMcabxOzjd/U6wRMwm9abk7SGUGsK5Tz0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5uVLN/dJMcabxOzjd/U6wRMwm9abk7SGUGsK5Tz0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5uVLN%2FdJMcabxOzjd%2FU6wRMwm9abk7SGUGsK5Tz0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;809&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;809&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 &lt;b&gt;노이즈를 적용하고 4회 샘플링&lt;/b&gt;한 결과다. 체적광 효과가 매우 연속적으로 보이고, 결과도 올바르다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eaeNVW/dJMcaf1hbH8/tgiQgu44UV6eh034q5fHF0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eaeNVW/dJMcaf1hbH8/tgiQgu44UV6eh034q5fHF0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eaeNVW/dJMcaf1hbH8/tgiQgu44UV6eh034q5fHF0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeaeNVW%2FdJMcaf1hbH8%2FtgiQgu44UV6eh034q5fHF0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;804&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노이즈를 적용하지 않으면 16회 샘플링을 해도 노이즈를 적용한 4회 샘플링보다 못하다. 이걸 보면 체적광 렌더링에서 노이즈가 얼마나 중요한지 바로 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ray Marching 기반 체적광에서 &lt;b&gt;노이즈는 광선步进의 시작점과 끝점, 즉 near와 far를 관찰 방향으로 약간 오프셋하는 데 사용&lt;/b&gt;한다. 주의할 점은 관찰 방향으로 오프셋한다는 것이다. 동시에 이 오프셋량은 한 번의 Ray Marching step 길이 안으로 제한해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mx4Ml/dJMcaiqbW5K/oJnUeaLxWzZc0pHVF8QfA0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mx4Ml/dJMcaiqbW5K/oJnUeaLxWzZc0pHVF8QfA0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mx4Ml/dJMcaiqbW5K/oJnUeaLxWzZc0pHVF8QfA0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmx4Ml%2FdJMcaiqbW5K%2FoJnUeaLxWzZc0pHVF8QfA0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;513&quot; height=&quot;448&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노이즈의 출처는 여러 가지일 수 있다. 랜덤 함수로 생성한 White Noise를 쓸 수도 있고, 오프라인에서 생성한 Noise Texture를 쓸 수도 있다. 《Inside》 개발자들은 GDC에서 &lt;b&gt;Blue Noise를 jitter sampling에 사용하면 더 좋은 렌더링 결과를 얻을 수 있다&lt;/b&gt;고 제안했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Blue Noise는 고주파 랜덤 노이즈&lt;/b&gt;이며, 실시간 생성은 어렵다. Christoph Peters의 Blog에는 Blue Noise에 대한 깊은 소개가 있고, 다양한 크기와 타입의 Blue Noise Texture도 제공된다. 다만 URP Package 안에도 3가지 크기의 Blue Noise Texture가 들어 있으므로, 나는 그냥 그걸 가져다 썼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 체적광 렌더링에서는 노이즈를 적용하는 동시에 &lt;b&gt;Temporal Anti-Aliasing, TAA&lt;/b&gt;를 함께 쓰면 효과가 매우 좋다. 내가 사용하는 URP14에는 아직 URP 기본 TAA가 없다. URP15부터 기본 TAA가 제공된다. 예전 실제 프로젝트에서는 URP15의 TAA를 낮은 버전으로 이식해 본 적도 있고, 여러 TAA 방안도 구현해 본 적이 있다. 이후 RecaNoMaho에도 추가할 예정이다. 또 구덩이를 파는 중이다~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 SardineFish 님의 구현을 참고하면, 체적광의 이론 모델에는 사람이 직관적으로 다루기 어려운 파라미터가 많다. 이런 파라미터를 그대로 조정하면 아티스트가 직관적으로 느끼기 어렵다. 그래서 좀 더 사람 친화적인 조정 파라미터를 제공한다. 이 부분은 여기서 자세히 펼치지 않겠다. SardineFish 님의 글을 직접 보면 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.4 더 스타일라이즈하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원신 콘솔판 렌더링 기술 공유 영상에서는 &lt;b&gt;매우 물리적인 체적광 효과는 보통 그렇게 강렬하지 않다&lt;/b&gt;고 언급한다. 예를 들어 아래 그림 같은 효과다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnf9EK/dJMcaiqbW5M/23IVdgy1yyh0CjHJRyBQ8K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnf9EK/dJMcaiqbW5M/23IVdgy1yyh0CjHJRyBQ8K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnf9EK/dJMcaiqbW5M/23IVdgy1yyh0CjHJRyBQ8K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnf9EK%2FdJMcaiqbW5M%2F23IVdgy1yyh0CjHJRyBQ8K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;758&quot; height=&quot;393&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 원신 실제 게임에서 사용된 체적광 효과다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;759&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwKlzR/dJMcaiXX0K7/LYVwgaCYELW8LqAkPki6uk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwKlzR/dJMcaiXX0K7/LYVwgaCYELW8LqAkPki6uk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwKlzR/dJMcaiXX0K7/LYVwgaCYELW8LqAkPki6uk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwKlzR%2FdJMcaiXX0K7%2FLYVwgaCYELW8LqAkPki6uk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;759&quot; height=&quot;393&quot; data-origin-width=&quot;759&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분명히 실제 게임 속 체적광은 더 선명하고 밝으며, 명암 대비도 뚜렷하다. 원신을 참고해 God Ray를 분석한 글에서도 말하듯, 이렇게 선명하고 밝은 광로가 나타난다면 공기 중 입자 밀도는 꽤 높아야 한다. 예를 들면 짙은 안개나 많은 먼지 같은 상황이다. 하지만 현실에서 이런 장면의 체적광은 오히려 더 흐릿해야 한다. 따라서 이 효과는 현실과 맞지 않는다. &lt;b&gt;하지만 게임에서는 원하는 효과다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체적광 이론 모델 관점에서 보면, 배경이 선명하다는 것은 &lt;b&gt;Extinction, 즉 흡수와 외산란 사건이 작다&lt;/b&gt;는 뜻이다. 동시에 강한 산란이 필요하므로 Albedo가 매우 커야 한다. 이 개념은 위에서 자세히 언급하지 않았지만 RTR4 14장에 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이런 스타일라이즈된 체적광을 구현하는 한 방법은 &lt;b&gt;흡수를 매우 낮게 설정하고, 동시에 투과율을 높이는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 방법은 광원에서 매질까지의 투과율은 높이고, 매질에서 카메라까지의 투과율은 낮추는 것이다. 이 방법은 매우 비물리적이지만, 효과는 아주 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 RecaNoMaho에서는 현재 후자의 방법으로 체적광 효과를 스타일라이즈했다. 아직 거칠게 만든 상태라, 앞으로 개선할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타일라이즈 조정을 적용하지 않은 효과는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MJKi8/dJMcaiqbW5U/Df3q7rTpafGYfKIgaPVdY1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MJKi8/dJMcaiqbW5U/Df3q7rTpafGYfKIgaPVdY1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MJKi8/dJMcaiqbW5U/Df3q7rTpafGYfKIgaPVdY1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMJKi8%2FdJMcaiqbW5U%2FDf3q7rTpafGYfKIgaPVdY1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;806&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타일라이즈를 적용한 뒤의 효과는 아래와 같다. 뭐, 그럭저럭 봐줄 만하다. 추가로 샘플 횟수도 조금 늘렸는데, 이 방법은 노이즈가 눈에 띄게 많아지는 문제가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;809&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lcdbc/dJMcaiqbW5S/dF2KYbkq9Z7Br8XhlKDAK0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lcdbc/dJMcaiqbW5S/dF2KYbkq9Z7Br8XhlKDAK0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lcdbc/dJMcaiqbW5S/dF2KYbkq9Z7Br8XhlKDAK0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flcdbc%2FdJMcaiqbW5S%2FdF2KYbkq9Z7Br8XhlKDAK0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;809&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;809&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cO9i9N/dJMcabxOzi8/LyINthJ8oGadQy3KeAroH0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cO9i9N/dJMcabxOzi8/LyINthJ8oGadQy3KeAroH0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cO9i9N/dJMcabxOzi8/LyINthJ8oGadQy3KeAroH0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcO9i9N%2FdJMcabxOzi8%2FLyINthJ8oGadQy3KeAroH0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;572&quot; height=&quot;380&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4 마무리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋다. RecaNoMaho 첫 번째 글, 《처음부터 시작하는 체적광 렌더링》은 일단 여기까지 실천해 보았다. 사실 지금까지 한 것은 &lt;b&gt;0에서 0.5까지의 체적광 렌더링&lt;/b&gt; 정도다. 체적광 효과를 초보적으로 구현했다고밖에 말할 수 없다. 억지로 보면 볼 수 있는 정도고, 현재는 Spot Light에만 적용된다. 실제 운용까지는 아직 갈 길이 멀다. 그러니 이건 상편이라고 해야 하나? 일단 여기서 p를 나누는 이유는 두 가지다. 하나는 이번 글의 내용이 이미 꽤 많아졌기 때문이다. 너무 힘들다! 다른 하나는 내가 너무 오랫동안 아무것도 생산하지 않았기 때문이다. 물고기 잡는 삶에 타락하면 안 된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 인터넷에는 이미 체적광에 관한 공유와 참고 자료가 많이 있다. 내가 쓴 내용의 대부분도 기존 공유 내용과 내 개인적인 체감에 가깝다. 이후에도 더 많은 자료를 참고해 코드를 최적화하고, 렌더링 효과와 성능 측면을 계속 확장할 생각이다. 함께 토론해 주면 좋겠다~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 체적광 속 Miku를 몇 장 공유한다~ Miku의 카툰 렌더링 쪽에 대한 태클은 너무 신경 쓰지 말아 달라 555. 나중에 카툰 렌더링도 제대로 탐구해 보겠다. 구덩이 매립 중이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IHuc2/dJMcabxOzjc/ESGX2z2xNxMAY20L4naY0K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IHuc2/dJMcabxOzjc/ESGX2z2xNxMAY20L4naY0K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IHuc2/dJMcabxOzjc/ESGX2z2xNxMAY20L4naY0K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIHuc2%2FdJMcabxOzjc%2FESGX2z2xNxMAY20L4naY0K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;807&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;807&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uT51q/dJMcaiqbW5R/5Jv21zxK2sTedtjNngh75K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uT51q/dJMcaiqbW5R/5Jv21zxK2sTedtjNngh75K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uT51q/dJMcaiqbW5R/5Jv21zxK2sTedtjNngh75K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuT51q%2FdJMcaiqbW5R%2F5Jv21zxK2sTedtjNngh75K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;807&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;807&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/logbH/dJMcaiqbW5P/NkkKuuA8q9zjKs8WKZBtjk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/logbH/dJMcaiqbW5P/NkkKuuA8q9zjKs8WKZBtjk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/logbH/dJMcaiqbW5P/NkkKuuA8q9zjKs8WKZBtjk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlogbH%2FdJMcaiqbW5P%2FNkkKuuA8q9zjKs8WKZBtjk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;804&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Unity 체적광 렌더링 구현 글&lt;/li&gt;
&lt;li&gt;Real-Time Rendering 4th 중국어 번역 저장소&lt;/li&gt;
&lt;li&gt;Low Complexity, High Fidelity - INSIDE Rendering&lt;/li&gt;
&lt;li&gt;틴들 효과 관련 자료&lt;/li&gt;
&lt;li&gt;체적광 관련 자료&lt;/li&gt;
&lt;li&gt;게임 개발 관련 실시간 렌더링 기술: 체적광&lt;/li&gt;
&lt;li&gt;Fast Extraction of Viewing Frustum Planes from the WorldView-Projection Matrix&lt;/li&gt;
&lt;li&gt;Blue Noise 자료&lt;/li&gt;
&lt;li&gt;원신 콘솔판 렌더링 기술 공유&lt;/li&gt;
&lt;li&gt;God Ray 분석 글&lt;/li&gt;
&lt;li&gt;추가 참고 자료&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원글&lt;br /&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/688803084?share_code=q3lYu8KUGb9B&amp;amp;utm_psn=2051080147810498025&quot;&gt;(73 封私信 / 59 条消息) 【RecaNoMaho】从零开始的体积光渲染 - 知乎&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TECH.ART.FLOW.IO</category>
      <category>URP</category>
      <category>라이팅</category>
      <category>유니티</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/783</guid>
      <comments>https://techartnomad.tistory.com/783#entry783comment</comments>
      <pubDate>Fri, 19 Jun 2026 00:29:43 +0900</pubDate>
    </item>
    <item>
      <title>[번역] 텐센트 델타포스 대형 월드 RVT 지형 렌더링 분석과 재현</title>
      <link>https://techartnomad.tistory.com/782</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저작: Lamp&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꽤 오래전에 만든 거라, 그냥 물 타듯이 한 편 써 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 기술 포인트를 간단히 요약하면 이렇다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;10km급 대형 월드에서 RVT를 사용하고, 1m당 512 texel을 쓴다.&lt;/li&gt;
&lt;li&gt;지형 머티리얼 32종을 지원한다. 전통적인 모바일 게임의 4~8레이어 제한을 훨씬 넘어선다.&lt;/li&gt;
&lt;li&gt;절벽 최적화, 대량 데칼, Tessellation, 습도 변화 같은 고급 효과도 구현했다.&lt;/li&gt;
&lt;li&gt;고화질 설정에서도 프레임, 발열, 대역폭 같은 핵심 지표가 CODM의 저화질 설정보다 오히려 더 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 영상: 삼각주 대형 월드 지형 렌더링 방안&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;777&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB0qIS/dJMcacjaumO/SWwZAjN6TNXIHk83yKJRO0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB0qIS/dJMcacjaumO/SWwZAjN6TNXIHk83yKJRO0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB0qIS/dJMcacjaumO/SWwZAjN6TNXIHk83yKJRO0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB0qIS%2FdJMcacjaumO%2FSWwZAjN6TNXIHk83yKJRO0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;777&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;777&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 지오메트리 쪽부터 보자. CDLOD(Continuous Distance-based Level of Detail)를 사용해 SVT로 로드한 Height Map을 샘플링한다. 이건 딱히 할 말이 없다. 넘어가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지표면 쪽은 런타임에 bake하는 RVT를 사용한다. 한 블록은 256x256이고, LOD0은 월드 공간에서 0.5m에 대응한다. GPU Readback인지 CPU 방식인지는 말하지 않았으니, 여기서는 일단 CPU 구현을 사용했다. 구현은 어느 고수님의 단순화 RVT 방식을 참고했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대형 지형을 위한 단순화 RVT&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1912&quot; data-origin-height=&quot;1224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUAlkB/dJMcaijqTPx/J2bBA201GOmgnRlSHZhJy1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUAlkB/dJMcaijqTPx/J2bBA201GOmgnRlSHZhJy1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUAlkB/dJMcaijqTPx/J2bBA201GOmgnRlSHZhJy1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUAlkB%2FdJMcaijqTPx%2FJ2bBA201GOmgnRlSHZhJy1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1912&quot; height=&quot;1224&quot; data-origin-width=&quot;1912&quot; data-origin-height=&quot;1224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11레벨까지 가도 1024m밖에 안 되기 때문에, Indirection Texture는 Adaptive Virtual Texture 방식으로 할당해야 한다. 나는 귀찮아서 그냥 Clipmap으로 굴렸다. 더 높은 mip의 전체 맵도 2K가 채 안 되니, 오프라인에서 미리 bake해 두고 로드하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VsaKZ/dJMcahY6weo/ydaRSyxJcxR6Coeg2OW0P0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VsaKZ/dJMcahY6weo/ydaRSyxJcxR6Coeg2OW0P0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VsaKZ/dJMcahY6weo/ydaRSyxJcxR6Coeg2OW0P0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVsaKZ%2FdJMcahY6weo%2FydaRSyxJcxR6Coeg2OW0P0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;334&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;지표면 블렌딩&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ID 블렌딩&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지표면 블렌딩은 2ID + 1Weight 방식을 사용한다. 이 방식으로 32레이어 머티리얼 블렌딩을 지원한다. 두 개의 ID는 각각 5bit, Weight는 6bit다. PPT에는 3bit라고 적혀 있었지만, R16에는 아직 6bit가 남아 있으니 여기서는 6bit로 본다. 해상도는 1m당 1픽셀이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방식은 1m 삼각형을 단위로 삼아, 현재 삼각형에 해당하는 6개의 머티리얼 ID와 대응 Weight를 샘플링한다. 그다음 중복을 제거하고, Weight가 가장 큰 3개만 골라 블렌딩한다. 실제로는 제작 단계에서 이미 1m 안에 최대 3레이어까지만 들어가도록 제한했기 때문에, 코드도 조금 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 아직 이해가 안 되는 부분이 있다. 더 높은 mip에서 한 픽셀이 2m를 덮을 때, 이걸 대체 어떻게 계산해야 하느냐는 것이다. 그래서 일단은 오프라인에서 전체 맵을 1m 1픽셀로 bake한 뒤, mip을 계산하고 런타임에는 SVT로 로드하는 방식으로 처리했다. 그런데 이렇게 하면 전역 텍스처가 좀 너무 많다&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;725&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDAW4Q/dJMcahY6wem/hQNV7EekYJxy3TZH5EFzH1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDAW4Q/dJMcahY6wem/hQNV7EekYJxy3TZH5EFzH1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDAW4Q/dJMcahY6wem/hQNV7EekYJxy3TZH5EFzH1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDAW4Q%2FdJMcahY6wem%2FhQNV7EekYJxy3TZH5EFzH1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;725&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;725&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;동적 적응형 텍스처 배열&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;32장의 머티리얼 레이어 텍스처는 공간을 매우 많이 차지한다. 그래서 동적 적응형 텍스처 배열을 사용한다. 각 영역에서 동시에 존재할 수 있는 머티리얼을 최대 12레이어로 제한하고, bake할 때 필요한 텍스처만 동적으로 업로드해 VRAM을 절약한다. 그런데 이미 영역별 레이어 수를 제어하고 동적 로딩까지 한다면, 전체 32레이어 제한은 또 무슨 의미인지 잘 모르겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;593&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q6Z2o/dJMcaijqTPt/WI3pa0sMxhCIC8XMf7aKJk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q6Z2o/dJMcaijqTPt/WI3pa0sMxhCIC8XMf7aKJk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q6Z2o/dJMcaijqTPt/WI3pa0sMxhCIC8XMf7aKJk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq6Z2o%2FdJMcaijqTPt%2FWI3pa0sMxhCIC8XMf7aKJk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;593&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;593&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 가까운 곳은 Height Blend를 사용하고, 먼 곳은 Linear Blend를 사용한다. 다만 제공된 블렌딩 방식은 세 가지 머티리얼을 어떻게 섞는 건지 잘 이해가 안 돼서, 일단은 전통적인 방식으로 섞었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EM7k9/dJMcacjaumR/Hyz26M0T8EjT4oTLK6LNnk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EM7k9/dJMcacjaumR/Hyz26M0T8EjT4oTLK6LNnk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EM7k9/dJMcacjaumR/Hyz26M0T8EjT4oTLK6LNnk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEM7k9%2FdJMcacjaumR%2FHyz26M0T8EjT4oTLK6LNnk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;758&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;758&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 중복 제거부터 보자. 제작팀이 동적 적응형 텍스처 배열을 사용한다고 했고, 동시에 최대 12개 layer가 존재한다고 했으니, 가장 간단한 방법은 리매핑 후 길이 12짜리 배열로 중복 제거를 하는 것이다. 또는 먼저 정렬한 뒤 중복 제거를 해도 된다. GatherRed를 사용하면 샘플링 횟수도 줄일 수 있다. 구현 코드는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;struct Element {
    int id;
    float weight;
};

void UnpackData(float input, float lrp, out Element e1, out Element e2)
{
    const int data = floor(input * 65535 + 0.5);
    e1.id = (data &amp;gt;&amp;gt; 11) &amp;amp; 31;
    e2.id = (data &amp;gt;&amp;gt; 6) &amp;amp; 31;
    const float weight = (data &amp;amp; 63) / 63.0 * 0.5 + 0.5;
    float2 weights = float2(weight, 1 - weight) * lrp;
    e1.weight = weights.x;
    e2.weight = weights.y;
}

inline void Swap(inout Element a, inout Element b)
{
    const Element temp = a;
    a = b;
    b = temp;
}

inline void CompareSwap(inout Element arr[8], int i, int j)
{
    if (arr[i].id &amp;gt; arr[j].id) Swap(arr[i], arr[j]);
}

void Sort6(inout Element arr[6])
{
    CompareSwap(arr, 0, 1);
    CompareSwap(arr, 2, 3);
    CompareSwap(arr, 4, 5);
    CompareSwap(arr, 0, 2);
    CompareSwap(arr, 1, 3);
    CompareSwap(arr, 1, 2);
    CompareSwap(arr, 0, 4);
    CompareSwap(arr, 1, 5);
    CompareSwap(arr, 1, 4);
    CompareSwap(arr, 2, 4);
    CompareSwap(arr, 3, 5);
    CompareSwap(arr, 3, 4);
}

void SortAndMerge(float2 uv, inout Element elements[6])
{
    Sort6(elements);

    int lastID = -1;
    int ptr = 0;
    int i;

    for (i = 0; i &amp;lt; 6; i++)
    {
        const int curID = elements[i].id;
        if (curID != lastID) elements[ptr++] = elements[i];
        else elements[ptr - 1].weight += elements[i].weight;
        lastID = curID;
    }

    float splatHeight[3];
    splatHeight[0] = elements[0].weight * SampleHeight(uv, elements[0].id);
    float maxHeight = splatHeight[0];

    splatHeight[1] = elements[1].weight * SampleHeight(uv, elements[1].id);
    if (splatHeight[1] &amp;gt; maxHeight) maxHeight = splatHeight[1];

    splatHeight[2] = elements[2].weight * SampleHeight(uv, elements[2].id);
    if (splatHeight[2] &amp;gt; maxHeight) maxHeight = splatHeight[2];

    float transition = max(1e-3, _HeightBlendSharpness * _HeightBlendSharpness);
    elements[0].weight *= max(1e-6, splatHeight[0] + transition - maxHeight);
    elements[1].weight *= max(1e-6, splatHeight[1] + transition - maxHeight);
    elements[2].weight *= max(1e-6, splatHeight[2] + transition - maxHeight);
}

void MixTerrainLayersTri(float2 uv, float2 tilling, int lod, out float4 col, out float3 normal)
{
    const float2 texUV = uv * tilling;
    const float2 uv0 = uv * (_IdMap_TexelSize.zw - 1);
    int2 base = int2(floor(uv0));

    float2 cornerUV = frac(uv0);
    int2 corner = 0;

    if (cornerUV.x + cornerUV.y &amp;gt; 1)
    {
        cornerUV = 1.0 - cornerUV.yx;
        corner = 1;
    }

    float c10 = LOAD_TEXTURE2D_LOD(_IdMap, base + int2(1, 0), 0).r;
    float c01 = LOAD_TEXTURE2D_LOD(_IdMap, base + int2(0, 1), 0).r;
    float c00 = LOAD_TEXTURE2D_LOD(_IdMap, base + corner, 0).r;

    Element elements[6];
    UnpackData(c00, 1.0 - cornerUV.x - cornerUV.y, elements[0], elements[1]);
    UnpackData(c10, cornerUV.x, elements[2], elements[3]);
    UnpackData(c01, cornerUV.y, elements[4], elements[5]);

    SortAndMerge(texUV, elements);

    const float weightSum = elements[0].weight + elements[1].weight + elements[2].weight;

    col = 0;
    normal = 0;

    float4 data0;
    float4 data1;

    UNITY_UNROLL
    for (int idx = 0; idx &amp;lt; 3; idx++)
    {
        const Element e = elements[idx];
        SampleTerrainTexture(texUV, e.id, lod, data00, data11);
        data0 += data00 * e.weight / weightSum;
        data1 += data11 * e.weight / weightSum;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤쪽에서는 tile마다 머티리얼 개수를 오프라인에서 미리 계산해 두고, 개수에 따라 다른 variant를 쓰는 방법도 언급했다. 예를 들어 한 레이어뿐인 tile이라면 중복 제거와 블렌딩이 필요 없고, 그냥 바로 샘플링하면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;표현력 향상&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전역 텍스처&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 SVT, 제작팀 기준으로는 Clipmap을 사용해 Height와 ID Map을 로드하고 있으니, 여기에 같은 크기의 Color, Roughness, AO 같은 전역 텍스처를 추가해 지표면 표현을 풍부하게 만든다. 지형 AO, 강&amp;middot;호수&amp;middot;절벽의 색 입히기, 물웅덩이 같은 디테일 표현을 할 수 있다. 동시에 원경에서는 전역 Normal을 샘플링해 낮은 폴리곤 수 때문에 사라지는 디테일을 보완할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2LyCc/dJMcaijqTPq/m5eTr4383vH3dsr9FdXrVk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2LyCc/dJMcaijqTPq/m5eTr4383vH3dsr9FdXrVk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2LyCc/dJMcaijqTPq/m5eTr4383vH3dsr9FdXrVk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2LyCc%2FdJMcaijqTPq%2Fm5eTr4383vH3dsr9FdXrVk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;530&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식생도 마찬가지로 Color Map을 샘플링해 변화를 줄 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;767&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnNLCQ/dJMcacjaumQ/n0ukARzBOuRYSUa5qmkB40/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnNLCQ/dJMcacjaumQ/n0ukARzBOuRYSUa5qmkB40/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnNLCQ/dJMcacjaumQ/n0ukARzBOuRYSUa5qmkB40/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnNLCQ%2FdJMcacjaumQ%2Fn0ukARzBOuRYSUa5qmkB40%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;767&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;767&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;절벽 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절벽 텍스처가 늘어나는 문제는 Triplanar Mapping 방식으로 VT의 UV를 다시 매핑해 처리했다. 서로 다른 방향 사이의 전환은 dither로 블렌딩한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhfJcg/dJMcacjaumP/KzyHi4yBhuOHnbk6kROOk0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhfJcg/dJMcacjaumP/KzyHi4yBhuOHnbk6kROOk0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhfJcg/dJMcacjaumP/KzyHi4yBhuOHnbk6kROOk0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhfJcg%2FdJMcacjaumP%2FKzyHi4yBhuOHnbk6kROOk0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;690&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 구현 코드는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;half3 blendWeights = pow(abs(i.worldNormal), _TripBlendSharpness);
blendWeights = blendWeights / (blendWeights.x + blendWeights.y + blendWeights.z);

float rnd = Random(i.vertex.xy);
float2 uv;

if (rnd &amp;lt; blendWeights.x) {
    uv = i.worldPos.zy;
}
else if (rnd &amp;lt; blendWeights.x + blendWeights.y) {
    uv = i.worldPos.xz;
}
else {
    uv = i.worldPos.xy;
}

// mix terrain layers use new uv
// ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이건 결국 텍스처가 늘어나는 것만 처리한 것이다. VT 위에서 차지하는 면적 자체는 변하지 않기 때문에, 조금 흐릿해 보일 수 있다. 절벽 각도가 크지 않다면 괜찮지만, 사실상 급경사의 UV 늘어남을 처리하는 정도다. 진짜 절벽은 결국 mesh를 배치해야 한다&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1409&quot; data-origin-height=&quot;872&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZqbzY/dJMcacjaumT/v4brkitkCHsNqJfLEDGo2K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZqbzY/dJMcacjaumT/v4brkitkCHsNqJfLEDGo2K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZqbzY/dJMcacjaumT/v4brkitkCHsNqJfLEDGo2K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZqbzY%2FdJMcacjaumT%2Fv4brkitkCHsNqJfLEDGo2K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1409&quot; height=&quot;872&quot; data-origin-width=&quot;1409&quot; data-origin-height=&quot;872&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9KC2g/dJMcaijqTPu/uNv90k4L2IpugcNj7XagJ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9KC2g/dJMcaijqTPu/uNv90k4L2IpugcNj7XagJ1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9KC2g/dJMcaijqTPu/uNv90k4L2IpugcNj7XagJ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9KC2g%2FdJMcaijqTPu%2FuNv90k4L2IpugcNj7XagJ1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;686&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데칼&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RVT는 태생적으로 대량 지표면 데칼을 잘 지원한다. 지형 위에 도로, 파손 흔적, 자갈, 물웅덩이 같은 디테일을 찍어 넣을 수 있다. 이건 딱히 설명할 것도 없다. 기본적으로 다들 쓰는 방식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;765&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rTYER/dJMcahY6wep/qCDOVs5HvbWH9nqBz1R2F1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rTYER/dJMcahY6wep/qCDOVs5HvbWH9nqBz1R2F1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rTYER/dJMcahY6wep/qCDOVs5HvbWH9nqBz1R2F1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrTYER%2FdJMcahY6wep%2FqCDOVs5HvbWH9nqBz1R2F1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;765&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;765&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음은 따옴표가 붙은 &amp;ldquo;Tessellation&amp;rdquo;이다. VT 기반 입체 데칼이라고 보면 된다. 실제로 지형을 세분화하는 것은 아니고, 특정 위치에 mesh를 몇 개 배치한 뒤 지형과 섞어서 마치 세분화된 것처럼 보이게 만드는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구체적인 방식은 이렇다. 데칼은 Color와 Normal을 VT에 찍어 넣을 뿐 아니라, mesh 자체도 가까운 거리에서는 렌더링된다. 그리고 이 mesh가 VT를 샘플링해 지형과 섞인다. 처음 로드 거리 안으로 들어올 때 z scale은 0이라 완전히 지면에 붙어 있고, 없는 것과 같다. 가까워질수록 z scale이 점점 1이 되면서 입체적인 형태가 된다. 낮은 폴리곤 지형에 약간의 굴곡을 추가하는 셈이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blRFGy/dJMcaijqTPs/XJQTeWQEagFpkwwFj8trgk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blRFGy/dJMcaijqTPs/XJQTeWQEagFpkwwFj8trgk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blRFGy/dJMcaijqTPs/XJQTeWQEagFpkwwFj8trgk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblRFGy%2FdJMcaijqTPs%2FXJQTeWQEagFpkwwFj8trgk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;665&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;665&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 간단한 구현 예시다. 사실상 지형 VT만 완전히 샘플링하고 블렌딩은 하지 않은 mesh를 하나 올려둔 것이다&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;833&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daJWgR/dJMcaijqTPv/i3xx3e8t28hqIK0036wTJK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daJWgR/dJMcaijqTPv/i3xx3e8t28hqIK0036wTJK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daJWgR/dJMcaijqTPv/i3xx3e8t28hqIK0036wTJK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaJWgR%2FdJMcaijqTPv%2Fi3xx3e8t28hqIK0036wTJK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;833&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VHFM과의 차이는, 여기서는 mesh 데칼이 있는 곳에만 입체 높이가 있고 지형 머티리얼 자체는 여전히 평평하다는 점이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;843&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbE4xJ/dJMcahY6weq/dtMvicDHsSZfqM4BDi3xD1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbE4xJ/dJMcahY6weq/dtMvicDHsSZfqM4BDi3xD1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbE4xJ/dJMcahY6weq/dtMvicDHsSZfqM4BDi3xD1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbE4xJ%2FdJMcahY6weq%2FdtMvicDHsSZfqM4BDi3xD1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;843&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VHFM은 지형 머티리얼 레이어 자체에도 높이가 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;성능 최적화&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 성능 최적화도 몇 가지 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원거리/근거리의 서로 다른 tiling은 dither로 블렌딩한다. 이건 딱히 할 말이 없다. 나는 CPU로 제어했다. VT에는 부모 레벨에서 복사된 mipmap이 세 레이어 있기 때문에, 샘플링할 때 하드웨어 trilinear가 자동으로 전환해 준다.&lt;/li&gt;
&lt;li&gt;Bake Shader variant를 사용한다. 삼각주에서는 tile 중 13%만 세 레이어 텍스처 블렌딩을 가득 사용한다고 한다. 그러면 각 tile의 블렌딩 상태를 미리 계산해 두고, 상황에 따라 다른 variant를 쓰면 된다. 예를 들어 tile 전체가 한 가지 머티리얼뿐이라면 복잡한 중복 제거와 블렌딩 없이 그냥 샘플링하면 끝이다. 삼각주의 지형 머티리얼은 PCG로 생성되어 복잡한 블렌딩이 적고, 1m에 512픽셀, VT page 크기는 256이므로 단순 variant를 쓸 수 있는 블록이 꽤 많다.&lt;/li&gt;
&lt;li&gt;데칼의 반투명 대신 dither를 사용한다. 이렇게 하면 RT에 alpha blending이 필요 없어지고, 3장의 RT를 2장으로 줄일 수 있다. 동시에 기존 블렌딩 경로도 남겨 둔다. 렌더링 후 FBF로 3장을 2장으로 합성한 뒤 압축해서 Texture Array에 넣는다. 즉 bake 시점에는 3장 경로와 2장 경로를 선택할 수 있고, 최종 압축은 모두 2장이다.&lt;/li&gt;
&lt;li&gt;각 tile의 데칼 상태를 미리 계산한다. 전체가 데칼로 덮여 있다면 데칼만 그리면 되고, 데칼이 없다면 Depth Buffer가 필요 없다. 나머지 경우에는 먼저 데칼을 그려 overdraw를 줄인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤쪽 최적화, 예를 들어 전역 Normal Color, 절벽 늘어남 처리, 입체 데칼, 대역폭 최적화 같은 방식은 블렌딩과 무관하므로 모두 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블렌딩 방식은 사용할지 말지 아직 논의가 필요하다. 글에서 언급한 것처럼 각 영역의 레이어 수를 제어할 수 있다면, 예를 들어 영역마다 8레이어로 제한하고 동적 텍스처 배열로 서로 다른 머티리얼 레이어 텍스처를 로드하면, 사실상 영역별 전체 레이어 수 제한은 존재하지 않는다. CPU에서 매핑만 잘 만들어 주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 두 방식을 비교해 보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삼각주 방식: 두 개의 3bit ID + 2bit Weight 방식으로 바꾼다고 가정하면, 10K의 8bit 비압축 맵은 100MB다. mip은 없다. 1m당 3레이어만 존재하도록 제어해야 하고, Weight 정밀도도 낮다. 샘플링은 3ID + 3Albedo + 3Normal + 3Mask, 총 12회다. 런타임에는 블록 내부 블렌딩 상태에 따라 단순화할 수 있다.&lt;/li&gt;
&lt;li&gt;전체 Weight 방식: 두 장의 RGBA32를 ASTC 8x8로 압축하면 50MB다. 머티리얼 텍스처와 VT texel을 정렬한 뒤, 둘씩 묶어 hardware bilinear로 블렌딩한다. Weight 정밀도가 더 높고, 영역 안에서 8레이어 임의 블렌딩도 지원한다. 샘플링은 2Weights + 4Albedo + 4Normal + 4Mask, 총 14회다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로는 프로젝트의 아트 요구에 따라 삼각주식 블렌딩 방식을 쓸지 말지 선택해야 할 것 같다. 픽셀마다 ID를 두 개만 저장하기 때문에, 세 레이어 사이의 전환이 이상하게 깨지지 않는 것까지만 보장할 수 있다. 하지만 진짜 세 레이어 동시 블렌딩은 할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 레이어의 부드러운 전환과 복잡한 블렌딩이 필요하다면 삼각주의 방법은 감당하기 어렵다. 반대로 그런 요구가 없다면 삼각주의 방법이 더 낫다. 어차피 툭툭 몇 번 칠해서 ID Map으로 내보내면 결과가 안 맞을 수도 있으니, 결국 아트팀이 받아들일 수 있느냐를 봐야 한다&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;842&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FdLpi/dJMcacjaumS/OeW2asPPnXP4jVSg2lkQw0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FdLpi/dJMcacjaumS/OeW2asPPnXP4jVSg2lkQw0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FdLpi/dJMcacjaumS/OeW2asPPnXP4jVSg2lkQw0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFdLpi%2FdJMcacjaumS%2FOeW2asPPnXP4jVSg2lkQw0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;842&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;842&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원문&lt;br /&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/2046364722652505513&quot;&gt;(73 封私信 / 57 条消息) 三角洲大世界RVT地形渲染解析复现 - 知乎&lt;/a&gt; &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TECH.ART.FLOW.IO</category>
      <author>jplee</author>
      <guid isPermaLink="true">https://techartnomad.tistory.com/782</guid>
      <comments>https://techartnomad.tistory.com/782#entry782comment</comments>
      <pubDate>Thu, 18 Jun 2026 18:34:46 +0900</pubDate>
    </item>
  </channel>
</rss>