<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Cinevva 블로그</title>
        <link>https://app.cinevva.com</link>
        <description>제품 업데이트, 창작자 노트, 실험.</description>
        <lastBuildDate>Tue, 28 Jul 2026 02:49:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright 2024-present Cinevva</copyright>
        <item>
            <title><![CDATA[팩트체크 노트: "스케치에서 영상으로, 그리고 플레이 가능한 3D로"]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-03-04-sketch-to-animated-3d-character-factcheck-note</link>
            <guid>https://app.cinevva.com/ko/blog/2026-03-04-sketch-to-animated-3d-character-factcheck-note</guid>
            <pubDate>Tue, 28 Jul 2026 02:44:15 GMT</pubDate>
            <content:encoded><![CDATA[<h1 id="팩트체크-노트-스케치에서-영상으로-그리고-플레이-가능한-3d로" tabindex="-1">팩트체크 노트: &quot;스케치에서 영상으로, 그리고 플레이 가능한 3D로&quot; <a class="header-anchor" href="#팩트체크-노트-스케치에서-영상으로-그리고-플레이-가능한-3d로" aria-label="Permalink to &quot;팩트체크 노트: &quot;스케치에서 영상으로, 그리고 플레이 가능한 3D로&quot;&quot;"></a></h1>
<p><strong>수신:</strong> Oleg Sidorkin<br>
<strong>관련:</strong> <a href="https://app.cinevva.com/blog/2026-03-04-sketch-to-animated-3d-character" target="_blank" rel="noreferrer">app.cinevva.com/blog/2026-03-04-sketch-to-animated-3d-character</a><br>
<strong>대조 기준:</strong> cinevva-site repo (마케팅 사이트 + worker)</p>
<hr>
<h2 id="확인됨-✓" tabindex="-1">확인됨 ✓ <a class="header-anchor" href="#확인됨-✓" aria-label="Permalink to &quot;확인됨 ✓&quot;"></a></h2>
<ul>
<li><strong>도구 이름</strong>(Image Generator, Video Generator, 3D Model Generator)과 <strong>링크</strong> <code>/tools/hunyuan3d</code>가 코드베이스와 일치합니다.</li>
<li><strong>작성자</strong>(Oleg Sidorkin, CTO)가 정확합니다.</li>
<li><strong>영상 워크플로:</strong> 시작 + 끝 프레임 보간, 9:16, 3~15초 길이, storyboard 모드 모두 지원됩니다.</li>
<li><strong>3D 파이프라인:</strong> Hunyuan3D와 &quot;3D Model Generator&quot;가 정확하고, 자동 리깅(Tripo)과 &quot;GLB 업로드 → 리깅된 모델 + 애니메이션 라이브러리&quot;가 구현과 일치합니다.</li>
<li><strong>Cinevva Engine</strong>과 &quot;2026년 초 기준 반영&quot;이 정확합니다.</li>
</ul>
<hr>
<h2 id="수정-필요" tabindex="-1">수정 필요 <a class="header-anchor" href="#수정-필요" aria-label="Permalink to &quot;수정 필요&quot;"></a></h2>
<p><strong>&quot;Seedance 1.5 Pro&quot;</strong> — 이 repo에서는 영상이 Seedance 1.5 Pro가 아니라 <strong>Kling 3.0 Pro</strong> (fal.ai)로 구현되어 있습니다:</p>
<ul>
<li><code>worker/src/genai/fal-video.ts</code>는 <code>fal-ai/kling-video/v3/pro/...</code>를 사용합니다</li>
<li><code>worker/src/index.ts</code>는 비용을 <code>model: 'kling-3.0-pro'</code>로 기록합니다</li>
<li><code>tools/video.md</code>에는 이렇게 적혀 있습니다: &quot;Generate short AI videos from text or images using <strong>Kling 3.0 Pro</strong>&quot;</li>
</ul>
<p>API/제품 이름은 &quot;seedance&quot;(예: <code>/genai/seedance/generate</code>)이지만, 실제 모델은 Kling 3.0 Pro입니다. Seedance 1.5 Pro는 다른 모델(ByteDance)입니다. 공개 자료에서는 Seedance 1.5 Pro를 보통 약 10초로 제한하는데, 여기서 15초가 지원되는 건 Kling을 쓰기 때문입니다.</p>
<p><strong>권장 사항:</strong> 글에서는 영상 모델 이름을 <strong>&quot;Kling 3.0 Pro&quot;</strong>(또는 예: &quot;Video Generator (Kling 3.0 Pro)&quot;)로 적어 마케팅 사이트 및 문서와 일치시키세요. 만약 앱 백엔드가 실제로 Seedance 1.5 Pro를 사용한다면, 앱 문구와 <code>tools/video.md</code>를 맞춰 같은 모델을 설명하도록 하세요.</p>
<hr>
<h2 id="repo에서-확인-불가" tabindex="-1">repo에서 확인 불가 <a class="header-anchor" href="#repo에서-확인-불가" aria-label="Permalink to &quot;repo에서 확인 불가&quot;"></a></h2>
<p>Cubcoats, Kali the Kitty, Mimi Chao 및 관련 비즈니스 주장은 외부 정보로, 확인하지 않았습니다.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Spike 소스 뷰어]]></title>
            <link>https://app.cinevva.com/ko/blog/spike-source</link>
            <guid>https://app.cinevva.com/ko/blog/spike-source</guid>
            <pubDate>Tue, 28 Jul 2026 02:44:15 GMT</pubDate>
            <description><![CDATA[오픈 월드 브라우저 시리즈의 모든 spike 소스 코드를 확인하세요.]]></description>
            <content:encoded><![CDATA[<h1 id="빌더를-여는-중" tabindex="-1">빌더를 여는 중… <a class="header-anchor" href="#빌더를-여는-중" aria-label="Permalink to &quot;빌더를 여는 중…&quot;"></a></h1>
<p v-if="spikeId">
  Game Creator의 <strong>spike {{ spikeId }}</strong>(으)로 이동하고 있습니다.
  자동으로 이동되지 않으면 <a :href="`/create#spike-${spikeId}`">여기서 열어 보세요</a>.
</p>
<p v-else>
  <a href="/create">Game Creator 열기</a>.
</p>
<p style="margin-top:1rem">
  <a href="/ko/blog/2026-02-25-open-world-browser-series-guide">← 시리즈 가이드로 돌아가기</a>
</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[지금 바로 즐기는 최고의 무료 브라우저 게임 (다운로드 불필요)]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-06-30-best-free-browser-games-no-download</link>
            <guid>https://app.cinevva.com/ko/blog/2026-06-30-best-free-browser-games-no-download</guid>
            <pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[다운로드나 설치 없이 바로 즐길 수 있는 최고의 브라우저 게임을 엄선한 목록입니다. 퍼즐, 로그라이크, 스토리, 리듬 등 최고 평점의 인디 게임들.]]></description>
            <content:encoded><![CDATA[<h1 id="지금-바로-즐기는-최고의-무료-브라우저-게임-다운로드-불필요" tabindex="-1">지금 바로 즐기는 최고의 무료 브라우저 게임 (다운로드 불필요) <a class="header-anchor" href="#지금-바로-즐기는-최고의-무료-브라우저-게임-다운로드-불필요" aria-label="Permalink to &quot;지금 바로 즐기는 최고의 무료 브라우저 게임 (다운로드 불필요)&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Mariana Muntean</a>, Cinevva CEO</em></p>
<p>솔직히 말하면 itch.io에 일주일을 통째로 쏟을 생각은 전혀 없었어요. 가벼운 리서치로 시작했는데... 뭐, 열두 시간쯤 지나서는 세는 걸 그만뒀습니다. 원래 목적은 바로 즐길 수 있는 게임을 찾는 거였어요. 다운로드도 없고, 백그라운드에서 끙끙대는 설치 프로그램도 없이요. 클릭하면 바로 게임 안입니다. 끝.</p>
<p>이게 그 관문을 통과한 게임들입니다.</p>
<h2 id="최고-평점의-인터랙티브-경험" tabindex="-1">최고 평점의 인터랙티브 경험 <a class="header-anchor" href="#최고-평점의-인터랙티브-경험" aria-label="Permalink to &quot;최고 평점의 인터랙티브 경험&quot;"></a></h2>
<div class="showcase-card">
<img src="/img/showcases/anxiety.png" alt="Adventures With Anxiety screenshot" loading="lazy">
<p><strong>Adventures With Anxiety!</strong> — 인터랙티브 스토리
평점 6,500개가 넘는데 평균 4.9입니다. 불안과 정면으로 마주하게 만드는 게임에 이렇게 팬이 많다니 신기하죠? 좋은 의미로 불편해집니다. 오래도록 마음에 남는 그런 불편함이요. <a href="https://ncase.itch.io/anxiety" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/wbwwb.png" alt="We Become What We Behold screenshot" loading="lazy">
<p><strong>We Become What We Behold</strong> — 사회 논평
평점 7,600개에 4.8/5. 끝내는 데 10분. 머릿속에서 지우는 데 며칠. <a href="https://ncase.itch.io/wbwwb" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/six-cats-under.png" alt="Six Cats Under screenshot" loading="lazy">
<p><strong>Six Cats Under</strong> — 퍼즐 어드벤처
아늑하고 영리합니다. 여기선 비주얼이 진짜 많은 일을 해내는데, 그게 게임에 유리하게 작용합니다. 6,400명 넘는 사람들에게서 4.8/5. <a href="https://teambeanloop.itch.io/six-cats-under" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/friday-night-funkin.gif" alt="Friday Night Funkin screenshot" loading="lazy">
<p><strong>Friday Night Funkin'</strong> — 리듬 게임
이건 이제 어디서나 볼 수 있죠. 평점 11,700개 이상, 4.7/5. <a href="https://ninja-muffin24.itch.io/funkin" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/sort-the-court.png" alt="Sort the Court screenshot" loading="lazy">
<p><strong>Sort the Court!</strong> — 왕국 시뮬레이션
당신이 할 일은 오직 하나, 예 또는 아니오를 말하는 겁니다. 별거 아닌 것처럼 들리죠. 그러다 작은 왕국을 여전히 운영하는 사이에 두 시간이 사라집니다. <a href="https://graebor.itch.io/sort-the-court" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/dragonsweeper.png" alt="Dragonsweeper screenshot" loading="lazy">
<p><strong>Dragonsweeper</strong> — 퍼즐 로그라이크
지뢰찾기에 RPG 시스템을 섞어 버무렸습니다. 4.9/5. 어쩌면 이 목록 전체에서 가장 좋은 게임일지도 모릅니다. <a href="https://danielben.itch.io/dragonsweeper" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<h2 id="로그라이크-전략-브라우저에서-플레이-가능" tabindex="-1">로그라이크 &amp; 전략 (브라우저에서 플레이 가능) <a class="header-anchor" href="#로그라이크-전략-브라우저에서-플레이-가능" aria-label="Permalink to &quot;로그라이크 &amp; 전략 (브라우저에서 플레이 가능)&quot;"></a></h2>
<div class="showcase-card">
<img src="/img/showcases/backpack-hero.png" alt="Backpack Hero screenshot" loading="lazy">
<p><strong>Backpack Hero</strong> — 인벤토리 로그라이크
브라우저 버전은 무료입니다. 유료 버전에 더 많은 콘텐츠가 있지만, 무료 웹 빌드만으로도 충분히 완성도가 있습니다. <a href="https://thejaspel.itch.io/backpack-hero" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/vampire-survivors.png" alt="Vampire Survivors screenshot" loading="lazy">
<p><strong>Vampire Survivors</strong> — 불릿 헤븐
데모만 제공됩니다. 스테이지 하나, 캐릭터 일곱. 그래도 이 게임이 왜 모두의 여가 시간을 집어삼켰는지 알기엔 충분합니다. <a href="https://poncle.itch.io/vampire-survivors" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/dome-romantik.gif" alt="Dome Romantik screenshot" loading="lazy">
<p><strong>Dome Romantik</strong> — 채굴 디펜스
게임 잼 작품으로 시작했습니다. Dome Keeper가 됐고요. 그리고 크게 성공했습니다. 원조 프로토타입은 지금도 잘 버텨 줍니다. <a href="https://bippinbits.itch.io/dome-romantik" target="_blank" rel="noreferrer">여기서 플레이하세요</a></p>
</div>
<h2 id="왜-하필-이-게임들일까요" tabindex="-1">왜 하필 이 게임들일까요? <a class="header-anchor" href="#왜-하필-이-게임들일까요" aria-label="Permalink to &quot;왜 하필 이 게임들일까요?&quot;"></a></h2>
<p>링크 하나하나 전부 직접 테스트했습니다. 대충 훑어본 게 아니라, 정말로 자리 잡고 앉아서 플레이했어요. 문제없이 로딩되고, 브라우저에서 이상하게 굴지도 않습니다. 수천 개의 평점은 다운로드 버튼 한 번 누른 적 없는 사람들에게서 나왔습니다. 클릭하고 바로 뛰어든 사람들이죠. &quot;오, 흥미로운데&quot;에서 실제로 플레이하기까지의 그 마찰 없는 경로요. 대부분의 사람은 그게 얼마나 많은 걸 바꾸는지 과소평가합니다.</p>
<h2 id="더-많은-웹-게임-둘러보기" tabindex="-1">더 많은 웹 게임 둘러보기 <a class="header-anchor" href="#더-많은-웹-게임-둘러보기" aria-label="Permalink to &quot;더 많은 웹 게임 둘러보기&quot;"></a></h2>
<p>아직 더 하고 싶으신가요?</p>
<ul>
<li><a href="https://itch.io/games/top-rated/html5" target="_blank" rel="noreferrer">itch.io 최고 평점 HTML5 게임</a></li>
<li><a href="https://itch.io/games/top-rated/genre-platformer/html5" target="_blank" rel="noreferrer">최고의 HTML5 플랫포머</a></li>
<li><a href="https://itch.io/games/top-rated/html5/year-2024" target="_blank" rel="noreferrer">2024-2025년 게임</a></li>
</ul>
<h2 id="주목할-만한-인디-게임-다운로드-필요" tabindex="-1">주목할 만한 인디 게임 (다운로드 필요) <a class="header-anchor" href="#주목할-만한-인디-게임-다운로드-필요" aria-label="Permalink to &quot;주목할 만한 인디 게임 (다운로드 필요)&quot;"></a></h2>
<p>브라우저에서 돌아가지 않는 좋은 게임들도 있습니다. 이런 게임들은 그 추가 단계를 감수할 가치가 있습니다.</p>
<div class="showcase-card">
<img src="/img/showcases/slice-dice.png" alt="Slice & Dice screenshot" loading="lazy">
<p><strong>Slice &amp; Dice</strong> — 주사위 로그라이크
Windows, Mac, Android에서 실행됩니다. <a href="https://tann.itch.io/slice-dice" target="_blank" rel="noreferrer">itch.io에서 받기</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/stacklands.png" alt="Stacklands screenshot" loading="lazy">
<p><strong>Stacklands</strong> — 카드 마을 건설
Windows와 Mac. <a href="https://sokpop.itch.io/stacklands" target="_blank" rel="noreferrer">itch.io에서 받기</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/luck-be-a-landlord.png" alt="Luck be a Landlord screenshot" loading="lazy">
<p><strong>Luck be a Landlord</strong> — 슬롯머신 로그라이크
말장난 같은 콘셉트처럼 들리죠. 아닙니다. 슬롯머신이라는 겉모습 아래에 진짜 전략이 있습니다. <a href="https://trampolinetales.itch.io/luck-be-a-landlord" target="_blank" rel="noreferrer">itch.io</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/patricks-parabox.png" alt="Patrick's Parabox screenshot" loading="lazy">
<p><strong>Patrick's Parabox</strong> — 재귀 퍼즐
머리가 지끈거릴 각오 하세요. 그래도 좋아하게 될 각오도요. <a href="https://patricktraynor.itch.io/patricks-parabox" target="_blank" rel="noreferrer">itch.io</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/dome-keeper.jpg" alt="Dome Keeper screenshot" loading="lazy">
<p><strong>Dome Keeper</strong> — 채굴 디펜스
앞서 언급한 그 잼 프로토타입의 정식 출시판입니다. <a href="https://store.steampowered.com/app/1637320/Dome_Keeper/" target="_blank" rel="noreferrer">Steam에서 찾기</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/brotato.jpg" alt="Brotato screenshot" loading="lazy">
<p><strong>Brotato</strong> — 아레나 서바이버
<a href="https://store.steampowered.com/app/1942280/Brotato/" target="_blank" rel="noreferrer">Steam에서 이용 가능</a></p>
</div>
<hr>
<p>게임을 만드는 사람이라면 한 번쯤 곱씹어 볼 게 있습니다. <strong>브라우저 빌드는 플레이어와 당신의 작품 사이에 아무것도 두지 않습니다</strong>. 대기열에 걸린 채 잊혀 버릴 다운로드도 없고, 넘겨야 할 설치 화면도 없습니다. 클릭 한 번이면 플레이어는 이미 당신이 만든 것에 대해 의견을 형성하기 시작합니다. 그런 즉시성은 충분히 이야기되지 않지만, 모든 걸 바꿔 놓습니다.</p>
<p>당신의 게임에도 이걸 원하시나요? <a href="/create.html">Cinevva 게임 크리에이터</a>로 브라우저에서 바로 하나 만들 수 있고, 저희가 소개하는 게임들은 <a href="/ko/arcade.html">커뮤니티 아케이드</a>에 실립니다.</p>
<ul>
<li><a href="/ko/creators.html">게임 크리에이터를 위한 안내</a></li>
<li><a href="/ko/tutorials/ship-web-game-fast.html">빠르게 로딩되는 웹 게임 만들기</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2026년 웹 게임 엔진: PlayCanvas vs Three.js vs Babylon.js vs Unity WebGL]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-06-09-web-game-engines-2026-comparison</link>
            <guid>https://app.cinevva.com/ko/blog/2026-06-09-web-game-engines-2026-comparison</guid>
            <pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[2026년에 브라우저에서 3D 게임을 만드는 주요 방법들을 최신 정보로 솔직하게 비교합니다. PlayCanvas(v2.19), Three.js, Babylon.js, Unity WebGL. 각각이 무엇인지, 누구를 위한 것인지, WebGL2 vs WebGPU 지원, 라이선스, 그리고 어떻게 고를지를 다룹니다.]]></description>
            <content:encoded><![CDATA[<h1 id="_2026년-웹-게임-엔진-playcanvas-vs-three-js-vs-babylon-js-vs-unity-webgl" tabindex="-1">2026년 웹 게임 엔진: PlayCanvas vs Three.js vs Babylon.js vs Unity WebGL <a class="header-anchor" href="#_2026년-웹-게임-엔진-playcanvas-vs-three-js-vs-babylon-js-vs-unity-webgl" aria-label="Permalink to &quot;2026년 웹 게임 엔진: PlayCanvas vs Three.js vs Babylon.js vs Unity WebGL&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<img src="https://cdn.cinevva.com/blog/web-engines-2026-hero.jpg" alt="A browser window showing a 3D scene transitioning from a white wireframe mesh on the left to a rendered colorful low-poly landscape on the right" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>2026년에 브라우저에서 돌아가는 3D 게임을 출시하고 싶다면, 주류 선택지 네 가지와 더 새로운 것 몇 가지가 있습니다. 흔히 &quot;웹 게임 엔진&quot;으로 한데 묶이지만, 사실은 서로 다른 문제를 푸는 진짜로 다른 도구들입니다. 잘못 고르면 몇 달을 날립니다. 이 글은 최신 정보로 사실 확인을 거친 비교이며, 웹 3D 엔진을 만드는 일을 직업으로 삼고 직접 엔진을 만들기 전에 이 모든 것을 평가한 사람들이 썼습니다.</p>
<p>각 선택지가 실제로 무엇인지, 누구를 위한 것인지, 어디서 무너지는지를 살펴본 다음, 마지막에 짧은 결정 가이드를 드리겠습니다. 버전 번호를 언급하는 곳은 2026년 6월 기준으로 정확합니다.</p>
<h2 id="빠른-비교" tabindex="-1">빠른 비교 <a class="header-anchor" href="#빠른-비교" aria-label="Permalink to &quot;빠른 비교&quot;"></a></h2>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
<th>Cinevva</th>
</tr>
</thead>
<tbody>
<tr>
<td>무엇인가</td>
<td>완전한 엔진 + 호스팅 에디터</td>
<td>렌더링 라이브러리</td>
<td>완전한 엔진 + 에디터</td>
<td>데스크톱 엔진, 웹 내보내기</td>
<td>AI 네이티브 월드 플랫폼</td>
</tr>
<tr>
<td>아키텍처</td>
<td>엔티티-컴포넌트(ECS)</td>
<td>씬 그래프</td>
<td>씬 그래프 + 컴포넌트</td>
<td>GameObject/컴포넌트</td>
<td>씬 그래프 + AI 빌더</td>
</tr>
<tr>
<td>스크립팅</td>
<td>TypeScript / JavaScript</td>
<td>JavaScript(나머지는 직접 구축)</td>
<td>TypeScript / JavaScript</td>
<td>C#(Wasm으로 컴파일)</td>
<td>자연어 + 코드</td>
</tr>
<tr>
<td>렌더러</td>
<td>WebGL2, WebGPU 성숙 중</td>
<td>WebGL2, WebGPU 성장 중</td>
<td>WebGL2, WebGPU 발전 중</td>
<td>WebGL2(내보내기)</td>
<td>WebGPU 전용</td>
</tr>
<tr>
<td>에디터</td>
<td>호스팅형, 상용</td>
<td>없음</td>
<td>웹 기반, 무료</td>
<td>데스크톱, 상용</td>
<td>월드 내, 몰입형</td>
</tr>
<tr>
<td>물리</td>
<td>Ammo / 통합</td>
<td>직접 준비</td>
<td>Havok 내장</td>
<td>내장(PhysX)</td>
<td>커스텀 캐릭터 솔버</td>
</tr>
<tr>
<td>라이선스</td>
<td>엔진 MIT, 에디터 독점</td>
<td>MIT</td>
<td>MIT</td>
<td>독점</td>
<td>독점</td>
</tr>
<tr>
<td>적합한 곳</td>
<td>스튜디오형 브라우저 게임</td>
<td>커스텀 3D, 완전한 제어</td>
<td>다 갖춰진 게임</td>
<td>기존 Unity 게임 이식</td>
<td>월드 내 AI 게임 제작</td>
</tr>
</tbody>
</table>
<p>이 글의 나머지는 이 표를 설명합니다.</p>
<h2 id="playcanvas" tabindex="-1">PlayCanvas <a class="header-anchor" href="#playcanvas" aria-label="Permalink to &quot;PlayCanvas&quot;"></a></h2>
<p>PlayCanvas는 웹에서 Unity 스타일 워크플로에 가장 가까운 물건입니다. 엔진은 MIT 라이선스의 오픈소스이며, 2026년 6월 5일 기준으로 v2.19.6입니다. 엔티티-컴포넌트 시스템을 쓰고, 게임 로직은 TypeScript나 JavaScript로 작성하며, 에셋은 GLB를 만들어 내는 서버 사이드 파이프라인을 거칩니다. 실제 상용 게임들이 이 위에서 돌아가고, 큰 회사들이 프로덕션에서 씁니다. Snap이 공개된 예입니다.</p>
<p>PlayCanvas에 대해 사람들이 흔히 잘못 아는 두 가지를 바로잡을 만합니다. 첫째, 엔진은 MIT 라이선스지만, 대부분의 팀이 실제로 쓰는 호스팅 비주얼 에디터는 오픈소스가 아니라 상용 제품입니다. 에디터 없이 엔진만 자유롭게 쓸 수 있지만, 에디터와 클라우드를 묶은 워크플로가 유료 부분입니다. 둘째, PlayCanvas는 WebGL2 우선입니다. WebGPU 경로가 있긴 하지만 기본 렌더러라기보다 아직 성숙해 가는 중이므로, 프로덕션용 WebGPU 컴퓨트 셰이더를 기대하고 오늘 PlayCanvas를 고르지는 마세요.</p>
<p>PlayCanvas가 진짜로 앞서는 곳은 3D 가우시안 스플래팅입니다. 팀이 오픈소스로 공개한 SuperSplat 에디터와 뷰어는 웹에서 스플랫 씬을 캡처하고 출시하는 데 있어 어디 내놔도 손꼽히는 도구이며, 대용량 캡처를 위한 WebGPU 기반 스트리밍을 갖췄습니다. 포토리얼하게 스캔한 환경이 목표라면, 여기서 시작할 진짜 이유가 됩니다.</p>
<p><strong>PlayCanvas를 고르세요</strong> 브라우저용으로 Unity 같은 에디터와 관리형 에셋 파이프라인을 원하고, 스튜디오가 만들 법한 게임을 출시하려 한다면. <strong>다른 곳을 보세요</strong> 오늘 당장 WebGPU 컴퓨트가 필요하거나, 호스팅형 상용 에디터를 피하고 싶다면.</p>
<h2 id="three-js" tabindex="-1">Three.js <a class="header-anchor" href="#three-js" aria-label="Permalink to &quot;Three.js&quot;"></a></h2>
<p>Three.js는 게임 엔진이 아닙니다. 렌더링 라이브러리이며, 이 분야에서 압도적인 차이로 가장 널리 쓰입니다. 씬 그래프, 카메라, 라이트, 머티리얼, 지오메트리, 로더, 렌더러를 주고 나서 거기서 멈춥니다. 에디터도, 물리도, 엔티티 시스템도 없고, 게임을 어떻게 구성해야 하는지에 대한 의견도 없습니다. 그건 직접 더하거나 생태계에서 끌어와야 합니다.</p>
<p>그 맞바꿈이 이야기의 전부입니다. 최대한의 제어와 웹 3D에서 가장 큰 커뮤니티를 얻는 대신, 렌더러 위의 모든 것을 직접 만들거나 조립해야 합니다. WebGPU 렌더러는 꾸준히 성장해 왔고 오늘날 쓸 만하지만, 다른 것들과 마찬가지로 WebGL2 경로가 여전히 성숙한 기본값입니다. Three.js는 MIT 라이선스입니다.</p>
<p><strong>Three.js를 고르세요</strong> 완전한 제어와 최소한의 기반을 원하고, 그 위에 게임 시스템을 직접 구축할 엔지니어링 역량이 있다면. <strong>다른 곳을 보세요</strong> 에디터와 게임 시스템을 손에 쥐여주길 원한다면.</p>
<h2 id="babylon-js" tabindex="-1">Babylon.js <a class="header-anchor" href="#babylon-js" aria-label="Permalink to &quot;Babylon.js&quot;"></a></h2>
<p>Babylon.js는 완전한 엔진으로, MIT 라이선스이며 Microsoft의 팀이 뒷받침합니다. Three.js와 달리, 직접 조립해야 할 부품들을 함께 제공합니다. 컴포넌트 모델, 통합된 Havok 물리 엔진, 무료 웹 기반 에디터, 에셋 파이프라인이 그것입니다. WebGPU 작업이 빠르게 진행돼 범용 엔진들 중에서도 더 앞선 축에 들지만, 여전히 넓은 호환성 경로로 WebGL2를 유지합니다.</p>
<p>&quot;완전한 엔진과 포함된 물리를 원하고, 그 규약 안에서 작업하는 게 편하다&quot;가 머릿속 그림이라면, Babylon은 강력한 기본 선택지이며 이 분야에서 가장 기능이 완비된 무료 옵션이라고 볼 만합니다.</p>
<p><strong>Babylon.js를 고르세요</strong> 배터리가 포함된 것, 내장 물리, 무료 에디터를 원한다면. <strong>다른 곳을 보세요</strong> 의존성 부담을 최소화하고 싶거나, 구체적으로 Unity 스타일 호스팅 워크플로를 원한다면.</p>
<h2 id="unity-webgl" tabindex="-1">Unity WebGL <a class="header-anchor" href="#unity-webgl" aria-label="Permalink to &quot;Unity WebGL&quot;"></a></h2>
<p>Unity WebGL은 웹 엔진이 아닙니다. 내보내기 대상입니다. Unity 데스크톱 에디터에서 C#으로 빌드한 다음, WebAssembly를 통해 브라우저에서 돌아가는 WebGL 번들로 컴파일합니다. 그래서 한 가지 특정 경우에는 분명한 답이 됩니다. 이미 Unity 게임이 있고 그것의 브라우저 버전을 원할 때입니다.</p>
<p>웹 우선 프로젝트에는 진짜 비용이 따릅니다. 런타임과 다운로드 무게가 상당하고, 시작이 네이티브 웹 엔진보다 느리며, 모바일 브라우저 성능은 알려진 골칫거리입니다. Unity는 독점이고 그 WebGL 출력은 WebGL2를 대상으로 합니다.</p>
<p><strong>Unity WebGL을 고르세요</strong> 브라우저로 가져올 기존 Unity 프로젝트가 있거나, 팀이 이미 Unity 안에서 산다면. <strong>다른 곳을 보세요</strong> 중급 휴대폰에서의 즉시 로드가 양보 불가한 요구사항이거나, 처음부터 웹 우선으로 새로 시작한다면.</p>
<h2 id="ai-네이티브와-월드-내-제작이-들어맞는-자리" tabindex="-1">AI 네이티브와 월드 내 제작이 들어맞는 자리 <a class="header-anchor" href="#ai-네이티브와-월드-내-제작이-들어맞는-자리" aria-label="Permalink to &quot;AI 네이티브와 월드 내 제작이 들어맞는 자리&quot;"></a></h2>
<p>위의 모든 것은 한 가지 가정을 공유합니다. 개발자가 책상에서, 에디터 안에서 게임을 만들고 런타임을 출시한다는 가정입니다. 그 가정은 대부분의 프로젝트에 맞고, 당신 프로젝트가 그렇다면 위의 넷 중에서 고르세요.</p>
<p>다만 그 가정이 더는 유일한 선택지가 아니라는 걸 알아둘 만합니다. 다른 범주가 떠오르고 있기 때문입니다. 우리는 Cinevva를 만듭니다. 게임이 월드 안에서 만들어지는 WebGPU 전용 월드 플랫폼입니다. 에디터를 여는 대신, 당신은 그 공간에 서 있는 아바타이고, 원하는 것을 말로 설명하면 AI 빌더가 당신이 거기 서 있는 동안 그것을 지형, 오브젝트, 동작으로 바꿔 줍니다. 제작과 플레이가 같은 세션입니다. 그 이면에서 이것은 컴퓨트 셰이더 지형으로 WebGPU 전용으로 가고, 범용 물리 엔진 대신 커스텀 캐릭터 솔버를 작성하고, 애니메이션과 리타게팅 시스템을 만든다는 뜻이었습니다. 이에 대해서는 <a href="/ko/blog/2026-06-08-why-we-built-our-own-webgpu-engine.html">우리가 직접 WebGPU 엔진을 만든 이유</a>에 적어 두었습니다.</p>
<p>이것은 PlayCanvas나 Babylon을 대체하는 게 아닙니다. 특정 게임을 만드는 개발자라면 그것들이 맞는 도구입니다. Cinevva는 엔진 개발자가 아닌 사람들이 설명만으로 플레이 가능한 공간을 만들고 공유하게 한다는 다른 목표를 위한 것입니다. 여기서 언급하는 이유는 &quot;어떤 웹 게임 엔진을 써야 하나&quot;라는 질문에 점점 더 엔진이 아닌 다섯 번째 답이 생기고 있기 때문입니다.</p>
<h2 id="전체-기능-매트릭스" tabindex="-1">전체 기능 매트릭스 <a class="header-anchor" href="#전체-기능-매트릭스" aria-label="Permalink to &quot;전체 기능 매트릭스&quot;"></a></h2>
<p>맨 위의 빠른 표가 헤드라인입니다. 이건 서브시스템별로 묶은 상세 버전입니다. 읽는 법에 대한 솔직한 메모 몇 가지를 드립니다. &quot;BYO&quot;는 직접 준비(bring your own)를 뜻하는데, 엔진이 기본으로 제공하지 않지만 생태계나 직접 작성한 코드로 더할 수 있다는 말입니다. 이건 설계상 렌더링 라이브러리인 Three.js에서 가장 중요하므로, 여기서 &quot;BYO&quot;는 빈틈이 아니라 철학의 특징입니다. Unity의 &quot;내보내기 전용(Export-only)&quot;은 그 기능이 데스크톱 에디터에 존재하고 WebGL 빌드에 함께 따라온다는 뜻이지 웹 네이티브라는 뜻이 아닙니다. 경쟁 제품 칸은 2026년 중반 기준 기본 제공 기능과 잘 문서화된 동작을 반영합니다. Cinevva 칸은 우리가 출시한 빌드에서 돌아가는 것을 반영하며, &quot;계획됨(planned)&quot;은 설계됐지만 아직 구축되지 않은 것을 표시합니다.</p>
<h3 id="렌더링" tabindex="-1">렌더링 <a class="header-anchor" href="#렌더링" aria-label="Permalink to &quot;렌더링&quot;"></a></h3>
<table tabindex="0">
<thead>
<tr>
<th>기능</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>주 렌더러</td>
<td>WebGPU 전용</td>
<td>WebGL2 (WebGPU 베타)</td>
<td>WebGL2 (WebGPU 성장 중)</td>
<td>WebGL2 (WebGPU 발전)</td>
<td>WebGL2 (내보내기)</td>
</tr>
<tr>
<td>프로덕션 컴퓨트 셰이더</td>
<td>예 (핵심 의존성)</td>
<td>베타</td>
<td>WebGPU 경유</td>
<td>예 (WebGPU)</td>
<td>내보내기 전용, 제한적</td>
</tr>
<tr>
<td>셰이더 작성</td>
<td>TSL 노드 + 컴퓨트</td>
<td>셰이더 청크 / GLSL</td>
<td>GLSL + 노드(TSL)</td>
<td>노드 머티리얼 / GLSL / WGSL</td>
<td>ShaderLab / HLSL</td>
</tr>
<tr>
<td>클러스터드 / forward+ 조명</td>
<td>예 (froxel)</td>
<td>예</td>
<td>BYO</td>
<td>예</td>
<td>예</td>
</tr>
<tr>
<td>볼류메트릭 구름과 날씨</td>
<td>예</td>
<td>BYO</td>
<td>BYO</td>
<td>일부</td>
<td>BYO</td>
</tr>
<tr>
<td>3D 가우시안 스플래팅 도구</td>
<td>계획됨</td>
<td>예 (SuperSplat, 선도)</td>
<td>커뮤니티</td>
<td>예</td>
<td>플러그인</td>
</tr>
</tbody>
</table>
<h3 id="월드와-지형" tabindex="-1">월드와 지형 <a class="header-anchor" href="#월드와-지형" aria-label="Permalink to &quot;월드와 지형&quot;"></a></h3>
<table tabindex="0">
<thead>
<tr>
<th>기능</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>내장 대규모 월드 스트리밍</td>
<td>예 (64m 청크)</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO</td>
<td>내보내기 전용</td>
</tr>
<tr>
<td>지형 시스템</td>
<td>하이브리드 하이트맵 + 마칭 큐브/SDF</td>
<td>BYO</td>
<td>BYO</td>
<td>확장</td>
<td>내장 (데스크톱)</td>
</tr>
<tr>
<td>런타임 지형 스컬핑</td>
<td>예 (GPU)</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO</td>
<td>아니오 (편집 시점)</td>
</tr>
<tr>
<td>동굴과 오버행 (진짜 3D 토폴로지)</td>
<td>예 (마칭 큐브)</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO</td>
</tr>
<tr>
<td>GPU 인스턴싱 초목과 풀</td>
<td>예</td>
<td>예</td>
<td>BYO</td>
<td>예</td>
<td>예</td>
</tr>
</tbody>
</table>
<h3 id="물리와-캐릭터" tabindex="-1">물리와 캐릭터 <a class="header-anchor" href="#물리와-캐릭터" aria-label="Permalink to &quot;물리와 캐릭터&quot;"></a></h3>
<table tabindex="0">
<thead>
<tr>
<th>기능</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>물리 엔진</td>
<td>커스텀 키네마틱 솔버</td>
<td>Ammo 통합</td>
<td>BYO (Rapier/Cannon/Ammo)</td>
<td>Havok 내장</td>
<td>PhysX 내장</td>
</tr>
<tr>
<td>강체 동역학</td>
<td>아니오 (설계상)</td>
<td>예</td>
<td>BYO</td>
<td>예</td>
<td>예</td>
</tr>
<tr>
<td>캐릭터 컨트롤러</td>
<td>예 (멀티 모드 FSM)</td>
<td>템플릿 / Ammo</td>
<td>BYO</td>
<td>예</td>
<td>내장</td>
</tr>
<tr>
<td>지형 통합 충돌 (SDF)</td>
<td>예</td>
<td>아니오</td>
<td>BYO</td>
<td>아니오</td>
<td>아니오</td>
</tr>
</tbody>
</table>
<h3 id="애니메이션" tabindex="-1">애니메이션 <a class="header-anchor" href="#애니메이션" aria-label="Permalink to &quot;애니메이션&quot;"></a></h3>
<table tabindex="0">
<thead>
<tr>
<th>기능</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>스켈레탈 애니메이션</td>
<td>예</td>
<td>예</td>
<td>예</td>
<td>예</td>
<td>예</td>
</tr>
<tr>
<td>블렌드 / 상태 머신</td>
<td>예 (리졸버 FSM)</td>
<td>예 (애니 상태 그래프)</td>
<td>믹서 (BYO 블렌딩)</td>
<td>예</td>
<td>예 (Mecanim)</td>
</tr>
<tr>
<td>스켈레톤 리타게팅</td>
<td>예 (파이프라인)</td>
<td>제한적</td>
<td>커뮤니티</td>
<td>일부</td>
<td>예 (휴머노이드)</td>
</tr>
<tr>
<td>역운동학</td>
<td>계획됨</td>
<td>제한적</td>
<td>커뮤니티</td>
<td>예</td>
<td>예</td>
</tr>
</tbody>
</table>
<h3 id="멀티플레이어와-백엔드" tabindex="-1">멀티플레이어와 백엔드 <a class="header-anchor" href="#멀티플레이어와-백엔드" aria-label="Permalink to &quot;멀티플레이어와 백엔드&quot;"></a></h3>
<table tabindex="0">
<thead>
<tr>
<th>기능</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>내장 멀티플레이어</td>
<td>예 (엣지 권위형)</td>
<td>BYO (Photon/Colyseus)</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO (Netcode, 웹 네이티브 아님)</td>
</tr>
<tr>
<td>영속 공유 월드</td>
<td>예 (청크별 Durable Objects)</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO</td>
</tr>
<tr>
<td>공간 음성 채팅</td>
<td>예 (WebRTC + HRTF)</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO</td>
<td>BYO</td>
</tr>
</tbody>
</table>
<h3 id="제작과-저작" tabindex="-1">제작과 저작 <a class="header-anchor" href="#제작과-저작" aria-label="Permalink to &quot;제작과 저작&quot;"></a></h3>
<table tabindex="0">
<thead>
<tr>
<th>기능</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>에디터</td>
<td>월드 내, 몰입형</td>
<td>호스팅 데스크톱형 (상용)</td>
<td>없음 (최소)</td>
<td>웹 기반 (무료)</td>
<td>데스크톱 (상용)</td>
</tr>
<tr>
<td>월드 내 체화형 제작</td>
<td>예</td>
<td>아니오</td>
<td>아니오</td>
<td>아니오</td>
<td>아니오</td>
</tr>
<tr>
<td>자연어 / AI 제작</td>
<td>예 (AI 빌더)</td>
<td>아니오</td>
<td>아니오</td>
<td>아니오</td>
<td>아니오</td>
</tr>
<tr>
<td>스크립팅</td>
<td>자연어 + JS</td>
<td>TypeScript / JS</td>
<td>JavaScript</td>
<td>TypeScript / JS</td>
<td>C#</td>
</tr>
</tbody>
</table>
<h3 id="에셋과-배포" tabindex="-1">에셋과 배포 <a class="header-anchor" href="#에셋과-배포" aria-label="Permalink to &quot;에셋과 배포&quot;"></a></h3>
<table tabindex="0">
<thead>
<tr>
<th>기능</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>서버 사이드 에셋 파이프라인</td>
<td>예 (GLB + LOD + KTX2 + Draco)</td>
<td>예 (GLB)</td>
<td>로더만</td>
<td>임포트 도구</td>
<td>예</td>
</tr>
<tr>
<td>내장 AI 에셋 생성</td>
<td>예 (3D, 이미지, 오디오, 음악)</td>
<td>아니오</td>
<td>아니오</td>
<td>아니오</td>
<td>아니오</td>
</tr>
<tr>
<td>페더레이티드 에셋 검색</td>
<td>예 (11개 제공자)</td>
<td>에셋 스토어</td>
<td>아니오</td>
<td>아니오</td>
<td>에셋 스토어</td>
</tr>
<tr>
<td>설치 없이 브라우저에서 실행</td>
<td>예</td>
<td>예</td>
<td>예</td>
<td>예</td>
<td>예 (무거움)</td>
</tr>
<tr>
<td>엔진 라이선스</td>
<td>독점 플랫폼</td>
<td>엔진 MIT, 에디터 독점</td>
<td>MIT</td>
<td>MIT</td>
<td>독점</td>
</tr>
</tbody>
</table>
<p>매트릭스의 패턴이 진짜 이야기입니다. 범용 엔진들은 강점을 수평으로 펼칩니다. 각자 대부분의 일을 능숙하게 해내고, 월드와 백엔드와 제작 흐름은 당신에게 맡깁니다. Cinevva는 수직으로 집중합니다. 더 적은 일을 하지만 렌더러에서부터 당신이 안에서 만드는 공유 월드까지 전 경로를 소유합니다. 추상적으로는 어느 모양이 더 낫지 않습니다. 서로 다른 질문에 답할 뿐입니다.</p>
<h2 id="어떻게-고를까" tabindex="-1">어떻게 고를까 <a class="header-anchor" href="#어떻게-고를까" aria-label="Permalink to &quot;어떻게 고를까&quot;"></a></h2>
<p>기능 체크리스트가 아니라 상황에 도구를 맞추세요.</p>
<p>이미 Unity 게임이 있다면, Unity WebGL로 내보내고 무게를 감수하세요. 브라우저 게임에 에디터 주도 워크플로를 원하는 스튜디오라면, PlayCanvas를 쓰세요. 물리가 포함된 완전한 무료 엔진을 원한다면, Babylon.js를 쓰세요. 완전한 제어를 원하고 맨 렌더러 위에 구축할 팀이 있다면, Three.js를 쓰세요. 그리고 목표가 게임 하나를 만드는 게 아니라 사람들이 설명만으로 공유 월드 안에서 만들고 플레이하게 하는 것이라면, 그게 우리가 일하는 범주이고, <a href="/ko/">Cinevva를 써 보세요</a>.</p>
<p>무엇을 고르든, 커밋하기 전에 진짜 스파이크로 평가하세요. 이 각각은 진짜 게임을 떠받칠 수 있고, 중간에 갈아타는 비용은 출시에 쓰지 못한 그 몇 달입니다.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PlayCanvas를 포크하지 않고 직접 WebGPU 엔진을 만든 이유]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-06-08-why-we-built-our-own-webgpu-engine</link>
            <guid>https://app.cinevva.com/ko/blog/2026-06-08-why-we-built-our-own-webgpu-engine</guid>
            <pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Three.js, Babylon.js, PlayCanvas, Unity WebGL. 직접 렌더러를 작성하기 전에 이 모두를 평가했습니다. 각각이 잘하는 부분, 기성 엔진을 떠나게 만든 네 가지 결정, 그리고 우리가 한 일을 절대 따라 하면 안 되는 경우를 정리했습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="playcanvas를-포크하지-않고-직접-webgpu-엔진을-만든-이유" tabindex="-1">PlayCanvas를 포크하지 않고 직접 WebGPU 엔진을 만든 이유 <a class="header-anchor" href="#playcanvas를-포크하지-않고-직접-webgpu-엔진을-만든-이유" aria-label="Permalink to &quot;PlayCanvas를 포크하지 않고 직접 WebGPU 엔진을 만든 이유&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<img src="https://cdn.cinevva.com/blog/why-webgpu-engine-hero.jpg" alt="A stylized low-poly world rendered by Cinevva's WebGPU engine: rolling hills, a cave carved into a cliff, a winding river, and an avatar mid-stride on a path at golden hour" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Cinevva World를 본 기술자라면 누구나 5분 안에 같은 질문을 합니다. 당신들은 작은 팀이다. 성숙한 웹 3D 엔진이 이미 존재한다. 그런데 왜 PlayCanvas나 Babylon 위에 올라타 더 빨리 출시하지 않고, 직접 렌더러를, 직접 캐릭터 물리를, 직접 애니메이션 시스템을 만들었나?</p>
<p>타당한 질문이고, &quot;여기서 만든 게 아니라서(not invented here)&quot;는 틀린 답입니다. 우리는 숙제를 했습니다. 기존 엔진들을 돌려봤고, 소스를 읽었고, 결정을 내리기 전에 그중 둘 위에 스파이크를 올려서 출시까지 해봤습니다. 이 글은 그 결정의 솔직한 버전입니다. 기성 옵션들이 진짜로 잘하는 것, 우리 요구가 직접 만드는 게 정당화될 만큼 크게 갈라진 네 곳, 그리고 우리를 따라 하기보다 그중 하나를 골라야 하는 상황을 다룹니다. 빌드 자체는 장기 연재인 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">브라우저 안의 오픈월드 엔지니어링 시리즈</a>에 기록해 두었으니, 아래 주장에 작업 로그가 있는 경우에는 링크를 걸겠습니다.</p>
<h2 id="우리가-실제로-평가한-옵션들" tabindex="-1">우리가 실제로 평가한 옵션들 <a class="header-anchor" href="#우리가-실제로-평가한-옵션들" aria-label="Permalink to &quot;우리가 실제로 평가한 옵션들&quot;"></a></h2>
<p>&quot;웹 게임 엔진&quot;이라고 불리는 네 가지가 있는데, 서로 같은 종류의 물건이 아닙니다.</p>
<p><strong>Three.js</strong>는 게임 엔진이 아니라 렌더링 라이브러리입니다. 씬 그래프, 머티리얼, 로더, 렌더러를 주고 나서 길을 비켜줍니다. 에디터도, 물리도, 엔티티 시스템도, 게임을 어떻게 구성해야 하는지에 대한 의견도 없습니다. 그게 매력이자 비용입니다. 렌더러 위의 모든 것을 직접 만들어야 하지만, 그 무엇도 당신과 싸우지 않습니다. MIT 라이선스고, 이 분야에서 가장 큰 생태계를 갖고 있으며, 새벽 2시에 난해한 셰이더 버그를 만나도 답을 주는 포럼 글이 기다리고 있습니다.</p>
<p><strong>Babylon.js</strong>는 씬 그래프, 물리 통합(Havok), 에셋 파이프라인, 웹 에디터를 갖춘 완전한 엔진입니다. MIT 라이선스고, Microsoft의 팀이 뒷받침하며, WebGPU 작업이 빠르게 진행돼 왔습니다. 배터리가 포함된 걸 원하고 엔진의 구조 안에서 사는 게 편하다면, 강력한 기본 선택지입니다.</p>
<p><strong>PlayCanvas</strong>는 &quot;웹용 Unity&quot;에 가장 가까운 물건입니다. 이 글을 쓰는 시점에 엔진은 2026년 6월 5일에 출시된 v2.19.6이고, 엔진 자체는 MIT 라이선스의 오픈소스입니다. 다만 대부분의 사람이 실제로 쓰는 건 호스팅 비주얼 에디터이고, 그 에디터는 오픈소스가 아니라 상용 제품입니다. PlayCanvas는 엔티티-컴포넌트 시스템을 쓰고, TypeScript나 JavaScript로 스크립팅하며, 에셋은 서버 사이드 GLB 파이프라인을 거치고, 실제 상용 게임들이 이 위에서 출시됐습니다(Snap이 프로덕션 작업을 PlayCanvas로 돌리는 게 한 예입니다). 렌더러는 WebGL2로 돌아가고 WebGPU 경로는 기본값이라기보다 아직 성숙해 가는 중입니다. 그 마지막 디테일이 들리는 것보다 더 중요한데, 뒤에서 다시 다루겠습니다.</p>
<p><strong>Unity WebGL</strong>은 애초에 웹 엔진이 아닙니다. 내보내기 대상입니다. Unity 데스크톱 에디터에서 빌드한 다음 WebGL 번들로 컴파일합니다. 이미 Unity 게임이 있고 그걸 브라우저에 넣고 싶을 때는 맞는 도구고, &quot;중급 휴대폰의 탭에서 즉시 로드된다&quot;가 강한 요구사항일 때는 틀린 도구입니다. 런타임과 다운로드 무게가 따라오기 때문입니다.</p>
<p>이 중 무엇이든 평범한 웹 게임의 합리적인 토대가 됩니다. 우리는 평범한 웹 게임을 갖고 있지 않았습니다.</p>
<h2 id="결정-하나-webgpu는-우리의-바닥이지-결승선이-아니다" tabindex="-1">결정 하나: WebGPU는 우리의 바닥이지 결승선이 아니다 <a class="header-anchor" href="#결정-하나-webgpu는-우리의-바닥이지-결승선이-아니다" aria-label="Permalink to &quot;결정 하나: WebGPU는 우리의 바닥이지 결승선이 아니다&quot;"></a></h2>
<p>우리를 모든 기성품에서 밀어내는 갈림은 이것입니다. 우리에게 WebGPU는 언젠가 도달할 기능이 아니라 요구사항입니다.</p>
<p>우리 지형은 정적 하이트맵이 아닙니다. 스트리밍되는 하이트맵 필드와, 부호 거리 필드(signed-distance field)로 뒷받침되는 마칭 큐브 청크의 하이브리드라서, 세계에 진짜 동굴과 오버행이 있을 수 있고 창작자가 실시간으로 조각할 수 있습니다. 조각 브러시, 식생 스캐터, 지형 메싱은 모두 컴퓨트 셰이더로 돌아갑니다. 컴퓨트를 빼면 세계는 품질이 떨어지는 게 아니라 아예 돌지 않습니다.</p>
<p>이건 오늘날 범용 엔진들이 서 있는 자리와 정반대입니다. 그들의 WebGPU 지원은 WebGL2 우선 렌더러 위에 얹은 점진적 향상으로 설계되어 있고, WebGPU가 없는 브라우저를 위한 폴백 경로를 둡니다. 특히 PlayCanvas는 WebGL2 우선이고 WebGPU는 아직 베타입니다. 그들에게는 그게 올바른 판단입니다. 그들의 일은 가능한 가장 넓은 게임 매트릭스를 가능한 가장 넓은 기기 매트릭스에서 돌리는 것이니까요. 우리 일은 더 좁고 깊어서, 우리는 반대로 판단했습니다. 스파이크 13에서 WebGPU 전용으로 갔고 다시는 뒤돌아보지 않았습니다. WebGPU가 없는 브라우저는 다운그레이드되는 게 아니라 미지원이고, 우리는 그걸 WebGL2 폴백이 설정 플래그 하나 거리에 있는 척하는 대신 도달률 수치로 추적합니다. 그건 설정 플래그 거리에 있지 않습니다. 우리 지형과 식생 단계의 부분 재작성이 될 겁니다.</p>
<p>WebGL2 우선 엔진 위에 짓는다는 건 모든 컴퓨트 기능마다 그 엔진의 폴백 가정과 싸우거나, 아니면 두 개의 렌더링 경로를 영원히 유지하거나 둘 중 하나를 뜻했을 겁니다. 렌더러를 소유하니 컴퓨트를 기준선으로 다룰 수 있었습니다.</p>
<h2 id="결정-둘-물리-엔진이-아니라-캐릭터-솔버" tabindex="-1">결정 둘: 물리 엔진이 아니라 캐릭터 솔버 <a class="header-anchor" href="#결정-둘-물리-엔진이-아니라-캐릭터-솔버" aria-label="Permalink to &quot;결정 둘: 물리 엔진이 아니라 캐릭터 솔버&quot;"></a></h2>
<p>교과서적인 수는 물리 엔진을 끼워 넣는 것입니다. 우리도 해봤습니다. 초기 스파이크에서 워커 안의 Rapier를 검증했고, 괜찮게 느껴졌습니다.</p>
<p>그래도 우리는 직접 만들었고, 출시 빌드 어디에도 Rapier, Cannon, Ammo가 없습니다. 이유는 범위입니다. 우리는 강체, 조인트, 래그돌, 제약 솔버가 필요 없습니다. 캡슐 하나가 지형에 대해 올바르게 움직이면 되고, 걷기, 미끄러지기, 활공, 등반, 수영이 &quot;내가 지면에 있는가, 어떤 표면 위에서, 어떤 각도로&quot;에 대한 하나의 공유된 답에 동의하기만 하면 됩니다. 범용 물리 엔진은 이걸 더 쉽게가 아니라 더 어렵게 만듭니다. 그 모드들이 결국 엔진 내부의 스프링과 댐퍼와 싸우게 되기 때문입니다.</p>
<p>그래서 우리 캐릭터 컨트롤러는 <a href="/ko/blog/2026-05-15-open-world-browser-part-29-pluggable-character.html">플러그형 멀티채널 상태 머신</a>입니다. 각 모드는 이번 프레임에 제어권을 원하는지 말하고, 이기면 속도와 방향을 쓰는 작은 유닛입니다. 이들은 자원, 자세, 이동이라는 세 채널에 걸쳐 우선순위로 중재하고, 모두 같은 지형 쿼리를 읽습니다. 충돌은 청크에 따라 하이트맵이나 부호 거리 필드에 대한 캡슐 프로브입니다.</p>
<p>제가 가장 자랑스러워하는 디테일은 화려하지 않습니다. 지면 검출은 SDF 기울기를 믿는 대신, 발밑 수직 기둥의 모든 표면을 스캔해 캡슐 이하에서 가장 높은 것을 고릅니다. 오버행 가장자리에서는 옆으로 가장 가까운 표면이 절벽 면이라, 기울기 기반 노멀은 &quot;바닥&quot;과 &quot;벽&quot; 사이를 깜빡거리고 유령 미끄러짐이 생깁니다. 기둥 쿼리는 턱 위에 서 있는 걸 지루하게 만드는데, 그게 바로 당신이 원하는 것입니다. 기성 하이트필드 콜라이더는 이걸 공짜로 주지 않았을 겁니다. 애초에 우리 지형을 볼 수 없기 때문입니다. 지형은 우리 포맷으로 GPU 위에 삽니다. 외부 엔진은 매 편집마다 우리가 필드 전체를 그 콜라이더 포맷으로 복사해 주지 않으면 거기에 충돌시킬 수 없습니다.</p>
<h2 id="결정-셋-리그를-가로질러-이동하는-애니메이션" tabindex="-1">결정 셋: 리그를 가로질러 이동하는 애니메이션 <a class="header-anchor" href="#결정-셋-리그를-가로질러-이동하는-애니메이션" aria-label="Permalink to &quot;결정 셋: 리그를 가로질러 이동하는 애니메이션&quot;"></a></h2>
<p>아바타는 Synty POLYGON 리그를 쓰고, 우리 모션 클립은 큰 오픈 애니메이션 라이브러리에서 옵니다. 리그와 클립이 본 이름을 공유하기 때문에, 일반적인 경우엔 런타임 리타게팅이 필요 없고 트랙이 이름으로 그냥 바인딩됩니다. 전체 캐릭터 파이프라인은 <a href="/ko/blog/2026-05-10-open-world-browser-part-25-universal-characters.html">범용 캐릭터</a>에 정리해 두었습니다.</p>
<p>흥미로운 작업은 둘이 맞지 않는 경우입니다. 우리는 한 스켈레톤을 다른 스켈레톤에 매핑하는 리타게팅 패스를 만들었고, 이걸 제대로 하려면 세 가지 구체적인 문제를 풀어야 했습니다. 먼저 바인드 포즈를 정렬합니다. A-포즈를 T-포즈에 맞추면 조인트마다 약 30도가 조용히 더해지기 때문입니다. 루트 모션과 보폭은 두 개의 별도 비율로 스케일합니다. 수직은 엉덩이-바닥(hip-to-floor), 수평은 전체 비율입니다. 그리고 리타게팅된 클립을 고정 샘플 레이트로 원본과 비교 테스트해서, 회귀가 플레이어보다 먼저 드러나게 합니다. 그 파이프라인이 새 애니메이션 소스를, 그리고 언젠가는 창작자가 제공한 캐릭터를, 모든 클립을 손으로 고치지 않고 추가할 수 있게 해줍니다.</p>
<p>그 위에는 모션 상태에서 매 프레임 올바른 클립 패밀리를 고르는 애니메이션 상태 머신이 있습니다. 속도에 따른 점프 변형, 충격에 따른 착지 강도, 속도와 지형 기울기의 내적에서 나오는 경사 방향, 멈출 때 문워크하지 않도록 하는 발 위상 정확 정지, 그리고 벽에 부딪혀도 걷기와 떨어지기 사이에서 깜빡이지 않게 하는 100밀리초 디바운스. 이 중 무엇도 이국적이지 않지만, 그 레이어를 소유해야만 얻을 수 있는 종류의 것입니다.</p>
<h2 id="결정-넷-어떤-엔진도-출시하지-않는-부분" tabindex="-1">결정 넷: 어떤 엔진도 출시하지 않는 부분 <a class="header-anchor" href="#결정-넷-어떤-엔진도-출시하지-않는-부분" aria-label="Permalink to &quot;결정 넷: 어떤 엔진도 출시하지 않는 부분&quot;"></a></h2>
<p>나머지 세 결정은 세계가 어떻게 돌아가는지에 관한 것입니다. 이 결정은 제품이 무엇인지에 관한 것이고, PlayCanvas와의 비교가 결국 범주 오류인 이유입니다.</p>
<p>PlayCanvas, Babylon, Unity, 그리고 직접 짠 Three.js 앱은 모두 같은 형태를 가정합니다. 당신은 책상에서, 2D 에디터 안에서, 세계를 바깥에서 들여다보며 게임을 만들고, 그다음 재생을 눌러 별도의 런타임을 출시합니다. 그들의 엔진 내 편집조차 워크스테이션 앞에 앉은 당신이 들여다보는 씬을 조작하는 것입니다.</p>
<p>Cinevva World는 그걸 뒤집습니다. 당신은 세계 안에서, 당신의 플레이어가 설 바로 그 공간에 선 아바타로서, 원하는 걸 묘사하고 그것이 나타나는 걸 지켜보며 만듭니다. 창작과 플레이는 런타임에 다리를 놓은 빌드 단계가 아니라 하나의 연속된 세션입니다. 가장 가까운 참조점은 웹 3D 엔진이 아니라 Roblox, Rec Room, Horizon Worlds이고, 그것들조차 창작 대부분을 책상에 둡니다. 마우스로 모는 에디터 없이 이걸 다룰 수 있게 만드는 건 AI 빌더인데, &quot;여기에 등불 켜진 부두를 놓아&quot;를 지오메트리와 배치로 바꿔줍니다.</p>
<p>이건 범용 엔진에 볼트로 조여 붙일 수 없습니다. 렌더링 기능이 아니기 때문입니다. 이건 스택 전체의 전제입니다. 지형이 런타임에 어떻게 편집 가능한지부터, 네트워크가 모든 오브젝트를 근처에 선 사람이 방금 만든 무언가로 어떻게 다루는지까지요.</p>
<h2 id="우리가-한-일을-따라-하면-안-되는-경우" tabindex="-1">우리가 한 일을 따라 하면 안 되는 경우 <a class="header-anchor" href="#우리가-한-일을-따라-하면-안-되는-경우" aria-label="Permalink to &quot;우리가 한 일을 따라 하면 안 되는 경우&quot;"></a></h2>
<p>여기가 &quot;우리가 직접 엔진을 만들었다&quot; 장르가 보통 건너뛰는 부분입니다. 이번 분기에 브라우저 게임을 출시하고 싶다면, 우리를 따라 하지 마세요. Unity 스타일 에디터와 관리형 파이프라인을 원하면 PlayCanvas를 쓰세요. 물리가 포함된 완전한 엔진을 원하고 그 구조 안에서 편하면 Babylon을 쓰세요. 최대한의 제어와 최소한의 의견을 원하고 그 위에 쌓아 올릴 팀이 있으면 Three.js를 쓰세요. 이미 Unity 게임이 있으면 Unity에서 포팅하세요.</p>
<p>직접 렌더러, 물리, 애니메이션을 작성하는 건 제품의 전제가 기성품과 양립할 수 없을 때, 만들고 있는 게 엔진 위의 게임이 아니라 마침 엔진으로 만들어진 장소일 때에만 올바른 판단입니다. 우리에겐 그게 사실이었습니다. 당신에겐 아마 사실이 아닐 거고, 그래도 괜찮습니다. 평가를 솔직하게 하는 핵심은 첫 줄을 쓰기 전에 자신이 어느 경우에 속하는지 아는 것입니다.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[텅 빈 세계는 쓸쓸한 세계다: 흥하거나 망한 모든 크리에이터 플랫폼이 우리에게 가르쳐 주는 것]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-06-06-how-creator-worlds-live-or-die</link>
            <guid>https://app.cinevva.com/ko/blog/2026-06-06-how-creator-worlds-live-or-die</guid>
            <pubDate>Sat, 06 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[우리는 한 문장만으로 공유 3D 세계 안에 건물 전체를 짓는 AI를 만들었습니다. 모두에게 공개하기 전에, 찾을 수 있는 모든 비슷한 플랫폼의 출시 사례를 연구했습니다. 무덤은 거대하고 생존자는 적으며, 둘을 가르는 선은 과장 광고가 인정하는 것보다 훨씬 선명합니다. 여기 그 이야기와 숫자, 그리고 우리가 다르게 하고 있는 것을 담았습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="텅-빈-세계는-쓸쓸한-세계다-흥하거나-망한-모든-크리에이터-플랫폼이-우리에게-가르쳐-주는-것" tabindex="-1">텅 빈 세계는 쓸쓸한 세계다: 흥하거나 망한 모든 크리에이터 플랫폼이 우리에게 가르쳐 주는 것 <a class="header-anchor" href="#텅-빈-세계는-쓸쓸한-세계다-흥하거나-망한-모든-크리에이터-플랫폼이-우리에게-가르쳐-주는-것" aria-label="Permalink to &quot;텅 빈 세계는 쓸쓸한 세계다: 흥하거나 망한 모든 크리에이터 플랫폼이 우리에게 가르쳐 주는 것&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<figure style="margin:1.5rem 0">
<img src="/img/blog/ai-builder-hero.webp" alt="Cinevva's AI Builder constructing a two-story house from a chat prompt" style="width:100%;border-radius:10px">
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">우리의 AI 빌더. 누군가 "2층을 지어줘"라고 입력했더니 AI가 바닥 데크를 깔고 벽을 세운 뒤, 이어서 계단과 지붕을 제안했습니다. 이 모든 일이 다른 사람들도 걸어 들어올 수 있는 세계 안에서 벌어집니다.</figcaption>
</figure>
<p>이제 우리는 세계를 생성할 수 있습니다. 데모 영상 얘기가 아닙니다. 위 그림은 우리 에디터입니다. 누군가 채팅창에 &quot;2층을 지어줘&quot;라고 입력했고, AI가 바닥 데크를 깔고 앞벽과 옆벽, 뒷벽을 세운 뒤 계단과 지붕으로 계속 이어가겠다고 제안하는 걸 지켜봤습니다. 소품이 아니라, 텍스처가 아니라, 구조물 전체입니다. 그리고 그것이 다른 사람들도 걸어 들어올 수 있는 세계 안에 놓였습니다. 우리 파이프라인은 그 부품들도 이미 만듭니다. 3D 모델, 음악, 사운드, 머티리얼까지.</p>
<p>그래서 우리는 Cinevva World를 대중에게 공개하기 직전입니다. 그러기 전에, 나는 가서 부고들을 읽었습니다.</p>
<p>우리가 만들고 있는 것에는 불편한 진실이 있기 때문입니다. 지난 15년 동안 아주 똑똑하고 아주 자금이 넉넉한 팀들이 공유 창작 세계를 작동시키려 했습니다. 몇몇은 인류가 만든 가장 큰 것들 중 하나가 되었습니다. 대부분은 죽었습니다. 두 결과 사이의 간극은 재능도 아니고 돈도 아닙니다. 죽은 것들 중 일부는 우리가 평생 가질 것보다 더 많은 재능과 돈을 가졌으니까요. 그 간극은, 거의 아무도 첫 시도에 제대로 해내지 못하는 소수의 결정에 있습니다. 이것이 내가 발견한 것입니다.</p>
<h2 id="무덤" tabindex="-1">무덤 <a class="header-anchor" href="#무덤" aria-label="Permalink to &quot;무덤&quot;"></a></h2>
<p>실패 사례부터 시작하겠습니다. 성공담보다 더 솔직하기 때문입니다. 승자는 자기 역사를 깔끔한 서사로 다시 씁니다. 패자는 메모를 흘립니다.</p>
<h3 id="meta-horizon-worlds-역사상-가장-비싼-빈-방" tabindex="-1">Meta Horizon Worlds: 역사상 가장 비싼 빈 방 <a class="header-anchor" href="#meta-horizon-worlds-역사상-가장-비싼-빈-방" aria-label="Permalink to &quot;Meta Horizon Worlds: 역사상 가장 비싼 빈 방&quot;"></a></h3>
<p>Meta는 메타버스 베팅에 수백억 달러를 썼습니다. Reality Labs는 2026년 초에 보고된 <a href="https://www.cnbc.com/2026/03/18/meta-horizon-worlds-metaverse-vr.html" target="_blank" rel="noreferrer">단일 분기 영업손실 60억 2천만 달러</a>를 기록했고, 수년간 분기마다 수십억 달러씩 출혈해 왔습니다. 그 대표작이 Horizon Worlds였습니다. 그 돈이 산 것이 무엇인지 여기 있습니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/mNbz7-ejnZw" title="Horizon Worlds - Official Trailer" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Meta의 Horizon Worlds 공식 트레일러. Meta가 수십억 달러를 쏟은 이 플랫폼은 2026년 6월 VR 지원을 중단하고 모바일 앱으로 살아남으려 합니다.</figcaption>
</figure>
<p><a href="https://fortune.com/2022/10/07/metas-horizon-world-quality-poor-not-even-employees-using-says-metaverse-vp-leaked-memo/amp/" target="_blank" rel="noreferrer">Fortune</a>와 <a href="https://ryanschultz.com/2022/10/07/leaked-internal-memos-from-meta-detail-problems-with-horizon-worlds-and-horizon-workrooms/" target="_blank" rel="noreferrer">Ryan Schultz</a>가 보도한 유출된 내부 메모는, 크리에이터들이 만든 세계 중 50명 이상이 방문한 곳이 약 9퍼센트에 불과했음을 드러냈습니다. 대다수는 제작자 본인 외에는 방문이 0이었습니다. 한 메모는 이 참여도 문제를 이 분야의 모든 창업자가 문신으로 새겨야 할 한 문장으로 요약했습니다. <a href="https://kotaku.com/meta-facebook-horizon-worlds-vr-mark-zuckerberg-1849669048" target="_blank" rel="noreferrer">&quot;텅 빈 세계는 쓸쓸한 세계다.&quot;</a> 활성 사용자를 설문하려던 연구자들은 겨우 514명밖에 찾지 못했습니다. 플레이어 기반이 그만큼 작았기 때문입니다.</p>
<p>리텐션 수치는 더 나빴습니다. 유출된 데이터는 첫 달 이후 <a href="https://mixed-news.com/en/horizon-worlds-leak-only-1-in-10-users-return-web-launch-coming/" target="_blank" rel="noreferrer">돌아온 사용자가 약 10명 중 1명뿐</a>이었음을 보여줬습니다. Meta는 2022년 자체 목표를 월 50만 명에서 20만 명으로 조용히 낮췄고, 그러고도 그 플랫폼은 VRChat보다, 그리고 2003년 게임인 Second Life보다 동시 접속자가 적었습니다. 내부 도그푸딩 대시보드는 Meta 자체 직원들조차 그걸 쓰지 않았음을 보여줬고, 이는 경영진이 관리자들에게 주간 로그인에 대한 책임을 묻기 시작하도록 만들었습니다. 한 VP는 팀을 그해 남은 기간 동안 &quot;품질 락다운&quot;에 들어가게 했고, 자신들이 제품-시장 적합성을 찾지 못한 제품을 만들고 있다고 글로 인정했습니다.</p>
<p>2026년 3월, Meta는 <a href="https://www.cnbc.com/2026/03/18/meta-horizon-worlds-metaverse-vr.html" target="_blank" rel="noreferrer">VR 지원을 완전히 종료한다고 발표</a>하고 Horizon Worlds를 거의 전적으로 모바일 앱으로 전환했습니다. 헤드셋 없는 사람들을 위한 진입점이자, 그들 자신의 표현으로는 Roblox처럼 기능하는 것이었습니다. 역사상 가장 비싼 메타버스는, 첫날부터 그랬어야 했던 바로 그것이 되려 애쓰며 생을 마감했습니다.</p>
<p>교훈은 &quot;VR이 너무 일렀다&quot;가 아닙니다. 물론 너무 이르긴 했지만요. 교훈은 어떤 자본도 텅 빈 세계를 채우지 못한다는 것입니다. 콘텐츠 밀도는 마케팅 예산으로 살 수 있는 것이 아닙니다. 세계가 비어 있으면 사람들이 떠나고, 사람들이 떠나면 세계는 계속 비어 있습니다. 그 고리가 Meta를 산 채로 집어삼켰습니다.</p>
<h3 id="decentraland와-the-sandbox-10억-달러짜리-유령-도시들" tabindex="-1">Decentraland와 The Sandbox: 10억 달러짜리 유령 도시들 <a class="header-anchor" href="#decentraland와-the-sandbox-10억-달러짜리-유령-도시들" aria-label="Permalink to &quot;Decentraland와 The Sandbox: 10억 달러짜리 유령 도시들&quot;"></a></h3>
<p>2022년 10월, 단 하나의 데이터 포인트가 크립토 세계에 불을 질렀습니다. <a href="https://www.coindesk.com/web3/2022/10/07/its-lonely-in-the-metaverse-decentralands-38-daily-active-users-in-a-13b-ecosystem" target="_blank" rel="noreferrer">DappRadar의 보도</a>에 따르면 Decentraland의 일일 활성 사용자는 38명이었습니다. The Sandbox는 522명이었습니다. 이 두 프로젝트는 당시 각각 약 13억 달러의 시가총액을 짊어지고 있었습니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/Zg5vcdEeLOA" title="The Sandbox Official Teaser" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">The Sandbox 공식 티저. 이것과 Decentraland는 각각 약 13억 달러의 가치를 짊어졌지만 일일 사용자는 수백에서 수천 명 수준이었습니다.</figcaption>
</figure>
<p>이제, 프로젝트 측은 반박했고 그 뉘앙스는 사실 비웃음보다 더 중요합니다. 38이라는 숫자는 하루에 온체인 거래를 한 고유 지갑만 셌습니다. DappRadar가 &quot;payers&quot;라고 부르는 것이지, 블록체인을 건드리지 않고 로그인해서 돌아다닌 사람들이 아닙니다. Decentraland는 <a href="https://blockworks.com/news/metaverse-platforms-set-the-record-straight-about-daily-active-users" target="_blank" rel="noreferrer">월간 로그인 사용자가 56,697명</a>이고 다른 추정으로는 일일 약 8,000명이라고 반박했습니다. The Sandbox는 알파 시즌 동안 일일 39,000명에, 14일차 리텐션 40퍼센트를 주장했습니다.</p>
<p>하지만 그 간극을 잠시 음미해 보세요. 이 글 전체에서 가장 중요한 숫자이기 때문입니다. 가장 후하게 잡은 수치를 받아들여도, 잘 봐줘야 일일 수천 명의 사용자 위에 10억 달러짜리 가치 평가가 얹혀 있는 셈입니다. 비교하자면, 조사 결과 같은 기간 블록체인이 아닌 Roblox는 <a href="https://blockworks.com/news/metaverse-platforms-set-the-record-straight-about-daily-active-users" target="_blank" rel="noreferrer">일일 활성 사용자 5,200만 명에 월간 결제 사용자는 1,130만 명뿐</a>이었습니다. 무료 가상 세계에 있는 대부분의 사람들은 거의 또는 전혀 거래하지 않습니다. 이건 양쪽 모두에 칼날을 들이댑니다. 38-DAU 비웃음이 부당했다는 뜻이기도 하고, 10억 달러짜리 가치 평가가 환상이었다는 뜻이기도 합니다. 둘 다 잘못된 숫자를 쟀습니다. 가치 평가는 토큰 투기를 쟀습니다. 비웃음은 지갑 거래를 쟀습니다. 어느 쪽도 누가 재미있어하는지는 재지 않았습니다.</p>
<p>그것이 가장 순수한 형태의 허영 지표 함정입니다. 가입 계정 수, 토큰 시가총액, 총 도달 가능 시장, 언론 노출 수. 그 어느 것도 당신의 세계가 살아 있는지 말해 주지 않습니다. 그걸 말해 주는 유일한 숫자는 얼마나 많은 사람이 다시 돌아오는지, 그리고 무언가를 만드는 사람들이 계속 만드는지뿐입니다.</p>
<h3 id="dreams-아무도-머무를-수-없었던-가장-아름다운-도구" tabindex="-1">Dreams: 아무도 머무를 수 없었던 가장 아름다운 도구 <a class="header-anchor" href="#dreams-아무도-머무를-수-없었던-가장-아름다운-도구" aria-label="Permalink to &quot;Dreams: 아무도 머무를 수 없었던 가장 아름다운 도구&quot;"></a></h3>
<p>LittleBigPlanet을 만든 스튜디오 Media Molecule은 거의 10년을 들여 Dreams를 만들었습니다. 사람들이 그 안에서 플레이 가능한 게임과 애니메이션 단편 영화, 음악 앨범까지 만들 만큼 깊은 창작 도구였습니다. 비평가들은 그것을 사랑했습니다. 그리고 <a href="https://www.pushsquare.com/news/2023/07/dreams-live-service-ending-as-media-molecule-couldnt-find-a-sustainable-path" target="_blank" rel="noreferrer">2023년 9월, 스튜디오는 라이브 서비스를 종료</a>하며, 지속 가능한 비즈니스 모델을 찾지 못했다고 솔직히 말했습니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/2ltgkcoQzow" title="Dreams | Release Date Trailer | PS4" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Media Molecule의 Dreams. 사람들이 사랑한 창작 도구였지만, 크리에이터가 단 한 푼도 벌 방법이 없는 채로 2023년에 라이브 서비스가 끝났습니다.</figcaption>
</figure>
<p>부검 결과는 스스로 자초한 상처의 체크리스트입니다. 그리고 나는 엄청난 존경심을 담아 이렇게 말합니다. 우리도 그 하나하나를 똑같이 저지를 수 있기 때문입니다. Dreams는 <a href="https://www.pushsquare.com/news/2023/07/dreams-live-service-ending-as-media-molecule-couldnt-find-a-sustainable-path" target="_blank" rel="noreferrer">크리에이터가 자기 작업을 수익화하도록 결코 허락하지 않았습니다</a>. 약속된 인게임 상점은 끝내 출시되지 않았습니다. 코스메틱도, 배틀 패스도, 아무것도 없었습니다. 도구를 플랫폼으로 바꾸는 부류의 진지한 크리에이터들에게는, 상방이 전혀 없는데 수년을 투자할 이유가 없었습니다. 그것은 PS4 전용으로 출시되었고, 출시 시점에 PC 버전도 네이티브 PS5 빌드도 없어서 가능한 관객 규모가 강하게 제한되었습니다. 그리고 공동 창업자 <a href="https://icon-era.com/threads/media-molecule-co-founders-biggest-regret-with-dreams-was-not-focusing-on-multiplayer-understands-new-ip-is-more-of-a-game-than-a-creative-tool.11724/" target="_blank" rel="noreferrer">Mark Healey는 나중에 자신의 가장 큰 후회가 멀티플레이어에 집중하지 않은 것이었다고 말했고</a>, 팀은 자신들의 창작물이 창작 도구보다 게임으로서 더 잘 작동한다는 것을 깨닫게 되었다고 했습니다.</p>
<p>그 마지막 부분을 다시 읽어 보세요. 지구상에서 가장 재능 있는 UGC 스튜디오가 사후에 내린 결론은, 그것이 도구이기보다 먼저 게임이었어야 했다는 것입니다. 그것이 이 연구 전체에서 가장 중요한 한 문장이고, 나중에 다시 돌아오겠습니다.</p>
<h3 id="나머지-묘지" tabindex="-1">나머지 묘지 <a class="header-anchor" href="#나머지-묘지" aria-label="Permalink to &quot;나머지 묘지&quot;"></a></h3>
<p>이 패턴은 음울할 정도로 일관되게 반복됩니다.</p>
<p>협업 UGC 창작 플랫폼 <a href="https://www.gamedeveloper.com/business/crayta-to-shut-down-after-launch-platform-stadia-bites-the-dust" target="_blank" rel="noreferrer">Crayta</a>는 2023년 3월에 문을 닫았고 사용자들은 만든 것을 전부 잃었습니다. 그 개발사는 2021년에 Meta에 인수되었는데도 플랫폼은 결국 죽었습니다. 직접적인 원인은 이것입니다. Google Stadia에서 출시되었는데, Stadia가 죽자 Crayta도 함께 죽었습니다. 플랫폼 의존성은 자기 머리에 겨눈 장전된 총입니다.</p>
<figure style="margin:1.5rem 0">
<img src="https://cdn.cinevva.com/blog/lived-or-died-crayta.webp" alt="Crayta, the collaborative game-creation platform" loading="lazy" style="width:100%;border-radius:10px">
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Crayta는 Google Stadia에서 출시되었습니다. 2023년 Stadia가 문을 닫자 Crayta도 함께 갔고, 크리에이터들은 만든 것을 전부 잃었습니다. 트레일러 스틸.</figcaption>
</figure>
<p>Microsoft의 UGC 게임 메이커 Project Spark는 몇 해 전에 같은 궤적으로 문을 닫았습니다. 강력한 도구였지만 머무르는 사람이 충분치 않았습니다. Linden Lab이 Second Life의 VR 후계자로 내놓은 Sansar는 관객을 찾지 못하고 매각되었습니다. Second Life 창업자 Philip Rosedale 자신의 두 번째 메타버스 회사인 High Fidelity는 가상 세계에서 완전히 방향을 틀었습니다.</p>
<figure style="margin:1.5rem 0">
<img src="https://cdn.cinevva.com/blog/lived-or-died-secondlife.webp" alt="Second Life, Linden Lab's user-created virtual world" loading="lazy" style="width:100%;border-radius:10px">
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Linden Lab의 2003년 세계 Second Life는 20년이 넘은 지금도 여전히 돌아가고 있습니다. 정작 그 VR 후계자인 Sansar와 Philip Rosedale의 High Fidelity는 둘 다 실패했습니다. 트레일러 스틸.</figcaption>
</figure>
<p>그리고 지금 당장 벌어지고 있어서 무시할 수 없는 신호로, Rec Room은 <a href="https://www.uploadvr.com/vrchat-statement-after-rec-room-and-horizon-worlds-fold/" target="_blank" rel="noreferrer">2026년 6월 1일부로 서비스를 종료한다고 발표</a>하며 지속적인 수익성에 결코 도달하지 못했다고 밝혔습니다.</p>
<p>메타버스를 만드는 메타버스 회사의 창업자들이, 자기 자신의 메타버스에 머무를 수 없었습니다. 어려운 부분이 렌더링이라고 생각하는 사람이라면 누구든 이 사실에 겁을 먹어야 합니다.</p>
<figure style="margin:1.5rem 0">
<img src="https://cdn.cinevva.com/blog/lived-or-died-recroom.webp" alt="Rec Room, the cross-platform social UGC world" loading="lazy" style="width:100%;border-radius:10px">
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">가장 큰 소셜 창작 세계 중 하나였던 Rec Room은 누적 1억 5천만 명이 넘는 플레이어에 도달하고도, 그 도달을 지속 가능한 비즈니스로 바꾸지 못한 채 2026년 6월 1일에 문을 닫았습니다. 트레일러 스틸.</figcaption>
</figure>
<h2 id="생존자들-그리고-정말로-그들을-구한-것" tabindex="-1">생존자들, 그리고 정말로 그들을 구한 것 <a class="header-anchor" href="#생존자들-그리고-정말로-그들을-구한-것" aria-label="Permalink to &quot;생존자들, 그리고 정말로 그들을 구한 것&quot;"></a></h2>
<p>이제 살아 있는 것들입니다. 흥미로운 점은, 그 누구도 예상한 방식으로 이기지 않았다는 것이고, 여럿은 실패자들이 따랐던 규칙을 깨면서 이겼다는 것입니다.</p>
<h3 id="roblox-12년에-걸친-하룻밤의-성공" tabindex="-1">Roblox: 12년에 걸친 하룻밤의 성공 <a class="header-anchor" href="#roblox-12년에-걸친-하룻밤의-성공" aria-label="Permalink to &quot;Roblox: 12년에 걸친 하룻밤의 성공&quot;"></a></h3>
<p>모두가 Roblox를 모델로 인용합니다. 거의 아무도 실제로 일어난 일을 따라 하지 않습니다. 실제로 일어난 일은 12년간 실패처럼 보이는 것이었기 때문입니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/LTnMKjXEnMY" title="ROBLOX - Game Trailer" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Roblox. 2006년에 약 100명을 끌어모았고, 커뮤니티가 게임을 짓도록 맡긴 덕분에 기하급수적 성장에 이르기까지 12년이 걸렸습니다.</figcaption>
</figure>
<p>Roblox의 2006년 베타는 <a href="https://www.howtheygrow.co/p/how-roblox-grows" target="_blank" rel="noreferrer">동시 접속 정점 30~40명에 약 100명의 기술 애호가</a>를 끌어모았습니다. 그 후 10년 넘게 묵묵히 앞으로 갈았습니다. 2016년 초 900만 명에서 2019년 9천만 명, 2023년 2억 1,400만 명까지 갔습니다. 창업자 David Baszucki는 2009년 Minecraft가 자신을 추월해 폭발했을 때조차 사용자 생성 콘텐츠 비전에서 방향을 틀기를 거부했습니다. 그는 그것을 의도적으로 느리게 굽는 과정으로 다뤘고, 결정적이었던 단 하나의 수는 게임을 사내에서 만드는 대신 커뮤니티가 모든 게임을 짓도록 맡긴 결정이었습니다. 그것이 콘텐츠 비용을 없애고 모든 크리에이터를 성장 엔진으로 바꿨습니다.</p>
<p>하지만 여기 카고 컬트 추종자들이 놓치는 부분이 있고, 그래서 나는 두 번째 출처를 항상 열어 둡니다. Matthew Ball의 <a href="https://www.matthewball.co/all/roblox2024" target="_blank" rel="noreferrer">2024년 분석</a>은 Roblox가 막대한 규모에서도 잔혹한 적자로, 영업이익률이 대략 마이너스 38퍼센트로 운영되고 있으며, 한 달에 그 통화를 구매하는 사용자는 6퍼센트뿐이고 사용자당 매출은 콘솔 플랫폼의 일부에 불과함을 보여줍니다. Roblox는 세계에서 가장 큰 게임인데도 여전히 돈을 버는 데 고전합니다. 플라이휠은 진짜이고 경제성은 어렵습니다. 크리에이터 플랫폼이 돈 찍는 면허라고 말하는 사람이 있다면, 그는 당신에게 뭔가를 팔고 있는 겁니다.</p>
<p>그러나 더 깊은 교훈은 그 사용자 숫자 속에 빤히 숨어 있습니다. Roblox의 수억 명 사용자 중 압도적 다수는 아무것도 짓지 않습니다. 그들은 다른 사람들이 만든 수천만 개 게임 카탈로그를 <em>플레이</em>하러 옵니다. 그 카탈로그를 키우는 데 10년과 개발자 수익 분배 경제가 들었습니다. Roblox는 사람들이 어쩌다 플레이하는 건축 도구가 아닙니다. 일부 사람들이 어쩌다 짓는 놀이 장소입니다. 그 순서가 전부입니다.</p>
<h3 id="minecraft-텅-빌-수-없었던-세계" tabindex="-1">Minecraft: 텅 빌 수 없었던 세계 <a class="header-anchor" href="#minecraft-텅-빌-수-없었던-세계" aria-label="Permalink to &quot;Minecraft: 텅 빌 수 없었던 세계&quot;"></a></h3>
<p>Minecraft는 텅 빈 세계 문제를 겪은 적이 없고, 그 이유를 이해하는 것이 게임의 전부입니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/MmB9b5njVbA" title="Official Minecraft Trailer" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Minecraft 공식 트레일러. 절차적 생존이라는 점은 세계가 결코 비지 않았고, 플레이할 가치를 갖기 위해 사용자 콘텐츠가 필요한 적이 없었다는 뜻입니다.</figcaption>
</figure>
<p>Minecraft는 절차적 생성을 갖춘 생존 게임으로 출시되었습니다. 세계가 스스로를 무한히 짓고, 1분째에 당신은 무엇을 해야 할지 고민하며 빈 캔버스를 응시하고 있지 않습니다. 밤이 오고 있고 무언가가 당신을 죽이려 하니, 당신은 땅을 팝니다. 이 게임은 다른 사용자가 0명이고 사용자 생성 콘텐츠가 0이어도 한 사람에게 영원히 재미있습니다. 절차적 생성기가 고갈되지 않는 콘텐츠 기계이기 때문입니다. 모드, 서버, 커스텀 맵, 창작 생태계 전체, 그 모든 것은 이미 스스로 팔린 게임 <em>위에서</em> 자랐습니다. 크리에이티브 모드는 이미 수백만 명이 생존에 빠진 뒤에 나왔습니다. 입소문과 YouTube가 나머지를 했습니다.</p>
<p>Minecraft는 콜드 스타트를 아예 겪지 않음으로써 해결했습니다. 그것이 치트 코드이고, 우리는 그것을 훔칠 겁니다.</p>
<h3 id="브라우저-게임-유일한-해자가-된-배포" tabindex="-1">브라우저 게임: 유일한 해자가 된 배포 <a class="header-anchor" href="#브라우저-게임-유일한-해자가-된-배포" aria-label="Permalink to &quot;브라우저 게임: 유일한 해자가 된 배포&quot;"></a></h3>
<p>그리고 우리의 실제 전달 방식에 가장 가까운 장르, 다운로드 없는 브라우저 게임이 있습니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/oznO3GGzu2s" title="Krunker.io trailer" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">.io 전통을 잇는 브라우저 FPS Krunker. 이 장르의 유일한 해자는 배포, 즉 다운로드 없이 게임 전체를 불러오는 링크입니다.</figcaption>
</figure>
<p><a href="https://news.viverse.com/post/what-are-io-games" target="_blank" rel="noreferrer">Agar.io는 2015년 출시 후 몇 주 만에 일일 약 500만 명</a>의 플레이어에 도달했습니다. Slither.io는 모바일 다운로드 6,800만 회와 브라우저 플레이 6,700만 회를 쌓았습니다. 조사는 그 이유에 대해 단도직입적입니다. <a href="https://news.viverse.com/post/what-are-io-games" target="_blank" rel="noreferrer">&quot;<code>.io</code> 장르의 경쟁 해자는 게임 메커니즘이 아니라 배포 그 자체다.&quot;</a> 링크를 클릭하면 곧바로 플레이 중입니다. 설치도, 계정도, 앱스토어도 없습니다. <a href="https://medium.com/the-megacool-blog/9-growth-hacks-from-viral-hit-game-agar-io-7d8f71f70a0c" target="_blank" rel="noreferrer">Agar.io의 온보딩은 클릭 한 번</a>이었습니다. 이름을 입력하고 플레이를 누르면 들어가 있습니다. TikTok에서 영상이 퍼지듯 채팅 앱을 타고 퍼졌습니다.</p>
<p>하지만 이 선물에는 칼이 들어 있고, 그 칼은 우리 쪽도 벱니다. 다운로드가 없다는 건 약속이 없다는 뜻입니다. 누군가를 들여보내는 바로 그 무마찰성이 그를 나가게도 만듭니다. 탭을 닫는 데 아무 비용도 들지 않으니까요. 브라우저 바이럴은 진짜이고 동시에 기본적으로 얕습니다. <code>.io</code> 게임들은 첫 10초 안에 즉각적이고 명백하게 재미있어서 그것을 견뎌냈습니다. 죽은 브라우저 세계들은 들어가는 데 마찰이 없었고, 일단 도착하면 머무를 이유를 전혀 주지 않았습니다.</p>
<h3 id="among-us-figma-townscaper-vrchat-이기는-네-가지-방법-더" tabindex="-1">Among Us, Figma, Townscaper, VRChat: 이기는 네 가지 방법 더 <a class="header-anchor" href="#among-us-figma-townscaper-vrchat-이기는-네-가지-방법-더" aria-label="Permalink to &quot;Among Us, Figma, Townscaper, VRChat: 이기는 네 가지 방법 더&quot;"></a></h3>
<p>빠르게 네 가지를 보겠습니다. 각각이 서로 다른 지렛대를 보여 주기 때문입니다.</p>
<p><a href="https://www.esports.net/news/how-among-us-blew-up-online-two-years-after-release/" target="_blank" rel="noreferrer">Among Us</a>는 2018년에 출시되어 2년 동안 상업적으로 아무것도 아니었습니다. 개발자들은 그것을 거의 포기할 뻔했습니다. 그러다 2020년 9월, <a href="https://howtomarketagame.com/2020/09/14/among-us-the-4-lessons-of-their-viral-success/" target="_blank" rel="noreferrer">점점 더 큰 스트리머들의 사다리</a>가 그것을 발견했고, 여러 시간에 걸친 Sodapoppin 방송에서 정점을 찍으며 전 세계적 현상이 되었습니다. 초기 산소는 itch.io 첫 페이지 피처와, 판매의 절반을 차지하게 된 한국 관객에게서 왔습니다. 교훈은, 발견될 만큼 오래 살아남는다면 돌파구는 출시 몇 년 뒤에, 당신이 계획하지 않은 채널에서 올 수 있다는 것입니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/NSJ4cESNQfE" title="Among Us Steam Release Trailer" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Among Us. 2년 동안 거의 주목받지 못한 채 있다가, 스트리머들의 사다리가 2020년에 그것을 전 세계적 현상으로 바꿔 놓았습니다.</figcaption>
</figure>
<p><a href="https://review.firstround.com/the-5-phases-of-figmas-community-led-growth-from-stealth-to-enterprise/" target="_blank" rel="noreferrer">Figma</a>는 약 3년간 스텔스 상태였고, 무료로 출시했으며, 과금을 시작하기까지 2년을 더 기다렸습니다. 그 활성화 순간은 멀티플레이어였습니다. 디자이너가 다른 누군가 같은 파일을 편집하는 것을 느낀 바로 그 순간이었습니다. 그리고 여기 중요한 부분이 있습니다. Figma의 무료 티어는 원래 협업자를 2명으로 제한했는데, 이는 제품을 팔리게 한 바로 그 마법 같은 순간을 목 졸랐습니다. 그들은 협업자를 무제한으로 만들어 사람들이 실제로 그것을 느끼게 함으로써 그것을 고쳤습니다. 그들은 Twitter에서 디자인 인플루언서를 직접 겨냥해 커뮤니티의 씨앗을 뿌렸습니다. 교훈은, 당신의 아하 순간을 찾은 뒤, 신규 사용자와 그 순간 사이의 모든 장애물을 치우라는 것입니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/n5gJgkO2Dg0" title="Figma product launch keynote" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Figma. 그 활성화 순간은 멀티플레이어였고, 그래서 제품을 팔리게 한 바로 그 마법을 가로막던 무료 티어 협업자 제한을 없애 버렸습니다.</figcaption>
</figure>
<p><a href="https://www.gamedeveloper.com/game-platforms/how-townscaper-works-a-story-four-games-in-the-making" target="_blank" rel="noreferrer">Townscaper</a>는 스크린샷의 힘으로 히트한 작은 창작 장난감이었습니다. 그 개발자는 개발 도중 클립을 올리는 것만으로 자신의 Twitter 팔로워가 약 2만 명에서 9만 명으로 뛰는 것을 지켜봤고, 그것을 잘될 것이라는 초기 신호로 읽었습니다. 교훈은, 당신의 것이 아름답고 출시도 하기 전에 사람들이 시키지도 않았는데 공유한다면, 그것이 존재하는 가장 진짜인 검증이라는 것입니다.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/hqq25n6cQqo" title="Townscaper Launch Trailer" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Townscaper 출시 트레일러. 목표가 없는 창작 장난감으로, 사람들이 시키지도 않았는데 공유한 스크린샷의 힘으로 퍼졌습니다.</figcaption>
</figure>
<p>그리고 <a href="https://www.uploadvr.com/vrchat-statement-after-rec-room-and-horizon-worlds-fold/" target="_blank" rel="noreferrer">VRChat</a>은 Meta의 수십억 달러와 Rec Room이 둘 다 접은 바로 그 몇 달 동안, 동시 접속자 거의 16만 명이라는 기록을 세웠습니다. 그것은 커뮤니티 주도, 크리에이터 주도이며, 주변에서 죽어간 것들만큼 자금이 넉넉하지도 않습니다. VRChat은 자신의 생존을 자본보다 커뮤니티의 충성심과 창의성 덕으로 돌립니다. 교훈은, 생존자 자신의 입으로 말하건대, 몰입한 크리에이터의 열정이 돈보다 오래간다는 것입니다.</p>
<h2 id="산-자와-죽은-자를-실제로-가르는-것" tabindex="-1">산 자와 죽은 자를 실제로 가르는 것 <a class="header-anchor" href="#산-자와-죽은-자를-실제로-가르는-것" aria-label="Permalink to &quot;산 자와 죽은 자를 실제로 가르는 것&quot;"></a></h2>
<p>이야기들을 나란히 놓으면 패턴은 미묘하지 않습니다.</p>
<table tabindex="0">
<thead>
<tr>
<th>플랫폼</th>
<th>무엇에 베팅했나</th>
<th>어디서 끝났나</th>
<th>교훈</th>
</tr>
</thead>
<tbody>
<tr>
<td>Minecraft</td>
<td>한 명에게도 재미있는 절차적 생존</td>
<td>역대 최다 판매 게임, 3억 5천만 장 이상</td>
<td>결코 텅 빈 세계를 두지 마라</td>
</tr>
<tr>
<td>Roblox</td>
<td>커뮤니티가 만든 게임에 크리에이터 수익 분배</td>
<td>12년에 걸쳐 일일 8천만 명 이상</td>
<td>먼저 놀 장소가 되고, 도구는 그다음</td>
</tr>
<tr>
<td>.io 게임</td>
<td>클릭 한 번, 다운로드 없는 브라우저 플레이</td>
<td>몇 주 만에 수백만 명의 플레이어</td>
<td>배포가 해자, 약속은 얕다</td>
</tr>
<tr>
<td>Figma</td>
<td>무료 티어, 실시간 멀티플레이어</td>
<td>약 200억 달러 인수 제안</td>
<td>아하 순간으로 가는 모든 장벽을 치워라</td>
</tr>
<tr>
<td>Among Us</td>
<td>값싼 소셜 게임, 그리고 인내</td>
<td>동시 접속 380만, 2년 늦게</td>
<td>발견될 만큼 오래 살아남아라</td>
</tr>
<tr>
<td>Townscaper</td>
<td>스크린샷할 가치가 있는 아름다운 장난감</td>
<td>약 38만 장 판매, 유기적 확산</td>
<td>시키지 않은 공유가 가장 진짜인 신호다</td>
</tr>
<tr>
<td>VRChat</td>
<td>커뮤니티와 크리에이터의 에너지</td>
<td>2026년 동시 접속 약 16만</td>
<td>열정이 자본보다 오래간다</td>
</tr>
<tr>
<td>Horizon Worlds</td>
<td>수십억 달러 자본, VR 우선</td>
<td>2026년 VR 종료, 약 10명 중 1명 복귀</td>
<td>돈은 텅 빈 세계를 채울 수 없다</td>
</tr>
<tr>
<td>Decentraland / Sandbox</td>
<td>게임보다 먼저 토큰 경제</td>
<td>약 13억 달러 가치, 일일 수백 명</td>
<td>가치 평가는 관객이 아니다</td>
</tr>
<tr>
<td>Dreams</td>
<td>깊은 도구, 경제 없음, 멀티플레이어 없음</td>
<td>2023년 라이브 서비스 종료</td>
<td>크리에이터에게 돈을 주고, 멀티플레이어를 내고, 게임이 되라</td>
</tr>
<tr>
<td>Crayta</td>
<td>Stadia 위에 사는 UGC 플랫폼</td>
<td>2023년 Stadia와 함께 종료</td>
<td>당신을 쫓아낼 수 있는 플랫폼 위에 짓지 마라</td>
</tr>
<tr>
<td>Project Spark / Sansar</td>
<td>강력한 도구, 돌아올 이유 없음</td>
<td>종료되거나 방향을 틀었다</td>
<td>게임 없는 도구에는 매일의 습관이 없다</td>
</tr>
</tbody>
</table>
<p>창작 세계를 죽이는 것은 빈 방입니다. Horizon Worlds, Decentraland, Dreams, Crayta, Project Spark, Sansar, 모두 같은 죽음을 맞았습니다. 사람이 충분치 않고, 콘텐츠가 충분치 않고, 돌아올 이유가 충분치 않은 것이, 스스로를 먹이로 삼는 고리 안에서 일어났습니다. 콜드 스타트 문제가 보스전입니다. 나머지는 전부 튜토리얼 레벨입니다.</p>
<p>그들을 구하는 것은 군중이 나타나기 전에 존재할 이유를 갖는 것입니다. Minecraft는 절차적 생존을 가졌습니다. Roblox는 10년간 인내심 있게 씨를 뿌린 게임들을 가졌습니다. <code>.io</code> 게임들은 10초의 재미를 가졌습니다. 모든 생존자는 카탈로그가 비어 있어도 당신의 시간을 쓸 가치가 있었습니다. 모든 희생자는 다른 사람들이 방문할 가치를 만들어 주기를 기다리는 아름다운 그릇이었습니다. 이것이 Dreams의 고백을 일반화한 것입니다. 먼저 게임을 짓고, 플랫폼은 그다음입니다. 플랫폼은 2막입니다. 사람들이 그 자체로 쓰는 무언가가 먼저 됨으로써 그것을 벌어야 합니다.</p>
<p>실제로 생존을 예측하는 지표는 보도자료에 있는 것들이 아닙니다. 조사는 여기서 일관됩니다. 제품-시장 적합성의 결정적 신호는 당신의 <a href="https://newsletter.pmcurve.com/p/retention-masterclass" target="_blank" rel="noreferrer">리텐션 곡선이 평평해지는 것</a>입니다. 어떤 코호트의 사람들이 영원히 계속 돌아오는 것입니다. 0으로 떨어지는 곡선은, 깔때기 위쪽이 아무리 커도 적합성이 없다는 뜻입니다. 대략적인 업계 벤치마크는 <a href="https://solsten.io/blog/d1-d7-d30-retention-in-gaming" target="_blank" rel="noreferrer">1일차 40퍼센트, 7일차 20퍼센트, 30일차 10퍼센트</a> 리텐션이고, 장기 건강을 예측하는 것은 30일차입니다. 그리고 크리에이터 측이 있는 모든 것에서, 당신이 죽는 곳은 공급 측입니다. <a href="https://forkoff.xyz/blog/founder-growth/two-sided-marketplace-cold-start-2026" target="_blank" rel="noreferrer">실패한 마켓플레이스의 약 67퍼센트가 수요가 아니라 공급에서 무너집니다</a>. 크리에이터 리텐션이 활력 징후입니다. 가입 계정 수와 가치 평가는 허영입니다.</p>
<p>이야기들에서 떨어지는 몇 가지가 더 있습니다. 크리에이터를 수익화하라, 아니면 그들을 잃는다. Dreams가 재능 있는 사람들은 상방이 없으면 수년을 투자하지 않는다는 것을 증명했기 때문입니다. 멀티플레이어는 대개 기능이 아니라 핵심입니다. Media Molecule 자신의 후회가 그렇습니다. 당신을 쫓아낼 수 있는 플랫폼 위에 절대 집을 짓지 마라, Crayta가 그렇습니다. 그리고 다운로드 없음은 양날의 검입니다. 존재하는 최고의 획득 채널이자 가장 약한 약속 장치이므로, 부담은 전적으로 첫 60초가 좋아야 한다는 데 떨어집니다.</p>
<h2 id="그-모든-것-아래의-함정" tabindex="-1">그 모든 것 아래의 함정 <a class="header-anchor" href="#그-모든-것-아래의-함정" aria-label="Permalink to &quot;그 모든 것 아래의 함정&quot;"></a></h2>
<p>한 겹이 더 있고, 그것은 우리 시대에 특유한 것입니다. 우리에게는 죽은 자들이 결코 갖지 못한 도구가 있기 때문입니다. 우리는 AI로 세계를 생성할 수 있습니다. 그것은 내가 몇 주 동안 오락가락한 역설을 제기합니다.</p>
<p>AI라면, 모든 세계가 각 사람에게 맞춰 새로 생성된, 고유한 것이어야 하지 않을까요? 하지만 각 사람의 세계가 고유하다면, 공유된 순간이 공유된 장소를 요구한다는 점을 감안할 때, 도대체 누가 다른 누군가와 마주칠 수 있을까요? 그리고 어차피 세계가 공유되어야 한다면, 진짜 스튜디오처럼 아름다운 장소 하나를 손으로 만드는 대신 굳이 AI를 쓸 이유가 뭘까요?</p>
<p>그 각각의 끌림을 끝까지 따라가면, 작동하지 않는 무언가에 도달합니다. 오직 당신만을 위해 생성된 세계는 아무도 없는 세계입니다. Google의 Genie는 한 문장에서 플레이 가능한 환경을 띄울 수 있지만 1분 뒤에 사라집니다. 싱글 플레이어, 기억 없음, 이웃 없음. 그것이 쓸쓸한 막다른 길입니다. 하지만 고정된 세계 하나를 손으로 만드는 것도 막다른 길입니다. 2제곱킬로미터를 손으로 채우는 것은 100명이 여러 해를 들이는 일이고, 다 끝나면 그것은 얼어붙어, 백 번째 방문에도 첫 번째와 똑같이, 사람들이 도착해도 자라지 못합니다.</p>
<p>빠져나갈 길은 &quot;세계&quot;를 하나의 것으로 취급하기를 멈추는 것입니다. 그것은 세 겹이고, 고유함과 공유됨은 서로 싸우지 않고 서로 다른 겹에서 살 수 있습니다. 모두가 서 있는 땅은 하나의 공유된 세계, 높은 기준으로 큐레이션된 만남의 장소입니다. 당신이 거기에 가져오는 것, 당신의 AI 생성 에셋, 당신이 만든 건물은 굉장히 고유하고, 당신은 그것을 공유된 세계 <em>안에</em> 예치해 당신의 고유함이 다른 모두의 발견이 되게 합니다. 그리고 그것을 통과하는 당신의 경로, 당신이 받는 퀘스트, 그것이 당신을 가리키는 방향은 공짜로 개인화됩니다. 경로는 장소가 아니기 때문입니다. 거짓 선택지는 &quot;개인화된 세계&quot;였습니다. 그것은 멀티플레이어를 죽입니다. 반면 &quot;공유된 세계를 통과하는 개인화된 경로&quot;는 그것을 더 깊게 합니다. 우리는 두 번째를 원합니다.</p>
<p>그러니 AI의 일은 결코 각 사람에게 사적인 세계를 건네는 것이 아니었습니다. 그 일은 하나의 공유된 세계가 무한하고, 살아 있고, 통과하기에 개인적으로 느껴지게 만드는 것입니다. 고유함은 시간이 흐르며 그 안에 쌓이는 모든 것, 모든 크리에이터의 단 하나뿐인 기여에서 옵니다. 모든 Minecraft 서버는 고유합니다. 특정 서버에 있는 모두가 그것을 공유합니다. 그것은 모순이 아닙니다. 그것이 전체 트릭이고, 이 글 맨 위의 스크린샷, 다른 사람들도 걸어 들어올 수 있는 세계에 그대로 머무는 집을 AI가 짓는 그것이, 현실이 된 그 트릭입니다.</p>
<h2 id="우리가-cinevva-world를-출시하는-방법" tabindex="-1">우리가 Cinevva World를 출시하는 방법 <a class="header-anchor" href="#우리가-cinevva-world를-출시하는-방법" aria-label="Permalink to &quot;우리가 Cinevva World를 출시하는 방법&quot;"></a></h2>
<p>그래서 이 모든 것이 우리에게 무엇으로 바뀌는지 여기 있습니다. 마케팅 계획이 아닙니다. 다섯 가지 베팅이고, 이 글 전반부에서 모두를 죽인 다섯 가지에 의도적으로 맞서 놓은 것입니다. 그리고 각각을 증거가 실제로 얼마나 뒷받침하는지로 채점하겠습니다. 채점할 수 없는 계획은 그저 조명만 좋은 소원이기 때문입니다.</p>
<p><strong>첫 번째 베팅, 내가 회사를 걸 그것: 우리는 플랫폼이 아니라 게임을 출시합니다.</strong> 이건 선호가 아니라, 이 연구 전체에서 가장 일관된 발견입니다. Minecraft, Roblox, Fortnite는 모두 <em>할</em> 재미있는 무언가로 시작했고 그 위에 크리에이터 층을 키웠습니다. 살아 있는 가장 재능 있는 창작 스튜디오 Media Molecule은 사후에 Dreams가 먼저 게임이었어야 했다고 결론지었습니다. 그래서 새로운 사람이 Cinevva World에서 처음 하는 일은 빈 부지를 응시하는 것이 아닐 겁니다. 그것은 목표가 있는 루프, 거의 아무도 온라인에 없는 화요일에도 거기 있을 이유일 겁니다. 나타나는 대부분의 사람은 플레이만 하고 결코 짓지 않을 것이며, 그것은 실패가 아니라 설계입니다. 그것이 Roblox의 실제 형태입니다. 플레이하는 수억 명이, 만드는 얇은 층 위에 앉아 있는 것입니다. 플라이휠은 2막이고, 우리는 그것을 벌어야 합니다. 이건 확신합니다. 무덤이 이미 그 실험을 돌렸기 때문입니다.</p>
<p><strong>두 번째 베팅, 솔직히 도박인 그것: AI 덕분에 우리는 다른 모두가 기다리다 죽은 공급을 제조할 수 있습니다.</strong> 이것이 왜 보장이 아니라 베팅인지 정확히 말하고 싶습니다. 이 연구의 어떤 플랫폼도 생성형 AI로 부트스트랩된 적이 없기 때문입니다. 나에게는 메커니즘이 있지, 증명이 있는 게 아닙니다. 메커니즘은 이렇습니다. 양면 플랫폼의 대략 3분의 2가 수요 측이 아니라 공급 측에서 죽습니다. 전형적인 해법은 진짜가 될 때까지 공급을 가짜로 채우는 것입니다. DoorDash가 음식 자체를 운전해 나르고, Reddit 팀이 가짜 핸들로 글을 쓰고, Roblox 창업자들이 수년간 초기 게임을 손으로 지은 방식입니다. 우리는 그것을 생성으로, 그들 누구도 갖지 못한 비용과 속도로 할 수 있습니다. 하지만 여기 나를 정직하게 잡아 두는 부분, 즉 Decentraland 묘비명이 있습니다. Decentraland는 생성된 것으로 가득했고 하루에 약 서른 명을 끌어모았습니다. 예쁜 것이 시간을 쓸 가치가 있는 것과 같지 않기 때문입니다. 그러니 나는 AI가 세계를 재미있게 만든다고 베팅하는 게 아닙니다. 그건 못 합니다. 나는 AI가 에셋 병목을 없애서, 우리의 희소한 인간 노력의 모든 시간이 실제로 사람들을 붙잡아 두는 단 하나, 즉 루프에 들어가도록 베팅하는 겁니다. AI가 언덕을 싸게 짓습니다. 우리는 그 언덕을 오를 이유를 손으로 짓습니다. 그리고 우리는 합성 씨앗을 <a href="https://forkoff.xyz/blog/founder-growth/two-sided-marketplace-cold-start-2026" target="_blank" rel="noreferrer">대략 30퍼센트로 제한하고, 약 60일 안에 진짜 크리에이터 콘텐츠로 전환</a>합니다. 진짜가 되지 않는 가짜 공급은 누군가 알아채는 순간 신뢰를 깨뜨리기 때문입니다.</p>
<p><strong>세 번째 베팅: 우리는 우리 자신의 중단 기준을 공개합니다.</strong> 이것이 근거 있는 계획과 희망적인 계획의 차이입니다. 모든 단일 사례에서 생존을 예측한 지표는 <a href="https://newsletter.pmcurve.com/p/retention-masterclass" target="_blank" rel="noreferrer">리텐션 곡선이 평평해지는지</a>, 어떤 코호트가 0으로 쇠퇴하는 대신 계속 돌아오는지였습니다. 그래서 그것이 우리가 우리 자신에게, 소리 내어, 적용하는 시험입니다. 알파 7일차 리텐션이 평평해지지 않는다면, 결코 짓지 않는 플레이어들이 돌아오지 않는다면, AI가 씨 뿌린 콘텐츠가 그냥 지나쳐지고 무시당한다면, 그 가설은 틀린 것이고, 우리는 그것을 바꾸거나 멈춥니다. 우리는 플레이어와 크리에이터를 두 개의 분리된 깔때기, 두 개의 분리된 아하 순간으로 추적할 겁니다. 그들이 같은 사람이 아니라는 것이 데이터로 분명하기 때문입니다. 그리고 우리는 돈이 초기 일을 한다고 가장하지 않을 겁니다. 50명, 아니 천 명 단위에서도 팁과 마켓플레이스 수익은 0에 수렴하므로, 아직 아무도 붙잡지 못합니다. 초기 리텐션은 루프에서 오거나, 아예 오지 않거나입니다. Dreams가 그걸 거꾸로 한 영수증입니다.</p>
<p><strong>네 번째 베팅: 우리는 의도적으로 좁게 시작합니다.</strong> 네트워크형 제품에 관한 조사는 만장일치입니다. 당신은 시장에 출시하는 게 아니라, <a href="https://www.lennysnewsletter.com/p/atomic-network" target="_blank" rel="noreferrer">&quot;원자 네트워크&quot;</a>, 즉 그 자체로 살아 있을 만큼 충분히 밀도 높은 가장 작은 그룹에 출시합니다. Facebook은 한 학교에서 시작했습니다. 우리 것은 이미 존재합니다. 3D 에셋, 음악, 사운드를 생성했고 이미 배치할 재고를 가진 Cinevva 크리에이터들입니다. 그들 중 50명이 같은 시간에 한 세계에, 목표와 개척지를 가지고 있는 것이, 흩어진 가입자 5만 명이 결코 될 수 없는 더 밀도 높고 더 살아 있는 것입니다. 증거가 이것을 강하게 뒷받침합니다.</p>
<p><strong>다섯 번째 베팅, 가장 무른 것이고, 나도 그렇다고 말하겠습니다: 우리는 텅 빔을 숨기는 대신 그것에 관한 진실을 말합니다.</strong> 잘 다듬어진 조용한 세계는 죽은 것으로 읽히고, 실패자들은 모두 그것을 분위기 효과로 덮으려 했습니다. 우리는 그 반대를 시도할 겁니다. 이것이 다섯 중 가장 덜 입증된 수이고, 발견이라기보다 직감에 가깝습니다. 처음 들어오는 사람들은 미완성 제품을 방문하는 게 아닙니다. 그들은 <em>일찍 왔기에</em> 텅 빈 어떤 장소의 창립 시민이고, 그들이 짓는 것은 다음 천 명이 도착할 때도 여전히 서 있을 겁니다.</p>
<p>그것이 정직하게 채점한 계획입니다. 무덤이 강하게 뒷받침하는 네 가지 베팅, 그리고 죽은 자 누구도 갖지 못한 도구에 거는 진짜 도박 하나, 그들이 결여했던 바로 그 규율로 울타리를 친 것입니다. 우리는 언덕을 생성할 수 있습니다. 우리는 그 언덕을 처음 오르는 느낌이나, 정상에서 손 흔드는 낯선 사람을 생성할 수 없습니다. 우리의 일은 그 손짓을 가능하게 만들고, 그것을 리텐션 곡선 위에서 증명하고, 곡선이 아니라고 말하는 순간 우리 자신을 속이기를 멈추는 것입니다.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 30부: 벽을 존중하는 카메라]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-06-04-open-world-browser-part-30-collision-aware-camera</link>
            <guid>https://app.cinevva.com/ko/blog/2026-06-04-open-world-browser-part-30-collision-aware-camera</guid>
            <pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[29개의 파트가 걷고, 수영하고, 짓는 세계를 만들었지만, 그 모든 것을 지켜보는 카메라는 언덕과 집 벽을 그대로 뚫고 지나갔습니다. 30부는 충돌을 인식하는 붐으로 이를 고칩니다. 자기 길이만 책임지는 스프링 암, 지형과 소품과 건물이 모두 같은 인터페이스를 통해 카메라를 멈추게 하는 플러그인 가능한 콜라이더 계약, 그리고 하이트맵으로는 결코 다룰 수 없던 돌출부와 동굴을 존중하는 부호 거리 프로브입니다. 이미 신뢰하던 OrbitControls 입력 코드를 단 한 줄도 다시 쓰지 않고, 그 위에 후처리로 끼워 넣습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-30부-벽을-존중하는-카메라" tabindex="-1">브라우저에서 오픈 월드 만들기, 30부: 벽을 존중하는 카메라 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-30부-벽을-존중하는-카메라" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 30부: 벽을 존중하는 카메라&quot;"></a></h1>
<p><em>글쓴이: <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva의 CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 파트로 연결해 둡니다.</p>
<p><a href="/ko/blog/2026-05-15-open-world-browser-part-29-pluggable-character.html">29부</a>에서는 어떤 몸이든 구동하는 컨트롤러 하나를 얻었습니다. 이제 몸은 제대로 움직입니다. 걷고, 미끄러지고, 수영하고, 활공하고, 동굴로 기어 들어가고, 돌출부 아래로 몸을 숙입니다. 문제는 그것을 지켜보는 쪽입니다. 29개 파트 동안 카메라는 플레이어를 따라다니는 평범한 오빗 리그였고, 망신을 피하려고 딱 한 가지 영리한 짓만 했습니다. 지평선 아래로 기울지 않으려 했고, 그래서 평평한 땅 밑으로 미끄러져 들어갈 수 없었습니다. 그 클램프가 바로 증거입니다. 카메라가 세계의 지오메트리가 실제로 어디에 있는지 전혀 몰랐기 때문에 존재하는 것이고, 클리핑을 막을 유일한 방어책은 클리핑이 가장 일어나기 쉬운 각도를 아예 금지하는 것뿐이었습니다. 언덕으로 다가가면 카메라가 언덕 안에 들어가 앉았습니다. <a href="/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes.html">7부</a>의 마칭 큐브 동굴 하나로 발을 들이면 바위 속을 들여다보게 됐습니다. <a href="/ko/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring.html">16부</a>의 저작 도구로 집을 짓고 방 안에 서면, 카메라는 벽 바깥으로 떠올라 외벽 마감재를 바라봤습니다. 이번 파트는 카메라에게도 몸이 이미 가진 것과 같은, 지오메트리에 대한 존중을 줍니다.</p>
<h2 id="문제의-모양-그리고-해법의-모양" tabindex="-1">문제의 모양, 그리고 해법의 모양 <a class="header-anchor" href="#문제의-모양-그리고-해법의-모양" aria-label="Permalink to &quot;문제의 모양, 그리고 해법의 모양&quot;"></a></h2>
<p>3인칭 카메라에는 어려운 일이 하나 있고 쉬운 일이 열두 가지 있습니다. 쉬운 쪽은 따라가기, 부드럽게 보정하기, 오빗 입력이고, 이건 이미 다 갖고 있었습니다. 어려운 쪽을 학계 문헌에서는 가시성 제약(visibility constraint)이라 부르고, 모두가 인용하는 서베이인 Christie와 Olivier의 <em>Camera Control in Computer Graphics</em>는 분야 전체를 이것을 중심으로 정리합니다. 세계를 존중하면서도 피사체를 프레임 안에 두고 가려지지 않게 유지하라. 런타임에서 이것은 매 프레임 던지는 속아 넘어가기 쉬울 만큼 단순한 질문으로 줄어듭니다. 플레이어가 피벗입니다. 사용자가 회전하고 줌해서 그들 뒤 어느 정도 거리에 원하는 카메라 위치를 정했습니다. 그 선을 따라 카메라가 무언가 단단한 것에 찔리기 전에 실제로 얼마나 뒤로 앉을 수 있을까요? 이 질문에 정직하게 답하면 카메라는 언덕 앞으로 몸을 집어넣고, 구석으로 후진할 때 붐을 따라 미끄러져 내려오며, 동굴 천장을 뚫는 대신 거기서 멈춥니다.</p>
<p>이 질문에 답하는 패턴은 오래됐고 검증됐습니다. Unreal은 스프링 암이라 부르고, Godot는 <code>SpringArm3D</code> 노드를 제공하며, Unity의 Cinemachine은 그것을 3인칭 팔로우 리그와 디오클루더(deoccluder) 확장으로 나눠 둡니다. 발상은 늘 같습니다. 카메라를 피벗에 고정된 붐 끝에 매답니다. 길이 트여 있으면 원하는 길이로 잡아두고, 무언가 가로막으면 피벗 쪽으로 거둬들이며, 길이 트이면 다시 펴 줍니다. Metroid Prime의 카메라 리드가 쓴 Mark Haigh-Hutchinson의 <em>Real-Time Cameras</em>는 이것의 순진한 버전이 플레이어를 멀미 나게 만드는 실패 모드에 챕터 여러 개를 통째로 씁니다. 우리는 그 패턴을 가져와 한자리에서 다 읽을 수 있을 만큼 작은 우리만의 것을 <code>public/world/src/camera-rig.mjs</code>에 만들었습니다.</p>
<figure style="margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12);border-radius:8px;overflow:hidden;background:#0d1117">
<svg viewBox="0 0 680 290" width="100%" role="img" aria-label="A spring-arm boom retracting along its own line so the probe sphere rests against a wall instead of clipping through it" style="display:block">
  <rect x="382" y="40" width="46" height="222" fill="#39424f" stroke="#5b6675"/>
  <text x="405" y="280" fill="#9aa7b4" font-size="13" text-anchor="middle" font-family="sans-serif">벽</text>
  <line x1="110" y1="212" x2="600" y2="70" stroke="#9aa7b4" stroke-width="2" stroke-dasharray="6 6"/>
  <line x1="110" y1="212" x2="360" y2="140" stroke="#6ea8fe" stroke-width="3"/>
  <circle cx="110" cy="212" r="6" fill="#e6edf3"/>
  <text x="110" y="234" fill="#e6edf3" font-size="13" text-anchor="middle" font-family="sans-serif">피벗 (플레이어 머리)</text>
  <circle cx="600" cy="70" r="9" fill="none" stroke="#9aa7b4" stroke-width="2"/>
  <text x="600" y="52" fill="#9aa7b4" font-size="13" text-anchor="middle" font-family="sans-serif">원하는 위치 (사용자 줌)</text>
  <circle cx="360" cy="140" r="22" fill="rgba(110,168,254,0.18)" stroke="#6ea8fe" stroke-width="2"/>
  <circle cx="360" cy="140" r="5" fill="#6ea8fe"/>
  <text x="300" y="104" fill="#6ea8fe" font-size="13" text-anchor="middle" font-family="sans-serif">카메라 + 프로브 반지름 r</text>
  <text x="222" y="192" fill="#6ea8fe" font-size="13" font-family="sans-serif" transform="rotate(-16 222 192)">ℓ (클램프됨)</text>
</svg>
<figcaption style="padding:0.6rem 1rem;color:#9aa7b4;font-size:0.85rem;border-top:1px solid rgba(255,255,255,0.12);font-family:sans-serif">붐은 장애물이 끼어들기 전까지 사용자가 원한 줌 거리에 카메라를 잡아둡니다. 그러다 같은 선을 따라 거둬들여, 근평면이 표면을 뚫는 대신 프로브 구가 표면에 가서 닿게 합니다.</figcaption>
</figure>
<h2 id="자기-길이만-책임지는-붐" tabindex="-1">자기 길이만 책임지는 붐 <a class="header-anchor" href="#자기-길이만-책임지는-붐" aria-label="Permalink to &quot;자기 길이만 책임지는 붐&quot;"></a></h2>
<p>리그를 작게 유지해 준 설계 규칙은 29부 컨트롤러 작업에서 빌려온 것입니다. 한 가지를 완전히 책임지고 나머지는 거절하라. 리그는 붐의 길이를 책임지고 그 외에는 아무것도 책임지지 않습니다. 요(yaw), 피치, 오빗 댐핑, 터치와 휠 제스처, 이 모든 것은 OrbitControls에 남겨 둡니다. OrbitControls는 이미 그것들을 잘 풀어내고 있고, 우리는 그걸 다시 쓸 생각이 전혀 없습니다. 그래서 리그는 카메라 컨트롤러가 아닙니다. 오빗 계산이 끝난 뒤에 돌면서 딱 한 숫자, 피벗에서 카메라까지의 거리만 보정하는 후처리입니다.</p>
<p>이 결정은 깔끔하게 들리지만 거의 곧바로 깨질 뻔했습니다. OrbitControls가 생각하는 방식 때문입니다. 매 업데이트의 맨 위에서 OrbitControls는 카메라의 현재 위치를 읽고 거기서 오빗 반지름을 끌어냅니다. 보통은 보이지 않는 동작입니다. 그런데 우리 리그가 벽을 피하려고 카메라를 짧게 당기는 순간, 다음 프레임에 OrbitControls가 그 짧아진 위치를 읽고 사용자가 줌인했다고 결론 내린 다음, 그 짧아짐을 사용자가 원한 줌에 구워 넣습니다. 그게 몇 프레임 이어지면 카메라는 플레이어 머리 위로 무너져 내리고 다시 나오지 않습니다. 해법은 오빗 업데이트를 앞뒤로 감싸는 호출 두 개이고, 통합은 그게 전부입니다. OrbitControls가 돌기 전에 <code>beforeControls()</code>가 카메라를 지난 프레임의 온전한, 짧아지지 않은 거리로 복원해서 오빗 계산이 항상 사용자의 진짜 줌을 읽게 합니다. OrbitControls가 돈 뒤에 <code>afterControls(dt)</code>가 방금 오빗된 원하는 위치를 읽어 충돌을 해결하고, 길이를 댐핑하고, 카메라가 실제로 렌더링되어야 할 곳에 씁니다. 사용자의 의도와 충돌 보정은 서로 절대 닿지 않고, 달리(dolly)는 리그가 존재하기 전과 정확히 똑같이 반응합니다. 리그를 위해 우리가 쓴 헤드리스 테스트가 이것을 정확히 못박습니다. 붐을 60프레임 동안 벽으로 밀어 넣고, 벽을 벗어나면 길이가 충돌 거리에 붙어 있는 대신 사용자의 온전한 줌인 10미터로 다시 튀어 나옵니다.</p>
<h2 id="계약-하나-콜라이더는-무엇이든" tabindex="-1">계약 하나, 콜라이더는 무엇이든 <a class="header-anchor" href="#계약-하나-콜라이더는-무엇이든" aria-label="Permalink to &quot;계약 하나, 콜라이더는 무엇이든&quot;"></a></h2>
<p>리그는 세계가 무엇으로 만들어졌는지 절대 묻지 않습니다. 콜라이더는 그저 <code>probe</code> 메서드를 가진 객체일 뿐이고, 리그는 거기에 레이, 최대 거리, 카메라의 프로브 반지름을 건네주고 숫자 하나를 돌려받습니다. 그 콜라이더가 막기 전에 카메라가 갈 수 있는 가장 먼 거리입니다. 리그는 등록된 모든 콜라이더에 질의하고 가장 가까운 히트를 택합니다. 그게 계약의 전부이고, 캐릭터 컨트롤러가 이동을 플러그인 가능한 동작으로 바꿨을 때 한 것과 같은 수입니다. 지형이 끼워지고, 소품이 끼워지고, 건물 셸이 끼워지는데, 각각이 같은 <code>probe</code> 뒤에 있고, 리그는 그 모두에 대해 무지한 채로 남습니다. 새로운 종류의 장애물을 더하는 일은 카메라를 고치는 게 아니라 콜라이더를 목록에 더하는 일입니다.</p>
<p>계약 안의 한 가지 디테일이 제 몫을 합니다. 바로 프로브 반지름입니다. 우리는 피벗에서 카메라로 가느다란 레이를 쏘지 않고, 카메라의 근평면을 담을 만큼 큰 구를 쏩니다. 단일 레이는 카메라 중심을 벽에서 멈추지만, 근평면에는 폭이 있어서 그 모서리들은 중심 레이가 히트를 보고하기도 전에 이미 벽에 파묻혀 있습니다. 레이 대신 작은 구를 휘둘러 쓰는 것은 출시된 모든 구현이 하는 일이고, Unreal은 그것을 프로브 크기로 노출합니다. 표면에 깨끗하게 가서 멈추는 카메라와 화면 가장자리에서 너머가 비쳐 보이게 두는 카메라의 차이가 바로 이것입니다.</p>
<p>우리는 그 반지름을 추측하지 않고 도출합니다. 카메라에서 근평면의 가장 먼 점은 그 모서리 중 하나이고, 거기까지의 거리는 투영에서 곧장 떨어져 나옵니다. 근평면 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.357ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 600 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>n</mi></math></mjx-assistive-mml></mjx-container>과 수직 시야각 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.023ex;" xmlns="http://www.w3.org/2000/svg" width="1.061ex" height="1.618ex" role="img" focusable="false" viewBox="0 -705 469 715" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D703" d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>θ</mi></math></mjx-assistive-mml></mjx-container>에서, 절반 높이는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="14.408ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 6368.2 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(853.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1909.6,0)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2676.2,0)"><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(389,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(889,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4121.2,0)"><path data-c="2061" d="" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4121.2,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(4510.2,0)"><path data-c="1D703" d="M35 200Q35 302 74 415T180 610T319 704Q320 704 327 704T339 705Q393 701 423 656Q462 596 462 495Q462 380 417 261T302 66T168 -10H161Q125 -10 99 10T60 63T41 130T35 200ZM383 566Q383 668 330 668Q294 668 260 623T204 521T170 421T157 371Q206 370 254 370L351 371Q352 372 359 404T375 484T383 566ZM113 132Q113 26 166 26Q181 26 198 36T239 74T287 161T335 307L340 324H145Q145 321 136 286T120 208T113 132Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(4979.2,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mn" transform="translate(5479.2,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(5979.2,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>h</mi><mo>=</mo><mi>n</mi><mi>tan</mi><mo data-mjx-texclass="NONE">⁡</mo><mo stretchy="false">(</mo><mi>θ</mi><mrow data-mjx-texclass="ORD"><mo>/</mo></mrow><mn>2</mn><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>, 절반 폭은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.439ex;" xmlns="http://www.w3.org/2000/svg" width="13.744ex" height="2.009ex" role="img" focusable="false" viewBox="0 -694 6075 888" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D464" d="M580 385Q580 406 599 424T641 443Q659 443 674 425T690 368Q690 339 671 253Q656 197 644 161T609 80T554 12T482 -11Q438 -11 404 5T355 48Q354 47 352 44Q311 -11 252 -11Q226 -11 202 -5T155 14T118 53T104 116Q104 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Q21 293 29 315T52 366T96 418T161 441Q204 441 227 416T250 358Q250 340 217 250T184 111Q184 65 205 46T258 26Q301 26 334 87L339 96V119Q339 122 339 128T340 136T341 143T342 152T345 165T348 182T354 206T362 238T373 281Q402 395 406 404Q419 431 449 431Q468 431 475 421T483 402Q483 389 454 274T422 142Q420 131 420 107V100Q420 85 423 71T442 42T487 26Q558 26 600 148Q609 171 620 213T632 273Q632 306 619 325T593 357T580 385Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(993.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2049.6,0)"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2847.8,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(3348,0)"><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(894,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1450,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(1894,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(2338,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>w</mi><mo>=</mo><mi>h</mi><mo>⋅</mo><mtext>aspect</mtext></math></mjx-assistive-mml></mjx-container>이고, 모서리는 다음 위치에 있습니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="22.335ex" height="2.878ex" role="img" focusable="false" viewBox="0 -1114.2 9872 1272" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(484,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mtext"><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1500,0)" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(2149.6,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msqrt" transform="translate(3205.4,0)"><g transform="translate(1020,0)"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(633,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1258.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(2259,0)"><g data-mml-node="mi"><path data-c="1D464" d="M580 385Q580 406 599 424T641 443Q659 443 674 425T690 368Q690 339 671 253Q656 197 644 161T609 80T554 12T482 -11Q438 -11 404 5T355 48Q354 47 352 44Q311 -11 252 -11Q226 -11 202 -5T155 14T118 53T104 116Q104 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Q21 293 29 315T52 366T96 418T161 441Q204 441 227 416T250 358Q250 340 217 250T184 111Q184 65 205 46T258 26Q301 26 334 87L339 96V119Q339 122 339 128T340 136T341 143T342 152T345 165T348 182T354 206T362 238T373 281Q402 395 406 404Q419 431 449 431Q468 431 475 421T483 402Q483 389 454 274T422 142Q420 131 420 107V100Q420 85 423 71T442 42T487 26Q558 26 600 148Q609 171 620 213T632 273Q632 306 619 325T593 357T580 385Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(749,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3633.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(4634,0)"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(609,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(0,204.2)"><path data-c="221A" d="M263 249Q264 249 315 130T417 -108T470 -228L725 302Q981 837 982 839Q989 850 1001 850Q1008 850 1013 844T1020 832V826L741 243Q645 43 540 -176Q479 -303 469 -324T453 -348Q449 -350 436 -350L424 -349L315 -96Q206 156 205 156L171 130Q138 104 137 104L111 130L263 249Z" style="stroke-width: 3;"/></g><rect width="5646.5" height="60" x="1020" y="994.2"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><msub><mi>r</mi><mrow data-mjx-texclass="ORD"><mtext>near</mtext></mrow></msub><mo>=</mo><msqrt><msup><mi>n</mi><mn>2</mn></msup><mo>+</mo><msup><mi>w</mi><mn>2</mn></msup><mo>+</mo><msup><mi>h</mi><mn>2</mn></msup></msqrt></math></mjx-assistive-mml></mjx-container><p>프로브 반지름은 그 모서리 거리에 작은 안전 여유를 곱한 값이고, 아주 좁은 절두체에서도 합리적인 최솟값 아래로 떨어지지 않도록 고정 하한을 둡니다. 시야각, 종횡비, 근평면이 바뀔 때마다 반지름을 다시 계산해서, 창 크기 변경이나 투영을 건드리는 줌이 프로브를 보호해야 할 모서리를 덮지 못할 만큼 조용히 작게 남겨 두는 일이 없게 합니다.</p>
<h2 id="동굴을-아는-콜라이더" tabindex="-1">동굴을 아는 콜라이더 <a class="header-anchor" href="#동굴을-아는-콜라이더" aria-label="Permalink to &quot;동굴을 아는 콜라이더&quot;"></a></h2>
<p>지형 콜라이더가 흥미로워지는 지점입니다. 우리 엔진의 지형은 하이트맵이 아니기 때문입니다. 7부 이후로 그것은 부호 거리 필드(signed distance field)였습니다. 공간의 임의의 점이 가장 가까운 단단한 표면에서 얼마나 떨어져 있는지, 그리고 바위 안쪽인지 바깥쪽인지를 돌려주는 함수입니다. 양수는 공기, 음수는 바위이고, 바로 그 단 하나의 사실이 우리 카메라가 하이트맵 카메라로는 구조적으로 불가능한 일을 할 수 있는 이유입니다. 하이트맵은 어떤 x와 z에서의 지면 높이를 압니다. 천장이라는 개념은 없습니다. 어떤 점 위에는 언제나 표면이 하나뿐이기 때문입니다. 그래서 하이트맵 카메라는 당신이 언덕으로 걸어 들어가는 것은 막을 수 있어도, 돌출부 입술이나 동굴 지붕이 피벗 위에 걸려 있다는 것은 전혀 모르고 둘 다 그대로 뚫고 지나갑니다. 거리 필드는 3차원의 모든 표면을 알기 때문에, 언덕 비탈에서 카메라를 멈추는 같은 프로브가 단 하나의 특수 처리도 없이 동굴 천장에서 카메라를 멈춥니다.</p>
<figure style="margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12);border-radius:8px;overflow:hidden;background:#0d1117">
<svg viewBox="0 0 680 320" width="100%" role="img" aria-label="Under an overhang a heightmap lets the boom clip through the ceiling rock, while a signed distance field stops it at the ceiling underside" style="display:block">
  <path d="M680,320 L680,40 L250,40 L250,150 L430,150 L430,250 L250,250 L250,320 Z" fill="#39424f" stroke="#5b6675" stroke-width="1.5"/>
  <text x="340" y="205" fill="#9aa7b4" font-size="13" text-anchor="middle" font-family="sans-serif">동굴</text>
  <text x="540" y="100" fill="#5b6675" font-size="13" text-anchor="middle" font-family="sans-serif">단단한 바위</text>
  <line x1="330" y1="212" x2="230" y2="60" stroke="#9aa7b4" stroke-width="2" stroke-dasharray="6 6"/>
  <line x1="290" y1="150" x2="250" y2="90" stroke="#f85149" stroke-width="4"/>
  <circle cx="330" cy="212" r="6" fill="#e6edf3"/>
  <text x="330" y="234" fill="#e6edf3" font-size="13" text-anchor="middle" font-family="sans-serif">플레이어</text>
  <circle cx="230" cy="60" r="10" fill="none" stroke="#f85149" stroke-width="2"/>
  <text x="230" y="42" fill="#f85149" font-size="13" text-anchor="middle" font-family="sans-serif">하이트맵: 뚫고 지나감 ✗</text>
  <circle cx="305" cy="170" r="9" fill="rgba(86,211,100,0.2)" stroke="#56d364" stroke-width="2"/>
  <text x="420" y="172" fill="#56d364" font-size="13" text-anchor="middle" font-family="sans-serif">SDF: 천장에서 멈춤 ✓</text>
</svg>
<figcaption style="padding:0.6rem 1rem;color:#9aa7b4;font-size:0.85rem;border-top:1px solid rgba(255,255,255,0.12);font-family:sans-serif">하이트맵은 기둥마다 표면을 하나씩 저장하므로, 플레이어 위에 놓인 바위 판을 절대 보지 못하고 붐이 천장을 뚫고 올라가게 둡니다. 거리 필드는 그 판 안쪽에서 음수이므로, 프로브가 거기에 닿아 카메라가 동굴 지붕 바로 아래에 머뭅니다.</figcaption>
</figure>
<p>필드를 따라 프로브를 걷게 하는 것은 이름과 논문이 있는 기법입니다. 1996년 John Hart의 <em>Sphere Tracing</em>은 거리 필드에 대해 레이를 행진시키는 표준 방법이고, 비결은 필드가 무언가에 부딪혔는지만 알려주는 게 아니라 부딪히지 않고 전진할 수 있는 안전 거리를 알려준다는 점입니다. 그래서 작고 고정된 보폭으로 살금살금 가는 대신, 필드를 샘플링하고, 보고된 여유만큼 앞으로 나아가고, 반복합니다. 트인 공기 속에서는 성큼성큼 걷고 표면에 가까워질수록 짧고 조심스럽게 걷습니다.</p>
<p>다만 우리 지형이 강요하는 함정이 하나 있습니다. 진짜 거리 필드는 가장 가까운 표면까지의 실제 유클리드 거리를 보고하고, 그 여유만큼 한 걸음 통째로 가는 것은 언제나 안전합니다. 그런데 지형이 깎인 복셀이 아니라 아직 하이트맵인 곳에서는, 우리가 싸게 샘플링할 수 있는 필드가 진짜 거리가 아니라 수직 여유(vertical clearance), 곧장 아래 지면까지의 간격입니다. 비탈에서는 가장 가까운 바위가 바로 아래가 아니라 옆쪽에 있기 때문에, 그 숫자는 카메라가 실제로 움직일 수 있는 거리를 과대 보고합니다. 정직한 거리는 경사도에 따라 커지는 인자 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.628ex;" xmlns="http://www.w3.org/2000/svg" width="12.643ex" height="2.851ex" role="img" focusable="false" viewBox="0 -982.5 5588 1260" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msqrt"><g transform="translate(1020,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1722.4,0)"><path data-c="2016" d="M133 736Q138 750 153 750Q164 750 170 739Q172 735 172 250T170 -239Q164 -250 152 -250Q144 -250 138 -244L137 -243Q133 -241 133 -179T132 250Q132 731 133 736ZM329 739Q334 750 346 750Q353 750 361 744L362 743Q366 741 366 679T367 250T367 -178T362 -243L361 -244Q355 -250 347 -250Q335 -250 329 -239Q327 -235 327 250T329 739Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2222.4,0)"><path data-c="2207" d="M46 676Q46 679 51 683H781Q786 679 786 676Q786 674 617 326T444 -26Q439 -33 416 -33T388 -26Q385 -22 216 326T46 676ZM697 596Q697 597 445 597T193 596Q195 591 319 336T445 80L697 596Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(3055.4,0)"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(3631.4,0)"><g data-mml-node="mo"><path data-c="2016" d="M133 736Q138 750 153 750Q164 750 170 739Q172 735 172 250T170 -239Q164 -250 152 -250Q144 -250 138 -244L137 -243Q133 -241 133 -179T132 250Q132 731 133 736ZM329 739Q334 750 346 750Q353 750 361 744L362 743Q366 741 366 679T367 250T367 -178T362 -243L361 -244Q355 -250 347 -250Q335 -250 329 -239Q327 -235 327 250T329 739Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(533,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(0,72.5)"><path data-c="221A" d="M263 249Q264 249 315 130T417 -108T470 -228L725 302Q981 837 982 839Q989 850 1001 850Q1008 850 1013 844T1020 832V826L741 243Q645 43 540 -176Q479 -303 469 -324T453 -348Q449 -350 436 -350L424 -349L315 -96Q206 156 205 156L171 130Q138 104 137 104L111 130L263 249Z" style="stroke-width: 3;"/></g><rect width="4568" height="60" x="1020" y="862.5"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msqrt><mn>1</mn><mo>+</mo><mo data-mjx-texclass="OPEN" fence="false" stretchy="false">‖</mo><mi mathvariant="normal">∇</mi><mi>h</mi><msup><mo data-mjx-texclass="CLOSE" fence="false" stretchy="false">‖</mo><mn>2</mn></msup></msqrt></math></mjx-assistive-mml></mjx-container>만큼 더 작아서, 보고된 여유에 맞춰 잡은 보폭은 과도하게 넘어가 능선을 깨끗이 뛰어넘어 버릴 수 있습니다. 해법은 과소 완화(under-relaxation)입니다. 보고된 여유 전부가 아니라 그 일부만큼만 전진하는 것으로, 대략 60도 경사까지 안전하게 유지되고 진짜 거리 복셀 영역에서는 샘플 몇 개를 더 쓰는 것 말고는 비용이 들지 않습니다. 여기에 보폭 하한을 짝지어, 한두 셀 두께의 동굴 벽이 깨끗이 건너뛰어지는 일이 없게 하고, 더 빡빡한 상한으로 행진을 싸게 유지합니다. 구가 마침내 표면에 닿으면 짧은 이분법으로 접촉점을 좁히고, 카메라는 자기 반지름만큼 물러나 거기에 머뭅니다.</p>
<p>써 놓고 보면, 붐은 피벗 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.439ex;" xmlns="http://www.w3.org/2000/svg" width="1.446ex" height="1.457ex" role="img" focusable="false" viewBox="0 -450 639 644" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D429" d="M32 442L123 446Q214 450 215 450H221V409Q222 409 229 413T251 423T284 436T328 446T382 450Q480 450 540 388T600 223Q600 128 539 61T361 -6H354Q292 -6 236 28L227 34V-132H296V-194H287Q269 -191 163 -191Q56 -191 38 -194H29V-132H98V113V284Q98 330 97 348T93 370T83 376Q69 380 42 380H29V442H32ZM457 224Q457 303 427 349T350 395Q282 395 235 352L227 345V104L233 97Q274 45 337 45Q383 45 420 86T457 224Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">p</mi></mrow></math></mjx-assistive-mml></mjx-container>에서 단위 방향 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.014ex;" xmlns="http://www.w3.org/2000/svg" width="1.446ex" height="1.584ex" role="img" focusable="false" viewBox="0 -694 639 700" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D41D" d="M351 686L442 690Q533 694 534 694H540V389Q540 327 540 253T539 163Q539 97 541 83T555 66Q569 62 596 62H609V31Q609 0 608 0Q588 0 510 -3T412 -6Q411 -6 411 16V38L401 31Q337 -6 265 -6Q159 -6 99 58T38 224Q38 265 51 303T92 375T165 429T272 449Q359 449 417 412V507V555Q417 597 415 607T402 620Q388 624 361 624H348V686H351ZM411 350Q362 399 291 399Q278 399 256 392T218 371Q195 351 189 320T182 238V221Q182 179 183 159T191 115T212 74Q241 46 288 46Q358 46 404 100L411 109V350Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">d</mi></mrow></math></mjx-assistive-mml></mjx-container>를 따라가는 레이 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="13.518ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 5975 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D42B" d="M405 293T374 293T324 312T305 361Q305 378 312 394Q315 397 315 399Q305 399 294 394T266 375T238 329T222 249Q221 241 221 149V62H308V0H298Q280 3 161 3Q47 3 38 0H29V62H98V210V303Q98 353 96 363T83 376Q69 380 42 380H29V442H32L118 446Q204 450 205 450H210V414L211 378Q247 449 315 449H321Q384 449 413 422T442 360Q442 332 424 313Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(474,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(863,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1224,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1890.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(2946.6,0)"><g data-mml-node="mi"><path data-c="1D429" d="M32 442L123 446Q214 450 215 450H221V409Q222 409 229 413T251 423T284 436T328 446T382 450Q480 450 540 388T600 223Q600 128 539 61T361 -6H354Q292 -6 236 28L227 34V-132H296V-194H287Q269 -191 163 -191Q56 -191 38 -194H29V-132H98V113V284Q98 330 97 348T93 370T83 376Q69 380 42 380H29V442H32ZM457 224Q457 303 427 349T350 395Q282 395 235 352L227 345V104L233 97Q274 45 337 45Q383 45 420 86T457 224Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3807.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(4808,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(5169,0)"><g data-mml-node="mspace"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(5336,0)"><g data-mml-node="mi"><path data-c="1D41D" d="M351 686L442 690Q533 694 534 694H540V389Q540 327 540 253T539 163Q539 97 541 83T555 66Q569 62 596 62H609V31Q609 0 608 0Q588 0 510 -3T412 -6Q411 -6 411 16V38L401 31Q337 -6 265 -6Q159 -6 99 58T38 224Q38 265 51 303T92 375T165 429T272 449Q359 449 417 412V507V555Q417 597 415 607T402 620Q388 624 361 624H348V686H351ZM411 350Q362 399 291 399Q278 399 256 392T218 371Q195 351 189 320T182 238V221Q182 179 183 159T191 115T212 74Q241 46 288 46Q358 46 404 100L411 109V350Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">r</mi></mrow><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">p</mi></mrow><mo>+</mo><mi>t</mi><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">d</mi></mrow></math></mjx-assistive-mml></mjx-container>이고, 행진은 접촉에 이르기까지 필드 여유의 과소 완화된 일부만큼 전진하며 양 끝에서 클램프됩니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.791ex;" xmlns="http://www.w3.org/2000/svg" width="46.581ex" height="2.713ex" role="img" focusable="false" viewBox="0 -849.5 20588.6 1199" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(394,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(600,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1378,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(2049.7,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3105.5,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(394,-150) scale(0.707)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(4196,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(5196.2,0)"><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(444,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(722,0)" style="stroke-width: 3;"/><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1222,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(2055,0)" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(7807.2,0)"><g data-mml-node="mspace"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(7806.9,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="28" d="M152 251Q152 646 388 850H416Q422 844 422 841Q422 837 403 816T357 753T302 649T255 482T236 250Q236 124 255 19T301 -147T356 -251T403 -315T422 -340Q422 -343 416 -349H388Q359 -325 332 -296T271 -213T212 -97T170 56T152 251Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(8264.9,0)"><path data-c="1D706" d="M166 673Q166 685 183 694H202Q292 691 316 644Q322 629 373 486T474 207T524 67Q531 47 537 34T546 15T551 6T555 2T556 -2T550 -11H482Q457 3 450 18T399 152L354 277L340 262Q327 246 293 207T236 141Q211 112 174 69Q123 9 111 -1T83 -12Q47 -12 47 20Q47 37 61 52T199 187Q229 216 266 252T321 306L338 322Q338 323 288 462T234 612Q214 657 183 657Q166 657 166 673Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(8847.9,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mo" transform="translate(9014.9,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(9403.9,0)"><path data-c="3A6" d="M312 622Q310 623 307 625T303 629T297 631T286 634T270 635T246 636T211 637H184V683H196Q220 680 361 680T526 683H538V637H511Q468 637 447 635T422 631T411 622V533L425 531Q525 519 595 466T665 342Q665 301 642 267T583 209T506 172T425 152L411 150V61Q417 55 421 53T447 48T511 46H538V0H526Q502 3 361 3T196 0H184V46H211Q231 46 245 46T270 47T286 48T297 51T303 54T307 57T312 61V150H310Q309 151 289 153T232 166T160 195Q149 201 136 210T103 238T69 284T56 342Q56 414 128 467T294 530Q309 532 310 533H312V622ZM170 342Q170 207 307 188H312V495H309Q301 495 282 491T231 469T186 423Q170 389 170 342ZM415 188Q487 199 519 236T551 342Q551 384 539 414T507 459T470 481T434 491T415 495H410V188H415Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(10125.9,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(10514.9,0)"><g data-mml-node="mi"><path data-c="1D42B" d="M405 293T374 293T324 312T305 361Q305 378 312 394Q315 397 315 399Q305 399 294 394T266 375T238 329T222 249Q221 241 221 149V62H308V0H298Q280 3 161 3Q47 3 38 0H29V62H98V210V303Q98 353 96 363T83 376Q69 380 42 380H29V442H32L118 446Q204 450 205 450H210V414L211 378Q247 449 315 449H321Q384 449 413 422T442 360Q442 332 424 313Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(10988.9,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(11377.9,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(394,-150) scale(0.707)"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(12246.1,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(12635.1,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(13246.4,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(14246.6,0)"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(14697.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(15086.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(15364.6,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(15809.3,0)"><g data-mml-node="mi"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(502,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1111,0)" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(17540,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(17818,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(18262.7,0)"><g data-mml-node="mi"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(502,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="78" d="M201 0Q189 3 102 3Q26 3 17 0H11V46H25Q48 47 67 52T96 61T121 78T139 96T160 122T180 150L226 210L168 288Q159 301 149 315T133 336T122 351T113 363T107 370T100 376T94 379T88 381T80 383Q74 383 44 385H16V431H23Q59 429 126 429Q219 429 229 431H237V385Q201 381 201 369Q201 367 211 353T239 315T268 274L272 270L297 304Q329 345 329 358Q329 364 327 369T322 376T317 380T310 384L307 385H302V431H309Q324 428 408 428Q487 428 493 431H499V385H492Q443 385 411 368Q394 360 377 341T312 257L296 236L358 151Q424 61 429 57T446 50Q464 46 499 46H516V0H510H502Q494 1 482 1T457 2T432 2T414 3Q403 3 377 3T327 1L304 0H295V46H298Q309 46 320 51T331 63Q331 65 291 120L250 175Q249 174 219 133T185 88Q181 83 181 74Q181 63 188 55T206 46Q208 46 208 23V0H201Z" transform="translate(1333,0)" style="stroke-width: 3;"/></g></g></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(20130.6,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="29" d="M305 251Q305 -145 69 -349H56Q43 -349 39 -347T35 -338Q37 -333 60 -307T108 -239T160 -136T204 27T221 250T204 473T160 636T108 740T60 807T35 839Q35 850 50 850H56H69Q197 743 256 566Q305 425 305 251Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><msub><mi>t</mi><mrow data-mjx-texclass="ORD"><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>=</mo><msub><mi>t</mi><mi>n</mi></msub><mo>+</mo><mi>clamp</mi><mstyle scriptlevel="0"><mspace width="-0.167em"/></mstyle><mrow data-mjx-texclass="ORD"><mo minsize="1.2em" maxsize="1.2em">(</mo></mrow><mi>λ</mi><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mo stretchy="false">(</mo><mi mathvariant="normal">Φ</mi><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">r</mi></mrow><mo stretchy="false">(</mo><msub><mi>t</mi><mi>n</mi></msub><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>−</mo><mi>r</mi><mo stretchy="false">)</mo><mo>,</mo><mstyle scriptlevel="0"><mspace width="0.278em"/></mstyle><msub><mi>s</mi><mrow data-mjx-texclass="ORD"><mo data-mjx-texclass="OP" movablelimits="true">min</mo></mrow></msub><mo>,</mo><mstyle scriptlevel="0"><mspace width="0.278em"/></mstyle><msub><mi>s</mi><mrow data-mjx-texclass="ORD"><mo data-mjx-texclass="OP" movablelimits="true">max</mo></mrow></msub><mrow data-mjx-texclass="ORD"><mo minsize="1.2em" maxsize="1.2em">)</mo></mrow></math></mjx-assistive-mml></mjx-container><p>여기서 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.633ex" height="1.545ex" role="img" focusable="false" viewBox="0 -683 722 683" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="3A6" d="M312 622Q310 623 307 625T303 629T297 631T286 634T270 635T246 636T211 637H184V683H196Q220 680 361 680T526 683H538V637H511Q468 637 447 635T422 631T411 622V533L425 531Q525 519 595 466T665 342Q665 301 642 267T583 209T506 172T425 152L411 150V61Q417 55 421 53T447 48T511 46H538V0H526Q502 3 361 3T196 0H184V46H211Q231 46 245 46T270 47T286 48T297 51T303 54T307 57T312 61V150H310Q309 151 289 153T232 166T160 195Q149 201 136 210T103 238T69 284T56 342Q56 414 128 467T294 530Q309 532 310 533H312V622ZM170 342Q170 207 307 188H312V495H309Q301 495 282 491T231 469T186 423Q170 389 170 342ZM415 188Q487 199 519 236T551 342Q551 384 539 414T507 459T470 481T434 491T415 495H410V188H415Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi mathvariant="normal">Φ</mi></math></mjx-assistive-mml></mjx-container>는 부호 거리로 공기 중에서 양수이고 바위 안에서 음수, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.02ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 451 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>r</mi></math></mjx-assistive-mml></mjx-container>은 프로브 반지름, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="8.862ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 3917.2 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D706" d="M166 673Q166 685 183 694H202Q292 691 316 644Q322 629 373 486T474 207T524 67Q531 47 537 34T546 15T551 6T555 2T556 -2T550 -11H482Q457 3 450 18T399 152L354 277L340 262Q327 246 293 207T236 141Q211 112 174 69Q123 9 111 -1T83 -12Q47 -12 47 20Q47 37 61 52T199 187Q229 216 266 252T321 306L338 322Q338 323 288 462T234 612Q214 657 183 657Q166 657 166 673Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(860.8,0)"><path data-c="2208" d="M84 250Q84 372 166 450T360 539Q361 539 377 539T419 540T469 540H568Q583 532 583 520Q583 511 570 501L466 500Q355 499 329 494Q280 482 242 458T183 409T147 354T129 306T124 272V270H568Q583 262 583 250T568 230H124V228Q124 207 134 177T167 112T231 48T328 7Q355 1 466 0H570Q583 -10 583 -20Q583 -32 568 -40H471Q464 -40 446 -40T417 -41Q262 -41 172 45Q84 127 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1805.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2194.6,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2694.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3139.2,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3639.2,0)"><path data-c="5D" d="M22 710V750H159V-250H22V-210H119V710H22Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>λ</mi><mo>∈</mo><mo stretchy="false">(</mo><mn>0</mn><mo>,</mo><mn>1</mn><mo stretchy="false">]</mo></math></mjx-assistive-mml></mjx-container>은 과대 보고하는 하이트맵 필드가 비탈을 뛰어넘지 못하게 막는 과소 완화 인자, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.439ex;" xmlns="http://www.w3.org/2000/svg" width="9.148ex" height="1.439ex" role="img" focusable="false" viewBox="0 -442 4043.3 636" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(502,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1111,0)" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(1730.7,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2175.4,0)"><g data-mml-node="mi"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(502,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="78" d="M201 0Q189 3 102 3Q26 3 17 0H11V46H25Q48 47 67 52T96 61T121 78T139 96T160 122T180 150L226 210L168 288Q159 301 149 315T133 336T122 351T113 363T107 370T100 376T94 379T88 381T80 383Q74 383 44 385H16V431H23Q59 429 126 429Q219 429 229 431H237V385Q201 381 201 369Q201 367 211 353T239 315T268 274L272 270L297 304Q329 345 329 358Q329 364 327 369T322 376T317 380T310 384L307 385H302V431H309Q324 428 408 428Q487 428 493 431H499V385H492Q443 385 411 368Q394 360 377 341T312 257L296 236L358 151Q424 61 429 57T446 50Q464 46 499 46H516V0H510H502Q494 1 482 1T457 2T432 2T414 3Q403 3 377 3T327 1L304 0H295V46H298Q309 46 320 51T331 63Q331 65 291 120L250 175Q249 174 219 133T185 88Q181 83 181 74Q181 63 188 55T206 46Q208 46 208 23V0H201Z" transform="translate(1333,0)" style="stroke-width: 3;"/></g></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>s</mi><mrow data-mjx-texclass="ORD"><mo data-mjx-texclass="OP" movablelimits="true">min</mo></mrow></msub><mo>,</mo><msub><mi>s</mi><mrow data-mjx-texclass="ORD"><mo data-mjx-texclass="OP" movablelimits="true">max</mo></mrow></msub></math></mjx-assistive-mml></mjx-container>는 얇은 벽이 건너뛰어지지 않고 행진이 너무 길어지지 않게 하는 보폭 클램프입니다. 접촉은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="11.08ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 4897.6 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="3A6" d="M312 622Q310 623 307 625T303 629T297 631T286 634T270 635T246 636T211 637H184V683H196Q220 680 361 680T526 683H538V637H511Q468 637 447 635T422 631T411 622V533L425 531Q525 519 595 466T665 342Q665 301 642 267T583 209T506 172T425 152L411 150V61Q417 55 421 53T447 48T511 46H538V0H526Q502 3 361 3T196 0H184V46H211Q231 46 245 46T270 47T286 48T297 51T303 54T307 57T312 61V150H310Q309 151 289 153T232 166T160 195Q149 201 136 210T103 238T69 284T56 342Q56 414 128 467T294 530Q309 532 310 533H312V622ZM170 342Q170 207 307 188H312V495H309Q301 495 282 491T231 469T186 423Q170 389 170 342ZM415 188Q487 199 519 236T551 342Q551 384 539 414T507 459T470 481T434 491T415 495H410V188H415Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(1111,0)"><g data-mml-node="mi"><path data-c="1D42B" d="M405 293T374 293T324 312T305 361Q305 378 312 394Q315 397 315 399Q305 399 294 394T266 375T238 329T222 249Q221 241 221 149V62H308V0H298Q280 3 161 3Q47 3 38 0H29V62H98V210V303Q98 353 96 363T83 376Q69 380 42 380H29V442H32L118 446Q204 450 205 450H210V414L211 378Q247 449 315 449H321Q384 449 413 422T442 360Q442 332 424 313Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1585,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1974,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2335,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2724,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3390.8,0)"><path data-c="2264" d="M674 636Q682 636 688 630T694 615T687 601Q686 600 417 472L151 346L399 228Q687 92 691 87Q694 81 694 76Q694 58 676 56H670L382 192Q92 329 90 331Q83 336 83 348Q84 359 96 365Q104 369 382 500T665 634Q669 636 674 636ZM84 -118Q84 -108 99 -98H678Q694 -104 694 -118Q694 -130 679 -138H98Q84 -131 84 -118Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(4446.6,0)"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi mathvariant="normal">Φ</mi><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">r</mi></mrow><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>≤</mo><mi>r</mi></math></mjx-assistive-mml></mjx-container>인 첫 번째 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="0.817ex" height="1.441ex" role="img" focusable="false" viewBox="0 -626 361 637" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>t</mi></math></mjx-assistive-mml></mjx-container>로, 구의 표면이 바위에 도달했다는 뜻이고, 카메라는 그 호 길이에서 반지름을 뺀 지점에 머뭅니다.</p>
<p>콜라이더는 안전망으로 메서드 하나를 더 지닙니다. 침투 해소(depenetration)입니다. 충돌은 애초에 카메라를 단단한 것 바깥에 두어야 하지만, 몇몇 상황이 그것을 슬쩍 빠져나갑니다. 붐이 그 안에서 시작될 만큼 얇은 벽에 걸쳐 선 피벗, 카메라가 앉아 있던 바위가 지형 도구로 방금 깎여 동굴이 되어버린 경우, 카메라 둘레로 떨어뜨려진 건물 조각 같은 것들입니다. 그런 경우를 위해 콜라이더는 카메라가 단단한 것 안에서 프레임을 끝냈는지, 곧 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="8.587ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 3795.6 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="3A6" d="M312 622Q310 623 307 625T303 629T297 631T286 634T270 635T246 636T211 637H184V683H196Q220 680 361 680T526 683H538V637H511Q468 637 447 635T422 631T411 622V533L425 531Q525 519 595 466T665 342Q665 301 642 267T583 209T506 172T425 152L411 150V61Q417 55 421 53T447 48T511 46H538V0H526Q502 3 361 3T196 0H184V46H211Q231 46 245 46T270 47T286 48T297 51T303 54T307 57T312 61V150H310Q309 151 289 153T232 166T160 195Q149 201 136 210T103 238T69 284T56 342Q56 414 128 467T294 530Q309 532 310 533H312V622ZM170 342Q170 207 307 188H312V495H309Q301 495 282 491T231 469T186 423Q170 389 170 342ZM415 188Q487 199 519 236T551 342Q551 384 539 414T507 459T470 481T434 491T415 495H410V188H415Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(1111,0)"><g data-mml-node="mi"><path data-c="1D41C" d="M447 131H458Q478 131 478 117Q478 112 471 95T439 51T377 9Q330 -6 286 -6Q196 -6 135 35Q39 96 39 222Q39 324 101 384Q169 453 286 453Q359 453 411 431T464 353Q464 319 445 302T395 284Q360 284 343 305T325 353Q325 380 338 396H333Q317 398 295 398H292Q280 398 271 397T245 390T218 373T197 338T183 283Q182 275 182 231Q182 199 184 180T193 132T220 85T270 57Q289 50 317 50H326Q385 50 414 115Q419 127 423 129T447 131Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1622,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2288.8,0)"><path data-c="3C" d="M694 -11T694 -19T688 -33T678 -40Q671 -40 524 29T234 166L90 235Q83 240 83 250Q83 261 91 266Q664 540 678 540Q681 540 687 534T694 519T687 505Q686 504 417 376L151 250L417 124Q686 -4 687 -5Q694 -11 694 -19Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(3344.6,0)"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi mathvariant="normal">Φ</mi><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">c</mi></mrow><mo stretchy="false">)</mo><mo>&lt;</mo><mi>r</mi></math></mjx-assistive-mml></mjx-container>인지를 확인하고, 그렇다면 필드의 그래디언트를 읽습니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.633ex" height="1.545ex" role="img" focusable="false" viewBox="0 -683 722 683" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="3A6" d="M312 622Q310 623 307 625T303 629T297 631T286 634T270 635T246 636T211 637H184V683H196Q220 680 361 680T526 683H538V637H511Q468 637 447 635T422 631T411 622V533L425 531Q525 519 595 466T665 342Q665 301 642 267T583 209T506 172T425 152L411 150V61Q417 55 421 53T447 48T511 46H538V0H526Q502 3 361 3T196 0H184V46H211Q231 46 245 46T270 47T286 48T297 51T303 54T307 57T312 61V150H310Q309 151 289 153T232 166T160 195Q149 201 136 210T103 238T69 284T56 342Q56 414 128 467T294 530Q309 532 310 533H312V622ZM170 342Q170 207 307 188H312V495H309Q301 495 282 491T231 469T186 423Q170 389 170 342ZM415 188Q487 199 519 236T551 342Q551 384 539 414T507 459T470 481T434 491T415 495H410V188H415Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi mathvariant="normal">Φ</mi></math></mjx-assistive-mml></mjx-container>는 바위를 벗어날수록 커지므로 그래디언트는 트인 공기 쪽을 곧장 가리킵니다. 그 방향을 따라 카메라를 밖으로 밀어냅니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -2.172ex;" xmlns="http://www.w3.org/2000/svg" width="29.076ex" height="5.475ex" role="img" focusable="false" viewBox="0 -1460 12851.4 2420" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D41C" d="M447 131H458Q478 131 478 117Q478 112 471 95T439 51T377 9Q330 -6 286 -6Q196 -6 135 35Q39 96 39 222Q39 324 101 384Q169 453 286 453Q359 453 411 431T464 353Q464 319 445 302T395 284Q360 284 343 305T325 353Q325 380 338 396H333Q317 398 295 398H292Q280 398 271 397T245 390T218 373T197 338T183 283Q182 275 182 231Q182 199 184 180T193 132T220 85T270 57Q289 50 317 50H326Q385 50 414 115Q419 127 423 129T447 131Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(788.8,0)"><path data-c="2190" d="M944 261T944 250T929 230H165Q167 228 182 216T211 189T244 152T277 96T303 25Q308 7 308 0Q308 -11 288 -11Q281 -11 278 -11T272 -7T267 2T263 21Q245 94 195 151T73 236Q58 242 55 247Q55 254 59 257T73 264Q121 283 158 314T215 375T247 434T264 480L267 497Q269 503 270 505T275 509T288 511Q308 511 308 500Q308 493 303 475Q293 438 278 406T246 352T215 315T185 287T165 270H929Q944 261 944 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(2066.6,0)"><g data-mml-node="mi"><path data-c="1D41C" d="M447 131H458Q478 131 478 117Q478 112 471 95T439 51T377 9Q330 -6 286 -6Q196 -6 135 35Q39 96 39 222Q39 324 101 384Q169 453 286 453Q359 453 411 431T464 353Q464 319 445 302T395 284Q360 284 343 305T325 353Q325 380 338 396H333Q317 398 295 398H292Q280 398 271 397T245 390T218 373T197 338T183 283Q182 275 182 231Q182 199 184 180T193 132T220 85T270 57Q289 50 317 50H326Q385 50 414 115Q419 127 423 129T447 131Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2799.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(3800,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="28" d="M152 251Q152 646 388 850H416Q422 844 422 841Q422 837 403 816T357 753T302 649T255 482T236 250Q236 124 255 19T301 -147T356 -251T403 -315T422 -340Q422 -343 416 -349H388Q359 -325 332 -296T271 -213T212 -97T170 56T152 251Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(4258,0)"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4931.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(5931.4,0)"><path data-c="3A6" d="M312 622Q310 623 307 625T303 629T297 631T286 634T270 635T246 636T211 637H184V683H196Q220 680 361 680T526 683H538V637H511Q468 637 447 635T422 631T411 622V533L425 531Q525 519 595 466T665 342Q665 301 642 267T583 209T506 172T425 152L411 150V61Q417 55 421 53T447 48T511 46H538V0H526Q502 3 361 3T196 0H184V46H211Q231 46 245 46T270 47T286 48T297 51T303 54T307 57T312 61V150H310Q309 151 289 153T232 166T160 195Q149 201 136 210T103 238T69 284T56 342Q56 414 128 467T294 530Q309 532 310 533H312V622ZM170 342Q170 207 307 188H312V495H309Q301 495 282 491T231 469T186 423Q170 389 170 342ZM415 188Q487 199 519 236T551 342Q551 384 539 414T507 459T470 481T434 491T415 495H410V188H415Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6653.4,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(7042.4,0)"><g data-mml-node="mi"><path data-c="1D41C" d="M447 131H458Q478 131 478 117Q478 112 471 95T439 51T377 9Q330 -6 286 -6Q196 -6 135 35Q39 96 39 222Q39 324 101 384Q169 453 286 453Q359 453 411 431T464 353Q464 319 445 302T395 284Q360 284 343 305T325 353Q325 380 338 396H333Q317 398 295 398H292Q280 398 271 397T245 390T218 373T197 338T183 283Q182 275 182 231Q182 199 184 180T193 132T220 85T270 57Q289 50 317 50H326Q385 50 414 115Q419 127 423 129T447 131Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(7553.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(7942.4,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="29" d="M305 251Q305 -145 69 -349H56Q43 -349 39 -347T35 -338Q37 -333 60 -307T108 -239T160 -136T204 27T221 250T204 473T160 636T108 740T60 807T35 839Q35 850 50 850H56H69Q197 743 256 566Q305 425 305 251Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mstyle" transform="translate(8400.4,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mfrac" transform="translate(8567.4,0)"><g data-mml-node="mrow" transform="translate(720,710)"><g data-mml-node="mi"><path data-c="2207" d="M46 676Q46 679 51 683H781Q786 679 786 676Q786 674 617 326T444 -26Q439 -33 416 -33T388 -26Q385 -22 216 326T46 676ZM697 596Q697 597 445 597T193 596Q195 591 319 336T445 80L697 596Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(833,0)"><path data-c="3A6" d="M312 622Q310 623 307 625T303 629T297 631T286 634T270 635T246 636T211 637H184V683H196Q220 680 361 680T526 683H538V637H511Q468 637 447 635T422 631T411 622V533L425 531Q525 519 595 466T665 342Q665 301 642 267T583 209T506 172T425 152L411 150V61Q417 55 421 53T447 48T511 46H538V0H526Q502 3 361 3T196 0H184V46H211Q231 46 245 46T270 47T286 48T297 51T303 54T307 57T312 61V150H310Q309 151 289 153T232 166T160 195Q149 201 136 210T103 238T69 284T56 342Q56 414 128 467T294 530Q309 532 310 533H312V622ZM170 342Q170 207 307 188H312V495H309Q301 495 282 491T231 469T186 423Q170 389 170 342ZM415 188Q487 199 519 236T551 342Q551 384 539 414T507 459T470 481T434 491T415 495H410V188H415Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1555,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(1944,0)"><g data-mml-node="mi"><path data-c="1D41C" d="M447 131H458Q478 131 478 117Q478 112 471 95T439 51T377 9Q330 -6 286 -6Q196 -6 135 35Q39 96 39 222Q39 324 101 384Q169 453 286 453Q359 453 411 431T464 353Q464 319 445 302T395 284Q360 284 343 305T325 353Q325 380 338 396H333Q317 398 295 398H292Q280 398 271 397T245 390T218 373T197 338T183 283Q182 275 182 231Q182 199 184 180T193 132T220 85T270 57Q289 50 317 50H326Q385 50 414 115Q419 127 423 129T447 131Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2455,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mrow" transform="translate(220,-710)"><g data-mml-node="mo"><path data-c="2016" d="M133 736Q138 750 153 750Q164 750 170 739Q172 735 172 250T170 -239Q164 -250 152 -250Q144 -250 138 -244L137 -243Q133 -241 133 -179T132 250Q132 731 133 736ZM329 739Q334 750 346 750Q353 750 361 744L362 743Q366 741 366 679T367 250T367 -178T362 -243L361 -244Q355 -250 347 -250Q335 -250 329 -239Q327 -235 327 250T329 739Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(500,0)"><path data-c="2207" d="M46 676Q46 679 51 683H781Q786 679 786 676Q786 674 617 326T444 -26Q439 -33 416 -33T388 -26Q385 -22 216 326T46 676ZM697 596Q697 597 445 597T193 596Q195 591 319 336T445 80L697 596Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1333,0)"><path data-c="3A6" d="M312 622Q310 623 307 625T303 629T297 631T286 634T270 635T246 636T211 637H184V683H196Q220 680 361 680T526 683H538V637H511Q468 637 447 635T422 631T411 622V533L425 531Q525 519 595 466T665 342Q665 301 642 267T583 209T506 172T425 152L411 150V61Q417 55 421 53T447 48T511 46H538V0H526Q502 3 361 3T196 0H184V46H211Q231 46 245 46T270 47T286 48T297 51T303 54T307 57T312 61V150H310Q309 151 289 153T232 166T160 195Q149 201 136 210T103 238T69 284T56 342Q56 414 128 467T294 530Q309 532 310 533H312V622ZM170 342Q170 207 307 188H312V495H309Q301 495 282 491T231 469T186 423Q170 389 170 342ZM415 188Q487 199 519 236T551 342Q551 384 539 414T507 459T470 481T434 491T415 495H410V188H415Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2055,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(2444,0)"><g data-mml-node="mi"><path data-c="1D41C" d="M447 131H458Q478 131 478 117Q478 112 471 95T439 51T377 9Q330 -6 286 -6Q196 -6 135 35Q39 96 39 222Q39 324 101 384Q169 453 286 453Q359 453 411 431T464 353Q464 319 445 302T395 284Q360 284 343 305T325 353Q325 380 338 396H333Q317 398 295 398H292Q280 398 271 397T245 390T218 373T197 338T183 283Q182 275 182 231Q182 199 184 180T193 132T220 85T270 57Q289 50 317 50H326Q385 50 414 115Q419 127 423 129T447 131Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2955,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3344,0)"><path data-c="2016" d="M133 736Q138 750 153 750Q164 750 170 739Q172 735 172 250T170 -239Q164 -250 152 -250Q144 -250 138 -244L137 -243Q133 -241 133 -179T132 250Q132 731 133 736ZM329 739Q334 750 346 750Q353 750 361 744L362 743Q366 741 366 679T367 250T367 -178T362 -243L361 -244Q355 -250 347 -250Q335 -250 329 -239Q327 -235 327 250T329 739Z" style="stroke-width: 3;"/></g></g><rect width="4044" height="60" x="120" y="220"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">c</mi></mrow><mo stretchy="false">←</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">c</mi></mrow><mo>+</mo><mrow data-mjx-texclass="ORD"><mo minsize="1.2em" maxsize="1.2em">(</mo></mrow><mi>r</mi><mo>−</mo><mi mathvariant="normal">Φ</mi><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">c</mi></mrow><mo stretchy="false">)</mo><mrow data-mjx-texclass="ORD"><mo minsize="1.2em" maxsize="1.2em">)</mo></mrow><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mfrac><mrow><mi mathvariant="normal">∇</mi><mi mathvariant="normal">Φ</mi><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">c</mi></mrow><mo stretchy="false">)</mo></mrow><mrow><mo data-mjx-texclass="OPEN" fence="false" stretchy="false">‖</mo><mi mathvariant="normal">∇</mi><mi mathvariant="normal">Φ</mi><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">c</mi></mrow><mo stretchy="false">)</mo><mo data-mjx-texclass="CLOSE" fence="false" stretchy="false">‖</mo></mrow></mfrac></math></mjx-assistive-mml></mjx-container><p>이런 반복 몇 번이면 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.02ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 451 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>r</mi></math></mjx-assistive-mml></mjx-container>-등위면으로 수렴하고, 이것이 바로 조각 도구가 카메라 발밑의 땅을 파내도 화면이 까매지는 대신 다음 프레임에 시야가 회복되게 만드는 것입니다.</p>
<h2 id="빠르게-들어가고-느리게-풀어주며-울타리-기둥에-움찔하지-않기" tabindex="-1">빠르게 들어가고, 느리게 풀어주며, 울타리 기둥에 움찔하지 않기 <a class="header-anchor" href="#빠르게-들어가고-느리게-풀어주며-울타리-기둥에-움찔하지-않기" aria-label="Permalink to &quot;빠르게 들어가고, 느리게 풀어주며, 울타리 기둥에 움찔하지 않기&quot;"></a></h2>
<p>매 프레임 충돌 거리로 그냥 점프하는 붐은 붐이 없느니만 못합니다. 세계는 카메라가 한 프레임 동안 뒤로 지나치는 얇은 것들로 가득하기 때문입니다. 울타리 기둥, 가로등, 나무줄기, 그리고 그 하나하나를 피하려 달려들었다가 다시 달려드는 카메라는 메스껍습니다. Haigh-Hutchinson의 책과 Itay Keren의 사랑받는 카메라 모션 강연은 둘 다 같은 직관에 도달합니다. 카메라는 위협과 위험에는 거기서 풀려나는 것보다 더 빨리 반응해야 한다는 것입니다. 그래서 댐핑은 일부러 비대칭입니다. 가림막이 나타나 붐이 짧아져야 할 때는 거의 즉시 들어옵니다. 한 프레임의 클리핑은 보기 흉하고, 플레이어는 빠른 끼워 넣기를 용서하기 때문입니다. 가림막이 사라져 붐이 늘어나려 할 때는 천천히 풀려 나오고, 그것도 연속해서 트여 있는 짧은 대기 타이머가 지난 뒤에야 그렇게 합니다. 그 대기가 움찔거림을 죽이는 히스테리시스입니다. 얇은 기둥 옆을 카메라로 휙 지나가면 기둥은 느린 확장을 촉발할 만큼 오래 트이는 법이 없어서, 카메라는 그것이 없는 것처럼 미끄러져 지나갑니다. 바로 당신의 눈이 원하는 것이죠. Cinemachine은 같은 발상을 충돌로 들어가는 댐핑과 충돌에서 나오는 댐핑이라는 별도의 값으로 노출하고, 이 비대칭이 그것을 스프링이 아니라 카메라 오퍼레이터처럼 느껴지게 만드는 부분입니다.</p>
<p>코드로는 변화의 부호에 따라 비율을 전환하는 지수 평활화 한 줄입니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.045ex;" xmlns="http://www.w3.org/2000/svg" width="0.943ex" height="1.64ex" role="img" focusable="false" viewBox="0 -705 417 725" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>ℓ</mi></math></mjx-assistive-mml></mjx-container>이 현재 붐 길이, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.023ex;" xmlns="http://www.w3.org/2000/svg" width="1.197ex" height="1.02ex" role="img" focusable="false" viewBox="0 -441 529 451" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>a</mi></math></mjx-assistive-mml></mjx-container>가 이번 프레임 충돌이 허용하는 길이, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="2.701ex" height="1.645ex" role="img" focusable="false" viewBox="0 -716 1194 727" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="394" d="M51 0Q46 4 46 7Q46 9 215 357T388 709Q391 716 416 716Q439 716 444 709Q447 705 616 357T786 7Q786 4 781 0H51ZM507 344L384 596L137 92L383 91H630Q630 93 507 344Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(833,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi mathvariant="normal">Δ</mi><mi>t</mi></math></mjx-assistive-mml></mjx-container>가 프레임 시간이라면,</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -2.149ex;" xmlns="http://www.w3.org/2000/svg" width="62.104ex" height="5.43ex" role="img" focusable="false" viewBox="0 -1450 27450 2400" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(694.8,0)"><path data-c="2190" d="M944 261T944 250T929 230H165Q167 228 182 216T211 189T244 152T277 96T303 25Q308 7 308 0Q308 -11 288 -11Q281 -11 278 -11T272 -7T267 2T263 21Q245 94 195 151T73 236Q58 242 55 247Q55 254 59 257T73 264Q121 283 158 314T215 375T247 434T264 480L267 497Q269 503 270 505T275 509T288 511Q308 511 308 500Q308 493 303 475Q293 438 278 406T246 352T215 315T185 287T165 270H929Q944 261 944 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1972.6,0)"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2611.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3612,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(4001,0)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4752.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(5752.4,0)"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6169.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(6558.4,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="28" d="M152 251Q152 646 388 850H416Q422 844 422 841Q422 837 403 816T357 753T302 649T255 482T236 250Q236 124 255 19T301 -147T356 -251T403 -315T422 -340Q422 -343 416 -349H388Q359 -325 332 -296T271 -213T212 -97T170 56T152 251Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mn" transform="translate(7016.4,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(7738.7,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(8738.9,0)"><g data-mml-node="mi"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(499,413) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(778,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(1299,0) scale(1.414)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(1535.2,0)"><path data-c="394" d="M51 0Q46 4 46 7Q46 9 215 357T388 709Q391 716 416 716Q439 716 444 709Q447 705 616 357T786 7Q786 4 781 0H51ZM507 344L384 596L137 92L383 91H630Q630 93 507 344Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2368.2,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(11217.7,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="29" d="M305 251Q305 -145 69 -349H56Q43 -349 39 -347T35 -338Q37 -333 60 -307T108 -239T160 -136T204 27T221 250T204 473T160 636T108 740T60 807T35 839Q35 850 50 850H56H69Q197 743 256 566Q305 425 305 251Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(11675.7,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(11953.7,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(14120.4,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(14919.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mrow" transform="translate(15974.9,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="7B" d="M618 -943L612 -949H582L568 -943Q472 -903 411 -841T332 -703Q327 -682 327 -653T325 -350Q324 -28 323 -18Q317 24 301 61T264 124T221 171T179 205T147 225T132 234Q130 238 130 250Q130 255 130 258T131 264T132 267T134 269T139 272T144 275Q207 308 256 367Q310 436 323 519Q324 529 325 851Q326 1124 326 1154T332 1205Q369 1358 566 1443L582 1450H612L618 1444V1429Q618 1413 616 1411L608 1406Q599 1402 585 1393T552 1372T515 1343T479 1305T449 1257T429 1200Q425 1180 425 1152T423 851Q422 579 422 549T416 498Q407 459 388 424T346 364T297 318T250 284T214 264T197 254L188 251L205 242Q290 200 345 138T416 3Q421 -18 421 -48T423 -349Q423 -397 423 -472Q424 -677 428 -694Q429 -697 429 -699Q434 -722 443 -743T465 -782T491 -816T519 -845T548 -868T574 -886T595 -899T610 -908L616 -910Q618 -912 618 -928V-943Z" style="stroke-width: 3;"/></g><g data-mml-node="mtable" transform="translate(750,0)"><g data-mml-node="mtr" transform="translate(0,700)"><g data-mml-node="mtd"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(554,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mtext"><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(278,0)" style="stroke-width: 3;"/></g></g></g></g><g data-mml-node="mtd" transform="translate(2625.8,0)"><g data-mml-node="mi"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(806.8,0)"><path data-c="2264" d="M674 636Q682 636 688 630T694 615T687 601Q686 600 417 472L151 346L399 228Q687 92 691 87Q694 81 694 76Q694 58 676 56H670L382 192Q92 329 90 331Q83 336 83 348Q84 359 96 365Q104 369 382 500T665 634Q669 636 674 636ZM84 -118Q84 -108 99 -98H678Q694 -104 694 -118Q694 -130 679 -138H98Q84 -131 84 -118Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1862.6,0)"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mtr" transform="translate(0,-700)"><g data-mml-node="mtd"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(554,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mtext"><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" style="stroke-width: 3;"/><path data-c="75" d="M383 58Q327 -10 256 -10H249Q124 -10 105 89Q104 96 103 226Q102 335 102 348T96 369Q86 385 36 385H25V408Q25 431 27 431L38 432Q48 433 67 434T105 436Q122 437 142 438T172 441T184 442H187V261Q188 77 190 64Q193 49 204 40Q224 26 264 26Q290 26 311 35T343 58T363 90T375 120T379 144Q379 145 379 161T380 201T380 248V315Q380 361 370 372T320 385H302V431Q304 431 378 436T457 442H464V264Q464 84 465 81Q468 61 479 55T524 46H542V0Q540 0 467 -5T390 -11H383V58Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1056,0)" style="stroke-width: 3;"/></g></g></g></g><g data-mml-node="mtd" transform="translate(2625.8,0)"><g data-mml-node="mi"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(806.8,0)"><path data-c="3E" d="M84 520Q84 528 88 533T96 539L99 540Q106 540 253 471T544 334L687 265Q694 260 694 250T687 235Q685 233 395 96L107 -40H101Q83 -38 83 -20Q83 -19 83 -17Q82 -10 98 -1Q117 9 248 71Q326 108 378 132L626 250L378 368Q90 504 86 509Q84 513 84 520Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1862.6,0)"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g></g></g></g><g data-mml-node="mo" transform="translate(5655.3,0) translate(0 250)"/></g><g data-mml-node="mo" transform="translate(21630.3,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(21908.3,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(23074.9,0)"><g data-mml-node="mi"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(554,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mtext"><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(278,0)" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(24546.4,0)"><path data-c="226B" d="M55 539T55 547T60 561T74 567Q81 567 207 498Q297 449 365 412Q633 265 636 261Q639 255 639 250Q639 241 626 232Q614 224 365 88Q83 -65 79 -66Q76 -67 73 -67Q65 -67 60 -61T55 -47Q55 -39 61 -33Q62 -33 95 -15T193 39T320 109L321 110H322L323 111H324L325 112L326 113H327L329 114H330L331 115H332L333 116L334 117H335L336 118H337L338 119H339L340 120L341 121H342L343 122H344L345 123H346L347 124L348 125H349L351 126H352L353 127H354L355 128L356 129H357L358 130H359L360 131H361L362 132L363 133H364L365 134H366L367 135H368L369 136H370L371 137L372 138H373L374 139H375L376 140L378 141L576 251Q63 530 62 533Q55 539 55 547ZM360 539T360 547T365 561T379 567Q386 567 512 498Q602 449 670 412Q938 265 941 261Q944 255 944 250Q944 241 931 232Q919 224 670 88Q388 -65 384 -66Q381 -67 378 -67Q370 -67 365 -61T360 -47Q360 -39 366 -33Q367 -33 400 -15T498 39T625 109L626 110H627L628 111H629L630 112L631 113H632L634 114H635L636 115H637L638 116L639 117H640L641 118H642L643 119H644L645 120L646 121H647L648 122H649L650 123H651L652 124L653 125H654L656 126H657L658 127H659L660 128L661 129H662L663 130H664L665 131H666L667 132L668 133H669L670 134H671L672 135H673L674 136H675L676 137L677 138H678L679 139H680L681 140L683 141L881 251Q368 530 367 533Q360 539 360 547Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(25824.2,0)"><g data-mml-node="mi"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(554,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mtext"><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" style="stroke-width: 3;"/><path data-c="75" d="M383 58Q327 -10 256 -10H249Q124 -10 105 89Q104 96 103 226Q102 335 102 348T96 369Q86 385 36 385H25V408Q25 431 27 431L38 432Q48 433 67 434T105 436Q122 437 142 438T172 441T184 442H187V261Q188 77 190 64Q193 49 204 40Q224 26 264 26Q290 26 311 35T343 58T363 90T375 120T379 144Q379 145 379 161T380 201T380 248V315Q380 361 370 372T320 385H302V431Q304 431 378 436T457 442H464V264Q464 84 465 81Q468 61 479 55T524 46H542V0Q540 0 467 -5T390 -11H383V58Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1056,0)" style="stroke-width: 3;"/></g></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi>ℓ</mi><mo stretchy="false">←</mo><mi>ℓ</mi><mo>+</mo><mo stretchy="false">(</mo><mi>a</mi><mo>−</mo><mi>ℓ</mi><mo stretchy="false">)</mo><mrow data-mjx-texclass="ORD"><mo minsize="1.2em" maxsize="1.2em">(</mo></mrow><mn>1</mn><mo>−</mo><msup><mi>e</mi><mrow data-mjx-texclass="ORD"><mo>−</mo><mi>k</mi><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></msup><mrow data-mjx-texclass="ORD"><mo minsize="1.2em" maxsize="1.2em">)</mo></mrow><mo>,</mo><mstyle scriptlevel="0"><mspace width="2em"/></mstyle><mi>k</mi><mo>=</mo><mrow data-mjx-texclass="INNER"><mo data-mjx-texclass="OPEN">{</mo><mtable columnalign="left left" columnspacing="1em" rowspacing="0.4em 0.2em"><mtr><mtd><msub><mi>k</mi><mrow data-mjx-texclass="ORD"><mtext>in</mtext></mrow></msub></mtd><mtd><mi>a</mi><mo>≤</mo><mi>ℓ</mi></mtd></mtr><mtr><mtd><msub><mi>k</mi><mrow data-mjx-texclass="ORD"><mtext>out</mtext></mrow></msub></mtd><mtd><mi>a</mi><mo>&gt;</mo><mi>ℓ</mi></mtd></mtr></mtable><mo data-mjx-texclass="CLOSE" fence="true" stretchy="true" symmetric="true"/></mrow><mo>,</mo><mstyle scriptlevel="0"><mspace width="1em"/></mstyle><msub><mi>k</mi><mrow data-mjx-texclass="ORD"><mtext>in</mtext></mrow></msub><mo>≫</mo><msub><mi>k</mi><mrow data-mjx-texclass="ORD"><mtext>out</mtext></mrow></msub></math></mjx-assistive-mml></mjx-container><p>이고, 풀려 나오는 분기는 트인 상태가 대기 시간 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.029ex;" xmlns="http://www.w3.org/2000/svg" width="1.17ex" height="1.005ex" role="img" focusable="false" viewBox="0 -431 517 444" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D70F" d="M39 284Q18 284 18 294Q18 301 45 338T99 398Q134 425 164 429Q170 431 332 431Q492 431 497 429Q517 424 517 402Q517 388 508 376T485 360Q479 358 389 358T299 356Q298 355 283 274T251 109T233 20Q228 5 215 -4T186 -13Q153 -13 153 20V30L203 192Q214 228 227 272T248 336L254 357Q254 358 208 358Q206 358 197 358T183 359Q105 359 61 295Q56 287 53 286T39 284Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>τ</mi></math></mjx-assistive-mml></mjx-container> 동안 유지된 뒤에만 돕니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="9.505ex" height="2.152ex" role="img" focusable="false" viewBox="0 -869.3 4201.3 951.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(1722.4,0)"><g data-mml-node="mi"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(778,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(1299,0) scale(1.414)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(1535.2,0)"><path data-c="394" d="M51 0Q46 4 46 7Q46 9 215 357T388 709Q391 716 416 716Q439 716 444 709Q447 705 616 357T786 7Q786 4 781 0H51ZM507 344L384 596L137 92L383 91H630Q630 93 507 344Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2368.2,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn><mo>−</mo><msup><mi>e</mi><mrow data-mjx-texclass="ORD"><mo>−</mo><mi>k</mi><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></msup></math></mjx-assistive-mml></mjx-container> 형태는 깔끔해 보이는 것 이상의 의미가 있습니다. 프레임 레이트와 무관하게 응답 시간 상수를 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="3.441ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 1521 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(500,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(1000,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn><mrow data-mjx-texclass="ORD"><mo>/</mo></mrow><mi>k</mi></math></mjx-assistive-mml></mjx-container>로 고정해서, 카메라가 초당 30프레임에서도 144프레임에서도 똑같이 느껴지게 합니다. 순진한 상수 블렌드 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="16.286ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 7198.4 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(694.8,0)"><path data-c="2190" d="M944 261T944 250T929 230H165Q167 228 182 216T211 189T244 152T277 96T303 25Q308 7 308 0Q308 -11 288 -11Q281 -11 278 -11T272 -7T267 2T263 21Q245 94 195 151T73 236Q58 242 55 247Q55 254 59 257T73 264Q121 283 158 314T215 375T247 434T264 480L267 497Q269 503 270 505T275 509T288 511Q308 511 308 500Q308 493 303 475Q293 438 278 406T246 352T215 315T185 287T165 270H929Q944 261 944 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1972.6,0)"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2611.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(3612,0)"><path data-c="1D6FC" d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4252,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(4641,0)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(5392.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(6392.4,0)"><path data-c="2113" d="M345 104T349 104T361 95T369 80T352 59Q268 -20 206 -20Q170 -20 146 3T113 53T99 104L94 129Q94 130 79 116T48 86T28 70Q22 70 15 79T7 94Q7 98 12 103T58 147L91 179V185Q91 186 91 191T92 200Q92 282 128 400T223 612T336 705Q397 705 397 636V627Q397 453 194 233Q185 223 180 218T174 211T171 208T165 201L163 186Q159 142 159 123Q159 17 208 17Q228 17 253 30T293 56T335 94Q345 104 349 104ZM360 634Q360 655 354 661T336 668Q328 668 322 666T302 645T272 592Q252 547 229 467T192 330L179 273Q179 272 186 280T204 300T221 322Q327 453 355 590Q360 612 360 634Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6809.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>ℓ</mi><mo stretchy="false">←</mo><mi>ℓ</mi><mo>+</mo><mi>α</mi><mo stretchy="false">(</mo><mi>a</mi><mo>−</mo><mi>ℓ</mi><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>였다면 빠른 기계에서는 더 빨리 끼워지고 느린 기계에서는 뭉개졌을 것입니다.</p>
<p>마지막 동작은 이 파트 전체를 시작하게 만든 좁은 실내를 위한 것입니다. 붐이 카메라가 플레이어 바로 위에 올 만큼 짧게 무너지면, 플레이어 자신의 아바타를 숨기고 시야가 1인칭에 가깝게 앉게 둡니다. 비좁은 사당에서 Breath of the Wild가 하는 일이고, 대부분의 3인칭 게임이 구석에서 기대는 동작입니다. 대안인 벽에 박혀 머리 뒤통수를 노려보는 카메라는 쓸모가 없기 때문이죠. 리그는 이를 위해 플래그 하나를 노출하고, 월드 루프는 그 플래그를 읽어 로컬 아바타의 가시성을 토글합니다. 붐이 1미터 아래면 당신은 사실상 1인칭이고, 벽은 존중되며, 공간이 있는 방으로 후진하는 순간 아바타가 다시 페이드 인되고 붐이 늘어납니다.</p>
<h2 id="다음에-끼워질-것" tabindex="-1">다음에 끼워질 것 <a class="header-anchor" href="#다음에-끼워질-것" aria-label="Permalink to &quot;다음에 끼워질 것&quot;"></a></h2>
<p>지형 콜라이더는 오늘 출시되고, 어려운 절반입니다. 지형은 어디에나 있고 거리 필드는 프로브하기 까다로운 대상이기 때문입니다. 저작 spike에서 나온 소품과 건물 셸은 쉬운 절반이고, 계약은 이미 그들을 기다리고 있습니다. 두 번째 콜라이더인 레이캐스트 콜라이더는 피벗에서 카메라를 향해 메시 목록에 대고 레이를 쏘고, 지형 콜라이더와 똑같은 방식으로 가장 가까운 히트를 보고합니다. 싼 버전은 단일 레이를 쏘는데, 소품 수가 늘기 전까지는 괜찮고, 업그레이드는 그 레이를 three-mesh-bvh를 쓴 휩쓸린 구로 바꾸는 것입니다. Garrett Johnson의 라이브러리로, 메시를 바운딩 볼륨 계층으로 감싸 공간 질의가 무차별 대입 대신 로그 시간에 돌게 합니다. 어느 쪽이든 리그는 바뀌지 않습니다. 더 긴 콜라이더 목록에 질의하고 가장 가까운 히트를 택할 뿐이고, 그것이 계약을 먼저 만들고 콜라이더를 나중에 만든 일의 전체 핵심입니다.</p>
<h2 id="이-챕터에서-참조한-기술" tabindex="-1">이 챕터에서 참조한 기술 <a class="header-anchor" href="#이-챕터에서-참조한-기술" aria-label="Permalink to &quot;이 챕터에서 참조한 기술&quot;"></a></h2>
<p><strong>숫자 하나만 책임지는 붐.</strong> 카메라 리그는 OrbitControls를 대체하는 것이 아니라 그 위의 후처리입니다. 붐의 길이를 책임지고, 요, 피치, 줌, 제스처 처리는 이미 신뢰하던 오빗 컨트롤러에 남깁니다. 통합은 앞뒤로 감싸는 호출 두 개입니다. <code>beforeControls()</code>가 지난 프레임의 온전한 거리를 복원해 오빗 계산이 충돌 짧아짐을 달리인으로 착각하지 않고 사용자의 진짜 줌을 읽게 하고, <code>afterControls(dt)</code>가 충돌을 해결하고 렌더링 위치를 씁니다. 이 한 쌍이 없으면 카메라는 몇 프레임에 걸쳐 플레이어 위로 무너집니다.</p>
<p><strong>플러그인 가능한 콜라이더 계약.</strong> 콜라이더는 &quot;이 레이를 따라 피벗에서 당신이 막기 전까지 카메라가 얼마나 갈 수 있는가&quot;에 답하는 <code>probe</code>를 가진 임의의 객체입니다. 리그는 모든 콜라이더에 질의하고 가장 가까운 히트를 택하며, 장애물이 지형인지 소품인지 벽인지 모릅니다. <a href="/ko/blog/2026-05-15-open-world-browser-part-29-pluggable-character.html">플러그인 가능한 캐릭터 컨트롤러</a>가 이동에 쓴 것과 같은 한 가지만 책임지는 규율입니다. 프로브는 가느다란 레이가 아니라 근평면을 담도록 크기를 맞춘 휩쓸린 구라서, 중심 레이가 놓칠 표면을 절두체 모서리가 절대 클리핑하지 않습니다. 그 반지름은 투영에서 도출됩니다. 근평면 모서리까지의 거리 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.212ex;" xmlns="http://www.w3.org/2000/svg" width="14.705ex" height="2.398ex" role="img" focusable="false" viewBox="0 -966.5 6499.5 1060" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msqrt"><g transform="translate(853,0)"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(633,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1258.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(2259,0)"><g data-mml-node="mi"><path data-c="1D464" d="M580 385Q580 406 599 424T641 443Q659 443 674 425T690 368Q690 339 671 253Q656 197 644 161T609 80T554 12T482 -11Q438 -11 404 5T355 48Q354 47 352 44Q311 -11 252 -11Q226 -11 202 -5T155 14T118 53T104 116Q104 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Q21 293 29 315T52 366T96 418T161 441Q204 441 227 416T250 358Q250 340 217 250T184 111Q184 65 205 46T258 26Q301 26 334 87L339 96V119Q339 122 339 128T340 136T341 143T342 152T345 165T348 182T354 206T362 238T373 281Q402 395 406 404Q419 431 449 431Q468 431 475 421T483 402Q483 389 454 274T422 142Q420 131 420 107V100Q420 85 423 71T442 42T487 26Q558 26 600 148Q609 171 620 213T632 273Q632 306 619 325T593 357T580 385Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(749,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3633.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(4634,0)"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(609,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(0,106.5)"><path data-c="221A" d="M95 178Q89 178 81 186T72 200T103 230T169 280T207 309Q209 311 212 311H213Q219 311 227 294T281 177Q300 134 312 108L397 -77Q398 -77 501 136T707 565T814 786Q820 800 834 800Q841 800 846 794T853 782V776L620 293L385 -193Q381 -200 366 -200Q357 -200 354 -197Q352 -195 256 15L160 225L144 214Q129 202 113 190T95 178Z" style="stroke-width: 3;"/></g><rect width="5646.5" height="60" x="853" y="846.5"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msqrt><msup><mi>n</mi><mn>2</mn></msup><mo>+</mo><msup><mi>w</mi><mn>2</mn></msup><mo>+</mo><msup><mi>h</mi><mn>2</mn></msup></msqrt></math></mjx-assistive-mml></mjx-container>에 안전 여유를 곱한 값이고, 시야각, 종횡비, 근평면이 바뀔 때마다 다시 계산됩니다.</p>
<p><strong>돌출부와 동굴을 존중하는 부호 거리 지형 프로브.</strong> 지형이 하이트맵이 아니라 <a href="/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes.html">부호 거리 필드</a>이기 때문에, 언덕 비탈에서 카메라를 멈추는 같은 프로브가 동굴 천장에서도 카메라를 멈춥니다. 하이트맵 레이캐스트로는 구조적으로 볼 수 없는 경우입니다. 행진은 Hart 방식의 스피어 트레이싱으로, 필드가 보고하는 여유의 과소 완화된 일부만큼 나아가며 양 끝에서 클램프됩니다. 하이트맵 영역은 진짜 거리가 아니라 수직 여유를 보고해서 비탈에서 카메라가 움직일 수 있는 거리를 과대 보고하므로, 한 걸음 통째로는 능선을 뛰어넘기 때문입니다. 그래디언트 기반 침투 해소 패스가 카메라 발밑의 땅이 깎여 나갔을 때 시야를 회복시키는 안전망입니다.</p>
<p><strong>대기 타이머가 딸린 비대칭 댐핑.</strong> 붐은 가림막이 나타나면 빠르게 들어가고, 가림막이 사라지면 천천히, 그것도 연속해서 트인 짧은 구간이 지난 뒤에야 풀려 나옵니다. 그래서 울타리 기둥을 휙 지나가도 카메라가 절대 달려들지 않습니다. 무너짐 임계값 아래에서는 리그가 1인칭에 가깝다는 플래그를 세우고 월드 루프가 로컬 아바타를 숨깁니다. 벽에 파묻힌 카메라 대신 좁은 실내에 쓰는 표준적인 대안입니다.</p>
<h2 id="참고-문헌" tabindex="-1">참고 문헌 <a class="header-anchor" href="#참고-문헌" aria-label="Permalink to &quot;참고 문헌&quot;"></a></h2>
<p>카메라 제어를 가시성 제약으로 바라보는 틀은 Marc Christie와 Patrick Olivier의 <a href="https://people.irisa.fr/Marc.Christie/Publications/2008/CON08.html" target="_blank" rel="noreferrer"><em>Camera Control in Computer Graphics</em></a> (Computer Graphics Forum, 2008)에서 왔습니다. 거리 필드 행진은 John C. Hart의 <a href="https://graphics.stanford.edu/courses/cs348b-20-spring-content/uploads/hart.pdf" target="_blank" rel="noreferrer"><em>Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of Implicit Surfaces</em></a> (The Visual Computer, 1996)입니다. 스프링 암 패턴과 그 프로브 구 충돌은 Epic의 <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/using-spring-arm-components-in-unreal-engine" target="_blank" rel="noreferrer">Spring Arm Component</a>, Unity의 <a href="https://docs.unity3d.com/Packages/com.unity.cinemachine@3.1/manual/CinemachineDeoccluder.html" target="_blank" rel="noreferrer">Cinemachine Deoccluder</a>와 <a href="https://docs.unity3d.com/Packages/com.unity.cinemachine@3.1/manual/CinemachineThirdPersonFollow.html" target="_blank" rel="noreferrer">Third Person Follow</a>에 문서화되어 있습니다. 모션과 댐핑 직관은 Mark Haigh-Hutchinson의 <em>Real-Time Cameras</em> (Morgan Kaufmann, 2009)와 Itay Keren의 <a href="https://www.gamedeveloper.com/design/scroll-back-the-theory-and-practice-of-cameras-in-side-scrollers" target="_blank" rel="noreferrer"><em>Scroll Back: The Theory and Practice of Cameras in Side-Scrollers</em></a> (GDC 2015)에서 왔습니다. 메시 콜라이더 업그레이드 경로는 Garrett Johnson의 <a href="https://github.com/gkjohnson/three-mesh-bvh" target="_blank" rel="noreferrer">three-mesh-bvh</a>입니다.</p>
<hr>
<p>30부 중 30부.
이전 글: <a href="/ko/blog/2026-05-15-open-world-browser-part-29-pluggable-character.html">29부 - 컨트롤러 하나로 어떤 몸이든</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 29부: 컨트롤러 하나로 어떤 몸이든]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-15-open-world-browser-part-29-pluggable-character</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-15-open-world-browser-part-29-pluggable-character</guid>
            <pubDate>Fri, 15 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 58은 물리 엔진이 걷기, 수영, 활공에 대해 아무것도 모르는 캐릭터 컨트롤러를 만듭니다. 모든 동작은 플러그인 형태의 컨트롤러이고, 같은 엔진이 플레이어, 탈 수 있는 말, 자율 NPC를 똑같이 구동하며, 전체가 Node에서 헤드리스로 돌아갑니다. Spike 59는 컨트롤러를 건드리지 않고 리타게팅한 아바타를 올리고, spike 60은 리타게팅이 전혀 필요 없는 Synty 팩을, 유닛 테스트가 가능한 클립 선택기 뒤에 올립니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-29부-컨트롤러-하나로-어떤-몸이든" tabindex="-1">브라우저에서 오픈 월드 만들기, 29부: 컨트롤러 하나로 어떤 몸이든 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-29부-컨트롤러-하나로-어떤-몸이든" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 29부: 컨트롤러 하나로 어떤 몸이든&quot;"></a></h1>
<p><em>글쓴이: <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva의 CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 파트로 연결해 둡니다.</p>
<p><a href="/ko/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion.html">28부</a>에서는 풀과 오클루전을 다뤘습니다. 28개 파트가 안에 서 있을 수 있는 세계를 만들었습니다. 읽어낼 수 있는 지형, 수영할 수 있는 물, 지평선까지 버텨주는 식생, 당신이 바꾼 것을 기억하는 서버. 이번 파트는 그 모든 것을 가로질러 움직이는 그 무언가에 관한 것이고, 엔진 전체의 결실입니다. 목표는 플레이어 컨트롤러가 아니거든요. 자기가 어떤 몸을 구동하는지, 애니메이션이 어디서 왔는지, 운전대를 잡은 게 사람인지 AI인지 신경 쓰지 않는 컨트롤러입니다. Spike 58은 locomotion에 대해 아무것도 모르는 물리 엔진 위에 플러그인 가능한 동작들을 쌓아 올린 형태로 움직임을 만들고, 그런 다음 한 벌의 같은 엔진으로 서로 다른 세 가지 몸을 굴려 이 아키텍처를 증명합니다. Spike 59는 그 컨트롤러를 단 한 줄도 바꾸지 않고 진짜로 리타게팅한 아바타를 올립니다. Spike 60은 리타게팅이 전혀 필요 없는 다른 애니메이션 팩을 올리고, 클립 선택 로직을 끄집어내 실제로 테스트할 수 있는 무언가로 만듭니다.</p>
<h2 id="걷기에-대해-아무것도-모르는-물리-엔진" tabindex="-1">걷기에 대해 아무것도 모르는 물리 엔진 <a class="header-anchor" href="#걷기에-대해-아무것도-모르는-물리-엔진" aria-label="Permalink to &quot;걷기에 대해 아무것도 모르는 물리 엔진&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/58-pluggable-character/" title="Spike 58 Pluggable Character" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/58-pluggable-character/" target="_blank">새 탭에서 Spike 58 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=58-pluggable-character">소스 보기</a></p>
<p>이 설계 규칙은 가혹하고, 그게 핵심 전부입니다. capsule 엔진은 어떤 locomotion도 소유하지 않습니다. 걷기도, 달리기도, 점프도, 마찰도, 최고 속도 상한도 없고, 중력조차 없습니다. kinematic capsule을 지형에 대해 적분하는 것, 그뿐입니다. 모든 locomotion 동작, 즉 걷기, 미끄러지기, 활공, 등반, 수영, 웅크리기, stamina는 엔진에 등록된 자기완결적인 컨트롤러 안에 삽니다. 매 프레임마다 엔진은 모든 컨트롤러를 tick하고, 각각에게 제어권을 원하는지 묻고, 우선순위가 가장 높은 요구자가 velocity를 쓰게 합니다. 걷기에는 특별한 지위가 없습니다. 항상 yes라고 말하는 가장 낮은 우선순위의 컨트롤러일 뿐이라서, 다른 게 아무것도 발동하지 않을 때의 기본값이 됩니다. 컨트롤러는 작은 함수 여섯 개입니다. 활성화되지 않았을 때조차 매 프레임 자기 내부 상태를 갱신하는 <code>tick</code>, 그 프레임을 요구하는 순수한 <code>wantsControl</code> 술어, 승자만 실행하며 velocity를 쓰고 원한다면 자기 몫의 중력을 적용하는 <code>applyForces</code>, 그리고 선택적인 <code>onEnter</code>, <code>onExit</code>, <code>stateName</code>입니다. 수영은 <code>applyForces</code>에서 <code>ownsCollision: true</code>를 반환해 지형 처리를 넘겨받는데, 그렇지 않으면 부력 스프링이 엔진의 발 스냅과 싸우기 때문입니다.</p>
<p>locomotion이 아닌 것들조차 여전히 그 계약을 통해 새어 나오고, 그게 다음 아이디어를 끌어냈습니다. 이 아키텍처가 본전을 뽑게 해주는 부분은 channel입니다. 이전의 단일 channel 설계는 모든 것을 하나의 중재를 거쳐 돌렸는데, 이는 stamina 추적기나 웅크림 자세가 locomotion인 척하고 나서 자기 장부 기록을 돌리려고 <code>wantsControl</code>이 false를 반환하는 꼼수로 제어권을 거절해야 했다는 뜻입니다. 해결책은 컨트롤러를 독립적으로 중재하고 고정된 순서로 적용되는 이름 붙은 channel로 나눕니다. resource 다음 stance 다음 locomotion 순입니다. resource가 먼저 도는 이유는 stamina 감소 같은 그 쓰기를 다른 것들이 읽기 때문입니다. stance가 두 번째로 도는 이유는 웅크림이 capsule 높이를 줄이는 일이, 걷기가 그것을 읽어 최고 속도를 제한하기 전에 자리잡아야 하기 때문입니다. locomotion은 마지막으로 돌고 프레임별 velocity 쓰기를 소유합니다. 그래서 stamina 관찰자와 웅크림 수정자와 활성화된 수영 컨트롤러가 모두 각자 자기 channel 안에서 깔끔하게 공존하고, 어떤 컨트롤러도 자기가 무엇인지에 대해 거짓말할 필요가 없습니다. 데모는 활성 컨트롤러에 따라 색이 바뀌는 헐벗은 capsule로 이 모든 것을 시각화해서, 중재가 일어나는 걸 지켜볼 수 있습니다. 초록색 걷기가 가파른 비탈에서 미끄러지기가 넘겨받으며 주황색으로 바뀌고, 호수에서는 수영이 이기며 청록색으로, 공중에서 활공을 톡 누르면 크림색으로 바뀝니다.</p>
<h2 id="엔진-하나-몸-셋" tabindex="-1">엔진 하나, 몸 셋 <a class="header-anchor" href="#엔진-하나-몸-셋" aria-label="Permalink to &quot;엔진 하나, 몸 셋&quot;"></a></h2>
<p>&quot;locomotion을 소유하지 않는다&quot;의 진짜 시험은 플레이어가 아닙니다. 같은 엔진이, 손대지 않은 채로, 플레이어가 전혀 아닌 무언가를 구동할 수 있느냐입니다. <code>createCapsuleEngine</code>은 모듈 수준 상태도, 싱글톤도, 인스턴스별 부작용도 없는 순수한 factory라서, 이 spike는 그것을 세 번 인스턴스화합니다. 플레이어는 전체 컨트롤러 세트를 가진 한 인스턴스입니다. 탈 수 있는 말은 걷기 컨트롤러만 등록하는 두 번째 인스턴스인데, 이게 그 아이디어를 글자 그대로 구현한 것입니다. 한 몸의 움직임 어휘는 당신이 등록한 컨트롤러들 그 자체일 뿐이라서, 말은 평지에서 더 빠르고 등반, 수영, 활공은 물리적으로 못 합니다. 그 컨트롤러들이 애초에 추가되지 않았기 때문입니다. 자율 NPC는 세 번째 인스턴스로, 플레이어와 나란히 매 프레임 tick되고, 자기 입력을 합성하는 wander 컨트롤러가 구동해서 키보드에 손이 없는데도 몸이 스스로 방향을 잡습니다. 엔진은 자기 몸 중 하나가 말이라거나 다른 하나가 AI 구동이라는 걸 결코 알지 못합니다. 모두 컨트롤러 목록만 다른 똑같은 capsule 적분기입니다.</p>
<p>탑승은 의도적으로 엔진 바깥에 사는 한 조각입니다. 플레이어와 말 사이에 제어권을 바꾸는 건 두 엔진을 조율한다는 뜻이고, 컨트롤러는 한 엔진 안에서 돌며 그 경계 너머를 볼 수 없어서, 탑승 로직은 host 수준에 앉습니다. 이번 프레임에 어느 엔진을 스텝할지 결정하고, 다른 하나는 얼리고, 4분의 3초에 걸친 smoothstep으로 라이더를 안장 위로 부드럽게 올리고, 카메라에 어느 몸을 추적할지 알려주는 작은 상태 기계입니다. 엔진 factory는 이 중 무엇도 듣지 못합니다. 그게 아키텍처가 긋고 지키는 선입니다. 한 몸에 속하는 동작은 컨트롤러이고, 몸 사이의 조율은 host의 일이며, 그것들을 분리해 두는 것이 네 번째나 마흔 번째 몸을 추가해도 새로 드는 비용이 전혀 없는 이유입니다.</p>
<h2 id="브라우저-없이-테스트하기" tabindex="-1">브라우저 없이 테스트하기 <a class="header-anchor" href="#브라우저-없이-테스트하기" aria-label="Permalink to &quot;브라우저 없이 테스트하기&quot;"></a></h2>
<p>엔진은 어떤 <code>window</code>도, <code>document</code>도, Three.js도 손대지 않기 때문에 전체가 헤드리스로 돌아갑니다. 이 spike는 지형 인터페이스를 mock하고, 스크립트로 짠 입력으로 엔진을 프레임 단위로 구동하고, 결과 상태에 대해 단언하는 Node harness를 함께 출하해서, 플레이 테스트로 잡기에는 비참한 회귀들이 대신 스크립트 안에서 잡힙니다. 점프와 착지 전환, 수영 진입과 이탈 임계값, 표면이 평평해질 때 등반 자동 해제, stamina 소모율 같은 것들입니다. 같은 입력과 timestep 시퀀스를 두 번 먹이고 바이트 단위로 동일한 출력 상태를 확인하는 것이 엔진을 결정적인 것으로 못 박는데, 그건 네트워크 빌드가 결국 기대게 될 속성입니다. harness가 잡은 회귀 하나는 간직할 만합니다. 걸을 수 있는 땅에서 걷기보다 가파른 비탈로 올라서면, 예전에는 미끄러지기 컨트롤러가 작동해 플레이어를 언덕 위로 도로 튕겨 올렸습니다. 해결책은 하강 게이트였습니다. capsule이 실제로 비탈 위로 떨어지고 있을 때만 미끄러지기가 시작되도록 해서, 이제는 가파른 면으로 수평으로 걸어 들어가면 미끄러지지 않고 깔끔하게 막히고, &quot;걸을 수 없는 비탈로 걸어 들어가면 플레이어가 막힌다&quot;를 단언하는 테스트가 그걸 고정해 둡니다.</p>
<h2 id="컨트롤러를-건드리지-않고-진짜-아바타-끼워-넣기" tabindex="-1">컨트롤러를 건드리지 않고 진짜 아바타 끼워 넣기 <a class="header-anchor" href="#컨트롤러를-건드리지-않고-진짜-아바타-끼워-넣기" aria-label="Permalink to &quot;컨트롤러를 건드리지 않고 진짜 아바타 끼워 넣기&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/59-pluggable-with-avatar/" title="Spike 59 Pluggable With Avatar" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/59-pluggable-with-avatar/" target="_blank">새 탭에서 Spike 59 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=59-pluggable-with-avatar">소스 보기</a></p>
<p>Spike 59는 컨트롤러 층이 정말로 몸과 분리되어 있는지에 대한 시험입니다. 색칠된 capsule을 진짜 스킨드 캐릭터로, 즉 Quaternius Universal Animation Library 클립을 리타게팅해 올린 3MIKE FBX rig로 바꾸는데, 컨트롤러는 전혀 바뀌지 않습니다. 이음매는 문자열 하나입니다. 각 컨트롤러는 이미 <code>stateName</code>을 통해 상태 이름을 보고합니다. idle, walk, run, jump, fall, land, slide, glide, swim, swimIdle이고, 아바타 층은 그 이름을 별칭 테이블을 통해 리타게팅한 클립으로 매핑하고 전환할 때 crossfade합니다. 걷기는 접지 더하기 수직 velocity 더하기 수평 속도로부터 자기 하위 상태를 동적으로 고르기 때문에, 단일 걷기 컨트롤러가 idle, walk, run, jump, fall, land를 구동하고, 아바타는 그저 보고된 이름을 따라갑니다. 이 spike는 싱글 플레이어라서, 아바타는 이전 네트워크 spike들의 wire-integer 간접 참조와 다중 캐릭터 추상을 떼어내고 상태 이름을 곧장 클립으로 매핑합니다. 증명은 capsule에서 rig를 가진 사람으로의 시각적 업그레이드 전체가 locomotion 코드를 0줄 건드렸다는 것이고, 그게 바로 플러그인 가능한 컨트롤러가 사주기로 한 것입니다.</p>
<h2 id="리타게팅이-필요-없는-팩-그리고-테스트할-수-있는-선택기" tabindex="-1">리타게팅이 필요 없는 팩, 그리고 테스트할 수 있는 선택기 <a class="header-anchor" href="#리타게팅이-필요-없는-팩-그리고-테스트할-수-있는-선택기" aria-label="Permalink to &quot;리타게팅이 필요 없는 팩, 그리고 테스트할 수 있는 선택기&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/60-polygon-animations/" title="Spike 60 Polygon Animations" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/60-polygon-animations/" target="_blank">새 탭에서 Spike 60 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=60-polygon-animations">소스 보기</a></p>
<p>Spike 60은 세 번째 몸, Synty의 POLYGON Base Locomotion 팩을 끼워 넣는데, 로더는 거의 아무것도 아닙니다. 각 클립은 같은 Synty 스켈레톤의 내장 복사본 하나에 더해 베이크된 애니메이션 하나를 실은 독립 FBX로 출하되고, 캐릭터 rig와 모든 클립이 동일한 뼈 이름을 쓰기 때문에 <code>fbx.animations[0]</code>에서 클립을 집어 캐릭터의 mixer에서 바로 재생합니다. 루프 안에 리타게팅 라이브러리가 전혀 없습니다. Three.js는 애니메이션 track의 대상을 객체 정체성이 아니라 뼈 이름으로 해석하기 때문에, 맞는 rig에 맞춰 제작된 Synty나 Mixamo 스타일의 팩은 그냥 동작합니다. 그게 이전 spike의 UAL 경로와의 의도적인 대비인데, 그 경로는 소스 클립과 대상 rig가 서로 다른 스켈레톤에 맞춰 제작되었기 때문에 무거운 리타게팅이 필요합니다. 같은 컨트롤러, 같은 상태 이름 이음매, 그 뒤에 완전히 다른 두 애니메이션 파이프라인.</p>
<p>Spike 60의 다른 절반은 클립 선택 로직을 테스트 가능하게 만드는 것입니다. 어느 클립을 재생할지 고르는 일은 판단 임계값으로 가득하고, 그 로직은 아바타 층 안 FBXLoader와 DOM 옆에 묻혀 있어서 거기서는 굴려볼 수가 없었습니다. 이 spike는 선택기를 Three.js도 window도 손대지 않는 순수 함수로 추출합니다. 평범한 플레이어 레코드(velocity, 수평 속도, 향하는 방향, 접지, 지면 법선, 충격 velocity)와 clip-action 대역을 받아 클립 별칭 문자열을 반환합니다. 그러면 임계값들이 이름 붙고 단언된 상수로 살 수 있습니다. 점프는 걷기 컨트롤러의 실제 스프린트 임계값에 맞춘 속도 버킷으로 걷기, 달리기, 스프린트 변형으로 나뉘고, 착지는 충격 velocity로 부드러움, 중간, 강함으로 나뉘고, 오르막과 내리막 클립 변형은 약 7도 아래에 평평한 클립 데드존을 둔 비탈 투영 내적으로 발동하고, idle에서 locomotion으로 가는 다리는 항상 앞쪽으로 해석되어 멈춰 서서 출발할 때 클립을 거꾸로 재생하는 일이 결코 없으며, 멈춤 다리는 최소 루프 내 시간으로 게이트됩니다. Synty의 발 위상 멈춤 클립이 제작된 감속을 약 1초 담고 있어서, 플레이어가 거의 떼지 않은 걸음에 붙이면 우스워 보이기 때문입니다. 작은 상태 디바운서가 fall 상태를 몇 프레임 미뤄서, 이음매를 가로지를 때 한 프레임 지면 접촉이 끊겨도 애니메이션이 깜빡이지 않습니다. 이 모든 것을 렌더링 껍데기에서 빼낸다는 건 규칙을 GPU 없이 유닛 테스트할 수 있다는 뜻이고, spike 58에서 엔진 자체가 받은 것과 같은 헤드리스 규율이며, 이것이 짐작으로 조율하는 locomotion 감각과 못 박을 수 있는 locomotion 감각 사이의 차이입니다.</p>
<h2 id="이-챕터에서-언급한-기술" tabindex="-1">이 챕터에서 언급한 기술 <a class="header-anchor" href="#이-챕터에서-언급한-기술" aria-label="Permalink to &quot;이 챕터에서 언급한 기술&quot;"></a></h2>
<p><strong>locomotion 없는 물리 엔진.</strong> capsule 엔진은 kinematic 몸을 지형에 대해 적분하고, 걷기, 달리기, 점프, 마찰, 속도 상한, 중력을 소유하지 않습니다. 모든 동작은 <code>tick</code>, <code>wantsControl</code>, <code>applyForces</code>와 선택적인 <code>onEnter</code>/<code>onExit</code>/<code>stateName</code>을 노출하는 등록된 컨트롤러입니다. 걷기는 가장 낮은 우선순위의 항상 yes 기본값일 뿐이고, 컨트롤러는 <code>ownsCollision: true</code>를 반환해 지형 처리를 넘겨받을 수 있습니다(수영이 그렇게 해서 부력 스프링이 발 스냅과 싸우지 않습니다).</p>
<p><strong>독립적인 중재 channel.</strong> 컨트롤러는 따로 중재하고 고정된 순서로 적용되는 이름 붙은 channel(resource, stance, locomotion)에 등록되어서, stamina 같은 관찰자와 웅크림 같은 수정자가 제어를 흉내 냈다가 거절하는 대신 활성 locomotion과 공존합니다. resource 쓰기(stamina)는 stance와 locomotion이 읽고, stance 쓰기(웅크림 capsule 높이)는 locomotion의 속도 상한이 읽고, locomotion은 마지막으로 돌며 velocity 쓰기를 소유합니다.</p>
<p><strong>factory 하나, 몸 여럿.</strong> <code>createCapsuleEngine</code>은 싱글톤 없는 순수 factory라서, 같은 엔진이 플레이어, 걷기만 하는 탈 수 있는 말, 합성 입력을 먹는 스스로 방향 잡는 NPC를 구동합니다. 한 몸의 움직임 어휘는 정확히 그 등록된 컨트롤러 세트라서, 말은 그 컨트롤러들이 애초에 추가되지 않았기 때문에 등반이나 수영을 못 합니다. 탑승은 컨트롤러가 아니라 host 수준에 사는데, 서로를 가로질러 볼 수 없는 두 엔진을 조율하기 때문입니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">GPU 구동 LOD</a>를 보세요.</p>
<p><strong>헤드리스, 결정적 테스트.</strong> 엔진은 어떤 <code>window</code>, <code>document</code>, Three.js도 손대지 않아서, Node harness가 프레임 단위로 그것을 구동하고 점프와 착지, 수영 임계값, 등반 자동 해제, stamina 소모에 대해 단언합니다. 동일한 입력을 두 번 재생하고 동일한 출력을 확인하는 것이 결정성을 증명하고, 회귀 테스트가 가파른 면으로의 수평 걷기가 플레이어를 뒤로 미끄러뜨리는 걸 막는 하강 게이트를 고정합니다.</p>
<p><strong>몸과 무관한 아바타 바인딩과 테스트 가능한 선택기.</strong> 컨트롤러는 상태 이름 문자열을 보고하고 시각 층이 그것을 클립으로 매핑해서, capsule을 리타게팅한 3MIKE + UAL 아바타로 바꿔도 locomotion 코드를 0줄 건드립니다. Synty POLYGON 클립은 rig와 뼈 이름을 공유해서 리타게팅 없이 재생되고(Three.js가 track을 뼈 이름으로 바인딩합니다), UAL 경로의 무거운 리타게팅과 다릅니다. 클립 선택기는 점프 속도 버킷, 착지 강도, 비탈 투영 변형, 항상 앞쪽인 idle 다리, 멈춤 다리 최소 시간 가드, fall 상태 디바운서를 위한 이름 붙은 상수와 함께 순수 함수로 추출되어서, locomotion 감각이 짐작이 아니라 유닛 테스트 가능합니다.</p>
<hr>
<p>29부 / 30부.
이전: <a href="/ko/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion.html">28부 - 지평선까지의 풀, 그리고 스스로를 숨기는 땅</a>
다음: <a href="/ko/blog/2026-06-04-open-world-browser-part-30-collision-aware-camera.html">30부 - 벽을 존중하는 카메라</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 28부: 지평선까지 이어지는 풀, 그리고 스스로를 가리는 지면]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion</guid>
            <pubDate>Thu, 14 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 56은 컴퓨트 커널 하나와 교차 quad 트릭으로 50만 개의 풀 덩어리를 초록색 색종이 조각이 아니라 하나의 들판처럼 보이게 만든다. Spike 57은 언덕이 무엇을 가리고 있는지 컬링하는 네 가지 방법을 벤치마킹하고, 가속된 경로가 곧 기하학적으로 올바른 경로이기도 하다는 것을 발견한다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-28부-지평선까지-이어지는-풀-그리고-스스로를-가리는-지면" tabindex="-1">브라우저에서 오픈 월드 만들기, 28부: 지평선까지 이어지는 풀, 그리고 스스로를 가리는 지면 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-28부-지평선까지-이어지는-풀-그리고-스스로를-가리는-지면" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 28부: 지평선까지 이어지는 풀, 그리고 스스로를 가리는 지면&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva의 CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-13-open-world-browser-part-27-island-and-terrain.html">27부</a>에서는 섬을 만들고 타일처럼 보이지 않는 지면을 입혔습니다. 이번 부분은 지형을 텅 빈 곳이 아니라 사람이 사는 곳처럼 느끼게 만드는 두 가지를 다룹니다. Spike 56은 풀, 즉 텍스처가 입혀진 비탈을 걸어 다니고 싶은 장소로 바꿔주는 표면 디테일이고, 여기서의 문제는 한 들판이 흩어진 줄무늬가 아니라 들판으로 읽히게 만드는 것입니다. Spike 57은 더 많이 그리는 것의 반대입니다. 언덕이 이미 가리고 있는 것을 그리지 않는 일이고, 흥미로운 결과는 그것을 검사하는 빠른 방법이 알고 보니 올바른 방법이기도 했다는 점입니다.</p>
<h2 id="색종이-조각이-아니라-들판으로-읽히는-풀" tabindex="-1">색종이 조각이 아니라 들판으로 읽히는 풀 <a class="header-anchor" href="#색종이-조각이-아니라-들판으로-읽히는-풀" aria-label="Permalink to &quot;색종이 조각이 아니라 들판으로 읽히는 풀&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/56-grass/" title="Spike 56 Grass" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/56-grass/" target="_blank">새 탭에서 Spike 56 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=56-grass">소스 보기</a></p>
<p>핵심 결정은 기하학적입니다. 가늘고 끝이 좁아지는 풀잎 하나는 대부분의 카메라 각도에서 서브 픽셀이라, 50만 개의 납작한 풀잎은 들판이 아니라 듬성듬성한 초록색 색종이 조각으로 읽힙니다. 해결책은 교차 quad 덩어리입니다. 끝이 좁아지는 quad 세 개를 로컬 업 축을 기준으로 서로 60도씩 회전시켜 두면, 어느 시점 방향에서 보든 적어도 하나의 quad가 카메라에 거의 수직으로 서고 각 instance가 실제 화면 면적으로 대략 풀잎 세 개 너비를 덮습니다. 이것이 초록색 줄무늬가 보이느냐 풀이 보이느냐의 차이입니다.</p>
<p>WebGPU 컴퓨트 커널이 init 시점에 모든 덩어리를 한 번씩 배치합니다. instance 인덱스를 다섯 개의 비상관 랜덤 스트림으로 해싱하고, 패치 안에서 XZ 위치를 고르고, CPU 지면 mesh가 쓰는 것과 같은 FBM에서 지면 높이를 샘플링하고(부호를 보존하는 mod를 쓴 TSL 포팅이라 값이 정확히 일치하고, 풀잎이 위에 떠 있지 않고 표면에 앉습니다), 중심 차분 법선을 취하고, 덩어리별 너비, 높이, 색조를 굴려서 정합니다. 렌더 쪽은 instance 행렬을 완전히 우회해 곧장 클립 공간에 쓰는 TSL 정점 그래프입니다. 단위 교차 quad의 크기를 조절하고, Rodrigues 공식으로 로컬 업을 지면 법선 위로 회전시키고, 덩어리 위치로 평행 이동합니다. 거리 LOD는 컬링 패스 없이 공짜로 따라옵니다. 정점 그래프가 덩어리의 높이에 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="38.925ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 17204.8 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(1722.4,0)"><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" style="stroke-width: 3;"/><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(394,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(1227,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(1727,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(2227,0)" style="stroke-width: 3;"/><path data-c="68" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 124T102 167T103 217T103 272T103 329Q103 366 103 407T103 482T102 542T102 586T102 603Q99 622 88 628T43 637H25V660Q25 683 27 683L37 684Q47 685 66 686T103 688Q120 689 140 690T170 693T181 694H184V367Q244 442 328 442Q451 442 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2616,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(3172,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(3566,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(3955,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(4399,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6677.4,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(7066.4,0)"><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(306,0)" style="stroke-width: 3;"/><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(806,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1362,0)" style="stroke-width: 3;"/><path data-c="4E" d="M42 46Q74 48 94 56T118 69T128 86V634H124Q114 637 52 637H25V683H232L235 680Q237 679 322 554T493 303L578 178V598Q572 608 568 613T544 627T492 637H475V683H483Q498 680 600 680Q706 680 715 683H724V637H707Q634 633 622 598L621 302V6L614 0H600Q585 0 582 3T481 150T282 443T171 605V345L172 86Q183 50 257 46H274V0H265Q250 3 150 3Q48 3 33 0H25V46H42Z" transform="translate(1806,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2556,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(3000,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(3500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(10958.4,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(11403.1,0)"><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(306,0)" style="stroke-width: 3;"/><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(806,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1362,0)" style="stroke-width: 3;"/><path data-c="46" d="M128 619Q121 626 117 628T101 631T58 634H25V680H582V676Q584 670 596 560T610 444V440H570V444Q563 493 561 501Q555 538 543 563T516 601T477 622T431 631T374 633H334H286Q252 633 244 631T233 621Q232 619 232 490V363H284Q287 363 303 363T327 364T349 367T372 373T389 385Q407 403 410 459V480H450V200H410V221Q407 276 389 296Q381 303 371 307T348 313T327 316T303 317T284 317H232V189L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" transform="translate(1806,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(2459,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(2959,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(14754.1,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(15198.8,0)"><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(834,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1228,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(16815.8,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn><mo>−</mo><mtext>smoothstep</mtext><mo stretchy="false">(</mo><mtext>fadeNear</mtext><mo>,</mo><mtext>fadeFar</mtext><mo>,</mo><mtext>dist</mtext><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>를 곱하기 때문에, 먼 덩어리는 높이가 0으로 납작하게 무너져 더 이상 fill 비용을 쓰지 않습니다. 바람은 덩어리의 월드 XZ에 시간을 더한 값에 대한 sin과 cos의 두 옥타브로, 수평으로 적용되고 높이 분수로 게이팅되어 밑동은 고정된 채 끝만 움직입니다. 그리고 작은 카메라 인식 기울기가 각 덩어리를 보는 사람 쪽으로 기울여 줘서, 납작한 카드처럼 읽히는 대신 원근감 있게 펼쳐집니다.</p>
<p>색상 레시피는 NedMakesGames의 Breath of the Wild URP 셰이더에서 빌려 왔습니다. 플랫 셰이딩에, 풀잎 색은 높이 분수를 따라 뿌리 톤에서 끝 톤으로 lerp 하고, 그 뿌리 톤과 끝 톤 자체는 덩어리별 색조 값에 따라 두 팔레트 사이에서 lerp 됩니다. 이것이 진짜 BotW 풀밭이 가진 얼룩덜룩한 투톤 룩을 만들어 냅니다. Diffuse는 지면 법선을 태양에 대고 환경광 바닥을 더해 씁니다. 교차 quad의 quad별 법선은 양식화된 룩으로 개별 셰이딩하기에는 너무 노이즈가 많기 때문입니다. 전체 들판은 한 번의 draw이고, 배치와 애니메이션 모두 GPU에서 이뤄집니다.</p>
<h2 id="언덕이-가리고-있는-것을-컬링하는-네-가지-방법" tabindex="-1">언덕이 가리고 있는 것을 컬링하는 네 가지 방법 <a class="header-anchor" href="#언덕이-가리고-있는-것을-컬링하는-네-가지-방법" aria-label="Permalink to &quot;언덕이 가리고 있는 것을 컬링하는 네 가지 방법&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/57-terrain-occlusion/" title="Spike 57 Terrain Occlusion" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/57-terrain-occlusion/" target="_blank">새 탭에서 Spike 57 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=57-terrain-occlusion">소스 보기</a></p>
<p>Spike 57은 프로덕션 클라이언트가 스트리밍하는 것과 같은 절차적 월드에서 네 가지 컬링 경로를 벤치마킹하는데, 언덕이 실제로 식생을 가리도록 수직으로 1.8배 스케일을 키웠습니다. T0은 거리 전용으로, 출시된 chunk 가시성이 이미 하고 있는 것과 같습니다. T1은 frustum 컬링을 더합니다. 가장 큰 단일 저비용 이득으로, 시야 원뿔 밖의 모든 것을 떨궈냅니다. T2는 지형 인식 지평선 검사를 더합니다. 눈에서 각 instance로 광선을 march 시켜, 경로 어디에서든 높이맵이 광선 위로 솟으면 그 instance를 기각합니다. 그래서 능선 뒤의 나무는 frustum 안에 있더라도 컬링됩니다. T3은 같은 지평선 검사를 유지하되 최대 높이 피라미드로 가속하고, T4는 거리에 frustum에 지평선까지 더한 검사 전체를 TSL 컴퓨트 커널로 포팅합니다. 이 커널은 instance별 가시성 스케일을 쓰고, 식생 머티리얼이 그것을 읽어 가려진 정점을 무너뜨립니다. 두 프레임 동안 보이는 상태를 유지하는 카운터가 단일 프레임 깜빡임을 부드럽게 다듬는데, 이는 카메라가 살짝 움직일 때 샘플 지점이 어떤 texel의 안이나 밖에 아슬아슬하게 떨어질 때 생기는 것입니다. 일부러 짧게 유지하는데, 더 길게 잡으면 알고리즘 버그를 고치는 게 아니라 가려버리기 때문입니다.</p>
<p>피라미드는 이 spike가 제 값을 하는 부분이고, 교훈은 검사를 실제로 화면에 있는 것에 맞추는 일에 관한 것입니다. 렌더링되는 지형은 정점이 고정된 2미터 격자 위에 있는 삼각형 mesh이고, 정점 사이에서 래스터라이저가 선형 보간을 하므로, 어느 사각형 안에서든 실제 렌더링되는 높이는 그 안에 있는 정점들의 최댓값이지 그것들 사이의 연속 노이즈 봉우리가 결코 아닙니다. 만약 오클루전 피라미드가 더 촘촘한 격자에서 노이즈를 샘플링하면, mesh가 절대 표시하지 않는 유령 봉우리를 찾아내 카메라가 빤히 꿰뚫어 볼 수 있는 광선을 막기 시작합니다. 그래서 피라미드의 베이스 texel은 정확히 정점 격자 위에 앉아 각각 자기 네 모서리 정점의 최댓값을 저장하고, 상위 레벨은 교과서적인 2x2 최댓값 리덕션이라, 렌더링되는 mesh에 대해 정확해집니다. 단계별 광선 검사에서는 코드가 일부러 피라미드를 질의하는 대신 양선형 보간으로 mesh를 점 샘플링합니다. 서브 texel AABB 질의는 texel 전체의 최댓값을 반환해 가파른 능선에서 높이를 몇 미터씩 부풀리는데, 그것이 바로 보이는 prop을 가려버릴 과도한 오클루전이기 때문입니다.</p>
<p>놀라운 결과는 무차별 대입 기준점인 T2가 틀린 쪽이라는 것입니다. T2는 연속 노이즈를 직접 점 샘플링하기 때문에 렌더링되지 않는 mesh 정점 사이의 봉우리를 잡아내고, 그래서 약간 과도하게 가려서 플레이어가 실제로 볼 수 있는 식생을 숨깁니다. 피라미드 경로는 더 빠르고(chunk 수준 검사에 대해 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="8.764ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 3873.7 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D442" d="M740 435Q740 320 676 213T511 42T304 -22Q207 -22 138 35T51 201Q50 209 50 244Q50 346 98 438T227 601Q351 704 476 704Q514 704 524 703Q621 689 680 617T740 435ZM637 476Q637 565 591 615T476 665Q396 665 322 605Q242 542 200 428T157 216Q157 126 200 73T314 19Q404 19 485 98T608 313Q637 408 637 476Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(763,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1152,0)"><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(278,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(778,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2430,0)"><path data-c="2061" d="" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2596.7,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3484.7,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>O</mi><mo stretchy="false">(</mo><mi>log</mi><mo data-mjx-texclass="NONE">⁡</mo><mi>N</mi><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>의 AABB 리덕션 덕분), 동시에 기하학적으로 더 올바릅니다(mesh가 진짜로 표시하는 높이만 반환할 수 있기 때문). 그것이 이 spike의 요점 전부입니다. 가속 구조는 속도를 위해 받아들이는 품질 타협이 아니라, 현실과 일치하는 버전입니다. Chunk 컬링은 chunk마다 5점 검사를 돌리고(꼭대기 네 모서리에 chunk의 최대 높이에서의 중심을 더함) 각 chunk 자신의 풋프린트를 오클루더 집합에서 제외해 chunk가 자기 자신을 가리는 일이 없게 합니다. 권장하는 프로덕션 경로는 T4입니다. instance 메타데이터와 높이 필드를 storage buffer로 밀어 넣고 동일한 루프를 컴퓨트 셰이더에서 indirect draw로 돌리면 됩니다. 어차피 렌더러가 WebGPU로 옮겨가는 중이니까요.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>교차 quad GPU 풀.</strong> 덩어리마다 끝이 좁아지는 quad 세 개를 서로 60도씩 회전시키면 어느 각도에서든 거의 수직인 quad 하나가 보장되어, 50만 개의 instance가 서브 픽셀 색종이 조각이 아니라 들판으로 읽힙니다. 컴퓨트 커널이 모든 덩어리를 배치하고(CPU mesh와 같은 부호 보존 mod로 샘플링한 FBM 지면 높이, 중심 차분 법선, 덩어리별 크기와 색조), TSL 정점 그래프가 instance 행렬을 우회해 크기를 조절하고, Rodrigues 회전으로 법선 위에 올리고, 평행 이동하고, 높이 게이팅된 바람을 적용합니다. 거리 LOD는 공짜입니다. 덩어리는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="38.925ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 17204.8 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(1722.4,0)"><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" style="stroke-width: 3;"/><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(394,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(1227,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(1727,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(2227,0)" style="stroke-width: 3;"/><path data-c="68" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 124T102 167T103 217T103 272T103 329Q103 366 103 407T103 482T102 542T102 586T102 603Q99 622 88 628T43 637H25V660Q25 683 27 683L37 684Q47 685 66 686T103 688Q120 689 140 690T170 693T181 694H184V367Q244 442 328 442Q451 442 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2616,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(3172,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(3566,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(3955,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(4399,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6677.4,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(7066.4,0)"><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(306,0)" style="stroke-width: 3;"/><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(806,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1362,0)" style="stroke-width: 3;"/><path data-c="4E" d="M42 46Q74 48 94 56T118 69T128 86V634H124Q114 637 52 637H25V683H232L235 680Q237 679 322 554T493 303L578 178V598Q572 608 568 613T544 627T492 637H475V683H483Q498 680 600 680Q706 680 715 683H724V637H707Q634 633 622 598L621 302V6L614 0H600Q585 0 582 3T481 150T282 443T171 605V345L172 86Q183 50 257 46H274V0H265Q250 3 150 3Q48 3 33 0H25V46H42Z" transform="translate(1806,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2556,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(3000,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(3500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(10958.4,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(11403.1,0)"><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(306,0)" style="stroke-width: 3;"/><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(806,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1362,0)" style="stroke-width: 3;"/><path data-c="46" d="M128 619Q121 626 117 628T101 631T58 634H25V680H582V676Q584 670 596 560T610 444V440H570V444Q563 493 561 501Q555 538 543 563T516 601T477 622T431 631T374 633H334H286Q252 633 244 631T233 621Q232 619 232 490V363H284Q287 363 303 363T327 364T349 367T372 373T389 385Q407 403 410 459V480H450V200H410V221Q407 276 389 296Q381 303 371 307T348 313T327 316T303 317T284 317H232V189L233 61Q240 54 245 52T270 48T333 46H360V0H348Q324 3 182 3Q51 3 36 0H25V46H58Q100 47 109 49T128 61V619Z" transform="translate(1806,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(2459,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(2959,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(14754.1,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(15198.8,0)"><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(834,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1228,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(16815.8,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn><mo>−</mo><mtext>smoothstep</mtext><mo stretchy="false">(</mo><mtext>fadeNear</mtext><mo>,</mo><mtext>fadeFar</mtext><mo>,</mo><mtext>dist</mtext><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>에 따라 높이 0으로 무너집니다. 색상은 NedMakesGames의 BotW 레시피를 따라, 색조를 섞은 두 팔레트 위에 뿌리에서 끝으로 가는 그라데이션을 깝니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">GPU 주도 LOD</a>를 보세요.</p>
<p><strong>지형 지평선 오클루전 컬링.</strong> 프로덕션 월드에서 벤치마킹한 네 가지 경로: 거리, 거기에 frustum, 거기에 능선 뒤의 instance를 기각하는 높이맵 광선 검사, 거기에 그것을 가속하는 최대 높이 피라미드, 거기에 TSL 컴퓨트 포팅. 피라미드는 mesh가 테셀레이션하는 바로 그 2미터 정점 격자 위에서 샘플링하므로(베이스 texel = 네 모서리 정점의 최댓값, 위로 2x2 최대 리덕션), 래스터라이저가 실제로 표시하는 높이만 반환합니다.</p>
<p><strong>가속되고 올바름, 타협이 아님.</strong> 연속 노이즈를 점 샘플링하면(무차별 대입 T2 경로) 절대 렌더링되지 않는 mesh 정점 사이의 봉우리를 찾아내 보이는 식생을 과도하게 가립니다. 정점 격자 피라미드는 더 빠르고(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="8.764ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 3873.7 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D442" d="M740 435Q740 320 676 213T511 42T304 -22Q207 -22 138 35T51 201Q50 209 50 244Q50 346 98 438T227 601Q351 704 476 704Q514 704 524 703Q621 689 680 617T740 435ZM637 476Q637 565 591 615T476 665Q396 665 322 605Q242 542 200 428T157 216Q157 126 200 73T314 19Q404 19 485 98T608 313Q637 408 637 476Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(763,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1152,0)"><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(278,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(778,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2430,0)"><path data-c="2061" d="" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2596.7,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3484.7,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>O</mi><mo stretchy="false">(</mo><mi>log</mi><mo data-mjx-texclass="NONE">⁡</mo><mi>N</mi><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container> AABB 리덕션) 기하학적으로 정확해서, 단계별 광선 검사는 피라미드의 texel별 최댓값을 질의하는 대신 mesh를 양선형 샘플링합니다. 후자는 가파른 능선에서 높이를 몇 미터씩 부풀릴 테니까요. Chunk 컬링은 5점 검사를 쓰고 각 chunk 자신의 풋프린트를 제외해 절대 자기 자신을 가리지 않습니다. 프로덕션 경로는 메타데이터와 높이 필드를 storage buffer로 밀어 넣어 indirect draw로 컴퓨트 셰이더 컬을 돌립니다.</p>
<hr>
<p>29부 중 28부.
이전: <a href="/ko/blog/2026-05-13-open-world-browser-part-27-island-and-terrain.html">27부 - 노이즈로 만든 섬, 지면처럼 보이는 지면</a>
다음: <a href="/ko/blog/2026-05-15-open-world-browser-part-29-pluggable-character.html">29부 - 컨트롤러 하나로 어떤 몸이든</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 27부: 노이즈로 만든 섬, 땅처럼 보이는 땅]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-13-open-world-browser-part-27-island-and-terrain</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-13-open-world-browser-part-27-island-and-terrain</guid>
            <pubDate>Wed, 13 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 54는 노이즈만으로 그럴듯한 섬을 키워냅니다. 방사형 감쇠로 형태를 잡은 도메인 워프 FBM, 그다음 실제 배수로를 깎아내는 수력 침식, 그다음 고도와 습도로 배정한 생물군계. Spike 55는 가장 오래된 텍스처 문제, 곧 반복되는 타일을 네 가지 샘플링 모드로 해결하고, 그중 실제로 이기는 하나를 보여줍니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-27부-노이즈로-만든-섬-땅처럼-보이는-땅" tabindex="-1">브라우저에서 오픈 월드 만들기, 27부: 노이즈로 만든 섬, 땅처럼 보이는 땅 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-27부-노이즈로-만든-섬-땅처럼-보이는-땅" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 27부: 노이즈로 만든 섬, 땅처럼 보이는 땅&quot;"></a></h1>
<p><em>글: <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-12-open-world-browser-part-26-water.html">26부</a>는 세계에 물을 올렸습니다. 이번 부분은 그 아래의 땅을 만듭니다. 실제 장소가 만들어지는 과정을 그대로 따라가는 두 단계로요. Spike 54는 지형 그 자체입니다. 손으로 조각한 게 아니라 노이즈에서 키워낸 뒤, 물이 실제로 흘러간 곳이 가질 법한 배수로와 해안선을 가질 때까지 풍화시킨 것이죠. Spike 55는 그 지형 위에 입히는 피부입니다. 거의 모든 절차적 지면을 무너뜨리는 문제, 곧 타일 텍스처가 타일처럼 보인다는 문제를 해결합니다. 둘을 합치면 하나의 질문에 답하게 됩니다. 창작자가 아티스트의 손을 전혀 거치지 않고도 그럴듯한 섬과 땅처럼 읽히는 땅을 얻을 수 있는가, 그리고 답은 올바른 레시피를 베끼면 그렇다 입니다.</p>
<h2 id="노이즈만으로는-얻을-수-없는-해안선" tabindex="-1">노이즈만으로는 얻을 수 없는 해안선 <a class="header-anchor" href="#노이즈만으로는-얻을-수-없는-해안선" aria-label="Permalink to &quot;노이즈만으로는 얻을 수 없는 해안선&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/54-procgen-island/" title="Spike 54 Procedural Island" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/54-procgen-island/" target="_blank">Spike 54를 새 탭에서 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=54-procgen-island">소스 보기</a></p>
<p>높이맵은 Red Blob Games 레시피를 따릅니다. 이건 작은 변환들을 쌓은 것으로, 각각이 원시 노이즈의 특정 결함 하나를 고칩니다. 프랙탈 브라운 운동은 Perlin 노이즈의 여러 옥타브를 더해서 지형이 넓은 언덕과 미세한 디테일을 둘 다 가지게 합니다. 하지만 순수 FBM은 흐물흐물하고 그리드에 정렬된 것처럼 보이기 때문에 샘플 지점을 먼저 도메인 워프합니다. 각 좌표를 다른 노이즈 필드로 옵셋하는 것이죠. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="19.194ex" height="2.283ex" role="img" focusable="false" viewBox="0 -759 8483.9 1009" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(536,363) scale(0.707)"><path data-c="2032" d="M79 43Q73 43 52 49T30 61Q30 68 85 293T146 528Q161 560 198 560Q218 560 240 545T262 501Q262 496 260 486Q259 479 173 263T84 45T79 43Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1058.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2114,0)"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2839.2,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(3839.5,0)"><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(1056,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(1334,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1728,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6011.5,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(6400.5,0)"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6903.5,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(7514.7,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(8014.9,0)"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>p</mi><mo data-mjx-alternate="1">′</mo></msup><mo>=</mo><mi>p</mi><mo>+</mo><mtext>noise</mtext><mo stretchy="false">(</mo><mi>p</mi><mo stretchy="false">)</mo><mo>⋅</mo><mi>s</mi></math></mjx-assistive-mml></mjx-container>. 이렇게 하면 능선이 축에 갇히는 대신 유기적인 무언가로 휘어집니다. 그다음 재분배는 고도를 거듭제곱 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="2.453ex" height="1.956ex" role="img" focusable="false" viewBox="0 -853.7 1084.4 864.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mstyle" transform="scale(1.414)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(236.2,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>e</mi><mrow data-mjx-texclass="ORD"><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mi>k</mi></mrow></msup></math></mjx-assistive-mml></mjx-container>로 올려서 중간 톤을 아래로 밀어냅니다. 그러면 세계는 모든 것이 똑같이 완만한 경사에 놓이는 대신 평평한 계곡과 날카로운 봉우리를 가지게 됩니다. 이것을 무한한 언덕이 아니라 섬으로 만드는 조각은 방사형 감쇠입니다. 중심으로부터의 유클리드 거리를 계산하고, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -1.467ex;" xmlns="http://www.w3.org/2000/svg" width="21.741ex" height="4.208ex" role="img" focusable="false" viewBox="0 -1211.5 9609.7 1860" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(797.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1853.6,0)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1111,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3520.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3909.6,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4409.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="msqrt" transform="translate(4854.2,0)"><g transform="translate(1020,0)"><g data-mml-node="msubsup"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(633,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(633,-247) scale(0.707)"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1309.7,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msubsup" transform="translate(2309.9,0)"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(633,289) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(633,-247) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(0,1.5)"><path data-c="221A" d="M1001 1150Q1017 1150 1020 1132Q1020 1127 741 244L460 -643Q453 -650 436 -650H424Q423 -647 423 -645T421 -640T419 -631T415 -617T408 -594T399 -560T385 -512T367 -448T343 -364T312 -259L203 119L138 41L111 67L212 188L264 248L472 -474L983 1140Q988 1150 1001 1150Z" style="stroke-width: 3;"/></g><rect width="3346.5" height="60" x="1020" y="1091.5"/></g><g data-mml-node="mo" transform="translate(9220.7,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>d</mi><mo>=</mo><mo data-mjx-texclass="OP" movablelimits="true">min</mo><mo stretchy="false">(</mo><mn>1</mn><mo>,</mo><msqrt><msubsup><mi>n</mi><mi>x</mi><mn>2</mn></msubsup><mo>+</mo><msubsup><mi>n</mi><mi>y</mi><mn>2</mn></msubsup></msqrt><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>, 고도를 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="5.073ex" height="1.756ex" role="img" focusable="false" viewBox="0 -694 2242.4 776" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1722.4,0)"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn><mo>−</mo><mi>d</mi></math></mjx-assistive-mml></mjx-container> 쪽으로 블렌딩하면 지형이 가장자리에서 바다로 떨어집니다. 두 번째 독립 노이즈 필드는 습도맵이 됩니다. 형태에는 아무것도 하지 않지만 나중의 생물군계 단계에 입력으로 들어갑니다.</p>
<p>이렇게 하면 형태가 나오지만, 그건 노이즈 형태입니다. 강도 없고, 물이 깎은 계곡도 없고, 퇴적 부채꼴도 없습니다. 그 위를 흐른 것이 아무것도 없었기 때문이죠. 해결책은 수력 침식으로, Sebastian Lague의 MIT 라이선스 구현에서 이식해 왔습니다. 수천 개의 물방울이 무작위로 생성되어 비탈을 따라 굴러 내려갑니다. 각각 관성을 지녀서 직각으로 꺾지 않고, 빨라지면 퇴적물을 집어 올리고 느려지거나 고이면 내려놓습니다. 미리 계산해 둔 원형 브러시가 각 침식 이벤트를 작은 반경에 펼쳐서 깎인 자국이 1픽셀짜리 긁힘이 아니라 매끄럽게 됩니다. 그리고 증발이 물방울을 수명 동안 은퇴시킵니다. 충분히 많은 물방울을 돌리면 지형은 노이즈가 흉내 낼 수 없는 것을 키워냅니다. 합류하는 배수망, 하류로 갈수록 넓어지는 계곡, 그리고 퇴적물이 가라앉은 평지죠.</p>
<h2 id="gpu-위의-침식-그리고-자기가-어디-있는지-아는-강" tabindex="-1">GPU 위의 침식, 그리고 자기가 어디 있는지 아는 강 <a class="header-anchor" href="#gpu-위의-침식-그리고-자기가-어디-있는지-아는-강" aria-label="Permalink to &quot;GPU 위의 침식, 그리고 자기가 어디 있는지 아는 강&quot;"></a></h2>
<p>CPU 침식은 정확하지만 느립니다. 그래서 spike는 이것을 WebGPU 컴퓨트 셰이더로도 이식하는데, 흥미로운 부분은 GPU 원자 연산이 무엇을 강제하는가입니다. 높이는 백만 배율의 고정소수점 <code>i32</code>로 저장됩니다. WGSL에는 부동소수점에 대한 atomic add가 없고, 수천 개의 물방울이 같은 셀에 퇴적물을 내려놓고 제거하는 일을 경쟁 상태 없이 병렬로 할 수 있는 유일한 방법이 정수에 대한 <code>atomicAdd</code>와 <code>atomicSub</code>이기 때문입니다. 이 고정소수점 왕복은 셀이 무거운 동시 드래그 아래에서 가끔 살짝 음수가 될 수 있다는 뜻인데, 이건 무해하고 읽어들일 때 클램프됩니다. CPU 버전은 셀마다의 브러시 테이블을 미리 계산하지만 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="5.513ex" height="2.005ex" role="img" focusable="false" viewBox="0 -864 2436.6 886" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" transform="translate(1500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2033,393.1) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>1001</mn><mn>2</mn></msup></math></mjx-assistive-mml></mjx-container> 그리드에서 그 테이블은 약 100MB라서, GPU 이식은 각 물방울의 브러시를 그때그때 다시 계산합니다. 약간의 산술을 많은 메모리와 맞바꾸는 것이죠. 물방울 시작 위치는 여전히 Mulberry32 생성기를 통해 CPU에서 오므로 실행이 결정론적입니다.</p>
<p>두 패스가 더 있어 풍화된 지형을 읽을 수 있는 지도로 바꿉니다. 배수는 Red Blob D8 흐름 누적 방식을 씁니다. 모든 셀에 비 한 단위를 떨어뜨리고, 모든 셀을 고도 내림차순으로 정렬하고, 각 셀의 누적된 물을 그 셀의 단 하나뿐인 가장 낮은 이웃에게 넘깁니다. 그러면 물이 자연스러운 계곡을 따라 쌓이고, 누적량이 임계값을 넘는 셀은 강으로 표시됩니다. 함정은 침식된 높이맵에 구덩이가 있다는 것입니다. 내리막 출구가 없는 국소 함몰지죠. 구덩이로 들어간 물은 그냥 멈춰서 누적을 깨버립니다. 그래서 배수가 돌기 전에 Planchon-Darboux 구덩이 채우기가 각 구덩이를 가장 낮은 이웃보다 살짝 높게 올립니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.466ex;" xmlns="http://www.w3.org/2000/svg" width="17.709ex" height="2.036ex" role="img" focusable="false" viewBox="0 -694 7827.4 900" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mtext"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1111,0)" style="stroke-width: 3;"/><path data-c="4E" d="M42 46Q74 48 94 56T118 69T128 86V634H124Q114 637 52 637H25V683H232L235 680Q237 679 322 554T493 303L578 178V598Q572 608 568 613T544 627T492 637H475V683H483Q498 680 600 680Q706 680 715 683H724V637H707Q634 633 622 598L621 302V6L614 0H600Q585 0 582 3T481 150T282 443T171 605V345L172 86Q183 50 257 46H274V0H265Q250 3 150 3Q48 3 33 0H25V46H42Z" transform="translate(1667,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2417,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(2861,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(3139,0)" style="stroke-width: 3;"/><path data-c="68" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 124T102 167T103 217T103 272T103 329Q103 366 103 407T103 482T102 542T102 586T102 603Q99 622 88 628T43 637H25V660Q25 683 27 683L37 684Q47 685 66 686T103 688Q120 689 140 690T170 693T181 694H184V367Q244 442 328 442Q451 442 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(3639,0)" style="stroke-width: 3;"/><path data-c="62" d="M307 -11Q234 -11 168 55L158 37Q156 34 153 28T147 17T143 10L138 1L118 0H98V298Q98 599 97 603Q94 622 83 628T38 637H20V660Q20 683 22 683L32 684Q42 685 61 686T98 688Q115 689 135 690T165 693T176 694H179V543Q179 391 180 391L183 394Q186 397 192 401T207 411T228 421T254 431T286 439T323 442Q401 442 461 379T522 216Q522 115 458 52T307 -11ZM182 98Q182 97 187 90T196 79T206 67T218 55T233 44T250 35T271 29T295 26Q330 26 363 46T412 113Q424 148 424 212Q424 287 412 323Q385 405 300 405Q270 405 239 390T188 347L182 339V98Z" transform="translate(4195,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(4751,0)" style="stroke-width: 3;"/><path data-c="75" d="M383 58Q327 -10 256 -10H249Q124 -10 105 89Q104 96 103 226Q102 335 102 348T96 369Q86 385 36 385H25V408Q25 431 27 431L38 432Q48 433 67 434T105 436Q122 437 142 438T172 441T184 442H187V261Q188 77 190 64Q193 49 204 40Q224 26 264 26Q290 26 311 35T343 58T363 90T375 120T379 144Q379 145 379 161T380 201T380 248V315Q380 361 370 372T320 385H302V431Q304 431 378 436T457 442H464V264Q464 84 465 81Q468 61 479 55T524 46H542V0Q540 0 467 -5T390 -11H383V58Z" transform="translate(5251,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(5807,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6421.2,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(7421.4,0)"><path data-c="1D716" d="M227 -11Q149 -11 95 41T40 174Q40 262 87 322Q121 367 173 396T287 430Q289 431 329 431H367Q382 426 382 411Q382 385 341 385H325H312Q191 385 154 277L150 265H327Q340 256 340 246Q340 228 320 219H138V217Q128 187 128 143Q128 77 160 52T231 26Q258 26 284 36T326 57T343 68Q350 68 354 58T358 39Q358 36 357 35Q354 31 337 21T289 0T227 -11Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mtext>minNeighbour</mtext><mo>+</mo><mi>ϵ</mi></math></mjx-assistive-mml></mjx-container>. 모든 셀이 배수할 곳을 가질 때까지 스무 번 미만의 패스로 반복합니다. 마지막으로 생물군계는 Red Blob 방식으로 배정됩니다. 고도 대 습도의 두 축 룩업이라서 높고 건조한 셀은 바위가 되고 낮고 습한 셀은 늪이 됩니다. 그 위에 경사를 인식하는 오버라이드가 얹힙니다. 가파른 면은 습도와 상관없이 바위로 강제되고, 수면 띠는 해변이 되고, 가장 높은 고도는 눈을 입습니다. 결과는 한눈에 읽히는 섬이고, 두 개의 노이즈 시드에서 끝에서 끝까지 생성됩니다.</p>
<h2 id="멈출-줄-모르고-반복되는-타일" tabindex="-1">멈출 줄 모르고 반복되는 타일 <a class="header-anchor" href="#멈출-줄-모르고-반복되는-타일" aria-label="Permalink to &quot;멈출 줄 모르고 반복되는 타일&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/55-terrain-shading/" title="Spike 55 Terrain Shading" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/55-terrain-shading/" target="_blank">Spike 55를 새 탭에서 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=55-terrain-shading">소스 보기</a></p>
<p>지형에는 고작 몇 미터 너비의 텍스처로 수 킬로미터를 덮는 재질이 필요합니다. 그런데 타일을 키워서 땅을 덮는 순간 눈이 그 반복을 딱 붙잡습니다. Spike 55는 같은 지오메트리와 조명 위에서 네 가지 샘플링 모드를 비교하는 A/B 벤치라서, 유일한 변수는 텍스처를 어떻게 읽느냐입니다. 기준선은 <code>plain</code>입니다. 스케일된 UV에서 한 번 샘플링하는 것이죠. 몇 미터마다 명백하게 타일이 보이고, 이길 대상으로서만 존재합니다. 무료 PBR 레이어는 Poly Haven에서 그들의 CDN을 통해 옵니다. diffuse 더하기 패킹된 ARM 맵(앰비언트 오클루전, roughness, metalness) 더하기 GL normal, 전부 CC0이고, 이방성 8과 밉맵으로 로드됩니다.</p>
<p>흥미로운 세 가지는 반복에 대한 서로 다른 공격입니다. <code>hex-linear</code> 모드는 Heitz-Neyret 삼각형 격자입니다. 표면 위에 비스듬한 삼각 격자를 깔면 각 프래그먼트가 하나의 삼각형 안에 놓이고, 그 삼각형의 세 꼭짓점이 각각 무작위로 옵셋된 탭을 가져와 무게중심 가중치로 블렌딩합니다. 그러면 인접한 영역이 텍스처의 서로 다른 부분을 샘플링하고 큰 스케일의 타일링이 녹아 없어집니다. 하지만 세 탭의 순수 선형 블렌드는 삼각형 가장자리에서 색을 평균 내버려서 눈에 보이는 삼각형 무늬를 남깁니다. spike 48이 부딪혔던 바로 그 아티팩트죠. <code>hex-vp</code> 모드는 같은 2018년 논문에서 발표된 해결책입니다. 무게중심 합 이후에 텍스처의 평균 색을 빼고, 제곱 가중치 합의 역제곱근으로 다시 스케일해서 분산을 일정하게 유지한 다음, 평균을 도로 더합니다. 이렇게 하면 블렌드 전체에서 대비가 안정적으로 유지되어 삼각형이 사라집니다. 그래서 이 재질은 로드된 각 텍스처를 1×1로 읽어들여 평균 색을 미리 추정합니다. 네 번째 모드 <code>iq-untiled</code>는 Inigo Quilez의 Texture Repetition 기법 3입니다. 두 개의 옵셋된 탭을 저주파 변화 패턴으로 블렌딩하는데, 세 번이 아니라 두 번만 샘플링하고 애초에 삼각형 구조가 없는, 잘 버티는 저렴한 선택지입니다.</p>
<p>어떤 모드 위에든 선택적인 삼평면 투영을 얹을 수 있습니다. 이것이 같은 재질로 절벽을 늘어남 없이 감쌀 수 있게 해주는 것이죠. UV 하나 대신 셰이더는 세 개의 월드 축 투영을 샘플링합니다. X를 향한 표면은 YZ 평면을 읽고, Y는 ZX를, Z는 XY를 읽고, <code>abs(normalWorld)</code>를 4에서 8 사이의 샤프닝 거듭제곱으로 올려 블렌딩합니다. 그래야 45도 경사가 세 투영을 다 뭉개서 유령처럼 만들지 않습니다. 이 벤치는 절충을 분명하게 보여줍니다. 분산을 보존하는 hex 블렌딩이 품질 승자이고, Quilez의 두 탭이 성능을 의식한 쪽입니다. 둘 다 plain을 충분히 큰 차이로 이기므로, 어떤 창작자도 plain 타일을 출시해서는 안 됩니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>레시피를 쌓은 높이맵 생성.</strong> Red Blob Games 레시피는 원시 노이즈를 지형으로 조합합니다. 유기적인 능선을 위한 도메인 워프 FBM(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="19.194ex" height="2.283ex" role="img" focusable="false" viewBox="0 -759 8483.9 1009" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(536,363) scale(0.707)"><path data-c="2032" d="M79 43Q73 43 52 49T30 61Q30 68 85 293T146 528Q161 560 198 560Q218 560 240 545T262 501Q262 496 260 486Q259 479 173 263T84 45T79 43Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1058.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2114,0)"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2839.2,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(3839.5,0)"><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(1056,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(1334,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1728,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6011.5,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(6400.5,0)"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6903.5,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(7514.7,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(8014.9,0)"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>p</mi><mo data-mjx-alternate="1">′</mo></msup><mo>=</mo><mi>p</mi><mo>+</mo><mtext>noise</mtext><mo stretchy="false">(</mo><mi>p</mi><mo stretchy="false">)</mo><mo>⋅</mo><mi>s</mi></math></mjx-assistive-mml></mjx-container>), 평평한 계곡과 날카로운 봉우리를 위한 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="2.453ex" height="1.956ex" role="img" focusable="false" viewBox="0 -853.7 1084.4 864.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D452" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(499,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mstyle" transform="scale(1.414)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(236.2,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>e</mi><mrow data-mjx-texclass="ORD"><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mi>k</mi></mrow></msup></math></mjx-assistive-mml></mjx-container> 재분배, 그리고 가장자리를 바다로 떨어뜨려 섬을 만드는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="5.073ex" height="1.756ex" role="img" focusable="false" viewBox="0 -694 2242.4 776" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1722.4,0)"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn><mo>−</mo><mi>d</mi></math></mjx-assistive-mml></mjx-container> 쪽으로 블렌딩되는 유클리드 방사형 감쇠. 두 번째 노이즈 필드는 생물군계 배정을 위한 습도맵입니다. <a href="/ko/guides/landscape-generation-browser.html">지형 생성</a>을 보세요.</p>
<p><strong>수력 침식, CPU와 GPU.</strong> Sebastian Lague의 물방울 모델(관성, 운반 용량, 미리 계산된 원형 퇴적 브러시, 증발)은 노이즈가 흉내 낼 수 없는 실제 배수로를 깎아냅니다. WebGPU 컴퓨트 이식은 높이를 백만 배율의 고정소수점 <code>i32</code>로 저장해서 물방울들이 같은 셀에 병렬로 <code>atomicAdd</code>/<code>atomicSub</code>할 수 있게 하고, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="5.513ex" height="2.005ex" role="img" focusable="false" viewBox="0 -864 2436.6 886" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" transform="translate(1500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2033,393.1) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>1001</mn><mn>2</mn></msup></math></mjx-assistive-mml></mjx-container>에서 약 100MB짜리 테이블을 피하려고 각 물방울의 브러시를 그때그때 다시 계산하며, 결정론적인 Mulberry32 생성기로 시작 위치를 시드합니다.</p>
<p><strong>구덩이 채우기를 포함한 D8 배수.</strong> Red Blob D8 흐름 누적은 셀마다 비 한 단위를 떨어뜨리고, 셀을 고도 내림차순으로 정렬하고, 물을 각 셀의 가장 낮은 이웃에게 넘기며, 임계값을 넘으면 강으로 표시합니다. Planchon-Darboux 구덩이 채우기가 먼저 모든 국소 함몰지를 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.466ex;" xmlns="http://www.w3.org/2000/svg" width="17.709ex" height="2.036ex" role="img" focusable="false" viewBox="0 -694 7827.4 900" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mtext"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1111,0)" style="stroke-width: 3;"/><path data-c="4E" d="M42 46Q74 48 94 56T118 69T128 86V634H124Q114 637 52 637H25V683H232L235 680Q237 679 322 554T493 303L578 178V598Q572 608 568 613T544 627T492 637H475V683H483Q498 680 600 680Q706 680 715 683H724V637H707Q634 633 622 598L621 302V6L614 0H600Q585 0 582 3T481 150T282 443T171 605V345L172 86Q183 50 257 46H274V0H265Q250 3 150 3Q48 3 33 0H25V46H42Z" transform="translate(1667,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2417,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(2861,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(3139,0)" style="stroke-width: 3;"/><path data-c="68" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 124T102 167T103 217T103 272T103 329Q103 366 103 407T103 482T102 542T102 586T102 603Q99 622 88 628T43 637H25V660Q25 683 27 683L37 684Q47 685 66 686T103 688Q120 689 140 690T170 693T181 694H184V367Q244 442 328 442Q451 442 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(3639,0)" style="stroke-width: 3;"/><path data-c="62" d="M307 -11Q234 -11 168 55L158 37Q156 34 153 28T147 17T143 10L138 1L118 0H98V298Q98 599 97 603Q94 622 83 628T38 637H20V660Q20 683 22 683L32 684Q42 685 61 686T98 688Q115 689 135 690T165 693T176 694H179V543Q179 391 180 391L183 394Q186 397 192 401T207 411T228 421T254 431T286 439T323 442Q401 442 461 379T522 216Q522 115 458 52T307 -11ZM182 98Q182 97 187 90T196 79T206 67T218 55T233 44T250 35T271 29T295 26Q330 26 363 46T412 113Q424 148 424 212Q424 287 412 323Q385 405 300 405Q270 405 239 390T188 347L182 339V98Z" transform="translate(4195,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(4751,0)" style="stroke-width: 3;"/><path data-c="75" d="M383 58Q327 -10 256 -10H249Q124 -10 105 89Q104 96 103 226Q102 335 102 348T96 369Q86 385 36 385H25V408Q25 431 27 431L38 432Q48 433 67 434T105 436Q122 437 142 438T172 441T184 442H187V261Q188 77 190 64Q193 49 204 40Q224 26 264 26Q290 26 311 35T343 58T363 90T375 120T379 144Q379 145 379 161T380 201T380 248V315Q380 361 370 372T320 385H302V431Q304 431 378 436T457 442H464V264Q464 84 465 81Q468 61 479 55T524 46H542V0Q540 0 467 -5T390 -11H383V58Z" transform="translate(5251,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(5807,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6421.2,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(7421.4,0)"><path data-c="1D716" d="M227 -11Q149 -11 95 41T40 174Q40 262 87 322Q121 367 173 396T287 430Q289 431 329 431H367Q382 426 382 411Q382 385 341 385H325H312Q191 385 154 277L150 265H327Q340 256 340 246Q340 228 320 219H138V217Q128 187 128 143Q128 77 160 52T231 26Q258 26 284 36T326 57T343 68Q350 68 354 58T358 39Q358 36 357 35Q354 31 337 21T289 0T227 -11Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mtext>minNeighbour</mtext><mo>+</mo><mi>ϵ</mi></math></mjx-assistive-mml></mjx-container>로 올려서(스무 번 미만의 패스로 반복) 물이 절대 갇히지 않고 누적이 연결된 채로 유지됩니다. 고도 대 습도의 두 축 룩업이 생물군계를 배정하고, 경사 오버라이드가 절벽에 바위를, 수면에 해변을, 봉우리에 눈을 강제합니다.</p>
<p><strong>텍스처 타일링을 깨는 네 가지 방법.</strong> 동일한 지오메트리와 조명 위에서: <code>plain</code>(한 탭, 명백하게 타일이 보임), <code>hex-linear</code>(Heitz-Neyret 삼각형 격자, 선형 블렌드가 삼각형 무늬를 남김), <code>hex-vp</code>(평균을 빼고, 제곱 가중치의 역제곱근으로 다시 스케일하고, 평균을 도로 더하는 EGSR 2018 §3.3 분산 보존 해결책, 텍스처마다 1×1 평균 읽어들이기가 필요), 그리고 <code>iq-untiled</code>(Inigo Quilez 두 탭 기법 3). 삼평면 투영은 세 개의 월드 축 평면을 <code>abs(normalWorld)</code>의 4-8 거듭제곱으로 블렌딩해서 샘플링하므로 절벽이 늘어나지 않습니다. 분산 보존이 품질에서 이기고, 두 탭이 비용에서 이깁니다. <a href="/ko/guides/landscape-generation-browser.html#terrain-materials">지형 재질</a>을 보세요.</p>
<hr>
<p>29부 중 27부.
이전: <a href="/ko/blog/2026-05-12-open-world-browser-part-26-water.html">26부 - 물을 만드는 세 가지 방법</a>
다음: <a href="/ko/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion.html">28부 - 지평선까지 펼쳐진 풀, 그리고 자신을 숨기는 땅</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 26부: 물을 만드는 세 가지 방법]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-12-open-world-browser-part-26-water</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-12-open-world-browser-part-26-water</guid>
            <pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 51은 스크린 스페이스 반사 물을 만들었고 근본적인 한계에 부딪쳤다. 카메라가 한 번도 보지 못한 것은 반사할 수 없다. Spike 52는 평면 거울 방식으로 바꿨는데, 출시되는 모든 게임이 쓰는 그 방법이고, 어두운 반사를 먹어버리던 버그도 잡았다. Spike 53은 완성된 물이 어떤 모습인지 보려고 프로덕션 수준의 물 라이브러리를 그대로 가져다 넣었다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-26부-물을-만드는-세-가지-방법" tabindex="-1">브라우저에서 오픈 월드 만들기, 26부: 물을 만드는 세 가지 방법 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-26부-물을-만드는-세-가지-방법" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 26부: 물을 만드는 세 가지 방법&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 편을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-10-open-world-browser-part-25-universal-characters.html">25부</a>에서는 아바타에게 옷을 입혔습니다. 이번 편은 물 이야기이고, spike가 세 개인 이유는 물이 바로 그런 표면이기 때문입니다. 값싼 지름길과 올바른 답이 스크린샷에서는 똑같아 보이지만 움직이면 완전히 달라지는 표면이죠. Spike 51은 스크린 스페이스 방식으로 반사를 만듭니다. 솔깃한 방식이지만 곧장 내장된 한계에 부딪칩니다. Spike 52는 출시되는 모든 게임이 실제로 쓰는 방법으로 바꿉니다. Spike 53은 완성된 물 라이브러리를 그대로 넣어서 &quot;완성&quot;이 지금 우리 위치에서 얼마나 떨어져 있는지 봅니다. 셋 다 굴절 레이어 하나를 공유하므로, 앞의 두 개 사이에서 변하는 유일한 변수는 반사를 어떻게 계산하느냐입니다.</p>
<h2 id="이미-가지고-있는-화면에서-반사를-얻는다" tabindex="-1">이미 가지고 있는 화면에서 반사를 얻는다 <a class="header-anchor" href="#이미-가지고-있는-화면에서-반사를-얻는다" aria-label="Permalink to &quot;이미 가지고 있는 화면에서 반사를 얻는다&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/51-water-ssr-caustics/" title="Spike 51 Water SSR" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/51-water-ssr-caustics/" target="_blank">새 탭에서 Spike 51 열기 ↗</a> · <a href="/blog/spike-source?spike=51-water-ssr-caustics">소스 보기</a></p>
<p>스크린 스페이스 반사는 이미 렌더링한 프레임을 재활용합니다. 각 물 픽셀마다 시선 광선을 표면에서 반사시키고, 그 반사된 광선을 깊이 버퍼를 따라 진행시키다가, 광선이 기록된 어떤 표면 뒤로 지나가는 순간 물이 무엇을 반사하는지 찾아낸 것이고, 그 값을 컬러 버퍼에서 바로 샘플링합니다. 이 포팅은 three.js의 <code>SSRNode</code>를 한 줄 한 줄 그대로 따라갔고, 그쪽은 다시 lettier의 SSR 입문서를 따릅니다. 진행 과정은 스크린 스페이스에서의 DDA 워크입니다. 광선의 시작점과 끝점을 픽셀 좌표로 투영하고, 더 긴 축을 따라 한 픽셀당 한 번씩 탭하며 나아갑니다. 각 스텝에서 반사 광선의 깊이는 원근 보정 보간이 필요합니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -1.238ex;" xmlns="http://www.w3.org/2000/svg" width="14.984ex" height="3.195ex" role="img" focusable="false" viewBox="0 -864.9 6622.8 1412" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="mn" transform="translate(3134.6,394) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mrow" transform="translate(220,-370.3) scale(0.707)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(500,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z" style="stroke-width: 3;"/></g></g><g data-mml-node="msub" transform="translate(1000,0)"><g data-mml-node="mi"><path data-c="1D467" d="M347 338Q337 338 294 349T231 360Q211 360 197 356T174 346T162 335T155 324L153 320Q150 317 138 317Q117 317 117 325Q117 330 120 339Q133 378 163 406T229 440Q241 442 246 442Q271 442 291 425T329 392T367 375Q389 375 411 408T434 441Q435 442 449 442H462Q468 436 468 434Q468 430 463 420T449 399T432 377T418 358L411 349Q368 298 275 214T160 106L148 94L163 93Q185 93 227 82T290 71Q328 71 360 90T402 140Q406 149 409 151T424 153Q443 153 443 143Q443 138 442 134Q425 72 376 31T278 -11Q252 -11 232 6T193 40T155 57Q111 57 76 -3Q70 -11 59 -11H54H41Q35 -5 35 -2Q35 13 93 84Q132 129 225 214T340 322Q352 338 347 338Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(498,-150) scale(0.707)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1901.6,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2679.6,0)"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(3148.6,0) scale(1.414)"><g data-mml-node="mspace"/></g><g data-mml-node="mo" transform="translate(3384.7,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3773.7,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(4273.7,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z" style="stroke-width: 3;"/></g></g><g data-mml-node="msub" transform="translate(4773.7,0)"><g data-mml-node="mi"><path data-c="1D467" d="M347 338Q337 338 294 349T231 360Q211 360 197 356T174 346T162 335T155 324L153 320Q150 317 138 317Q117 317 117 325Q117 330 120 339Q133 378 163 406T229 440Q241 442 246 442Q271 442 291 425T329 392T367 375Q389 375 411 408T434 441Q435 442 449 442H462Q468 436 468 434Q468 430 463 420T449 399T432 377T418 358L411 349Q368 298 275 214T160 106L148 94L163 93Q185 93 227 82T290 71Q328 71 360 90T402 140Q406 149 409 151T424 153Q443 153 443 143Q443 138 442 134Q425 72 376 31T278 -11Q252 -11 232 6T193 40T155 57Q111 57 76 -3Q70 -11 59 -11H54H41Q35 -5 35 -2Q35 13 93 84Q132 129 225 214T340 322Q352 338 347 338Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(498,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5675.3,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(6453.3,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(6953.3,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z" style="stroke-width: 3;"/></g></g><g data-mml-node="msub" transform="translate(7453.3,0)"><g data-mml-node="mi"><path data-c="1D467" d="M347 338Q337 338 294 349T231 360Q211 360 197 356T174 346T162 335T155 324L153 320Q150 317 138 317Q117 317 117 325Q117 330 120 339Q133 378 163 406T229 440Q241 442 246 442Q271 442 291 425T329 392T367 375Q389 375 411 408T434 441Q435 442 449 442H462Q468 436 468 434Q468 430 463 420T449 399T432 377T418 358L411 349Q368 298 275 214T160 106L148 94L163 93Q185 93 227 82T290 71Q328 71 360 90T402 140Q406 149 409 151T424 153Q443 153 443 143Q443 138 442 134Q425 72 376 31T278 -11Q252 -11 232 6T193 40T155 57Q111 57 76 -3Q70 -11 59 -11H54H41Q35 -5 35 -2Q35 13 93 84Q132 129 225 214T340 322Q352 338 347 338Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(498,-150) scale(0.707)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(8354.8,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g><rect width="6382.8" height="60" x="120" y="220"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mfrac><mn>1</mn><mrow><mn>1</mn><mrow data-mjx-texclass="ORD"><mo>/</mo></mrow><msub><mi>z</mi><mn>0</mn></msub><mo>+</mo><mi>s</mi><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mo stretchy="false">(</mo><mn>1</mn><mrow data-mjx-texclass="ORD"><mo>/</mo></mrow><msub><mi>z</mi><mn>1</mn></msub><mo>−</mo><mn>1</mn><mrow data-mjx-texclass="ORD"><mo>/</mo></mrow><msub><mi>z</mi><mn>0</mn></msub><mo stretchy="false">)</mo></mrow></mfrac></math></mjx-assistive-mml></mjx-container> 형태인데, view-Z를 선형 보간하는 것은 그냥 틀린 방법이고 엉뚱한 위치에 히트를 만들어내기 때문입니다.</p>
<p>두 가지가 이 방식을 슬라이드쇼가 아니라 쓸 만하게 만듭니다. 거친 진행은 64스텝으로 제한합니다. 천 픽셀에 걸쳐 투영되는 긴 광선은 그러지 않으면 프래그먼트마다 수백 번씩 반복하게 되고, 백만 개 프래그먼트짜리 물 평면에 수백 번 반복에 텍스처 샘플 몇 번을 곱하면 그건 30fps짜리 장면이 됩니다. 품질 설정은 반복 횟수가 아니라 그 한도 안에서의 실효 보폭을 조절합니다. 그리고 제한된 거친 진행은 눈에 보이는 계단형 밴딩을 남기므로, 6회 반복의 이진 정제가 마지막 미스와 히트 사이의 구간을 이등분합니다. 이는 64배 서브 스텝 정확도이고, 이웃한 물 프래그먼트들이 같은 거친 히트 위치에 들러붙는 것을 멈출 만큼 충분합니다. 마지막으로 점과 직선 사이의 거리 검사가, 후보가 단지 같은 깊이에 있을 뿐인지 아니면 정말로 반사 광선 위에 있는지를 확인합니다. 두께 허용치는 해당 깊이에서 한 픽셀의 view 공간 폭에 맞춰 자동으로 스케일링되어 가까이서는 더 빡빡하고 멀리서는 더 느슨해집니다.</p>
<p>이 spike의 솔직한 부분은 그 자신의 주석에 적혀 있습니다. SSR은 메인 카메라가 한 번도 샘플링하지 않은 것을 반사할 수 없습니다. 나무의 아랫면, 화면 밖의 무엇이든, 가려진 무엇이든, 그 어느 것도 버퍼에 존재하지 않으므로 반사에 나타날 수 없습니다. 그것이 바로 진행 품질을 아무리 높여도 고칠 수 없는 &quot;잘못된 쪽 정보 손실&quot;이고, 다음 spike가 존재하는 이유가 바로 이것입니다.</p>
<h2 id="거짓말할-수-없는-거울" tabindex="-1">거짓말할 수 없는 거울 <a class="header-anchor" href="#거짓말할-수-없는-거울" aria-label="Permalink to &quot;거짓말할 수 없는 거울&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/52-water-planar/" title="Spike 52 Water Planar" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/52-water-planar/" target="_blank">새 탭에서 Spike 52 열기 ↗</a> · <a href="/blog/spike-source?spike=52-water-planar">소스 보기</a></p>
<p>평면 반사는 물 평면을 기준으로 거울처럼 뒤집은 카메라에서 장면을 한 번 더 오프스크린 타깃에 렌더링하고, 물 셰이더가 그 타깃을 샘플링합니다. 이것이 정석적인 패턴이고, UE5 Water, three.js 자체의 <code>WaterMesh</code>, ABZÛ, Sea of Thieves가 모두 쓰는 방식입니다. 장면의 모든 픽셀을 그릴 재료로 가지고 있기 때문인데, SSR이 절대 볼 수 없는 지오메트리까지 포함합니다. TSL에서는 거의 김빠질 만큼 간단합니다. <code>reflector()</code>가 거울 헬퍼 카메라와 그 렌더 타깃을 할당하고, 그 타깃을 메시에 추가하면 매 프레임 갱신되며, 그 색을 샘플링하면 됩니다. 나중에 파도가 들어오면, 리플렉터의 UV 노드에 왜곡 오프셋을 더해서 반사가 일렁이게 됩니다. 이건 정확히 <code>WaterMesh</code>가 쓰는 그 라인입니다.</p>
<p>기록해 둘 만한 버그는 거울이 아니라 안전망에 있었습니다. 이전 버전은 리플렉터의 출력을 절차적 하늘과 폴백으로 블렌딩했는데, 반사 색의 크기에 따라 가중치를 줬습니다. 거의 0에 가까운 반사는 타깃에 아무것도 없다는 뜻이라는 이론에서였죠. 그런데 어두운 나무 그늘도 크기가 작아서, 클램프가 풀 강도에 도달하지 못했고 진짜로 어두운 그 픽셀들이 밝은 하늘과 섞여버렸습니다. 사용자가 잡아낸 증상은 정확했습니다. 디버그 모드에서 원본 거울 타깃은 완벽하게 어두운 나무를 보여주는데 합성된 렌더는 반사가 바래 있었고, 진단은 셰이더가 &quot;어두운 색을 사라지게 한다&quot;는 것이었습니다. 해결책은 삭제였습니다. 리플렉터 타깃은 첫 프레임 이후로 믿을 수 있으므로 폴백 자체가 필요 없습니다. 두 spike는 그 아래에 같은 굴절을 공유합니다. 표면 뒤의 장면을 샘플링하고, 각 픽셀이 수면 아래로 얼마나 깊이 있는지 재구성하고, 채널별 Beer-Lambert 소광을 적용해서 빨강은 몇 미터 안에 죽고 파랑은 살아남게 하며, 먼 평면 배경이 안개에 덮이지 않도록 하늘 마스크를 둡니다. Schlick Fresnel은 물을 똑바로 내려다볼 때의 굴절과 가로질러 볼 때의 반사를 섞어줍니다.</p>
<h2 id="완성된-모습은-이렇다" tabindex="-1">완성된 모습은 이렇다 <a class="header-anchor" href="#완성된-모습은-이렇다" aria-label="Permalink to &quot;완성된 모습은 이렇다&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/53-water-pro/" title="Spike 53 Water Pro" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/53-water-pro/" target="_blank">새 탭에서 Spike 53 열기 ↗</a> · <a href="/blog/spike-source?spike=53-water-pro">소스 보기</a></p>
<p>Spike 53은 직접 만들 것인가 사 올 것인가를 확인하는 작업입니다. <code>threejs-water-pro</code>를 출시된 그대로 넣습니다. 열대 프리셋, 기본 바다 클립맵, 카메라 추적, Rayleigh 하늘까지 함께 넣고, 라이브러리 자체 데모가 쓰는 것과 같은 섬 glTF를 로드합니다. 핵심은 직접 짠 평면 물 셰이더와 완전한 바다 시스템 사이의 격차를 보는 것인데, 그 격차는 큽니다. 이쪽에는 배 선체 아래 여러 지점에서 파도 높이를 샘플링해 배가 그냥 위아래로 까딱이는 게 아니라 피칭과 롤링을 하게 하는 부력 시스템, 항적 생성기, 해안선과 표면 거품, 그리고 배 선체 안쪽의 물 렌더링을 억제해서 잔물결이 갑판을 통해 새어 나오지 않게 하는 마스크 패스가 있습니다.</p>
<p>통합 과정에서, README를 읽어서가 아니라 라이브러리를 실제로 써봐야만 배우게 되는 종류의 디테일들이 드러났습니다. 거품 텍스처는 프리셋에서 파일명으로 참조되지만 그것을 로드하는 일은 사용하는 쪽의 몫이고, 그게 없으면 해안선이 부서지는 파도가 아니라 딱딱한 수면 경계선으로 보입니다. 섬은 그 수중 지오메트리가 바다 바닥 아래로 떨어지도록 배치되어, 라이브러리의 바닥 메시가 모델의 바깥 테두리를 가려서 평면 가장자리가 보이지 않게 합니다. 이것이 라이브러리가 의도한 패턴입니다. 3D 모델을 가져오되 지형을 합성하지는 말라는 거죠. 그리고 안티앨리어싱은 렌더러에서 일부러 끄고 대신 후처리 FXAA 패스를 씁니다. MSAA는 깊이 인식 대기 안개가 돌기 전에 가장자리 프래그먼트를 배경과 블렌딩해서, 지오메트리와 안개가 만나는 곳마다 얇고 어두운 테두리를 남기기 때문입니다. 안개 전이 아니라 후에 앨리어싱을 해소하면 그 테두리가 사라집니다. 이것이 줄여주는 리스크는 결정 그 자체입니다. 프로덕션 바다는 크고 특화된 시스템이고, 그게 필요한 경우라면 항적과 부력과 거품을 처음부터 다시 만드는 것보다 유지보수되는 라이브러리를 도입하는 편이 낫습니다. 한편 spike 52의 평면 거울 셰이더는 크리에이터가 자기 월드에 두는 더 작은 내륙 물에는 여전히 옳은 답으로 남습니다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>스크린 스페이스 반사 물.</strong> 반사된 시선 광선이 DDA로 스크린 스페이스에서 깊이 버퍼를 진행하며, 원근 보정 1/z 보간, 프래그먼트당 비용을 묶는 강한 스텝 제한, 그리고 제한된 진행이 남기는 밴딩을 없애는 이진 정제 패스를 씁니다. 깊이 스케일 두께를 적용한 점과 직선 확인이 거짓 히트를 걸러냅니다. 이 방식의 절대적 한계는 메인 카메라가 이미 샘플링한 지오메트리만 반사할 수 있다는 것이어서, 화면 밖이나 잘못된 쪽 표면은 절대 나타나지 않습니다. <a href="/ko/guides/landscape-generation-browser.html#terrain-materials">지형 머티리얼</a>을 참고하세요.</p>
<p><strong>평면 거울 반사.</strong> 물 평면을 기준으로 거울처럼 뒤집은 헬퍼 카메라가 장면을 오프스크린 타깃에 렌더링하고 물 셰이더가 그것을 샘플링해서, SSR이 볼 수 없는 지오메트리까지 포함한 픽셀 단위로 완벽한 반사를 줍니다. 이것이 UE5 Water와 three.js <code>WaterMesh</code>가 쓰는 패턴이고, 파도 왜곡은 리플렉터의 UV 노드에 오프셋으로 적용됩니다. 크기 가중 하늘 폴백은 어두운 반사 픽셀을 잘못 지워버렸고, 리플렉터 타깃은 첫 프레임 이후 믿을 수 있으므로 폴백을 제거하는 것이 해결책이었습니다.</p>
<p><strong>Beer-Lambert 깊이 틴트 굴절.</strong> 두 셰이더 모두 표면 뒤의 장면을 샘플링하고, 각 배경 픽셀의 수면 아래 깊이를 재구성하고, 채널별 지수 소광(빨강은 미터 단위로 죽고 파랑은 살아남음)을 적용해 물 안개 색 쪽으로 합성하며, 먼 평면이 안개에 덮이지 않도록 하늘 마스크를 둡니다. Schlick Fresnel은 수직 입사에서의 굴절과 스치는 각도에서의 반사를 섞습니다.</p>
<p><strong>프로덕션 물 라이브러리 도입.</strong> <code>threejs-water-pro</code>는 바다 클립맵, Rayleigh 하늘, 배의 피칭과 롤링을 위한 다중 지점 부력, 항적, 거품, 그리고 선체 마스크 패스를 함께 제공합니다. 사용하는 쪽의 디테일이 중요합니다. 거품 텍스처는 명시적으로 로드해야 하고, 섬의 수중 지오메트리는 바다 바닥 아래로 떨어뜨려 바닥이 그 가장자리를 가리게 해야 하며, 지오메트리 가장자리의 어두운 안개 테두리를 피하려면 안티앨리어싱은 MSAA가 아니라 후처리 FXAA 패스로 돌려야 합니다.</p>
<hr>
<p>29부 중 26부.
이전: <a href="/ko/blog/2026-05-10-open-world-browser-part-25-universal-characters.html">25부 - 골격 하나, 모든 의상</a>
다음: <a href="/ko/blog/2026-05-13-open-world-browser-part-27-island-and-terrain.html">27부 - 노이즈에서 만든 섬, 땅처럼 보이는 땅</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[최신 엔진은 식생 overdraw를 어떻게 이기는가]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-11-foliage-overdraw</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-11-foliage-overdraw</guid>
            <pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Z-prepass, 팔면체 임포스터, GPU 구동 클러스터 컬링, hashed alpha, 가시성 버퍼, 거리장 그림자. 빽빽한 숲 장면에서 8-15배의 식생 overdraw를 1-2배로 줄여주는 기술 스택.]]></description>
            <content:encoded><![CDATA[<h1 id="최신-엔진은-식생-overdraw를-어떻게-이기는가" tabindex="-1">최신 엔진은 식생 overdraw를 어떻게 이기는가 <a class="header-anchor" href="#최신-엔진은-식생-overdraw를-어떻게-이기는가" aria-label="Permalink to &quot;최신 엔진은 식생 overdraw를 어떻게 이기는가&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<img src="/img/blog/foliage_overdraw_hero.webp" alt="Dense forest canopy with overlapping leaf cards stacked behind each other in front of a setting sun, suggesting heavy overdraw" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>숲은 GPU에게 렌더링을 시킬 수 있는 것 중 가장 까다로운 대상 중 하나다. 잎 하나하나가 alpha 마스크로 잘라낸 텍스처 쿼드다. 그런 쿼드 수십 개가 시선 방향마다 겹겹이 쌓인다. 래스터라이저는 어떤 프래그먼트가 alpha 테스트를 통과할지 미리 알 방법이 없어서, 불투명 장면을 살려주는 표준 early-Z 최적화가 여기서는 대부분 꺼진다. 그 결과 하나의 화면 픽셀이 프레임이 정리되기 전까지 잎 셰이더를 10번이나 15번씩 돌리게 된다. 이게 바로 식생 overdraw다. 지난 10년 동안 출시된 어느 게임에서든 오픈월드 프레임에서 가장 비싼 단일 요소다.</p>
<p>좋은 소식은 이미 해결된 문제라는 점이다. 누군가 트릭 하나로 고쳤다는 뜻이 아니라, 일곱여덟 가지 기법을 묶으면 빽빽한 숲에서의 실효 overdraw를 8-15배에서 1-2배까지 끌어내릴 수 있다는 뜻이다. 모든 최신 엔진은 이 스택의 어떤 버전이든 탑재하고 있다. 그 안에 무엇이 들었는지, 각 조각이 왜 존재하는지, 그리고 각각의 정석 참고 자료를 정리한다.</p>
<h2 id="_1-식생-overdraw가-왜-이렇게-괴로운가" tabindex="-1">1. 식생 overdraw가 왜 이렇게 괴로운가 <a class="header-anchor" href="#_1-식생-overdraw가-왜-이렇게-괴로운가" aria-label="Permalink to &quot;1. 식생 overdraw가 왜 이렇게 괴로운가&quot;"></a></h2>
<p>전형적인 불투명 장면에서 GPU는 early depth rejection을 한다. 픽셀 셰이더가 돌기도 전에, 하드웨어가 기존 깊이 버퍼를 확인해서 이미 뒤에 가려진 프래그먼트를 건너뛴다. 이건 사실상 공짜고, 밀집된 지오메트리의 비용을 정상 범위로 유지해주는 핵심이다.</p>
<p>alpha-tested 식생은 이걸 깨뜨린다. 프래그먼트 셰이더가 실제로 돌면서 alpha 텍스처를 평가하고, 마스크로 가려진 픽셀에 <code>discard</code>(또는 <code>clip</code>)를 호출해야 한다. 하드웨어는 셰이더가 돌기 전까지 프래그먼트가 버려질지 알 수 없으므로, 대부분의 GPU에서는 셰이더 어딘가에 <code>discard</code>가 들어가 있으면 그 draw call의 early-Z가 통째로 꺼진다. 타일 기반 GPU(모바일, M 시리즈, 일부 콘솔)에서는 프레임 전체의 Hi-Z와 깊이 압축까지 꺼질 수 있다. 픽셀을 덮는 삼각형마다 픽셀 셰이더가 한 번씩 돌고, 그중 대부분은 discard로 끝난다.</p>
<p>잎 쿼드 10개를 하나의 화면 픽셀 앞에 쌓으면 잎 셰이더가 10번 돈다. 거기에 400만 픽셀을 곱하면 비용이 잔혹해진다. Marco Salvi의 글 <a href="https://therealmjp.github.io/posts/to-earlyz-or-not-to-earlyz/" target="_blank" rel="noreferrer">To Early-Z, or Not To Early-Z</a>는 이게 하드웨어 수준에서 왜 벌어지는지를 가장 부드럽게 설명한다. 한 번도 생각해본 적 없다면 여기서 시작하는 게 맞다.</p>
<img src="/img/blog/foliage_overdraw_layers.webp" alt="Side view of a single screen pixel ray passing through twelve overlapping leaf cards, with each card highlighted to show stacked alpha-tested fragments" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<h2 id="_2-마스크-지오메트리를-위한-깊이-prepass" tabindex="-1">2. 마스크 지오메트리를 위한 깊이 prepass <a class="header-anchor" href="#_2-마스크-지오메트리를-위한-깊이-prepass" aria-label="Permalink to &quot;2. 마스크 지오메트리를 위한 깊이 prepass&quot;"></a></h2>
<p>가장 큰 단일 이득이자 모든 최신 엔진이 탑재한 기법은 식생 드로를 두 패스로 쪼개는 것이다. 첫 번째 패스는 깊이만 쓴다. alpha 테스트를 하고, 마스크로 가려진 픽셀을 버리고, 그 외에는 아무것도 쓰지 않는 최소한의 셰이더를 쓴다. 두 번째 패스는 깊이 테스트를 &quot;equal&quot;로 설정하고 깊이 쓰기는 끈 채 완전한 머티리얼을 렌더링한다. 이제 뒤에 잎 쿼드가 몇 장 쌓여 있든, 보이는 픽셀 하나하나는 완전한 BRDF를 정확히 한 번만 셰이딩한다.</p>
<p>같은 삼각형을 두 번 건드리니 두 배 일하는 것처럼 들리지만, prepass 셰이더가 워낙 싸서(텍스처 샘플 한 번, discard 한 번, 깊이 쓰기 한 번) 메인 패스에서 아끼는 비용이 그 추가 부담을 훌쩍 넘는다. 빽빽한 숲에서 메인 패스는 픽셀당 잎 셰이더를 10-15번 돌리던 것에서 정확히 한 번 돌리는 것으로 바뀐다.</p>
<p>Unreal, Frostbite, Decima, 그리고 최신 Rage 및 Dunia 브랜치가 모두 이렇게 한다. 이런 엔진들에서 마스크 머티리얼이 여전히 반투명 머티리얼보다 싼 핵심 이유이기도 하다.</p>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Pettineo, <a href="https://therealmjp.github.io/posts/to-earlyz-or-not-to-earlyz/" target="_blank" rel="noreferrer">To Early-Z, or Not To Early-Z</a> (<code>discard</code>가 Hi-Z 및 early-Z와 어떻게 상호작용하는지에 대한 정석 설명).</li>
<li>Wihlidal, <a href="http://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/" target="_blank" rel="noreferrer">Optimizing the Graphics Pipeline with Compute</a> (GDC 2016, Frostbite의 깊이 prepass와 prepass 구동 컬링 아키텍처).</li>
<li>Sanders, <a href="https://www.gdcvault.com/play/1025066/Between-Tech-and-Art-The" target="_blank" rel="noreferrer">Between Tech and Art: The Vegetation of Horizon Zero Dawn</a> (GDC 2018, Decima의 두 패스 식생 렌더링).</li>
<li>Persson, <a href="http://www.humus.name/index.php?page=News&amp;ID=255" target="_blank" rel="noreferrer">A couple of notes about Z</a> (depth-equal 테스트와 prepass 경제학을 가장 명료하게 설명한 글 중 하나).</li>
</ul>
<h2 id="_3-공격적인-lod와-팔면체-임포스터" tabindex="-1">3. 공격적인 LOD와 팔면체 임포스터 <a class="header-anchor" href="#_3-공격적인-lod와-팔면체-임포스터" aria-label="Permalink to &quot;3. 공격적인 LOD와 팔면체 임포스터&quot;"></a></h2>
<p>두 번째로 큰 이득은 그릴 필요가 없을 때 잎을 아예 그리지 않는 것이다. 식생 에셋은 여러 LOD 단계를 함께 담고 출시된다. 가장 가까운 단계는 잎 카드가 각각 들어 있는 완전한 메시다. 중간 거리에서는 잎들이 더 빽빽한 복합 카드로 합쳐진다(잎 30장 한 뭉치가 같은 실루엣을 가진 텍스처 카드 1장이 된다). 어떤 거리 임계값을 넘으면 나무 전체가 <em>임포스터</em>가 된다. 여러 각도에서 사전 렌더링한 나무의 뷰로 텍스처를 입힌 작은 지오메트리 조각이다.</p>
<p>최신 임포스터 포맷은 <strong>팔면체 임포스터</strong>다. 8개 면으로 된 지오메트리 조각에, 팔면체 매핑으로 구면 위 점들에서 캡처한 뷰들의 아틀라스를 텍스처로 입힌 것이다. 런타임에 셰이더는 카메라 방향에 따라 가장 가까운 사전 렌더링 뷰 두세 개를 고르고 그 사이를 블렌딩한다. 결과는 어느 각도에서 봐도 3D처럼 보이는, 삼각형 몇 개짜리 대역이다. 제대로 된 셰이딩, 노멀 맵, 심지어 바람 애니메이션까지 가질 수 있다. Ryan Brucks의 구현은 처음엔 커뮤니티 플러그인이었다가 이제 Unreal의 일부가 됐고, 이 분야의 참고 구현이다. Microsoft Flight Simulator의 수십억 그루 숲은 카메라 근처를 빼면 본질적으로 어디든 팔면체 임포스터다.</p>
<p>더 큰 구조적 이득은 임포스터가 먼 거리에서 <em>불투명하거나 거의 불투명하다</em>는 점이다. 잎 30장짜리 복합 카드는 쿼드 30장이 아니라 마스크 쿼드 1장이다. 나무 전체 임포스터는 수천 개가 아니라 몇 개의 면이다. 원거리 overdraw가 거의 0으로 줄어든다.</p>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Brucks, <a href="https://shaderbits.com/blog/octahedral-impostors" target="_blank" rel="noreferrer">Octahedral Impostors</a> (수학과 UE 구현이 함께 있는 정석 참고 자료).</li>
<li>Halen, <a href="https://dev.epicgames.com/community/learning/tutorials/JmL3/octahedral-impostors-unreal-engine" target="_blank" rel="noreferrer">Octahedral Impostors in Unreal Engine</a> (UE에 통합된 워크플로).</li>
<li>Häggström, <a href="https://www.diva-portal.org/smash/get/diva2:1135856/FULLTEXT01.pdf" target="_blank" rel="noreferrer">Real-Time Rendering of Vegetation</a> (LOD 체인, 임포스터, 그 배후의 수학을 다루는 깔끔한 논문).</li>
<li>Crytek, <a href="http://developer.nvidia.com/gpugems/gpugems3/part-i-geometry/chapter-4-next-generation-speedtree-rendering" target="_blank" rel="noreferrer">SpeedTree integration in CryEngine 3</a> (GPU Gems 3, 나무 LOD 체인 입문으로는 여전히 최고).</li>
</ul>
<h2 id="_4-클러스터-및-gpu-구동-컬링" tabindex="-1">4. 클러스터 및 GPU 구동 컬링 <a class="header-anchor" href="#_4-클러스터-및-gpu-구동-컬링" aria-label="Permalink to &quot;4. 클러스터 및 GPU 구동 컬링&quot;"></a></h2>
<p>깊이 prepass가 있어도 prepass 자체에는 비용이 있다. 보이는(또는 잠재적으로 보이는) 나무마다 모든 삼각형을 여전히 <em>건드려야</em> 한다. 최신 엔진은 GPU 구동 클러스터 컬링으로 그 비용을 더 낮춘다. 래스터라이저가 보기도 전에 삼각형 무리 전체를 버린다.</p>
<p>파이프라인은 이렇게 생겼다. 모든 메시는 미리 삼각형 64개나 128개 단위의 클러스터로 쪼개지고, 각 클러스터는 꽉 맞는 경계 상자와 노멀 콘을 갖는다. 렌더링 시점에 compute 셰이더가 인스턴스 목록을 훑으며 각 인스턴스에 프러스텀 테스트를 하고, 보이는 인스턴스마다 모든 클러스터에 프러스텀 테스트를 한 다음, 살아남은 클러스터마다 직전 프레임의 깊이 피라미드에 대해 <em>Hi-Z 오클루전 테스트</em>를 한다. 언덕 뒤에 숨었거나 다른 나무 앞에 가려진 나무 가지 전체가 정점 셰이더가 돌기도 전에 컬링된다. 출력은 &quot;이 클러스터들을 그려라&quot;라는 인자들의 압축된 목록이고, 이게 단 한 번의 <code>DrawIndirect</code> 호출로 그대로 들어간다.</p>
<p>나무 1만 그루의 숲이 몇 초가 아니라 몇 밀리초 안에 렌더링되는 이유가 이것이다. Ubisoft의 어쌔신 크리드 유니티 발표가 이 파이프라인을 양산 형태로 처음 소개했고(삼각형 20-40% 컬링, 그림자 삼각형 30-80% 컬링, 화면상 인스턴스 수가 이전 세대 대비 10배), Wihlidal의 Frostbite 발표가 더 멀리 밀어붙였다. UE5 Nanite는 이 궤적의 눈에 보이는 종착점이다. 클러스터 컬링을 픽셀 단위까지 밀어붙인다.</p>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Haar와 Aaltonen, <a href="https://advances.realtimerendering.com/s2015/aaltonenhaar_siggraph2015_combined_final_footer_220dpi.pdf" target="_blank" rel="noreferrer">GPU-Driven Rendering Pipelines</a> (SIGGRAPH 2015, 어쌔신 크리드 유니티의 기초가 된 발표).</li>
<li>Wihlidal, <a href="http://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/" target="_blank" rel="noreferrer">Optimizing the Graphics Pipeline with Compute</a> (GDC 2016, Frostbite의 GPU 구동 prepass).</li>
<li>Karis, Stubbe, Wihlidal, <a href="https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf" target="_blank" rel="noreferrer">A Deep Dive into Nanite Virtualized Geometry</a> (SIGGRAPH 2021, meshlet 단위의 클러스터 컬링).</li>
<li>Liktor, <a href="https://research.activision.com/publications/2021/09/geometry-rendering-pipeline-architecture-at-activision" target="_blank" rel="noreferrer">Geometry Rendering Pipeline Architecture at Activision</a> (콜 오브 듀티 버전의 클러스터 컬링, 2021).</li>
</ul>
<h2 id="_5-인스턴스와-클러스터의-앞에서-뒤로-정렬" tabindex="-1">5. 인스턴스와 클러스터의 앞에서 뒤로 정렬 <a class="header-anchor" href="#_5-인스턴스와-클러스터의-앞에서-뒤로-정렬" aria-label="Permalink to &quot;5. 인스턴스와 클러스터의 앞에서 뒤로 정렬&quot;"></a></h2>
<p>prepass가 제 역할을 하기 시작하면 <em>순서</em>가 중요해진다. prepass는 깊이를 쓰지만 alpha 테스트를 통과한 프래그먼트에 대해서만 쓴다. 숲의 뒤쪽을 먼저 그리고 앞쪽을 나중에 그리면, 앞쪽 프래그먼트마다 뒤쪽 프래그먼트를 덮어쓰게 되고, prepass 셰이더는 뒤쪽을 위해 여전히 돈다. 앞에서 뒤로 그리면 연속된 draw call마다 더 작은 값으로 깊이 버퍼를 더 많이 채우고, Hi-Z는 셰이더가 돌기 전에 뒤쪽 프래그먼트를 점점 더 많이 걸러낸다.</p>
<p>거의 모든 최신 엔진이 prepass를 발행하기 전에 카메라까지의 거리로 식생 인스턴스를 정렬하는 이유가 이것이다. 정렬은 싸고(GPU에서 radix sort로 인스턴스 수십만 개를 한 번에 처리), prepass 자체를 스스로 가지치기하는 작업으로 바꿔준다. 클러스터 단위 컬링도 같은 이유로 meshlet 단위에서 정렬한다. 깊이 prepass와 앞에서 뒤로 순서는 각각이 좋고 조합하면 훌륭한 그런 한 쌍이다.</p>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Persson, <a href="http://www.humus.name/Articles/Persson_DepthInDepth.pdf" target="_blank" rel="noreferrer">Depth in-depth</a> (깊이 버퍼 순서, prepass 경제학, Hi-Z 동작에 대한 아키텍처 노트).</li>
<li>Giesen, <a href="https://fgiesen.wordpress.com/2011/07/04/a-trip-through-the-graphics-pipeline-2011-part-7/" target="_blank" rel="noreferrer">A trip through the graphics pipeline</a> (Hi-Z 걸러내기 비율이 그리는 순서에 어떻게 의존하는지에 대한 깊은 기술적 설명).</li>
<li>Wihlidal, <a href="http://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/" target="_blank" rel="noreferrer">Optimizing the Graphics Pipeline with Compute</a> (GDC 2016, Frostbite의 GPU 측 인스턴스 정렬 포함).</li>
</ul>
<h2 id="_6-디더링-lod-전환과-hashed-alpha" tabindex="-1">6. 디더링 LOD 전환과 hashed alpha <a class="header-anchor" href="#_6-디더링-lod-전환과-hashed-alpha" aria-label="Permalink to &quot;6. 디더링 LOD 전환과 hashed alpha&quot;"></a></h2>
<p>또 다른 큰 함정은 페이드다. 두 LOD 사이를 전환하거나(또는 카메라가 다가올 때 인스턴스를 페이드 인/아웃하는) 가장 순진한 방법은 alpha 블렌딩이다. 하지만 블렌딩된 지오메트리는 깊이 버퍼에 쓸 수 없어서, 페이드 중인 모든 나무를 느린 반투명 경로로 밀어넣고 prepass를 깨뜨린다. 해법은 지오메트리를 마스크 경로에 그대로 두고 <em>alpha 테스트 안에서</em> 페이드를 하는 것이다.</p>
<p>주요 기법 두 가지:</p>
<ul>
<li><strong>디더링 LOD 전환</strong>은 4x4 또는 8x8 Bayer 패턴(또는 화면 공간 블루 노이즈 텍스처)을 샘플링해서 픽셀별 컷오프 보정값으로 쓴다. 50% 블렌드 상태의 나무는 체커보드 형태로 픽셀이 살아남고, 빠진 픽셀은 다음 LOD의 상보적 체커보드가 채운다. TAA가 두세 프레임에 걸쳐 체커를 매끄러운 블렌드로 정리한다. 싸고, 안정적이고, 엔진의 다른 모든 것과 잘 어울린다.</li>
<li><strong>Hashed alpha testing</strong> (Wyman &amp; McGuire, I3D 2017)은 고정된 0.5 alpha 임계값을 픽셀별 [0,1) 해시 임계값으로 바꾼다. 보통은 완전히 사라질 먼 거리 alpha 지오메트리(밉맵된 alpha가 0.5 아래로 떨어지기 때문)가 안정적으로 흩어진 채 살아남는 픽셀들을 유지한다. 여기서도 TAA가 정리를 맡는다.</li>
</ul>
<p>두 기법 모두 식생을 깊이 prepass가 작동하는 불투명/마스크 경로에 유지하므로, 뭔가를 페이드 인하려고 반투명 렌더링 비용 전체를 치르지 않아도 된다. <strong>Alpha to coverage</strong>는 같은 아이디어의 MSAA 시대 사촌뻘이다. alpha를 서브픽셀 커버리지 마스크로 바꿔서, 마스크 경로를 떠나지 않고도 부분 투명을 얻는다. 함정은 A2C가 MSAA에서만 진가를 발휘한다는 점인데, 요즘 대부분의 최신 디퍼드 렌더러는 MSAA를 더 이상 쓰지 않는다.</p>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Wyman과 McGuire, <a href="https://research.nvidia.com/labs/rtr/publication/wyman2017hashed/" target="_blank" rel="noreferrer">Hashed Alpha Testing</a> (I3D 2017, hashed alpha의 정석 논문).</li>
<li>Castaño, <a href="http://the-witness.net/news/2010/09/computing-alpha-mipmaps/" target="_blank" rel="noreferrer">Computing Alpha Mipmaps</a> (The Witness 블로그, 먼 거리의 나무가 사라지지 않도록 alpha-tested 텍스처를 밉맵하는 올바른 방법).</li>
<li>Yuksel, <a href="https://cemyuksel.com/research/alphadistribution/alpha_distribution.pdf" target="_blank" rel="noreferrer">Alpha Distribution for Alpha Testing</a> (alpha 밉맵에 대한 더 최근의 개선).</li>
<li>NVIDIA, <a href="https://developer.nvidia.com/content/transparency-or-translucency-rendering" target="_blank" rel="noreferrer">Anti-Aliased Alpha Testing</a> (A2C, hashed alpha, 디더링 대안에 대한 개관).</li>
</ul>
<h2 id="_7-마스크-픽셀의-셰이딩-비용-줄이기" tabindex="-1">7. 마스크 픽셀의 셰이딩 비용 줄이기 <a class="header-anchor" href="#_7-마스크-픽셀의-셰이딩-비용-줄이기" aria-label="Permalink to &quot;7. 마스크 픽셀의 셰이딩 비용 줄이기&quot;"></a></h2>
<p>완벽한 prepass와 완벽한 컬링이 있어도, 보이는 식생 픽셀마다 한 번은 셰이딩해야 한다. 엔진은 그 비용도 줄인다:</p>
<ul>
<li><strong>더 싼 BRDF</strong>. 식생은 무광이라 완전한 Cook-Torrance 스페큘러 경로가 사실 필요 없다. wrapped-Lambertian 디퓨즈에 한 줄짜리 스페큘러 근사면 충분하다.</li>
<li><strong>저주파 노멀 맵</strong>. 잎은 이미 어수선하다. 보통 보는 거리에서는 256x256 노멀 맵이 1024x1024와 똑같아 보이고, 대역폭도 아낀다.</li>
<li><strong>패럴랙스 없음, 이방성 없음, 클리어코트 없음</strong>. 잎에서는 PBR 기능 메뉴를 다 끈다.</li>
<li>완전한 서브서피스 산란 대신 <strong>양면 박막 투과</strong>. 잎은 뒤에서 빛을 투과시키는데, 역광 내적 하나로 흉내 낼 수 있다.</li>
<li>일부 엔진의 <strong>절반 해상도 셰이딩</strong>. 식생은 1/4 또는 1/2 픽셀 레이트로 셰이딩한 뒤 업스케일한다. TAA의 확률적 노이즈가 리샘플링을 가려준다.</li>
<li>마스크 머티리얼에서는 기본적으로 <strong>디테일 텍스처와 데칼 생략</strong>.</li>
</ul>
<p>각각은 개별로 보면 작은 이득이다. 조합하면 마스크 식생 셰이더는 동등한 불투명 머티리얼보다 2-3배 빠르게 돌 수 있다.</p>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Lagarde와 de Rousiers, <a href="https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/" target="_blank" rel="noreferrer">Moving Frostbite to Physically Based Rendering 3.0, 식생과 투과에 관한 절</a> (SIGGRAPH 2014, 박막 양면 머티리얼을 위한 정석 PBR 조정).</li>
<li>Jimenez, <a href="https://www.iryoku.com/stare-into-the-future" target="_blank" rel="noreferrer">Next Generation Character Rendering</a> (wrapped-Lambertian과 역광 투과 수학. 원래는 피부용이지만 잎으로 널리 이식됐다).</li>
<li>Sanders, <a href="https://www.gdcvault.com/play/1025066/Between-Tech-and-Art-The" target="_blank" rel="noreferrer">Between Tech and Art: The Vegetation of Horizon Zero Dawn</a> (GDC 2018, Decima의 식생 셰이더 단순화).</li>
</ul>
<h2 id="_8-가시성-버퍼와-마스크-머티리얼을-위한-nanite" tabindex="-1">8. 가시성 버퍼와 마스크 머티리얼을 위한 Nanite <a class="header-anchor" href="#_8-가시성-버퍼와-마스크-머티리얼을-위한-nanite" aria-label="Permalink to &quot;8. 가시성 버퍼와 마스크 머티리얼을 위한 Nanite&quot;"></a></h2>
<p>overdraw에 대한 가장 깔끔한 답은 <em>셰이딩을 래스터화에서 완전히 분리하는</em> 것이다. 가시성 버퍼는 지오메트리를 얇은 버퍼(픽셀당 삼각형 ID와 인스턴스 ID만)로 래스터화한 다음, 그 가시성 버퍼를 읽어 픽셀마다 정확히 한 번 셰이딩하는 디퍼드 패스로 완전한 머티리얼을 돌린다. 구조상 셰이딩 단계에는 overdraw가 없다. Burns와 Hunt의 2013년 논문이 이 아이디어를 소개했고, UE5 Nanite는 그 양산 품질 구현이다. UE 5.5부터는 마스크 식생도 포함한다.</p>
<p>Nanite의 묘수는 이걸 클러스터 단위 가상화 지오메트리로 한다는 점이다. 그래서 래스터라이저 자체가 서브픽셀 삼각형에 대해 소프트웨어 경로로 돌면서 overdraw를 유계로 유지한다. Nanite의 마스크 머티리얼은 &quot;programmable raster&quot; 기능이 필요하다. alpha 테스트는 가시성 버퍼 패스 동안 돌지만, 머티리얼 셰이딩은 여전히 디퍼드 리졸브에서 보이는 픽셀마다 한 번씩 일어난다. 그 결과, 한때 마스크 머티리얼에서 느리기로 악명 높던 아주 빽빽한 Nanite 식생이 이제 불투명 머티리얼과 견줄 만하거나 오히려 더 싸졌다. 셰이딩 시점의 overdraw가 0이기 때문이다. 절충점이 하나 있다. 마스크 경로가 programmable-raster 비용을 더하기 때문에, 저폴리 마스크 카드 나무를 유지하기보다 고폴리 <em>불투명</em> 나무 지오메트리를 Nanite로 밀어넣는 게 나을 때가 많다.</p>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Burns와 Hunt, <a href="http://jcgt.org/published/0002/02/04/" target="_blank" rel="noreferrer">The Visibility Buffer: A Cache-Friendly Approach to Deferred Shading</a> (JCGT 2013, 원조 논문).</li>
<li>Karis, Stubbe, Wihlidal, <a href="https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf" target="_blank" rel="noreferrer">A Deep Dive into Nanite Virtualized Geometry</a> (SIGGRAPH 2021, 양산 아키텍처).</li>
<li>Epic, <a href="https://media.gdcvault.com/gdc2024/Slides/GDC+slide+presentations/Nanite+GPU+Driven+Materials.pdf" target="_blank" rel="noreferrer">Nanite GPU Driven Materials</a> (GDC 2024, 마스크 머티리얼과 programmable-raster 파이프라인 포함).</li>
<li><a href="https://www.sctheblog.com/blog/nanite-materials-notes/" target="_blank" rel="noreferrer">Notes from &quot;Nanite GPU Driven Materials&quot;</a> (같은 발표를 깔끔하게 정리한 제3자 정리).</li>
</ul>
<h2 id="_9-식생을-위한-별도의-그림자-표현" tabindex="-1">9. 식생을 위한 별도의 그림자 표현 <a class="header-anchor" href="#_9-식생을-위한-별도의-그림자-표현" aria-label="Permalink to &quot;9. 식생을 위한 별도의 그림자 표현&quot;"></a></h2>
<p>alpha-tested 식생의 그림자 맵은 어느 오픈월드 프레임에서든 큰 캐스케이드 다음으로 두 번째로 비싼 그림자 문제다. 캐스케이드마다 자기만의 깊이 prepass가 필요하고, prepass마다 alpha 테스트를 돌리며, 그 비용이 캐스케이드 4개와 광원 프러스텀 수십 개를 거치며 빠르게 쌓인다. 그래서 대부분의 엔진은 식생 색을 렌더링하는 것과 같은 방식으로 식생 그림자를 렌더링하지 않는다.</p>
<p>흔한 대체 방식:</p>
<ul>
<li><strong>메시 거리장 그림자</strong> (UE Lumen, 자체 엔진). 각 메시는 미리 계산된 signed distance field를 갖는다. SDF를 짧게 콘 트레이스하면 alpha-tested 메시를 전혀 건드리지 않고도 부드러운 그림자를 얻는다. 나무에 특히 좋다. SDF가 나뭇잎 하나하나의 디테일은 무시하고 수관 실루엣을 하나의 단단한 덩어리로 포착하기 때문이다.</li>
<li><strong>식생용 저해상도 캐스케이드</strong>. 식생 그림자는 절반 해상도 슬라이스로 들어가고 엣지 인식 필터링으로 업샘플링된다. 그림자가 이미 부드러워서 눈은 해상도 저하를 알아차리지 못한다.</li>
<li><strong>MSAA를 곁들인 alpha-to-coverage 그림자 맵</strong>. 그림자 경로에 아직 MSAA가 있는 엔진에서는 A2C가 완전한 alpha 테스트 비용 없이 가장자리가 부드러운 식생 그림자를 만든다.</li>
<li><strong>줄기와 큰 가지에는 캡슐 그림자</strong>, 수관에는 거리장, 완전한 alpha 테스트는 가장 가까운 캐스케이드에서만. 거리에 따라 다른 표현을 쓰고 라이팅 패스에서 블렌딩한다.</li>
<li><strong>WPO 비활성화 거리</strong>. 바람으로 구동되는 World Position Offset이 임계값을 넘으면 꺼져서, 캐싱된 그림자 데이터가 프레임 간에 유효하게 유지된다. UE의 Virtual Shadow Maps가 이걸 크게 활용한다.</li>
</ul>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Epic, <a href="https://dev.epicgames.com/documentation/unreal-engine/distance-field-soft-shadows-in-unreal-engine" target="_blank" rel="noreferrer">Distance Field Soft Shadows in Unreal Engine</a> (메시 DF 그림자에 대한 정석 UE 참고 자료).</li>
<li>Wright, <a href="https://advances.realtimerendering.com/s2022/SIGGRAPH2022-Advances-Lumen-Wright%20et%20al.pdf" target="_blank" rel="noreferrer">Lumen: Real-Time Global Illumination in Unreal Engine 5</a> (SIGGRAPH 2022, Lumen의 식생용 메시 SDF 통합).</li>
<li>Epic, <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/virtual-shadow-maps-in-unreal-engine" target="_blank" rel="noreferrer">Virtual Shadow Maps</a> (최신 UE5 그림자 아키텍처, 식생 전용 WPO 비활성화 및 캐싱 규칙 포함).</li>
<li>Persson, <a href="https://www.humus.name/index.php?page=3D&amp;ID=81" target="_blank" rel="noreferrer">Practical Cascaded Shadow Maps</a> (alpha-tested 캐스터에 대한 노트를 담은, 여전히 정석인 CSM 참고 자료).</li>
</ul>
<h2 id="_10-바람-애니메이션-그림자-캐싱" tabindex="-1">10. 바람, 애니메이션, 그림자 캐싱 <a class="header-anchor" href="#_10-바람-애니메이션-그림자-캐싱" aria-label="Permalink to &quot;10. 바람, 애니메이션, 그림자 캐싱&quot;"></a></h2>
<p>미묘하게 연관된 문제가 하나 있다. 대부분의 식생은 움직인다. 바람으로 구동되는 정점 애니메이션(UE의 World Position Offset, Frostbite와 Decima의 대응 기능)은 식생 지오메트리가 프레임 간에 안정적이지 않다는 뜻이고, 이건 그림자 캐싱과 리프로젝션을 깨뜨린다. 최신 엔진은 두 가지 방식으로 이에 맞선다:</p>
<ul>
<li><strong>거리에서 WPO 제한</strong>. 임계값을 넘으면 바람 애니메이션 진폭이 매끄럽게 0으로 간다. 그 정도 멀어지면 어차피 눈으로 흔들림을 볼 수 없고, 그림자 캐시는 유효하게 유지된다.</li>
<li><strong>바람을 클러스터 경계에 굽기</strong>. 클러스터 경계 상자를 최대 WPO 오프셋만큼 부풀려서, 프레임마다 다시 업로드하지 않고도 컬링이 보수적으로 유지되게 한다.</li>
<li><strong>인스턴스별 위상 오프셋</strong>. 똑같은 나무들이 인스턴스별 랜덤 시드로 바람 위상을 어긋나게 해서, 나무마다 고유 애니메이션을 치르지 않으면서도 숲이 일사불란하게 흔들리지 않게 한다.</li>
</ul>
<p>이런 종류의 디테일은 기법 목록에는 안 나오지만, 실전에서 3 ms 숲과 9 ms 숲을 가르는 차이다.</p>
<p>깊이 있게 읽을 자료:</p>
<ul>
<li>Sanders, <a href="https://www.gdcvault.com/play/1025066/Between-Tech-and-Art-The" target="_blank" rel="noreferrer">Between Tech and Art: The Vegetation of Horizon Zero Dawn</a> (GDC 2018, Decima의 바람 애니메이션 파이프라인과 그림자 캐싱).</li>
<li>McAuley, <a href="https://www.gdcvault.com/play/1022235/Rendering-the-World-of-Far" target="_blank" rel="noreferrer">Rendering the World of Far Cry 4</a> (GDC 2015, 식생을 위한 바람 그리드 샘플링 포함).</li>
<li>Epic, <a href="https://dev.epicgames.com/community/learning/tutorials/qLk6/unreal-engine-virtual-shadow-maps" target="_blank" rel="noreferrer">Foliage and Virtual Shadow Maps</a> (WPO 비활성화 거리와 VSM 캐싱에 대한 UE5 커뮤니티 안내).</li>
</ul>
<h2 id="_11-합쳐서-따져보는-계산" tabindex="-1">11. 합쳐서 따져보는 계산 <a class="header-anchor" href="#_11-합쳐서-따져보는-계산" aria-label="Permalink to &quot;11. 합쳐서 따져보는 계산&quot;"></a></h2>
<p>이 트릭들 중 어느 하나도 만능 해결책은 아니다. 흥미로운 건 이걸 쌓았을 때 무슨 일이 벌어지는가다:</p>
<ul>
<li>빽빽한 숲 장면에서 순진한 마스크 식생 패스는 실효 overdraw가 8-15배로 측정된다. 보이는 픽셀마다 잎 셰이더를 8번에서 15번 돌린다.</li>
<li>깊이 prepass를 더하면 메인 패스의 overdraw가 ~1배로 떨어지지만, prepass 자체는 여전히 모든 걸 건드린다.</li>
<li>앞에서 뒤로 정렬을 더하면 prepass가 스스로 가지치기를 시작한다.</li>
<li>클러스터 단위 GPU 컬링을 더하면 prepass는 보일 가능성이 있는 것만 건드린다.</li>
<li>LOD 체인과 임포스터를 더하면 30 m 너머에서 보이는 쿼드의 <em>개수</em>가 한 자릿수 차수만큼 떨어진다.</li>
<li>가시성 버퍼 / Nanite 경로를 더하면 빽빽하게 겹쳐도 셰이딩 단계가 진정 픽셀당 한 번만 돈다.</li>
<li>거리장 그림자를 더하면 그림자 비용이 더 이상 alpha 테스트에 비례해 늘지 않는다.</li>
</ul>
<p>위에 링크한 발표들에서 반복되는 핵심 결론은 이렇다. 실효 overdraw가 8-15배에서 1-2배로 무너지고, 빽빽한 숲 장면에서 전체 식생 프레임 비용이 4-6배 떨어진다. 최신 오픈월드 게임이 소비자용 하드웨어에서 숲을 60+ fps로 렌더링할 수 있는 이유가 통째로 이것이다.</p>
<img src="/img/blog/foliage_overdraw_pipeline.webp" alt="Diagram showing the foliage rendering pipeline as five stacked stages: GPU culling, sorted prepass, masked color pass with depth-equal, visibility-buffer shading, and separate distance-field shadow path" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<h2 id="_12-이것이-브라우저에-갖는-의미" tabindex="-1">12. 이것이 브라우저에 갖는 의미 <a class="header-anchor" href="#_12-이것이-브라우저에-갖는-의미" aria-label="Permalink to &quot;12. 이것이 브라우저에 갖는 의미&quot;"></a></h2>
<p>이 스택의 대부분은 WebGPU에 깔끔하게 매핑된다. 우리는 이미 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">오픈월드 브라우저 엔진</a>에서 GPU 구동 컬링, 간접 디스패치, Hi-Z 오클루전, 앞에서 뒤로 정렬한 prepass를 출시했다. 마스크 지오메트리를 위한 깊이 prepass는 간단하다. WebGPU는 depth-equal 테스트와 프래그먼트 셰이더의 <code>discard</code>를 지원하고, early-Z에 관한 주의사항도 똑같다. 팔면체 임포스터는 기계적으로 이식된다. 수학은 그저 구면에서 팔면체로의 펼침과 아틀라스 인덱싱일 뿐이다.</p>
<p>더 어려운 건 최신 기법들이다. WebGPU의 가시성 버퍼는 32비트 삼각형 ID를 렌더 타깃에 쓰고 풀스크린 compute 패스에서 머티리얼을 리졸브하는 것을 뜻한다. 구성 요소는 다 있지만 조율이 까다롭다. 메시 거리장 그림자는 에셋당 3D 텍스처 하나와 짧은 콘 트레이스를 원하는데, 둘 다 WebGPU의 사정거리 안에 있다. Hashed alpha와 디더링 LOD는 각각 셰이더 함수 하나면 된다.</p>
<p>브라우저 식생이 나아갈 길은 이 스택의 다른 모든 것과 같다. 싸고 견고한 부품(prepass, 정렬된 인스턴스, LOD, 임포스터, hashed alpha)을 먼저 출시하고, 그 위에 무거운 기계장치(가시성 버퍼, 메시 SDF 그림자)를 얹는다. 브라우저 하드웨어 하한선이 마침내 충분히 높아져서, WebGPU 숲이 콘솔 숲처럼 보이고 돌지 못할 구조적 이유는 없다. 그저 엔지니어링상의 이유만 있을 뿐이고, 엔지니어링상의 이유는 우리가 좋아하는 종류다.</p>
<h2 id="스택-전체에-걸친-더-읽을거리" tabindex="-1">스택 전체에 걸친 더 읽을거리 <a class="header-anchor" href="#스택-전체에-걸친-더-읽을거리" aria-label="Permalink to &quot;스택 전체에 걸친 더 읽을거리&quot;"></a></h2>
<p>이 모든 걸 하나로 엮은 자료를 원한다면, SIGGRAPH &quot;Advances in Real-Time Rendering in Games&quot; 아카이브(<a href="https://advances.realtimerendering.com/" target="_blank" rel="noreferrer">advances.realtimerendering.com</a>)에 2014년까지 거슬러 올라가는 식생과 GPU 구동 렌더링의 정석 발표들이 있다. Adrian Courrèges의 <a href="http://www.adriancourreges.com/blog/" target="_blank" rel="noreferrer">GPU 프로파일링 글들</a>에는 GTA V와 Horizon Zero Dawn의 프레임별 분석이 있어서, 여기서 다룬 모든 패스를 양산 순서대로 보여준다. alpha 테스트 수학 자체로는 Chris Wyman의 <a href="https://cwyman.org/" target="_blank" rel="noreferrer">연구 페이지</a>에 hashed alpha와 확률적 투명 논문이 참조 셰이더와 함께 있다. 그리고 <a href="https://www.realtimerendering.com/" target="_blank" rel="noreferrer">Real-Time Rendering, 4th edition</a>의 투명, 샘플링, 깊이 처리 장은 여전히 교과서적 출발점이다.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 25부: 골격 하나로 모든 의상]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-10-open-world-browser-part-25-universal-characters</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-10-open-world-browser-part-25-universal-characters</guid>
            <pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 50은 CC0 캐릭터 팩 하나가 아바타 커스터마이징 제품 전체를 떠받칠 수 있는지 시험했다. 네 개의 Quaternius 팩이 의도적으로 동일한 65개 관절 골격을 공유한다는 게 드러났고, 그 덕에 이 spike는 애니메이션 파이프라인 문제에서 이름 기준 골격 재바인딩 작업으로 바뀌었다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-25부-골격-하나로-모든-의상" tabindex="-1">브라우저에서 오픈 월드 만들기, 25부: 골격 하나로 모든 의상 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-25부-골격-하나로-모든-의상" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 25부: 골격 하나로 모든 의상&quot;"></a></h1>
<p><em>작성: <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 보시나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind.html">24부</a>에서는 세계를 영속적으로 만들고 식생에 바람을 입혔습니다. 이번 부분은 다시 그 안의 사람들 이야기인데, 이번엔 옷장 쪽에서 봅니다. 창작자가 기본 몸을 고르고, 옷을 바꾸고, 헤어스타일을 고르고, 아무 애니메이션이나 재생하는 것을, 전부 무료 에셋 팩 하나만으로, 리깅도 애니메이션 제작도 없이 할 수 있을까요? 커스텀 리그를 만드는 건 디리스크할 대상이 아닙니다. 답할 가치가 있는 질문은 CC0 팩 하나가 짐 전체를 짊어질 수 있느냐입니다.</p>
<h2 id="애초에-서로-맞물리도록-만들어진-팩" tabindex="-1">애초에 서로 맞물리도록 만들어진 팩 <a class="header-anchor" href="#애초에-서로-맞물리도록-만들어진-팩" aria-label="Permalink to &quot;애초에 서로 맞물리도록 만들어진 팩&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/50-universal-characters/" title="Spike 50 Universal Characters" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/50-universal-characters/" target="_blank">새 탭에서 Spike 50 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=50-universal-characters">소스 보기</a></p>
<p>Quaternius는 의심스러울 만큼 잘 들어맞는 에셋 네 개를 제공합니다. Universal Base Characters는 남성과 여성 몸에 헤어스타일 여덟 가지와 눈썹 세트 두 가지를 더한 것이고, Modular Character Outfits는 몸통, 팔, 다리, 발 부위로 나뉘며 견갑(pauldron)과 후드 같은 액세서리가 딸려 있고, Universal Animation Library 1번과 2번 팩은 도합 262개 클립으로 이동, 전투, 등반, 농사, 낚시, 대기 동작, 사교 동작을 다룹니다. 이들의 glTF를 살펴보니 왜 들어맞는지 드러났습니다. 네 팩의 모든 메시 하나하나가 똑같은 65개 관절의 UE5 스타일 골격에 리깅되어 있고, 관절 이름도 같고, 바인드 포즈도 같으며, root에서 pelvis, spine을 거쳐 head까지, 양쪽이 미러링된 팔에 각 측마다 손가락 관절 열다섯 개, 미러링된 다리까지 동일합니다. 리타기팅이 전혀 필요 없습니다. 이건 Spike 35의 세 골격 리타기팅 문제와 정확히 반대입니다. 거기서는 213개 뼈의 얼굴 리그가 65개 뼈의 Mixamo 리그와 대화해야 했죠. 여기서는 네 팩 모두 의도적으로 애니메이션 라이브러리의 골격 위에서 제작되었고, 결합이 정확합니다.</p>
<p>그래서 이 spike는 애니메이션 파이프라인 작업이 아니라 바인딩 작업이 되었습니다. 베이스 레이어는 몸 glTF를 불러오고, <code>SkeletonUtils.clone</code>으로 씬을 복제해 각 캐릭터가 로더의 캐시된 씬에 뼈 변형을 다시 흘려보내는 대신 새 골격 인스턴스를 받게 하며, 그 65개 뼈 골격을 애니메이션을 떠받치는 아마추어 객체와 함께 표준(canonical) 버전으로 캐싱합니다.</p>
<h2 id="코트를-몸에-다시-바인딩하기" tabindex="-1">코트를 몸에 다시 바인딩하기 <a class="header-anchor" href="#코트를-몸에-다시-바인딩하기" aria-label="Permalink to &quot;코트를 몸에 다시 바인딩하기&quot;"></a></h2>
<p>이 모든 걸 동작하게 하는 요령은, 의상의 메시를 그냥 씬에 다시 부모로 붙일 수 없다는 점입니다. 그 메시는 여전히 자기 glTF의 뼈를 참조하고 있고, 그 뼈들은 다른 서브트리에 자리 잡고 있기 때문입니다. 각 모듈식 부위, 농민의 몸이든 레인저의 다리든, 같은 아마추어의 자기 클론을 지닌 자기만의 SkinnedMesh로 도착합니다. 바인딩은 소스 골격의 뼈를 원래 순서대로 훑으면서 각 뼈를 표준 골격에서 이름으로 찾아내고, 그 재바인딩된 뼈들로 새 <code>Skeleton</code>을 만들면서 소스의 bind-inverse 행렬을 재사용한 다음, 소스의 단위 bind 행렬로 <code>SkinnedMesh.bind</code>를 호출합니다. 바인딩 후에는 메시가 소스 씬에서 분리되어 캐릭터 root 바로 아래에 부모로 붙습니다. bind 행렬이 바인드 시점의 월드 변환을 담고 있고 root가 단위 변환에 자리하므로, 메시 자신의 월드 변환은 결과에 전혀 영향을 주지 않으며 스키닝은 전적으로 이제 공유된 뼈를 통해 일어납니다.</p>
<p>머리카락과 눈썹도 슬롯이며, 이들은 잘못된 가정을 바로잡아 줬습니다. 폴더 구조에는 &quot;head 뼈에 리깅됨&quot;이라고 적혀 있었고, 이는 머리카락이 구운 오프셋으로 머리에 부모로 붙은 정적 메시일 거라고 암시했습니다. 그렇지 않았습니다. 모든 머리카락 파일은 65개 관절 전체에 걸쳐 가중치가 분포된 SkinnedMesh이며, 긴 머리의 가중치는 위쪽 spine과 목까지 번져 들어가 캐릭터가 고개를 숙일 때 머리가 드리워집니다. 그래서 머리카락도 다른 의상 부위와 똑같은 이름 기준 재바인딩 경로를 탑니다. 유일한 특수 사례는 의상의 몸통 슬롯입니다. 이게 부착되면 의상이 뚫고 나오지 않도록 베이스 몸 메시가 숨겨지고, 팔, 다리, 발, 액세서리는 그냥 쌓입니다. 팩이 옷이 피부를 드러내는 곳마다 베이스 몸이 비쳐 나오도록 공존하게 제작했기 때문입니다.</p>
<h2 id="_262개-애니메이션이-공짜로" tabindex="-1">262개 애니메이션이 공짜로 <a class="header-anchor" href="#_262개-애니메이션이-공짜로" aria-label="Permalink to &quot;262개 애니메이션이 공짜로&quot;"></a></h2>
<p>골격이 공유되고 나면 애니메이션은 거의 김 빠질 만큼 싱겁습니다. 라이브러리 glb 두 개를 불러오면 그 클립들이 이름 붙은 하나의 목록으로 펼쳐지고, 그 클립 안의 트랙 이름들은 <code>bone.position</code>, <code>bone.quaternion</code>, <code>bone.scale</code>로 정확한 관절 이름을 참조합니다. 캐릭터의 아마추어에 뿌리내린 <code>AnimationMixer</code>가 그 뼈들을 이름으로 찾아 직접 구동하고, 전환 시 크로스페이드합니다. 뷰어의 오른쪽 패널은 262개 클립 전체를 필터링할 수 있는 목록이고 소스 표시 알약(pill)이 달려 있어서, &quot;fish&quot;를 검색하면 두 라이브러리에 걸친 모든 낚시 애니메이션이 떠오릅니다. 부드러운 그림자가 있는 표준 3점 조명, 발밑의 극좌표 그리드, ACES 톤 매핑이 스타일화된 베이스 텍스처를 읽기 좋게 유지하면서도 어두운 바디수트의 그림자를 으스러뜨리지 않습니다.</p>
<p>이것이 제품을 위해 디리스크하는 것은 큽니다. 아바타 커스터마이징 기능은 리깅 작업 제로, 애니메이션 제작 제로로 CC0 팩 위에서 출시할 수 있습니다. 네 팩을 넣고, 옷장 UI를 연결하면, 대략 의상 여섯 가지 곱하기 헤어스타일 여덟 가지 곱하기 성별 두 가지 곱하기 애니메이션 262개만큼의 변형이 박스째로 나옵니다. 65개 관절 골격은 충분히 작아서 GPU 스키닝 비용이 무시할 만하고, Spike 45의 배치 스키닝 작업이 이미 이 정도 규모의 리그에서 아바타 200개 이상을 처리합니다. CC0는 사용 제한이 전혀 없어서 유료 창작자 플랫폼에서 상업적으로 써도 괜찮습니다. 남은 미해결 질문은 사용자가 직접 업로드한 의상인데, 이는 Phase 3 문제로, 업로드 시점에 이 표준 골격으로 리타기팅하면 풀립니다. Spike 35의 런타임 리타기팅을 거꾸로 뒤집은 셈이죠. 에셋 용량은 디스크에서 약 147MB로 원본 2K PNG와 무압축 애니메이션 glb입니다. 프로덕션에서는 KTX2 텍스처 압축과 gltf-transform 한 번을 거치면 대략 30MB로 줄어듭니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>팩 전체에 걸친 표준 골격 하나.</strong> 네 개의 Quaternius 팩(베이스 몸, 모듈식 의상, 두 개의 애니메이션 라이브러리)은 전부 동일한 65개 관절의 UE5 스타일 골격에 리깅되어 있고 관절 이름과 바인드 포즈가 같아서, 이들을 조합하는 데 리타기팅이 필요 없습니다. <code>SkeletonUtils.clone</code>으로 베이스를 복제하면 로더의 캐시된 씬을 변형하는 대신 각 캐릭터가 새 골격 인스턴스를 받습니다.</p>
<p><strong>이름 기준 골격 재바인딩.</strong> 각 모듈식 부위는 자기 아마추어를 참조하는 자기만의 SkinnedMesh를 가지고 옵니다. 재바인딩은 소스 뼈를 순서대로 훑으며 각각을 이름으로 표준 골격에 매핑하고, 소스의 bind-inverse를 재사용해 새 <code>Skeleton</code>을 만들고, 단위 bind 행렬로 <code>SkinnedMesh.bind</code>를 호출한 다음, 메시를 공유 캐릭터 root 아래에 부모로 붙여 스키닝이 전적으로 공유 뼈를 통해 돌아가게 합니다. 의상의 몸통 슬롯은 뚫림(clipping)을 피하려고 베이스 몸을 숨기고, 다른 슬롯은 그냥 쌓입니다.</p>
<p><strong>스키닝 슬롯으로서의 머리카락.</strong> 머리카락은 head 뼈에 붙은 정적 부착물이 아니라 65개 관절 전체에 걸쳐 가중치가 분포된 SkinnedMesh이고, 긴 머리는 위쪽 spine과 목에 가중치가 들어가 고개를 숙일 때 드리워집니다. 의상 부위와 똑같은 재바인딩 경로를 탑니다.</p>
<p><strong>이름 키 기반 애니메이션 리타기팅이 공짜로.</strong> Animation Library 클립은 관절을 정확한 이름으로 참조하므로, 공유 아마추어에 뿌리내린 <code>AnimationMixer</code>가 클립별 리타기팅 없이 크로스페이드로 262개 클립 전부를 직접 구동합니다. CC0 라이선스가 상업적 사용을 커버하고, 적은 관절 수 덕분에 GPU 스키닝이 충분히 저렴해서 Spike 45의 배치 스키닝 경로를 재사용할 수 있습니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">GPU 주도 LOD</a>를 보세요.</p>
<hr>
<p>29부 중 25부.
이전: <a href="/ko/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind.html">24부 - 세계를 저장하기, 그리고 눈에 보이는 바람</a>
다음: <a href="/ko/blog/2026-05-12-open-world-browser-part-26-water.html">26부 - 모든 스케일에서 버티는 물</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 24부: 월드를 저장하기, 그리고 눈에 보이는 바람]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind</guid>
            <pubDate>Sat, 09 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 47은 월드 편집이 남도록 만들었습니다. 소유권을 중재하고, chunk별 바이너리 blob을 영속화하고, 가환 편집 프로토콜로 모든 peer의 지형을 수렴시키는 Durable Object입니다. Spike 49는 Quaternius의 Godot 바람 셰이더를 TSL로 충실하게 이식한 뒤, 장면을 1 fps로 떨어뜨린 프레임마다 일어나는 재컴파일을 쫓았습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-24부-월드를-저장하기-그리고-눈에-보이는-바람" tabindex="-1">브라우저에서 오픈 월드 만들기, 24부: 월드를 저장하기, 그리고 눈에 보이는 바람 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-24부-월드를-저장하기-그리고-눈에-보이는-바람" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 24부: 월드를 저장하기, 그리고 눈에 보이는 바람&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice.html">23부</a>에서는 사람들을 월드 안에 넣고 목소리를 주었습니다. 이번 부분은 월드가 사람들이 자신에게 한 일을 기억하게 만들고, 아무도 건드리지 않을 때에도 살아 있는 느낌을 주는 이야기입니다. Spike 47은 영속화입니다. 창작자가 지형을 조각하고 소품을 배치하면, 그 편집이 다시 로드해도 살아남고, 다른 모든 peer로 동기화되고, 두 사람이 동시에 편집할 때 깔끔하게 중재됩니다. Spike 49는 바람입니다. 양식화된 자연 에셋 팩의 식생 셰이더를 이식해서 나무, 덤불, 풀이 아티스트가 의도한 대로 움직이게 했는데, 이건 수학보다는 셰이더 컴파일러와의 싸움에 더 가까워졌습니다.</p>
<h2 id="기억하는-월드" tabindex="-1">기억하는 월드 <a class="header-anchor" href="#기억하는-월드" aria-label="Permalink to &quot;기억하는 월드&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/47-world-persistence/" title="Spike 47 World Persistence" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/47-world-persistence/" target="_blank">새 탭에서 Spike 47 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=47-world-persistence">소스 보기</a></p>
<p>설정은 공유 창작 세션입니다. 플레이어가 월드를 걸어 다니며 클릭으로 소품을 배치하고, 우클릭으로 제거하고, 브러시를 드래그해 지면을 조각합니다. 높이맵을 올리고 내리거나, 한 chunk를 marching cubes로 승격시키는 SDF 지형을 통해 부피 있는 동굴을 파냅니다. 이들이 하는 모든 것은 Cloudflare <code>WorldChunkDO</code>에 영속화됩니다. 자체 SQLite 저장소로 뒷받침되는, 서버 권위형 Durable Object입니다. 클라이언트는 상태를 직접 쓰지 않습니다. 클라이언트는 의도를 보내고, DO가 중재하고 결과를 브로드캐스트하며, DO가 유일한 진실의 원천이기 때문에 새로 들어온 사람은 스냅샷을 받아 다른 모든 사람이 보는 것과 정확히 같은 월드에 안착합니다.</p>
<p>두 가지 영속화 세부 사항이 제 몫을 해냈습니다. 지형은 들어올 때 다시 재생하는 이벤트 로그로 저장되지 않습니다. chunk별 바이너리 blob으로 저장되는데, 이 blob이 진실의 원천이고 스트로크가 끝날 때 업로드되므로, 들어온 사람은 수천 번의 브러시 샘플을 다시 돌리는 대신 커밋된 바이트를 직접 로드합니다. 그리고 그 blob은 큰 한 행이 아니라 chunk당 저장 키 하나로 살아 있습니다. 단일 SDF chunk가 168 KB이고 DO에는 행당 2 MB 제한이 있기 때문입니다. chunk 인덱스가 어떤 키가 존재하는지 추적하므로 DO는 깨어날 때 맵 전체를 다시 수화할 수 있습니다. 신원은 클라이언트에서 두 가지 저장소로 처리됩니다. 플레이어 id는 <code>sessionStorage</code>에 살아서 두 탭이 한 peer가 DO의 플레이어 맵에서 자기 자신을 덮어쓰는 게 아니라 서로 다른 두 peer가 되고, 표시 이름은 <code>localStorage</code>에 살아서 한 탭에서 이름을 바꾸면 모든 탭에 걸쳐 적용됩니다.</p>
<h2 id="동시-편집을-수렴시키기" tabindex="-1">동시 편집을 수렴시키기 <a class="header-anchor" href="#동시-편집을-수렴시키기" aria-label="Permalink to &quot;동시 편집을 수렴시키기&quot;"></a></h2>
<p>멀티플레이어 창작에서 정말로 어려운 부분은 두 사람이 같은 순간에 겹치는 지면을 편집할 때 무슨 일이 벌어지느냐입니다. 이 spike는 편집을 그 대수로 나눕니다. 덧셈 연산, 즉 높이맵에서의 올리기와 내리기, SDF에서의 더하기와 빼기는 가환입니다. 어떤 순서로 적용해도 같은 결과에 도달하므로, 이들은 낙관적-스탬프 경로를 탑니다. 각 클라이언트가 로컬에서 적용하고 스탬프를 보내면 DO가 조율 없이 그것을 모두에게 브로드캐스트합니다. 순서가 정말로 상관없으니 조율할 것이 없습니다.</p>
<p>순서에 의존하는 연산, 즉 스무딩과 평탄화가 흥미로운 경우였습니다. 첫 설계는 이들에게 영역 잠금을 주었습니다. 클라이언트가 포인터를 누를 때 잠금을 요청하면 DO가 허가하거나 거부하고, 클라이언트는 누르고 있는 동안 샘플을 버퍼링하며, 포인터를 뗄 때 DO가 스트로크 전체를 원자적으로 적용합니다. 작동하긴 하지만, 자체 잠금 TTL과 허가/거부 왕복을 가진 별개의 프로토콜입니다. 이를 대체한 더 깔끔한 답은 미리 계산된 delta입니다. 발신자가 스무딩이나 평탄화 브러시를 로컬에서 돌린 뒤 그 결과인 셀별 delta 목록을 보내면, 각 peer는 아무것도 다시 유도하지 않고 그 delta를 자기 셀에 더하기만 하면 됩니다. 이는 결과를 원천에서 얼려 버림으로써 순서 의존 연산을 가환 연산으로 바꿉니다. 그래서 편집 시스템 전체가 동일한 수렴 결과를 가진 하나의 균일한 가환 프로토콜 위에서, 잠금 없이 완전히 돌아갑니다. 소품 잠금은 다른 이유로 살아남았습니다. 레코드별 잠금이 소유자만 삭제 가능하던 방식을 대체해서, 누가 잠그지 않은 한 어떤 peer든 어떤 소품이든 삭제할 수 있고, 잠근 사람만 그것을 풀 수 있습니다. 실행 취소와 재실행은 클라이언트가 소품을 배치하기 전에 그 id를 직접 이름 짓게 함으로써 작동합니다. 그래서 서버 응답 이전에 id를 알고 자기 동작을 결정론적으로 되돌릴 수 있습니다. Hibernating WebSocket이 줄곧 유휴 방을 무료로 유지하는데, 이전 부분에서 avatar 릴레이를 저렴하게 만든 바로 그 성질입니다.</p>
<h2 id="충실하게-이식한-바람-그리고-시작된-싸움" tabindex="-1">충실하게 이식한 바람, 그리고 시작된 싸움 <a class="header-anchor" href="#충실하게-이식한-바람-그리고-시작된-싸움" aria-label="Permalink to &quot;충실하게 이식한 바람, 그리고 시작된 싸움&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/49-gpu-wind-props/" title="Spike 49 GPU Wind Props" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/49-gpu-wind-props/" target="_blank">새 탭에서 Spike 49 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=49-gpu-wind-props">소스 보기</a></p>
<p>Spike 49는 Quaternius의 Stylized Nature MegaKit을 가져와 그 바람을 우리 스택으로 이식합니다. 이 팩은 소스 Godot 셰이더 네 개를 함께 제공하는데, 올바른 선택은 재발명이 아니라 충실한 번역이었습니다. Bark는 빈 정점 함수를 가지므로 줄기는 강체입니다. 앞선 절차적 마스크 시도가 줄기를 흔들리게 만들고 있었는데, 해결책은 그냥 bark에 바람을 아예 적용하지 않는 것이었습니다. Leaves는 삼각 펄스 해시에서 정점별 무질서한 흔들림을 얻고, 높이로 마스킹되어 수관은 움직이고 밑동은 심긴 채로 있습니다. Base foliage는 월드 공간에서 노이즈로 변조된 sin/cos 흔들림을 얻습니다. Grass는 base foliage에 wind-line 흔들림을 더한 것으로, 거듭제곱 곡선을 통해 스크롤하는 노이즈 텍스처를 샘플링해서 텍스처의 밝은 띠만 기여하게 합니다. 이것이 초원을 가로질러 이동하는 눈에 보이는 잔물결을 만들어 냅니다. 디스패치는 팩 자체의 머티리얼 명명 규칙을 따르므로, <code>Leaves_Birch</code>라는 머티리얼은 leaves 경로로, <code>Grass_Common</code>은 grass 경로로 라우팅되며 추측할 필요가 없습니다.</p>
<p>이식에서 나온 놀라움은 잎 색이 텍스처에 없다는 점입니다. Quaternius는 잎의 외형을 전적으로 수직 그라디언트와 Fresnel 림으로 만듭니다. 알베도는 수관 아래쪽의 추가 색에서 위쪽의 잎 색으로 가는 혼합이며 높이로 키잉되고, 여기에 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="12.282ex" height="2.451ex" role="img" focusable="false" viewBox="0 -833.2 5428.4 1083.2" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(389,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1111.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(2111.4,0)"><g data-mml-node="mi"><path data-c="1D40D" d="M314 0Q296 3 181 3T48 0H39V62H147V624H39V686H171H265Q288 686 297 686T309 684T315 679Q317 676 500 455T684 233V624H576V686H585Q603 683 718 683T851 686H860V624H752V319Q752 15 750 11Q747 4 742 2T718 0H712Q708 0 706 0T700 0T696 1T693 2T690 4T687 7T684 11T679 16T674 23Q671 27 437 311L215 579V62H323V0H314Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3233.7,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(3733.9,0)"><g data-mml-node="mi"><path data-c="1D415" d="M592 686H604Q615 685 631 685T666 684T700 684T724 683Q829 683 835 686H843V624H744L611 315Q584 254 546 165Q492 40 482 19T461 -6L460 -7H409Q398 -4 391 9Q385 20 257 315L124 624H25V686H36Q57 683 190 683Q340 683 364 686H377V624H289L384 403L480 185L492 212Q504 240 529 298T575 405L670 624H582V686H592Z" style="stroke-width: 3;"/></g></g><g data-mml-node="msup" transform="translate(4602.9,0)"><g data-mml-node="mo"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(422,363) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">N</mi></mrow><mo>⋅</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">V</mi></mrow><msup><mo stretchy="false">)</mo><mn>3</mn></msup></math></mjx-assistive-mml></mjx-container> Fresnel 항으로 스케일된 발광으로 더해진 표면하 산란 색조가 붙습니다. 평범한 텍스처 pass가 밋밋해 보였던 이유가 이것입니다. 색은 칠해진 맵이 아니라 그라디언트와 림에서 옵니다. 이식은 원시 로컬 Y 대신 베이크된 <code>heightFactor</code> 정점 속성을 읽으며, 로드 시점에 월드 공간 Y로부터 잎 그룹마다 정규화합니다. 그래서 FBX 임포트가 각 mesh의 로컬 축을 어떻게 회전시켰든 그라디언트와 바람 마스크가 모두 올바르게 동작합니다. Godot 색 상수는 sRGB로 태그되어 셰이더가 보기 전에 선형으로 변환되므로, 이식도 같은 변환을 합니다. 밝은 sRGB 수치를 선형인 양 그냥 먹여서 식생을 바래게 만드는 대신에요.</p>
<h2 id="프레임률을-먹어-치운-재컴파일" tabindex="-1">프레임률을 먹어 치운 재컴파일 <a class="header-anchor" href="#프레임률을-먹어-치운-재컴파일" aria-label="Permalink to &quot;프레임률을 먹어 치운 재컴파일&quot;"></a></h2>
<p>이것이 완전한 바람 머티리얼을 <code>.bak</code> 파일에 따로 빼 두고 먼저 FBX 기준선으로 출시된 이유는, 장면을 약 1 fps로 떨어뜨린 프레임마다 일어나는 재컴파일 버그 때문입니다. 커스텀 TSL을 FBX로 로드된 머티리얼 위에 얹으면 Three.js가 프레임마다 셰이더 프로그램을 다시 빌드하도록 촉발했고, <code>needsUpdate</code>가 사실상 켜진 채로 막혀 있었습니다. 진단 규율은 각 식생 머티리얼을 커스텀 노드가 없는 평범한 텍스처 pass로 되돌려 놓고 재컴파일 루프가 계속되는지 보는 것이었습니다. 멈추면 커스텀 그래프가 범인이고, 계속되면 원인은 상류의 FBX 머티리얼 설정이나 Three.js 자체에 있었습니다. 진짜 셰이더를 되돌아오게 한 수정은 머티리얼별 차이인 잎 색, SSS 색, 강도, 블렌드를 전부 uniform으로 바인딩해서, 컴파일러가 고유한 색 조합마다 새 셰이더를 내뱉어 컴파일 큐를 들쑤시는 대신 모든 잎 에셋이 컴파일된 프로그램 하나를 공유하게 한 것입니다.</p>
<p>기록해 둘 만한 조각이 두 개 더 있습니다. 풀은 소스 파일마다 <code>InstancedMesh</code> 하나로 렌더링되고, sin 위상이 월드 위치를 키로 삼기 때문에 그 바람은 월드 공간에서 계산됩니다. 하지만 변위는 인스턴스 행렬이 돌기 전에 로컬 공간에서 적용해야 하는데, WGSL에는 호출할 <code>inverse()</code>가 없습니다. 평행이동, Y 회전, 균일 스케일로 이루어진 인스턴스 행렬의 경우 상단 3×3의 역은 그저 그것의 전치를 스케일 제곱으로 나눈 것입니다. 그래서 셰이더는 월드 변위에 전치된 모델 행렬을 곱하고 행렬 첫 열 길이의 제곱으로 나누어, 제곱근 없이 스케일을 복원합니다. 정점 변환이 행렬을 다시 적용한 뒤, 운동은 각 풀 다발의 회전이나 스케일과 무관하게 정확히 만든 대로 월드 공간에 안착합니다. 그리고 각 풀 다발은 정점별 GPU 절두체 컬링을 돌립니다. 인스턴스 중심을 클립 공간으로 투영하고, 여유를 두고도 절두체 밖에 떨어지면 모든 정점을 로컬 원점으로 붕괴시켜 각 삼각형의 세 정점이 일치하게 합니다. 그러면 래스터라이저가 퇴화 삼각형을 버리고, 화면 밖 풀에 대해서는 어떤 프래그먼트, 알파 테스트, 그림자 작업도 일어나지 않습니다. 이것은 Three.js가 이미 하는 거친 chunk별 바운딩 구 컬링 위에 쌓이며, 불리언이 아니라 부동소수점 <code>step</code>으로 만들어져 위치 혼합에 곧장 곱해집니다.</p>
<h2 id="이-장에서-언급된-기술" tabindex="-1">이 장에서 언급된 기술 <a class="header-anchor" href="#이-장에서-언급된-기술" aria-label="Permalink to &quot;이 장에서 언급된 기술&quot;"></a></h2>
<p><strong>서버 권위형 월드 영속화.</strong> <code>WorldChunkDO</code> Durable Object가 소품 배치와 지형 편집을 중재하고, chunk별 바이너리 blob을 진실의 원천으로 영속화하며(그래서 들어온 사람은 이벤트 로그를 재생하는 대신 커밋된 바이트를 로드합니다), DO의 행당 2 MB 제한 아래로 유지하기 위해 chunk당 저장 키 하나로 저장합니다. 플레이어 id는 <code>sessionStorage</code>에 살아서 탭이 서로 다른 peer가 되고, 표시 이름은 <code>localStorage</code>에 살아서 이름 변경이 탭 전체에 적용됩니다.</p>
<p><strong>가환 편집 수렴.</strong> 덧셈 지형 연산(올리기/내리기, SDF 더하기/빼기)은 가환이며 조율 없이 낙관적-스탬프 경로를 탑니다. 순서 의존 연산(스무딩, 평탄화)은 영역 잠금을 얻는 대신 미리 계산된 셀별 delta를 보냄으로써 가환으로 만들어지므로, 시스템 전체가 잠금 없이 하나의 균일한 프로토콜 아래 수렴합니다. 레코드별 소품 잠금이 소유자만 삭제 가능하던 방식을 대체하고, 클라이언트가 이름 지은 객체 id가 서버 응답이 도착하기 전에 결정론적인 실행 취소/재실행을 가능하게 합니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">GPU 구동 LOD</a>를 보세요.</p>
<p><strong>Godot에서 TSL로의 충실한 셰이더 이식.</strong> Quaternius의 소스 바람 셰이더 네 개를 한 줄씩 번역합니다. 강체 bark, 높이로 마스킹된 잎 흔들림, 월드 공간 식생 흔들림, 그리고 스크롤하는 wind-line 흔들림을 가진 풀이며, 팩의 머티리얼 명명 규칙으로 디스패치됩니다. 잎 색은 텍스처가 아니라 높이 그라디언트에 Fresnel 구동 SSS 림을 더한 데서 오고, sRGB 제작 상수는 선형으로 변환되어 외형이 참조 렌더와 일치합니다.</p>
<p><strong>프레임마다 일어나는 셰이더 재컴파일 피하기.</strong> 커스텀 TSL을 FBX 머티리얼 위에 얹으면 <code>needsUpdate</code>가 고정되어 프레임마다 프로그램을 다시 빌드하고, 약 1 fps로 붕괴할 수 있습니다. 머티리얼별 차이를 전부 uniform으로 바인딩하면 고유한 매개변수 집합마다 새 셰이더를 내뱉는 대신 모든 변형이 컴파일된 프로그램 하나를 공유합니다. 평범한 텍스처 진단 pass가 커스텀 그래프가 원인인지 상류 설정이 원인인지 격리해 줍니다.</p>
<p><strong>인스턴스화된 식생의 월드 공간 바람.</strong> WGSL에 <code>inverse()</code>가 없기 때문에, 풀 바람은 월드 공간에서 계산되어 손으로 유도한 역(스케일 제곱으로 나눈 전치)으로 로컬로 변환됩니다. 정점별 GPU 절두체 컬링이 화면 밖 풀 다발을 퇴화 삼각형으로 붕괴시켜 어떤 프래그먼트나 그림자 작업도 돌지 않게 하며, Three.js의 chunk별 바운딩 구 컬링 위에 쌓입니다.</p>
<hr>
<p>29부 중 24부.
이전: <a href="/ko/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice.html">23부 - 쉰 명의 avatar와 방 안의 목소리</a>
다음: <a href="/ko/blog/2026-05-10-open-world-browser-part-25-universal-characters.html">25부 - 하나의 스켈레톤, 모든 의상</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 23부: 아바타 50개와 방 안의 목소리]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice</guid>
            <pubDate>Fri, 08 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 45는 캐릭터 50개를 프레임당 13ms의 JS에서 배치 GPU 스키닝으로 단일 draw call로 줄였고, WGSL 오류를 쫓느라 두 시간을 썼는데 원인은 morph target이었다. Spike 46은 HRTF 공간 음향으로 근접 음성을 만들었다가, Meet와 Teams가 실제로 출시하는 것에 맞추려고 오디오 체인의 절반을 지웠다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-23부-아바타-50개와-방-안의-목소리" tabindex="-1">브라우저에서 오픈 월드 만들기, 23부: 아바타 50개와 방 안의 목소리 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-23부-아바타-50개와-방-안의-목소리" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 23부: 아바타 50개와 방 안의 목소리&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 안내</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets.html">22부</a>는 세계 위에 하늘을 덮었습니다. 이번 부분은 그 안에 사람을 넣습니다. 3인칭 오픈 월드는 어느 순간에든 50명이 넘는 캐릭터가 보이길 원하고, 바로 옆에 서 있는 사람들의 목소리도 들리길 원합니다. Spike 45는 렌더링 쪽입니다. 그 많은 애니메이션 아바타를 메인 스레드를 녹이지 않고 GPU에 올리는 일이죠. Spike 46은 오디오 쪽입니다. 위치에 따라 패닝되고 감쇠하는 P2P 음성을, 기술 데모가 아니라 평범한 화상 통화처럼 들리도록 튜닝했습니다.</p>
<h2 id="댄서-50명에게-draw-call-하나" tabindex="-1">댄서 50명에게 draw call 하나 <a class="header-anchor" href="#댄서-50명에게-draw-call-하나" aria-label="Permalink to &quot;댄서 50명에게 draw call 하나&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/45-avatar-network-sync/" title="Spike 45 Avatar Network Sync" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/45-avatar-network-sync/" target="_blank">새 탭에서 Spike 45 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=45-avatar-network-sync">소스 보기</a></p>
<p>기본 Three.js 경로는 캐릭터마다 자기 <code>SkinnedMesh</code>, 자기 <code>AnimationMixer</code>, 자기 본 행렬 업로드, 자기 draw call을 줍니다. 로컬 Mac에서 아바타 50개일 때 그건 GPU가 일을 하나라도 하기 전에 프레임당 약 13ms의 순수 JavaScript 오버헤드였습니다. 멀티플레이어 트랙 전체의 리스크 해소 질문은, 하나의 배치 스키닝 아키텍처가 이걸 통제하고 캐릭터 수에 따라 선형으로 확장될 수 있느냐였습니다.</p>
<p>답은 애니메이션을 어디서 계산하는가와 어디서 그리는가를 나누는 것입니다. 세 개의 캐릭터 클래스가 하나의 FBX 템플릿을 공유합니다. 로컬 플레이어는 평범한 <code>Avatar</code>로, 자기 mixer를 가진 완전한 스켈레톤 클론이며 표준 Three.js 경로를 따릅니다. 어차피 하나뿐이니까요. 모든 원격 peer는 <code>VirtualSkeleton</code>입니다. 마찬가지로 자기 mixer를 가지고 같은 클립을 돌리는 완전한 클론이지만, 모든 <code>SkinnedMesh</code> 노드는 클론 직후에 곧바로 벗겨내서 본만 남습니다. 그것은 절대 씬에 들어가지 않습니다. 매 프레임, mixer가 업데이트되고 행렬이 자리를 잡은 뒤에, 100개 본 전부의 <code>(bone.matrixWorld × boneInverse)</code>를 공유 <code>Float32Array</code>의 한 슬롯에 채워 넣습니다. 그러면 <code>BatchSkinnedRenderer</code>가 지오메트리 조각마다 하나의 <code>InstancedMesh</code>를 소유하고, 모두 <code>maxInstances × numBones × mat4</code> 크기의 단일 <code>StorageBufferAttribute</code>에서 본 행렬을 읽습니다. 즉 60 × 100 × 64 = 384 KB입니다. 커스텀 <code>positionNode</code>와 <code>normalNode</code>를 가진 <code>MeshStandardNodeMaterial</code>이 정점마다 네 개의 본 영향을 그 storage buffer에서 곧장 읽습니다. 결과는 군중 전체가 안에 몇 명이 있든 지오메트리 조각마다 storage 업로드 한 번과 draw call 한 번뿐입니다. 스키닝은 정점 셰이더 안에 살고, 아바타당 JavaScript 비용은 mixer를 돌리고 행렬 100개를 복사하는 수준으로 떨어집니다.</p>
<p>이걸 측정하는 HUD도 다시 만들어야 했습니다. 옛 버전은 전체 프레임 GPU 시간이 3ms를 넘으면 &quot;예산 초과&quot;라고 표시했지만, 프레임에는 항상 shadow map, 지면, 로컬 플레이어의 완전한 skinned mesh가 들어가고, 이들이 합쳐 실제 하드웨어에서 합성 peer가 몇 개든 상관없이 3~5ms를 돌립니다. 해결책은 스스로 보정하는 예산입니다. 배치 아바타가 없는 동안에는 빠른 EMA를 통해 실시간 GPU 시간을 기준선으로 잡고, 그 기준선을 동결한 다음 합성체가 나타나면 아바타가 추가될 때마다 0.06ms씩 예산을 선형으로 키웁니다. 모든 머신에서 유휴 상태일 때 PASS로 읽히고, 군중이 늘면 비례해서 조여집니다.</p>
<h2 id="버그는-볼-수-없는-얼굴이었다" tabindex="-1">버그는 볼 수 없는 얼굴이었다 <a class="header-anchor" href="#버그는-볼-수-없는-얼굴이었다" aria-label="Permalink to &quot;버그는 볼 수 없는 얼굴이었다&quot;"></a></h2>
<p>Chrome에서 첫 실행은 지면에 은색 그림자만 보이고 아바타는 하나도 없이, WGSL 파싱 오류를 냈습니다. <code>cannot index type 'f32'</code>였고, 스칼라로 선언된 uniform인데 <code>object.nodeUniform2[i]</code>로 첨자 접근을 시도하는 줄에서 났습니다. 이 이야기의 정직한 부분은, 첫 수정이 틀렸는데도 어쨌든 작동했다는 겁니다. 추측은 <code>InstancedMesh</code>의 인스턴스 행렬 경로가 그 나쁜 코드를 생성한다는 것이었고, <code>StorageInstancedBufferAttribute</code>로 바꿔 끼우니 Chrome에서 오류가 사라졌습니다. 하지만 그건 새 경로가 다른 셰이더 코드를 내보냈기 때문에 사라진 것이지, 원인을 다뤘기 때문이 아니었습니다. 가장 위험한 종류의 수정이죠.</p>
<p>진짜 범인은 morph target이었습니다. 3MIKE.fbx에는 blend-shape 표정이 딸려 오고, 클론된 지오메트리는 <code>morphAttributes</code>를 상속하며, Three.js의 <code>MorphNode.setup()</code>은 <code>morphTargetInfluences</code>를 스칼라 <code>float</code>로 선언한 다음 합성된 루프 안에서 그것을 <code>.element(i)</code> 하려 합니다. 이게 바로 컴파일러가 거부한 그 스칼라 첨자입니다. 수정은 한 줄로, morph를 쓰지 않는 지오메트리에서 <code>geometry.morphAttributes = {}</code>를 비워서 Three.js가 <code>MorphNode</code>를 아예 주입하지 않게 합니다. 그 우연한 Chrome 수정은 한동안 남아 있다가 되갚아 줬습니다. Safari에서 storage-instanced 경로가 <code>Vertex buffer is not big enough</code>를 256번이나 냈는데, Safari의 WebGPU 백엔드가 그걸 깔끔하게 변환하지 못하기 때문이었습니다. 되돌린 건 옳은 결정이었고, 생성된 인스턴스 경로가 아니라 코어 WebGPU인 평범한 본 행렬 storage buffer는 어디서나 잘 작동합니다. 새겨둘 만한 교훈은 이겁니다. 어떤 수정이 한 브라우저에서 작동하는데 그 메커니즘을 설명할 수 없다면, 당신은 증상에 반창고를 붙인 것이니 실제로 생성된 WGSL을 읽으세요. spike 후반에 추가한 <code>getCompilationInfo()</code> 심은 Three.js의 두루뭉술한 &quot;module is not valid&quot;를 진짜 Tint 오류로 바꿔 줘서, 그 값을 여러 번 톡톡히 했습니다.</p>
<p>그 옆에는 관련된 프레임워크 회피 트릭이 하나 있습니다. Three.js는 표준 <code>skinIndex</code>와 <code>skinWeight</code> 속성 이름을 감지하면, 커스텀 <code>positionNode</code>가 이미 스키닝을 하는 <code>InstancedMesh</code>에서도 자기 <code>SkinningNode</code>를 주입하려 듭니다. 그 속성들을 <code>boneIndex</code>와 <code>boneWeight</code>로 이름 바꾸면 프레임워크 눈에서 숨겨지고, 커스텀 TSL이 새 이름으로 그것들을 읽습니다.</p>
<h2 id="말과-말-사이에-너를-잊는-릴레이" tabindex="-1">말과 말 사이에 너를 잊는 릴레이 <a class="header-anchor" href="#말과-말-사이에-너를-잊는-릴레이" aria-label="Permalink to &quot;말과 말 사이에 너를 잊는 릴레이&quot;"></a></h2>
<p>첫 버전은 <code>BroadcastChannel</code>로 peer를 동기화했습니다. 실제 와이어 포맷과 박자를 가진, 같은 브라우저 안의 대역이었고, 프로토콜 주석은 실제 전송으로 교체하는 게 한 줄이면 된다고 약속했습니다. 그 약속을 현금으로 바꾸는 건 <code>AvatarRoomDO</code>, 즉 36바이트 바이너리 프레임을 디코드조차 하지 않는 74줄짜리 Cloudflare Durable Object를 뜻했습니다. 그것은 각 메시지를 방 안의 다른 모든 peer에게 그대로 전달합니다. 발신자의 id가 프레임에 박혀 있고 각 수신자가 자기 echo를 클라이언트 쪽에서 걸러내기 때문입니다. 이 릴레이는 신원에 대한 인식이 전혀 없습니다. Hibernating WebSocket은 유휴 방을 공짜로 만듭니다. DO는 메시지 사이에 메모리에서 빠져나가고, 런타임은 다음 패킷에서 태그된 소켓을 복원합니다. peer당 초당 10개 이벤트면 그건 peer-시간당 36,000번의 DO 요청, 약 0.5센트이고, Cloudflare에서 egress가 공짜이며 동등한 AWS WebSocket 형태보다 대략 6~10배 저렴합니다.</p>
<p>이 교체는 간직할 만한 상태 기계 버그를 드러냈습니다. 한 원격 플레이어가 멈춘 뒤에도 계속 걸었습니다. 애니메이션 요청은 마지막으로 큐에 들어간 이름이 아니라 <code>this._state</code>, 즉 지금 재생 중인 클립을 기준으로 가드했습니다. 그래서 같은 tick에 두 네트워크 메시지가 도착해 먼저 <code>walk</code> 다음 <code>idle</code>이 오면, <code>idle</code>이 아직 전진하지 않은 상태와 비교되어 조용히 버려졌습니다. peer는 영원히 걷기에 갇혔는데, 미래의 <code>idle</code> 패킷이 변하지 않은 것으로 상류에서 중복 제거되었기 때문입니다. 수정은 대기 중인 이름을 항상 덮어쓰고, 진짜 같은 상태 요청에 대해서는 전환 헬퍼가 단락하도록 두는 것입니다. 헬퍼는 이미 그렇게 하고 있었죠. 이 부류의 버그는 일반적입니다. 잘못된 참조 값에 대한 중복 제거 검사는 정작 중요한 입력을 조용히 삼킵니다.</p>
<p>Safari는 가드 두 개를 더 필요로 했습니다. Chrome보다 WebSocket을 빨리 여는 탓에, 첫 인바운드 peer 메시지가 배치 렌더러 구성이 끝나기 전에 도착해 null을 역참조할 수 있었습니다. 렌더러가 없는 동안 메시지를 버리는 건 안전한데, peer가 100ms마다 다시 브로드캐스트하기 때문입니다. 그리고 <code>'gpu' in navigator</code>는 true를 반환하는데 <code>requestAdapter()</code>는 null을 반환해서, Three.js가 조용히 WebGL2로 폴백했고, 거기서는 storage-buffer 스키닝 체인에 유효한 변환이 없어 오류를 쏟아냈습니다. 진짜 adapter가 있는지 확인하고 백엔드가 실제로 WebGPU인지 단언하면, 망가진 렌더링을 명확한 로딩 화면 메시지로 바꿔 줍니다. WGSL 방언 격차마저 있었습니다. Three.js는 현대적인 두 인자 <code>@interpolate(flat, either)</code>를 내보내는데 WebKit의 컴파일러는 아직 출시하지 않았습니다. <code>createShaderModule</code>로 들어가는 길에 셰이더 소스를 다시 써서 두 번째 인자를 떨어뜨려 패치했고, 이건 공짜입니다. flat 보간은 어차피 모든 정점에서 같은 값을 나르니까요.</p>
<h2 id="방과-함께-패닝되는-목소리" tabindex="-1">방과 함께 패닝되는 목소리 <a class="header-anchor" href="#방과-함께-패닝되는-목소리" aria-label="Permalink to &quot;방과 함께 패닝되는 목소리&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/46-proximity-voice/" title="Spike 46 Proximity Voice" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/46-proximity-voice/" target="_blank">새 탭에서 Spike 46 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=46-proximity-voice">소스 보기</a></p>
<p>Spike 46은 근접 음성입니다. HRTF 공간 음향을 쓰는 P2P WebRTC로, 조용하거나 적당히 시끄러운 방에서 Google Meet와 Microsoft Teams 품질을 맞추는 것으로 명시적으로 범위를 좁혔습니다. <code>VoiceRoomDO</code>가 시그널링을 JSON 릴레이로 처리합니다. 새 peer마다 명단을 보내고, 입장과 퇴장을 알리고, 소켓 태그로 SDP와 ICE를 특정 peer 하나에게 라우팅하고, 공간 패너를 구동하는 위치 업데이트를 브로드캐스트합니다. 모든 메시지에 발신자 id를 찍어서 peer들이 서로를 사칭하지 못하게 하고, 오디오 자체는 절대 DO를 거치지 않습니다. 원격 peer마다 <code>RTCPeerConnection</code> 하나이며, 사전순으로 더 작은 peer id가 항상 offer를 보내서 완전한 perfect-negotiation 구현 없이도 양쪽이 누가 시작할지 합의합니다.</p>
<p>받는 쪽에서는 각 peer의 오디오가 HRTF에 역거리 롤오프로 설정된 <code>PannerNode</code>를 통과하고, <code>AudioListener</code>는 로컬 플레이어의 위치와 방향에서 매 프레임 <code>forwardX = sin(facing)</code>, <code>forwardZ = cos(facing)</code>로 업데이트되는데, 이는 씬의 <code>atan2(wx, wz)</code> 방향 규약과 맞습니다. Chrome 특유의 버릇 하나가 한 시간을 잡아먹었습니다. Web Audio만 소비하는 <code>MediaStream</code>은 때때로 패킷을 끌어오지 않으므로, 각 스트림을 숨겨진 음소거 <code>&lt;audio&gt;</code> 요소에도 붙여서 디코더가 스케줄링하도록 강제합니다. 품질 쪽에서는 브라우저가 기본적으로 약 32 kbps 모노 Opus를 쓰므로, 이 spike는 모든 offer와 answer의 <code>fmtp</code> 줄을 손봐서 in-band FEC를 켜고 DTX를 끈 채 128 kbps로 올린 다음, 높은 최대 비트레이트로 <code>setParameters</code>를 호출해 인코더가 SDP가 광고한 값을 실제로 쓰도록 보장합니다. FEC는 비트레이트 향상 다음으로 두 번째로 큰 들리는 이득으로, 재협상 없이 패킷 손실에서 복구합니다.</p>
<h2 id="깨끗한-오디오로-가는-삭제의-길" tabindex="-1">깨끗한 오디오로 가는 삭제의 길 <a class="header-anchor" href="#깨끗한-오디오로-가는-삭제의-길" aria-label="Permalink to &quot;깨끗한 오디오로 가는 삭제의 길&quot;"></a></h2>
<p>출시된 오디오 체인은 내가 시작했던 것보다 훨씬 작고, 그걸 줄인 것이 진짜 교훈이었습니다. 첫 버전에는 하이패스 필터, 키보드 소음을 잡으려고 튜닝한 클릭 리미터, 컴프레서, 노이즈 게이트, 그리고 wet-dry 크로스페이드가 있었고, 앞쪽엔 슬라이더가 열두 개도 넘는 떠다니는 패널이 붙어 있었습니다. 사용자가 들리는 키보드 클릭을 신고했을 때, 본능은 클릭 리미터를 더 세게 조이고 dry 믹스를 낮추는 것, 즉 반창고 더미였습니다. 구조적인 답은, 일단 체인에 ML 디노이저가 들어오면 클릭 리미터와 게이트와 하이패스 대부분이 전부 군더더기라는 것이었습니다. RNNoise는 정확히 키보드와 마우스와 타이핑 소음으로 학습되었고, 진폭 클리핑은 같은 일을 명백히 더 못하는 버전이기 때문입니다. 프로덕션 클라이언트는 ML 디노이즈, 에코 캔슬, 자동 게인, 그리고 레벨용 소프트 컴프레서를 출시하고 그 외엔 아무것도 안 합니다. 그래서 네 단계가 빠졌고, 슬라이더 패널이 빠졌고, &quot;노이즈 감소를 골라라&quot; 토글도 빠지면서, 고정된 파이프라인 하나가 남았습니다.</p>
<p>살아남은 단계마다 자기 자리를 벌었습니다. 브라우저 에코 캔슬은 켜진 채로 둡니다. RNNoise는 에코를 다루지 않고, 그게 없으면 스피커-마이크 피드백이 무한정이기 때문입니다. 브라우저 노이즈 억제는 끕니다. RNNoise 위에 그걸 쌓으면 마찰음에 아티팩트가 생기므로 디노이저는 하나만 고릅니다. 브라우저 자동 게인은 켜진 채로 둡니다. 그걸 끄면 신호가 너무 작아져 컴프레서가 작업할 게 없어지고, Web Audio의 <code>DynamicsCompressorNode</code>에는 이를 보정할 makeup-gain 파라미터가 없기 때문입니다. 브라우저의 넓은 레벨링과 spike의 빠른 컴프레서는 다른 시간 척도에서 작동하며 공존합니다. RNNoise는 92퍼센트 wet에 8퍼센트 dry를 섞어 돌리는데, s, sh, f 같은 무성 자음을 과하게 억제할 수 있기 때문입니다. 이런 음들은 voice 확률이 떨어지는데, 작은 dry 경로가 약간의 키 입력 누출을 대가로 그것들을 보존합니다.</p>
<p>두 기능이 마무리를 짓습니다. Push-to-talk는 <code>track.enabled</code>를 뒤집지 않습니다. 그러면 파이프라인 버퍼에 아직 남은 모든 걸 버리고 키를 뗄 때 마지막 음절을 잘라내기 때문입니다. 대신 꼬리 근처의 <code>GainNode</code>가 <code>setTargetAtTime</code>으로 램프하는데, 빠른 어택으로 첫 음절이 살아남고 느린 릴리스로 마지막 자음이 빠져나가며, 트랙은 영구히 켜둡니다. 그리고 라디오 스타일 기능으로 요청된 5초 방송 지연은, 바이패스 갈래와 <code>DelayNode</code> 갈래를 크로스페이드해서 함께 돌리고, 지연된 출력을 순간 무음으로 끊고 오디오가 돌아오기 전 HUD에서 카운트다운하는 덤프 버튼을 둡니다. 디노이저를 번들링하는 건 그 자체로 작은 무용담이었습니다. 발행된 RNNoise worklet은 어떤 CDN도 해석하지 못하는 bare-specifier 임포트를 쓰므로, 수정은 로컬 esbuild 번들로 WASM을 base64로 인라인한 자체 포함 1.9 MB 파일 하나를 만들어 리포에 커밋하고, 모듈에 상대적인 URL로 참조해서 개발 서버, VitePress 빌드, 커스텀 도메인 모두에서 해석되게 하는 것이었습니다. 혹시 worklet이 로드에 실패하면 체인은 여전히 평범한 하이패스와 컴프레서를 통해 오디오를 내고, HUD가 그 실패를 빨간색으로 보여줍니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>군중을 위한 배치 GPU 스키닝.</strong> 원격 아바타는 헤드리스 <code>VirtualSkeleton</code>(skinned mesh를 벗기고 본을 남긴, 자기 mixer를 가진 완전한 클론)을 돌려서 모든 본의 <code>bone.matrixWorld × boneInverse</code>를 공유 <code>StorageBufferAttribute</code>에 채웁니다. 지오메트리 조각마다 하나의 <code>InstancedMesh</code>가 그 행렬들을 커스텀 TSL <code>positionNode</code>/<code>normalNode</code>에서 읽으므로, 군중 전체가 조각당 storage 업로드 한 번과 draw call 한 번이 들고, 아바타당 CPU 작업은 mixer 업데이트 한 번과 행렬 복사 한 번으로 제한됩니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">GPU 구동 LOD</a>를 보세요.</p>
<p><strong>증상이 아니라 생성된 WGSL을 읽기.</strong> <code>cannot index type 'f32'</code> 컴파일 오류는 Three.js의 <code>MorphNode</code>가 <code>morphTargetInfluences</code>를 스칼라로 선언하고 첨자를 다는 데서 비롯됐고, morph를 쓰지 않는 지오메트리에서 <code>morphAttributes</code>를 비워 고쳤습니다. 어떤 셰이더 경로가 생성되는지만 바꾼 첫 수정은 원인을 가렸고 나중에 Safari를 깨뜨렸습니다. <code>skinIndex</code>/<code>skinWeight</code>를 <code>boneIndex</code>/<code>boneWeight</code>로 이름 바꾸면 Three.js의 자동 <code>SkinningNode</code> 주입에서 속성을 숨겨, 커스텀 스키닝 머티리얼이 수학을 소유합니다.</p>
<p><strong>Hibernating Durable Object 릴레이.</strong> 순수 바이너리 <code>AvatarRoomDO</code>는 36바이트 프레임을 디코드하지 않고 다른 모든 peer에게 전달하며, 발신자 신원은 프레임에 박혀 있고 자기 echo는 클라이언트 쪽에서 걸러집니다. Hibernating WebSocket은 유휴 방을 공짜로 만들고, 이 형태는 10 Hz에서 peer-시간당 약 0.5센트로, 동등한 관리형 WebSocket 가격보다 훨씬 낮습니다. 마지막으로 큐에 들어간 상태가 아니라 재생 중인 애니메이션 상태와 비교한 중복 제거 가드는 정지 메시지를 조용히 버려서 원격 플레이어를 걷기 루프에 가두었습니다.</p>
<p><strong>HRTF를 쓰는 WebRTC 근접 음성.</strong> peer마다 하나의 <code>RTCPeerConnection</code>으로 offer/answer 역할은 peer-id 순서로 결정하고, 오디오는 HRTF <code>PannerNode</code>를 통과하며 <code>AudioListener</code>는 플레이어 방향에서 매 프레임 업데이트되고, Opus는 회복력을 위해 in-band FEC와 함께 128 kbps로 손봤습니다. 음소거된 숨겨진 <code>&lt;audio&gt;</code> 요소가 Chrome이 Web Audio 전용 스트림에서 패킷을 끌어오게 강제합니다.</p>
<p><strong>빼는 오디오 엔지니어링.</strong> Meet/Teams 품질을 맞추는 건 단계를 더하는 게 아니라 빼는 것이었습니다. ML 디노이즈 더하기 에코 캔슬 더하기 자동 게인 더하기 소프트 컴프레서, 게이트도 클릭 리미터도 없이. 키보드 소음으로 학습된 ML 디노이저가 진폭 클리핑을 군더더기로 만들기 때문입니다. Push-to-talk는 트랙을 뒤집는 대신 비대칭 엔벨로프로 꼬리 <code>GainNode</code>를 램프해서 음절이 잘리지 않게 하고, 디노이저 worklet은 bare-specifier 임포트 해석을 피하려고 단일 자체 포함 esbuild 번들로 출시됩니다.</p>
<hr>
<p>29부 중 23부.
이전: <a href="/ko/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets.html">22부 - 빛을 줄 수 있는 구름, 그리고 먹여야만 하는 컬링</a>
다음: <a href="/ko/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind.html">24부 - 세계를 저장하기, 그리고 눈에 보이는 바람</a>
시리즈 안내: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 22부: 빛을 줄 수 있는 구름, 그리고 잘 먹여야 하는 컬링]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets</guid>
            <pubDate>Thu, 07 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 43은 물리 기반 하늘과 볼류메트릭 구름을 2 ms 미만으로 화면에 올렸고, 시간대별 튜닝 없이도 노을이 제대로 나온다. Spike 44는 meshlet GPU 컬링을 만들었고, Hi-Z 오클루전은 오클루더가 max-reduce를 견딜 만큼 충분히 클 때만 동작한다는 걸 배웠다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-22부-빛을-줄-수-있는-구름-그리고-잘-먹여야-하는-컬링" tabindex="-1">브라우저에서 오픈 월드 만들기, 22부: 빛을 줄 수 있는 구름, 그리고 잘 먹여야 하는 컬링 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-22부-빛을-줄-수-있는-구름-그리고-잘-먹여야-하는-컬링" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 22부: 빛을 줄 수 있는 구름, 그리고 잘 먹여야 하는 컬링&quot;"></a></h1>
<p><em>글: <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-06-open-world-browser-part-21-visibility-buffer.html">21부</a>는 결과적으로 별 소득이 없었던 렌더링 기법에 관한 것이었습니다. 이번 부분에는 소득이 있었던 것 하나, 그리고 동작하게 만들려면 세심한 수정이 필요했던 것 하나가 있습니다. Spike 43은 하늘입니다. 물리 기반 대기와 볼류메트릭 구름, 즉 어떤 장면을 기술 데모가 아니라 하나의 장소로 읽히게 만드는 토대입니다. Spike 44는 meshlet 방식의 GPU 컬링이고, 거기서 얻은 교훈은 오클루전 테스트의 좋고 나쁨은 거기에 무엇을 먹이느냐에 달려 있다는 것입니다.</p>
<h2 id="그래디언트가-아니라-물리에서-나온-하늘" tabindex="-1">그래디언트가 아니라 물리에서 나온 하늘 <a class="header-anchor" href="#그래디언트가-아니라-물리에서-나온-하늘" aria-label="Permalink to &quot;그래디언트가 아니라 물리에서 나온 하늘&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/43-clouds-atmosphere/" title="Spike 43 Clouds and Atmosphere" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/43-clouds-atmosphere/" target="_blank">새 탭에서 Spike 43 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=43-clouds-atmosphere">소스 보기</a></p>
<p>거의 모든 영화적인 날씨 효과는 두 가지 기반 위에 놓입니다. 하나는 물리 기반 대기입니다. 하늘색과 태양색이 손으로 조정한 그래디언트가 아니라 물리로부터 시간대를 따라가게 합니다. 다른 하나는 볼류메트릭 구름 볼륨입니다. 하늘이 구운 큐브맵 대신 3D 구조를 갖게 합니다. Spike 43은 기존 WebGPU와 TSL 스택 위에 바로 이 한 쌍을 만들 뿐 그 이상은 하지 않습니다. 이 둘이 존재하고 나면 날씨 스택의 나머지(안개, 신의 광선, 젖은 표면, 눈)는 이미 알려진 더 작은 후속 작업들의 연속이 되기 때문입니다.</p>
<p>대기는 Hillaire 2020 모델입니다. WGSL 컴퓨트 셰이더에서 계산하는 룩업 테이블 묶음이죠. 투과율 테이블은 Rayleigh, Mie, 오존 밀도 프로파일을 통과하는 태양광을 적분하고 태양이 움직일 때만 다시 계산합니다. 스카이뷰 테이블은 매 프레임 다시 굽습니다. 게이팅하느라 코드를 쓸 가치가 없을 만큼 충분히 싸기 때문이며, 지평선 주변에서 밴딩을 피하려고 비선형 파라미터화를 씁니다. 다중 산란은 지금은 제대로 된 테이블 대신 해석적 피팅을 쓰는데, 노을이 제대로 읽히니 그 지름길이 잘 숨어 있는 셈입니다. 구름은 Schneider Nubis 방식으로 수평 슬래브를 가로지르는 레이 마치이고, 형태는 32³ Worley 텍스처로 침식된 128³ Perlin-Worley 텍스처에서 나오며, 둘 다 부팅 시 컴퓨트로 굽고 네트워크 요청은 없습니다. Beer 법칙 감쇠, 이중 로브 위상 함수, powder 근사로 빛을 줍니다. 핵심 결합은 구름의 태양색이 매 스텝마다 같은 투과율 테이블을 샘플링한다는 점입니다. 그래서 구름 조명이 두 번째 튜닝 패스 없이도 노을을 따라갑니다.</p>
<p>M1에서는 절반 해상도 구름 기준으로 전체가 1.1에서 2.0 ms에 들어옵니다. 6 ms 예산을 한참 밑돌고, GPU 메모리는 약 14 MB를 쓰며, 100 FPS를 넘겨 돌아갑니다. 두 가지 명제는 실전에서 모두 버텼습니다. 노을은 히어로 샷, 렌더러가 영화처럼 느껴지게 하는 그 순간이고, 시간대별 튜닝 없이 물리에서 떨어져 나옵니다. 그리고 행복한 우연도 있었습니다. 구름 슬래브를 800 m와 4000 m 사이로 파라미터화하니, 낮은 카메라에서 보면 지평선의 먼 구름이 어두운 산등성이처럼 읽힙니다. 누구도 배경 지형을 모델링하지 않았는데 세계에 배경 지형이 생긴 셈입니다.</p>
<p>기록해 둘 만한 아키텍처 메모가 하나 있습니다. 가장 자연스러운 형태는 하늘을 먼저 스왑 체인(swap chain)에 그린 다음 three.js가 <code>autoClear = false</code>로 그 위에 지오메트리를 그리게 하는 것입니다. 이건 r184의 WebGPU 렌더러에서는 살아남지 못합니다. 그 플래그가 WebGL에서처럼 컬러 load op를 게이팅하지 않아서 three.js가 매 프레임 하늘을 덮어 버리기 때문입니다. 해결책은 three.js를 오프스크린 타깃에 렌더링하고, 스왑 체인을 소유하는 우리 자신의 패스에서 최종 합성(<code>mix(skyCloud, scene, scene.alpha)</code> 다음 ACES 다음 sRGB)을 하는 것입니다.</p>
<h2 id="오클루더만큼만-좋은-컬링" tabindex="-1">오클루더만큼만 좋은 컬링 <a class="header-anchor" href="#오클루더만큼만-좋은-컬링" aria-label="Permalink to &quot;오클루더만큼만 좋은 컬링&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/44-meshlet-clusters/" title="Spike 44 Meshlet Clusters" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/44-meshlet-clusters/" target="_blank">새 탭에서 Spike 44 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=44-meshlet-clusters">소스 보기</a></p>
<p>Spike 44는 네 가지 렌더링 모드를 서로 벤치마크합니다. 평범한 포워드, CPU 클러스터 컬링, GPU 컴퓨트 컬링, 그리고 Hi-Z 오클루전 컬링이 붙은 visibility buffer입니다. 흥미로운 건 Hi-Z 경로인데, 여기에 조용한 버그가 하나 있었습니다. HUD는 오클루전이 켜져 있다고 말했지만 &quot;Hi-Z killed&quot; 카운터는 영원히 정확히 0.0%에 머물렀습니다. 프러스텀 컬링은 동작했으니 컬 셰이더의 앞단은 문제가 없었습니다. 오클루전 쪽 절반이 풀 비용을 치르는 무동작이었던 겁니다.</p>
<p>Hi-Z 오클루전 테스트는 클러스터의 바운딩 박스를 화면에 투영하고, 화면 사각형이 약 2×2 텍셀이 되도록 깊이 피라미드의 mip 레벨을 고르고, 그 사각형 안에서 가장 깊은 오클루더 깊이를 샘플링한 뒤, 클러스터의 가장 가까운 점이 그 오클루더보다도 멀면 클러스터를 거부합니다. 깊이 피라미드는 매 프레임 만들어지는데, 불투명 깊이 프리패스로 mip 0을 시드한 다음 위로 max-reduce 합니다. 이 불투명 프리패스는 의도적으로 단단한 오클루더, 즉 지면과 나무별 줄기 프록시만 포함합니다. 알파 테스트된 잎은 구멍을 뚫어 max-reduce를 속이기 때문입니다.</p>
<p>버그는 기하학적이었지 논리적인 게 아니었습니다. 줄기 프록시는 0.5 m × 4 m × 0.5 m 박스였습니다. 30 m에서는 화면에 약 17픽셀로 투영됩니다. 그런데 전형적인 50 m 풀 클러스터는 mip 5를 고르고, 거기서는 텍셀 하나가 소스 픽셀 32개를 덮습니다. 17픽셀짜리 줄기는 단일 mip-5 텍셀을 완전히 덮지 못하므로, 줄기에 닿는 모든 텍셀은 주변 지면에도 닿습니다. 맨 처음의 2×2 max-reduce는 더 큰 깊이 값, 즉 줄기 뒤의 더 먼 지면을 고르고, 그래서 줄기의 깊이는 첫 번째 리덕션에서 지워집니다. mip 5에 이르면 피라미드는 거의 어디서나 지면 깊이를 들고 있고, 클러스터는 결코 지면보다 멀지 않으며, 그래서 어떤 것도 결코 오클루드되지 않습니다.</p>
<p>해결책은 프록시를 그것이 떨어지는 텍셀들을 지배할 만큼 충분히 크게, 나무의 목재가 아니라 실루엣에 맞춰 크기를 정하는 것입니다. 대략 2 m × 6 m × 2 m 프록시는 여전히 실제 수관보다 작아서 틈으로 보이는 잎이 과도하게 컬링되는 일은 없지만, 중요한 거리까지 max-reduce를 견딜 만큼은 크고, 그러자 오클루전 카운터가 즉시 0이 아니게 되었습니다. 이 교훈은 프로덕션 엔진을 위한 규칙으로 일반화됩니다. Hi-Z 오클루더로 신뢰받는 것은 무엇이든 물리적 본체가 아니라 화면상 실루엣에 맞춰 크기를 정해야 합니다. 트인 식생 장면에서 Hi-Z의 효과는 깊이 테스트 수식의 우아함이 아니라 해당 mip에서의 오클루더 커버리지가 좌우하기 때문입니다. 풀 대 풀 오클루전은 어차피 발동할 수 없습니다. 풀잎은 그 아래 지면과 같은 깊이에 있으니까요. 그래서 진짜 이득은 나무가 먼 식생을 가리는 것, 그리고 나무가 나무를 가리는 것입니다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>Hillaire 2020 대기 LUT.</strong> 투과율 테이블(Rayleigh, Mie, 오존 프로파일을 통과하는 태양광)은 태양이 움직일 때만 다시 계산하고, 여기에 지평선 비선형 파라미터화를 곁들인 프레임별 스카이뷰 테이블을 더하면, 손으로 조정한 그래디언트 없이 시간대를 따라가는 물리 기반 하늘색과 태양색이 나옵니다. 어떤 아티팩트가 제대로 된 굽기를 강요하기 전까지는 해석적 다중 산란 피팅이 완전한 테이블을 대신합니다. 노을은 시간대별 튜닝 없이 물리에서 떨어져 나옵니다.</p>
<p><strong>Schneider Nubis 볼류메트릭 구름.</strong> 수평 슬래브를 가로지르는 레이 마치로, 부팅 시 구운 128³ Perlin-Worley 텍스처를 32³ Worley 텍스처로 침식해 형태를 잡고, Beer 법칙 감쇠와 이중 로브 위상과 powder 항으로 빛을 줍니다. 매 스텝마다 같은 투과율 테이블에서 구름의 태양색을 샘플링하면 구름 조명이 일출과 일몰을 공짜로 따라갑니다. 절반 해상도 레이 마치는 전체 해상도보다 대략 4배 싸고, 전형적인 거리에서 눈에 띄는 품질 손실이 없습니다. 표준적인 프로덕션 트레이드오프죠.</p>
<p><strong>r184에서 raw WebGPU와 three.js 합성하기.</strong> 하늘을 스왑 체인에 그린 다음 <code>autoClear = false</code>로 그 위에 three.js 지오메트리를 그리는 방식은 실패합니다. 그 플래그가 WebGPU 백엔드에서 컬러 load op를 게이팅하지 않기 때문입니다. three.js를 오프스크린 RGBA16F 타깃에 렌더링하고, 스왑 체인을 소유하는 패스에서 최종 <code>mix</code> 더하기 톤맵 더하기 sRGB를 하세요.</p>
<p><strong>Hi-Z 오클루전 컬링과 오클루더 크기 정하기.</strong> max-reduce로 만든 깊이 피라미드는 GPU 컬 패스가 화면 사각형 내 가장 깊은 오클루더보다 가장 가까운 점이 뒤에 있는 클러스터를 거부하게 해줍니다. 오클루더가 선택된 mip에서 텍셀을 지배하기에 너무 작으면 이 테스트는 조용히 아무것도 하지 않습니다. 첫 max-reduce가 오클루더의 깊이를 그 뒤의 더 먼 배경으로 바꿔 버리기 때문입니다. 오클루더는 물리적 본체가 아니라 화면상 실루엣에 맞춰 크기를 정해야 합니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">GPU 주도 LOD</a>를 보세요.</p>
<hr>
<p>29부 중 22부.
이전: <a href="/ko/blog/2026-05-06-open-world-browser-part-21-visibility-buffer.html">21부 - 더 빠르지 않았던 더 빠른 렌더러</a>
다음: <a href="/ko/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice.html">23부 - 아바타 쉰 명과 방 안의 목소리</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 21부: 더 빠르지 않았던 더 빠른 렌더러]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-06-open-world-browser-part-21-visibility-buffer</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-06-open-world-browser-part-21-visibility-buffer</guid>
            <pubDate>Wed, 06 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 40은 빽빽한 풀을 위해 visibility buffer를 만들었습니다. 다들 overdraw에서 이긴다고 말하는 그 기법인데, Apple Silicon 고밀도 환경에서는 평범한 forward 렌더링에 44% 차이로 졌습니다. 왜 그런지, 그리고 실제로 언제 이 기법을 꺼내야 하는지 이야기합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-21부-더-빠르지-않았던-더-빠른-렌더러" tabindex="-1">브라우저에서 오픈 월드 만들기, 21부: 더 빠르지 않았던 더 빠른 렌더러 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-21부-더-빠르지-않았던-더-빠른-렌더러" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 21부: 더 빠르지 않았던 더 빠른 렌더러&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion.html">20부</a>에서는 평평한 쿼드 위에 표면 깊이를 가짜로 만들었습니다. 이번 부분은 렌더 아키텍처 결정에 관한 것이고, 교과서적인 정답이 우리 하드웨어에서는 틀린 것으로 드러난 바로 그 spike입니다. 질문은 이렇습니다. 3인칭 카메라 아래 영화 수준 밀도의 alpha-test 풀에 대해, 200명 밀도로 밀어붙이기 전에 visibility buffer가 필요한가? 통상적인 조언은 단호하게 &quot;그렇다&quot;입니다. 우리는 그것을 만들었고, 측정했고, 답은 &quot;아니다&quot;였습니다.</p>
<h2 id="모두가-추천하는-그-기법" tabindex="-1">모두가 추천하는 그 기법 <a class="header-anchor" href="#모두가-추천하는-그-기법" aria-label="Permalink to &quot;모두가 추천하는 그 기법&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/40-visibility-buffer/" title="Spike 40 Visibility Buffer" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/40-visibility-buffer/" target="_blank">새 탭에서 Spike 40 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=40-visibility-buffer">소스 보기</a></p>
<p>visibility buffer는 렌더링을 두 개의 pass로 나눕니다. Pass 1은 지오메트리를 래스터화하고 삼각형 ID와 인스턴스 ID만 깊이와 함께 압축된 정수 타깃에 쓰며, 셰이딩은 전혀 하지 않습니다. Pass 2는 풀스크린 pass로, 덮인 각 픽셀의 ID를 읽고 그 삼각형의 정점을 다시 가져와서 보간된 속성을 재구성하고, 보이는 각 픽셀을 정확히 한 번씩만 셰이딩합니다. 핵심 강점은 완벽한 overdraw 제거입니다. 깊이 테스트는 셰이딩 작업을 하나도 하지 않은 프래그먼트에 대해 실행되므로, 비싼 머티리얼은 당신이 실제로 보는 것에만 돌아갑니다.</p>
<p>이 spike는 한 캔버스, 한 device 위에서 두 경로를 돌려서 유일한 변수가 셰이딩이 어디에서 일어나는지가 되도록 합니다. forward 경로는 three.js를 통한 평범한 <code>MeshStandardNodeMaterial</code>입니다. vis-buffer 경로는 three.js 밖에서 도는 raw WebGPU 2-pass 파이프라인으로, three.js의 풀 텍스처를 백엔드에서 곧장 읽어 pass 1에서 <code>(instanceId, triId)</code>를 <code>RG32Uint</code> 타깃에 쓰고 pass 2에서 라이팅을 해석합니다. 둘은 하나의 ground-truth 라이팅 설정을 공유합니다.</p>
<p>기억해 둘 만한 구현 노트가 두 가지 있습니다. WebGPU는 프래그먼트 셰이더에서 여전히 이식 가능한 <code>primitive_index</code> 빌트인이 없어서, 정점별 삼각형 ID를 비인덱스 지오메트리에 구워 넣고 <code>flat</code> 보간으로 읽는 게 요령입니다. 이건 정점 수를 3배로 만들지만 12정점짜리 풀 카드에서는 무시할 만합니다. 그리고 three.js의 렌더러와 캔버스를 공유하는 일은, 컨텍스트를 다시 구성하지 않고 캔버스 크기를 건드리지 않는 한 거의 아무 일도 아닙니다. 둘 다 three.js가 관리하는 것이거든요. forward 경로의 시간을 재는 게 까다로운 부분이었는데, three.js가 자기 렌더 pass 안에 GPU 타임스탬프 쿼리를 주입할 훅을 노출하지 않기 때문입니다. 우회책은 그 작업 앞뒤로 no-op 타임스탬프 pass를 두 개 제출해 작업을 감싸는 것이고, GPU는 이들을 제출 순서대로 실행합니다.</p>
<h2 id="숫자가-잘못된-방향으로-간다" tabindex="-1">숫자가 잘못된 방향으로 간다 <a class="header-anchor" href="#숫자가-잘못된-방향으로-간다" aria-label="Permalink to &quot;숫자가 잘못된 방향으로 간다&quot;"></a></h2>
<p>M 시리즈 Mac에서 약 1080p, 80m 들판 위에 교차 카드 풀잎을 깔고 측정했습니다.</p>
<p>인스턴스 5만 개에서 vis-buffer 경로가 25% 이겼습니다. 4.13ms 대 forward의 5.51ms입니다. 10만 개에서는 비겼습니다. 20만 개에서는 forward가 44% 이겼습니다. 5.44ms 대 vis-buffer의 7.80ms입니다. 밀도가 올라갈수록 vis-buffer 경로는 <em>상대적으로 더 나빠지는데</em>, 이는 overdraw가 심할 때 바로 이긴다는 통설과 정확히 반대입니다.</p>
<h2 id="forward가-버티는-이유" tabindex="-1">forward가 버티는 이유 <a class="header-anchor" href="#forward가-버티는-이유" aria-label="Permalink to &quot;forward가 버티는 이유&quot;"></a></h2>
<p>Apple Silicon GPU는 타일 기반 디퍼드 렌더러(TBDR)이고, 이것이 계산 전체를 바꿔 놓습니다. TBDR 위의 forward 셰이딩에는 프래그먼트 셰이더가 돌기 전에 실행되는 은면 제거(HSR) 단계가 있습니다. 래스터라이저가 한 타일에 매핑되는 모든 프래그먼트를 모아 깊이로 정렬하고, 살아남은 것들(alpha-test 통과 이후)만 프래그먼트 셰이더에 도달합니다. 그래서 forward 경로는 이미 하드웨어 안에서, 공짜로, visibility buffer의 &quot;픽셀당 한 번만 셰이딩&quot; 약속의 대부분을 이행하고 있습니다. 풀잎이 화면을 가득 채울수록 더 많은 프래그먼트가 셰이딩이 일어나기 전에 HSR에서 거절되고, forward의 실효 픽셀당 비용은 overdraw와 함께 늘어나는 대신 대체로 평평하게 유지됩니다.</p>
<p>vis-buffer 경로의 pass 1도 똑같은 TBDR 이점을 얻습니다. 문제는 전부 pass 2에 있습니다. Pass 2는 각 픽셀의 인스턴스 행렬을 버퍼에서 읽는데, 이 버퍼는 인스턴스 20만 개에서 12.8MB로, 어떤 GPU 캐시보다도 훨씬 큽니다. 화면에서 인접한 픽셀들은 대개 서로 다른 풀 인스턴스에 속하므로(scatter가 지터링된 그리드라서 이웃 풀잎들은 임의의 인스턴스 ID를 가집니다), 그 버퍼를 치는 모든 wave가 발산적으로 캐시를 놓칩니다. 이 비일관 랜덤 접근 하나만으로도 프레임당 약 4ms가 숨어 있습니다. forward는 이를 완전히 피하는데, 인스턴스 행렬이 정점과 함께 인스턴스별 속성 경로로 도착하기 때문입니다. 그래서 프래그먼트 셰이더가 돌 때쯤이면 변환된 정점 데이터가 이미 타일 로컬 레지스터에 있어서 메가바이트 규모의 랜덤 읽기가 필요 없습니다.</p>
<p>이것이 바로 Nanite의 머티리얼 분류 pass가 분산시키려고 존재하는 그 비용입니다. 픽셀을 인스턴스별로 분류하고 정렬된 compute wave를 디스패치해서 각 wave의 읽기가 일관되게 만드는 것이죠. 우리에게는 그게 없습니다. 대략 계산해 보면 픽셀을 인스턴스별로 정렬하면 그 4ms를 1.5에서 2ms 정도로 떨어뜨리고 교차점을 인스턴스 40만에서 50만 개로 밀어낼 수 있습니다. 하지만 그건 애초에 여기서 이기지 못하는 아키텍처 위에 최적화를 쌓는 일입니다.</p>
<h2 id="솔직한-결론-그리고-그것을-얻어-낸-감사" tabindex="-1">솔직한 결론, 그리고 그것을 얻어 낸 감사 <a class="header-anchor" href="#솔직한-결론-그리고-그것을-얻어-낸-감사" aria-label="Permalink to &quot;솔직한 결론, 그리고 그것을 얻어 낸 감사&quot;"></a></h2>
<p>Apple Silicon WebGPU에서 alpha-test 교차 카드 식물에 대해서는, three.js TSL 파이프라인의 forward 경로가 이미 vis-buffer 비용에 맞먹거나 그보다 낮습니다. 그리고 vis-buffer 배선은 인스턴스 20만 개를 한참 넘어서기 전까지, 그것도 정렬이나 비닝 pass를 추가로 넣어야만 눈에 보이는 어떤 것도 사 주지 못합니다. 프로덕션 엔진에 대한 현실적인 판단은 앞선 spike들에서 만든 forward 더하기 LOD 더하기 imposter 스택을 유지하고, 두 가지 중 하나가 될 때까지는 vis-buffer 인프라에 투자하지 않는 것입니다. 하나는 우리가 별도의 NVIDIA나 AMD GPU를 주력 배포 대상으로 삼는 경우(거기서는 overdraw 비용이 더 선형적입니다)이고, 다른 하나는 vis-buffer가 어차피 자연스러운 출력이 되는 meshlet 아키텍처로 옮겨 가는 경우입니다.</p>
<p>이 결과가 직관에 반하기 때문에, 결론은 비교가 공정할 때만 가치가 있습니다. 그래서 이 spike는 전체 감사를 한 번 거쳤습니다. 실제 버그 몇 개가 드러나서 고쳐졌습니다. 두 경로를 조용히 어긋나게 하던 풀잎 스케일 슬라이더, 반평행 법선 때문에 forward 풀잎의 절반이 칠흑같이 어둡게 렌더되던 문제(법선을 위로 통일하는 정석적인 식물 기법으로 해결), 그리고 vis-buffer가 약 2배 너무 밝게 읽히던 문제입니다. 이는 에너지 보존 <code>1/π</code> 대신 손으로 고른 Lambert 인자, 하드코딩된 앰비언트 항, 누락된 톤 매핑 때문이었습니다. 수정은 three.js의 정확한 ACES filmic 곡선을 WGSL로 그대로 옮기고, 매 프레임 실제 씬 라이트에서 조명 색과 강도를 읽도록 했습니다. 남은 알려진 격차인 pass 2의 직접 스페큘러 누락은 비교를 <em>vis-buffer 쪽으로</em> 편향시킵니다. 즉 forward는 픽셀당 엄밀히 더 많은 일을 하면서도 고밀도에서 여전히 이기고 있다는 뜻입니다. 그래서 헤드라인 결론은 낙관적인 게 아니라 보수적입니다. 유효한 단서 하나는 이렇습니다. 이 모든 것은 M 시리즈에 특정한 이야기이고, 교차점은 별도 카드에서는 충분히 뒤집힐 수 있으므로, 비 Apple 대상에 스택을 확정하기 전에 다시 돌려 볼 가치가 있습니다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>visibility buffer 렌더링.</strong> Pass 1은 지오메트리를 래스터화하고 삼각형 ID와 인스턴스 ID만 깊이와 함께 쓰며 셰이딩은 하지 않습니다. Pass 2는 풀스크린 해석으로, 덮인 픽셀마다 ID를 읽고 원본 삼각형을 다시 가져와 원근 보정된 무게중심 속성을 재구성하고, 보이는 각 픽셀을 한 번씩 셰이딩합니다. WebGPU에는 이식 가능한 프래그먼트 <code>primitive_index</code>가 없으므로, 삼각형 ID는 비인덱스 지오메트리 위에 <code>flat</code> 보간되는 정점별 속성으로 구워 넣습니다.</p>
<p><strong>TBDR 은면 제거 대 디퍼드 해석.</strong> 타일 기반 디퍼드 GPU(Apple Silicon)에서는 forward 셰이딩이 프래그먼트 셰이더가 돌기 전에 이미 가려진 프래그먼트를 거절하므로, visibility buffer의 한 번만 셰이딩하는 이점 대부분을 공짜로 가져가고, 그 픽셀당 비용은 overdraw가 늘어도 대체로 평평하게 유지됩니다. 반면 vis-buffer 해석 pass는 큰 인스턴스별 버퍼(인스턴스 20만 개에서 12.8MB)로의 비일관 랜덤 접근에 비용을 치르는데, 이는 Nanite의 머티리얼 분류처럼 픽셀을 먼저 인스턴스별로 정렬하거나 비닝하지 않는 한 고밀도에서 지배적입니다.</p>
<p><strong>three.js의 WebGPURenderer와 캔버스 공유.</strong> raw WebGPU 커맨드 버퍼는 <code>context.configure()</code>를 다시 호출하지 않고 <code>canvas.width/height</code>를 쓰지 않는 한 공유 큐 위에서 three.js 제출과 올바르게 교차됩니다. 둘 다 렌더러가 관리합니다. three.js가 훅을 노출하지 않는 forward 경로 GPU 타이밍은, 그 렌더 호출 앞뒤로 no-op 타임스탬프 렌더 pass를 두 개 제출해서 감쌀 수 있습니다. GPU가 커맨드 버퍼를 제출 순서대로 실행하기 때문입니다.</p>
<p><strong>직관에 반하는 벤치마크 검증하기.</strong> 놀라운 성능 결과는 비교의 공정성만큼만 믿을 수 있습니다. 두 경로를 동일한 씬 콘텐츠와 셰이딩으로 감사하는 것(일치하는 ACES 톤 매핑, 에너지 보존 Lambert, 같은 오브젝트에서 읽은 라이트, 동일한 풀잎 스케일)이 바로 &quot;vis-buffer가 더 느리다&quot;를 그럴듯한 측정 잡음에서 방어 가능한 결론으로 바꿔 놓았고, 남은 한 가지 비대칭은 보수적인 방향으로 편향되어 있습니다.</p>
<hr>
<p>29부 중 21부.
이전: <a href="/ko/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion.html">20부 - 평평한 면에 깊이를 가짜로 만들기</a>
다음: <a href="/ko/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets.html">22부 - 뚫고 날아갈 수 있는 구름, 그리고 값을 하는 컬링</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 20부: 평평한 면 위에서 깊이를 흉내내기]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion</guid>
            <pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 39는 시차 차폐 매핑을 TSL로 이식하면서 WebGPU 셰이더 제어 흐름의 두 벽에 부딪혔고, 버그의 원인이 한 줄 한 줄 그대로 이식하는 규율의 실패였음을 알아냈으며, 스스로를 정직하게 유지하기 위해 실제 지오메트리로 만든 기준 평면을 만들었다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-20부-평평한-면-위에서-깊이를-흉내내기" tabindex="-1">브라우저에서 오픈 월드 만들기, 20부: 평평한 면 위에서 깊이를 흉내내기 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-20부-평평한-면-위에서-깊이를-흉내내기" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 20부: 평평한 면 위에서 깊이를 흉내내기&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva의 CTO이자 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부를 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-04-open-world-browser-part-19-imposters.html">19부</a>는 평평한 쿼드 하나로 멀리 있는 나무 전체를 흉내냈습니다. 이번 부는 평평한 쿼드 하나로 가까이에서 깊이를 흉내냅니다. 시차 차폐 매핑(parallax occlusion mapping), 추가 정점을 단 하나도 쓰지 않고 자갈길에 5cm 깊이로 들어간 줄눈이 있는 것처럼 보이게 만드는 기법입니다. 목표는 이걸 프로덕션 스택(Three.js r184, WebGPU, TSL)에 안착시켜서, 지형 디테일 머티리얼이 깊이가 중요한 곳에서는 그 깊이 착시를 가져가고 나머지 모든 곳에서는 평평한 텍스처 비용만 내도록 하는 것이었습니다.</p>
<h2 id="깊이를-흉내내는-세-가지-방법-나란히" tabindex="-1">깊이를 흉내내는 세 가지 방법, 나란히 <a class="header-anchor" href="#깊이를-흉내내는-세-가지-방법-나란히" aria-label="Permalink to &quot;깊이를 흉내내는 세 가지 방법, 나란히&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/39-parallax-pom/" title="Spike 39 Parallax Occlusion Mapping" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/39-parallax-pom/" target="_blank">새 탭에서 Spike 39 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=39-parallax-pom">소스 보기</a></p>
<p>이 spike는 평평한 5×5m 평면 세 개를 나란히 놓습니다. 모두 같은 머티리얼 골격을 쓰고, 다른 점은 샘플러에 들어가는 UV뿐입니다. Flat은 텍스처를 그대로 샘플링하는, 기준선이 되는 베이스라인입니다. 단일 샘플 시차는 그 지점의 높이만큼 시선 방향을 따라 UV를 한 번 밀어내는데, 저렴하고 낮은 진폭에서는 괜찮지만 비스듬한 각도에서는 출렁입니다. POM은 접선 공간에서 광선 행진(ray-march)을 합니다. 시선 광선을 따라 한 단계씩 나아가며 광선이 높이장 아래로 내려가는 첫 번째 층을 찾고, 그 교차점을 정교하게 다듬습니다. 모든 테스트 평면이 축에 정렬되어 있어서 접선 공간은 단순하게 유지됩니다. 그래서 시선 방향은 정점마다 필요한 완전한 TBN 행렬 대신 부호 몇 개만 뒤집으면 접선 공간으로 패킹됩니다. 텍스처 세트는 Polyhaven 파일 API에서 실시간으로 가져오는데, 17부의 모델 검색이 쓴 것과 같은 경로입니다.</p>
<h2 id="webgpu의-두-벽-그리고-분기-없는-광선-행진" tabindex="-1">WebGPU의 두 벽, 그리고 분기 없는 광선 행진 <a class="header-anchor" href="#webgpu의-두-벽-그리고-분기-없는-광선-행진" aria-label="Permalink to &quot;WebGPU의 두 벽, 그리고 분기 없는 광선 행진&quot;"></a></h2>
<p>교과서적인 POM 루프는 첫 교차에서 검색을 빠져나옵니다. r184에서는 이게 통하지 않는데, 서로 별개인 두 가지 이유 때문입니다. <code>If(...).and(...)</code>는 오류 없이 컴파일됐지만 루프 본문이 절대 실행되지 않는 WGSL을 만들어내서, 루프 뒤의 정교화가 쓰레기 데이터 위에서 돌았고 평면이 거의 흰색으로 렌더링됐습니다. 그리고 독립 노드로서의 <code>Break()</code>는 r184 빌드에 아예 들어오지 않아서, <code>If</code>가 제대로 동작하더라도 &quot;첫 교차에서 멈춰라&quot;를 표현할 방법이 없었습니다. 둘 다 이 버전 구간에서 TSL 제어 흐름이 <code>If</code>와 <code>Loop</code> 경계를 넘어 과하게 최적화하는, three.js의 알려진 이슈들로 거슬러 올라갑니다.</p>
<p>다시 쓴 버전은 분기가 없습니다. 매 반복마다 무조건 텍스처를 샘플링하는데, 이렇게 하면 WGSL 명세가 원하는 대로 텍스처 접근을 균일한 제어 흐름 안에 유지하게 되고, 그런 다음 float으로 들고 있는 <code>done</code> 플래그를 통해 새 상태를 접어 넣습니다. <code>done</code>이 1로 뒤집히면 반복마다의 <code>mix</code> 호출은 &quot;상태를 그대로 유지&quot;로 퇴화하는데, 이것이 break의 분기 없는 등가물입니다. <code>done</code> 플래그는 <code>0.5 + 0.5 × sign(x + ε)</code>로 구현한 <code>step</code> 헬퍼로 만듭니다. 불리언에서 float으로의 강제 변환이 r18x 계열 전반에서 들쭉날쭉했던 반면 <code>sign()</code>은 어디서나 안전하기 때문입니다. 비용은 프래그먼트가 실제로 어디서 교차하든 모든 프래그먼트가 64회 반복을 전부 돈다는 것이지만, 프래그먼트 규모에서는 이게 맞는 거래입니다. 런타임이 어차피 최대 단계 수로 제한을 걸고, 진짜 GPU도 &quot;진짜&quot; break를 만나면 그것을 넘어 추측 실행을 했을 테니까요. 여기서는 깔끔한 폴백이 중요합니다. 마지막 <code>mix(baseUV, refined, done)</code> 덕분에, 진폭이 0일 때(거리 페이드의 먼 끝) 어떤 프래그먼트도 교차하지 않고 <code>done</code>은 0으로 남으며 POM 머티리얼은 flat과 비트 단위로 동일해집니다. 이것이 바로 거리-LOD 트릭의 핵심입니다. 효과가 어차피 서브픽셀인 곳에서는 비용을 평평한 비용으로 무너뜨리는 것이죠.</p>
<h2 id="버그는-수학의-실패가-아니라-규율의-실패였다" tabindex="-1">버그는 수학의 실패가 아니라 규율의 실패였다 <a class="header-anchor" href="#버그는-수학의-실패가-아니라-규율의-실패였다" aria-label="Permalink to &quot;버그는 수학의 실패가 아니라 규율의 실패였다&quot;"></a></h2>
<p>분기 없는 버전은 돌긴 했지만 왜곡되어 보였습니다. 중간 진폭에서는 줄무늬 같은 수평 아티팩트가, 낮은 진폭에서는 &quot;미묘하게 틀렸지만 또렷하지는 않은&quot; 결과가 나왔습니다. 해결책은 한 줄짜리 프롬프트에서 나왔습니다. 정본 참조를 가서 읽어라. 이걸 떠올리게 한 LlamAcademy 튜토리얼은 그저 Unity ShaderGraph 노드 하나라서, 진짜 구현은 Unity의 <code>PerPixelDisplacement.hlsl</code>에 들어 있습니다. 한 줄 한 줄 읽으면서, 제가 모르고 들여놓은 세 가지 의미 차이가 드러났습니다. 광선 높이 베이스라인의 하나 차이 오류(Unity는 루프 전에 초기 전진을 한 번 해서, 제 기준 틀이 한 단계 통째로 위상이 어긋나 있었고 그래서 약 절반의 경우 교차점이 잘못된 층에 떨어졌습니다), 정교화 단계가 의존하는 최대 오프셋의 부호 관례, 그리고 제 정교화 수학을 더 힘들게 만들고 부호를 엉키게 한 누적 오프셋 대 누적 UV의 장부 기록 선택이었습니다.</p>
<p>근본 원인은 어느 한 가지 실수가 아니라 두 참조를 섞은 것이었습니다. 저는 LearnOpenGL의 POM 튜토리얼을 길잡이로 삼았는데, 거기는 비슷하지만 다른 부호 관례와 다른 정교화 공식을 씁니다. 결국 수학의 3분의 2는 한 출처와 맞고 3분의 1은 다른 출처와 맞는 잡종 상태에 빠졌습니다. 다시 쓴 버전은 Unity의 HLSL을 거의 한 글자 한 글자 TSL로 옮긴 것으로, 같은 변수 이름, 같은 초기 전진, 같은 정교화에 분기 없는 <code>done</code> 플래그를 위에 얹었습니다. 새겨둘 만한 교훈입니다. 다른 스택에서 검증된 셰이더를 이식할 때는, 먼저 같은 이름으로 한 줄 한 줄 옮긴 다음에 로컬 스타일에 맞게 리팩터링하세요. 이식 중간에 두 번째 참조에 대고 다시 유도하지 마세요.</p>
<h2 id="거짓말을-할-수-없는-기준-평면" tabindex="-1">거짓말을 할 수 없는 기준 평면 <a class="header-anchor" href="#거짓말을-할-수-없는-기준-평면" aria-label="Permalink to &quot;거짓말을 할 수 없는 기준 평면&quot;"></a></h2>
<p>나란히 놓은 비교에는 가장 뻔한 것이 빠져 있었습니다. 실제 지오메트리 평면 말입니다. 그게 없으면 &quot;POM이 꽤 괜찮아 보인다&quot;는 반증할 수 없습니다. 꽤 괜찮다는 건 무엇과 비교해서요? 그래서 spike는 네 번째 평면을 추가했습니다. 같은 높이 맵을 실제 정점 위치로 밀어낸 것입니다. WebGPU에는 하드웨어 테셀레이션이 없어서(그냥 명세에 들어 있지 않고, Metal 호환성 때문에 잘려나갔습니다), 그 대체물은 정점 단계에서 정점 변위를 적용한 촘촘하게 분할된 평면(256×256 세그먼트, 131,072개 삼각형)입니다. 같은 진폭 uniform이 POM과 지오메트리 평면을 둘 다 구동하므로, 둘은 함께 페이드되고 비교는 모든 거리에서 같은 것끼리의 비교로 유지됩니다.</p>
<p>화면에 정답이 떠 있게 되자 정성적인 주장들이 측정 가능해졌습니다. 아래를 내려다보는 16° 궤도에서 POM과 테셀레이션된 평면은 내부 음영에서 일치합니다. 비스듬한 각도에서는 둘이 갈라져야 할 바로 그 지점에서 갈라집니다. POM은 지오메트리의 완벽하게 곧은 직사각형 가장자리에 클램프되는 반면, 진짜 메시는 빛을 받는 실제 봉우리와 골짜기들로 이루어진 울퉁불퉁한 지평선 윤곽을 보여줍니다. 그래서 POM의 가장자리 &quot;출렁임&quot;은 이제 텍스처나 조명의 아티팩트가 아니라 알고리즘에 본질적으로 내재한 것임이 증명됩니다. 두 가지 비용 형태도 분명해집니다. POM은 프래그먼트에 묶여 있고(비용이 덮인 픽셀에 비례), 테셀레이션된 평면은 정점에 묶여 있습니다(비용이 커버리지와 무관하게 메시 밀도에 비례). 이미 높이 맵으로 구동되는 평면의 정점 비용을 내고 있는 지형 청크에게는, 메시보다 작은 디테일에 대해서는 POM이 정답입니다.</p>
<p>기준 평면은 미묘한 UX 버그도 잡아냈습니다. 사용자는 진폭이 커질수록 표면이 가라앉는 것처럼 보인다는 걸 알아챘습니다. 이는 기하 평면을 높이장의 꼭대기로 취급하는 Unity의 관례로 거슬러 올라갑니다. 봉우리들이 딱 붙어 고정되고 나머지 모든 것이 아래로 시차 처리되면서, 평균 표면을 평평한 베이스라인 아래로 <code>(1 − mean_h) × amplitude</code>만큼 끌어내린 것이죠. 해결책은 관례를 다시 중앙에 맞춰 <code>h = 0.5</code>가 평면이 되고, 봉우리는 카메라 쪽으로 솟고 골짜기는 안으로 들어가게 한 것입니다. 알고리즘은 Unity가 규정한 그대로 돌아갑니다. spike는 그저 슬라이더를 끄는 사람에게 &quot;진폭&quot;이 의미해야 할 바에 맞추기 위해 출력을 절반 오프셋만큼 후처리할 뿐입니다.</p>
<p>기준 평면이 정리해 준 게 하나 더 있습니다. &quot;Steps&quot; 슬라이더가 아무것도 안 하는 것처럼 보였는데, 배관 버그처럼 읽혔지만 아니었습니다. 선형 검색 뒤의 세 번 할선법(secant) 정교화가 너무 좋아서(Tatarchuk의 2006년 POM 논문은 4단계 검색에 3단계 할선법을 더하면 64단계 검색과 시각적으로 구별할 수 없다고 적습니다), 매끄러운 높이 맵에서는 4부터 64까지 모든 단계 수가 같은 서브텍셀 UV로 수렴합니다. 해결책은 다시 배관하는 게 아니라 토글이었습니다. 할선법을 끄면 단계 슬라이더가 교차 정밀도를 다루는 유일한 컨트롤이 되어서, 4로 떨어뜨리면 자갈이 눈에 띄게 계단처럼 끊기고 64로 끌어올리면 다시 매끈해집니다. 이 토글은 0/1 uniform으로, 꺼져 있을 때 매 할선법 상태 갱신을 no-op으로 <code>mix</code>하므로, 토글해도 머티리얼을 절대 다시 만들지 않고 절대 끊기지 않습니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>TSL 안의 시차 차폐 매핑.</strong> POM은 접선 공간에서 높이장을 따라 시선 방향으로 광선 행진을 하고, 광선이 표면 아래로 떨어지는 첫 번째 층을 찾아 교차점을 정교화하여, 추가 지오메트리 없이 평평한 쿼드 위에 들어간 줄눈의 깊이를 만들어냅니다. 마지막 <code>mix(baseUV, refined, done)</code>은 어떤 프래그먼트도 교차하지 않을 때 머티리얼을 flat과 비트 단위로 동일하게 만들고, 이것이 거리-LOD 진폭 감쇠가 멀리서 비용을 평평한 텍스처 비용으로 무너뜨리게 해주는 핵심입니다. <a href="/ko/guides/landscape-generation-browser.html#terrain-materials">지형 머티리얼</a>을 보세요.</p>
<p><strong>WebGPU 제어 흐름을 위한 분기 없는 루프.</strong> Three.js r184에서 TSL <code>If(...).and(...)</code>는 루프 본문이 절대 돌지 않는 WGSL로 컴파일될 수 있고, 독립 <code>Break()</code>는 쓸 수 없습니다. 이식 가능한 패턴은 반복마다 무조건 텍스처를 한 번 샘플링하고(WGSL 명세에 따라 텍스처 접근을 균일한 제어 흐름에 유지), float으로 들고 있는 <code>done</code> 플래그를 더해 한 번 설정되면 매 상태 갱신을 no-op으로 <code>mix</code>하는 것입니다. <code>sign(x + ε)</code>로 만든 <code>step</code> 헬퍼는 신뢰할 수 없는 불리언-float 강제 변환을 피합니다. 비용은 조기 종료 지점이 어디든 최대 반복 수를 도는 것이고, 이는 프래그먼트 규모에서 올바른 거래입니다.</p>
<p><strong>한 글자 그대로 셰이더 이식.</strong> 다른 엔진에서 검증된 셰이더를 이식할 때는, 먼저 원본의 변수 이름으로 한 줄 한 줄 옮기고 그다음에 로컬 스타일에 맞게 리팩터링해야 합니다. 두 참조(Unity의 <code>PerPixelDisplacement.hlsl</code>과 LearnOpenGL 튜토리얼)를 섞으면 잡종이 나왔습니다. 광선 베이스라인의 하나 차이, 뒤집힌 오프셋 부호, 그리고 클램프가 범위 밖 가중치를 공간적 불연속으로 가려버린 정교화 공식이 나온 것이죠. 다시 유도하는 게 아니라 하나의 정본 정답이 답입니다.</p>
<p><strong>정점 변위로 만든 정답 기준.</strong> WebGPU에 하드웨어 테셀레이션이 없으니, 정점 단계에서 변위시킨 촘촘하게 분할된 평면(256² 세그먼트)이 진짜 지오메트리를 대신해 프래그먼트 단계의 흉내를 검증합니다. 같은 진폭 uniform으로 둘 다 구동하면 비교가 거리 전반에서 정직하게 유지됩니다. POM은 프래그먼트에 묶여 있고(덮인 픽셀에 비례), 지오메트리 평면은 정점에 묶여 있어서(메시 밀도에 비례), 둘은 정확히 실루엣 가장자리에서 갈라지며, POM의 가장자리 출렁임이 아티팩트가 아니라 본질적인 것임을 증명합니다.</p>
<hr>
<p>29부 중 20부.
이전: <a href="/ko/blog/2026-05-04-open-world-browser-part-19-imposters.html">19부 - 숲에서 살아남아야 하는 임포스터</a>
다음: <a href="/ko/blog/2026-05-06-open-world-browser-part-21-visibility-buffer.html">21부 - 더 빠르지 않았던 더 빠른 렌더러</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈월드 만들기, 19부: 숲에서 살아남아야 하는 임포스터]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-04-open-world-browser-part-19-imposters</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-04-open-world-browser-part-19-imposters</guid>
            <pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 38은 나무 하나를 빌보드 위 두 장의 텍스처로 구워냈고, 그다음 KISS 재작성과 홀수 N 수정으로 모양을 맞췄다. Spike 41-42는 헤미옥타헤드럴 블렌딩으로 스냅을 없애고 나무 백만 그루를 GPU로 밀어 올렸다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈월드-만들기-19부-숲에서-살아남아야-하는-임포스터" tabindex="-1">브라우저에서 오픈월드 만들기, 19부: 숲에서 살아남아야 하는 임포스터 <a class="header-anchor" href="#브라우저에서-오픈월드-만들기-19부-숲에서-살아남아야-하는-임포스터" aria-label="Permalink to &quot;브라우저에서 오픈월드 만들기, 19부: 숲에서 살아남아야 하는 임포스터&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-02-open-world-browser-part-18-ai-scattering.html">18부</a>는 창작자에게 산비탈을 나무로 채우는 브러시를 줬습니다. 문제는 화면에 나무가 수만 그루 있을 때 그 나무들이 얼마나 비싸지는가입니다. 멀리 있는 나무는 픽셀 네 개를 채우려고 삼각형 2,000개를 쓸 필요가 없습니다. 이번 편은 가장 깊은 LOD입니다. 임포스터, 즉 나무 사진을 입은 평평한 quad, 그리고 &quot;제대로 보이는 나무 한 그루&quot;에서 GPU 위 백만 그루까지 가는 길입니다.</p>
<h2 id="나무-하나는-빌보드-위-두-장의-텍스처" tabindex="-1">나무 하나는 빌보드 위 두 장의 텍스처 <a class="header-anchor" href="#나무-하나는-빌보드-위-두-장의-텍스처" aria-label="Permalink to &quot;나무 하나는 빌보드 위 두 장의 텍스처&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/38-imposters/" title="Spike 38 Octahedral Imposters" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/38-imposters/" target="_blank">새 탭에서 Spike 38 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=38-imposters">소스 보기</a></p>
<p>임포스터는 프롭을 시점 각도 격자에서 두 장의 텍스처 아틀라스로 미리 렌더링합니다. 하나는 색상용, 하나는 월드 공간 노멀용입니다. 그런 다음 런타임에는 현재 시점과 맞는 타일을 샘플링하는, 카메라를 향한 단일 quad 하나를 보여줍니다. 베이크는 타일마다 두 패스입니다. 디퓨즈는 무광 머티리얼로 굽기 때문에 조명이 텍스처에 구워지지 않고, 노멀은 <code>normalWorld × 0.5 + 0.5</code>로 인코딩하며 알파는 소스에서 그대로 가져와 실루엣이 픽셀 단위로 맞습니다. 런타임 머티리얼은 완전한 <code>MeshStandardNodeMaterial</code>이라서, 임포스터도 다른 표면과 똑같이 씬의 태양광과 IBL을 받습니다. 이득은 지오메트리에 있습니다. 삼각형 수천 개 대신 quad 하나, 그리고 디테일은 1 MB짜리 텍스처 안에 들어 있습니다.</p>
<p>이걸 별도 spike로 떼어낸 것 자체가 하나의 교훈이었습니다. 임포스터는 처음에 spike 37의 스캐터 시스템 안에서 가장 깊은 LOD였고, 베이크를 한 번 고칠 때마다 전체 스캐터 파이프라인을 거쳐 테스트해야 했습니다. 베이크의 정확성이 인스턴스 행렬 마이그레이션과 LOD 교체에 뒤엉켜 있었던 거죠. 이걸 떼어내 프롭 하나, quad 하나로 원본과 나란히 놓으니 반복 시간이 몇 분에서 몇 초로 줄었습니다.</p>
<h2 id="교과서-정답이-오답일-때" tabindex="-1">교과서 정답이 오답일 때 <a class="header-anchor" href="#교과서-정답이-오답일-때" aria-label="Permalink to &quot;교과서 정답이 오답일 때&quot;"></a></h2>
<p>첫 번째 구현은 옥타헤드럴 인코딩을 썼습니다. 구면 방향을 정사각형에 채우는 교과서적 매핑이죠. 수치 왕복 테스트는 통과했는데, 사용자는 임포스터가 정면이 아니라 약간 위에서 본 나무처럼 보이는 타일로 스냅됐다는 스크린샷을 계속 보냈습니다. 여섯 라운드의 수정이 이어졌습니다(quad별 시점 방향 uniform, 정사각형 베이크 종횡비, 디버그 머티리얼, 정적 빌보딩). 모두 진짜로 필요한 것이었지만, 그중 어느 것도 실제 버그는 아니었습니다. 수정은 &quot;처음부터 다시 생각하자, KISS, 반창고는 그만&quot;에서야 나왔습니다.</p>
<p>재작성은 옥타헤드럴 폴딩을 버리고 단순한 방위각 곱하기 고도각으로 갔습니다. <code>az = atan2(dir.x, dir.z)</code>, <code>el = asin(dir.y)</code>, <code>uv = (az/2π, el/π + ½)</code>. 이게 인코딩의 전부입니다. L1 정규화도 없고, 부호가 0인 코너 케이스도 없습니다. 여기서 이게 더 나은 이유는 더 정확해서가 아니라(오히려 덜 균일한 구면을 샘플링합니다), CPU 셀 선택기와 GPU 셰이더가 같은 기본 연산을 써서 옥타헤드럴 쌍이 조용히 그랬던 것처럼 경계 방향에서 서로 어긋날 수가 없기 때문입니다. 아틀라스는 컨택트 시트처럼 읽힙니다. 열은 프롭 주위를 도는 각도, 행은 고도각이라서 오버레이에서 한눈에 분명합니다.</p>
<p>그 뒤에도 &quot;약간 위에서 본 것 같다&quot;는 불만은 살아남았고, 원인은 인코딩이 아니라 양자화 선택이었습니다. 4×4 격자에서는 행 중심이 ±22.5°와 ±67.5°에 떨어져서 정확히 0° 고도각인 행이 없습니다. 수평으로 보는 시청자는, 압도적으로 흔한 경우인데, 항상 기울어진 채로 구워진 행에 떨어집니다. 해법은 홀수 N입니다. 5×5 격자는 행 중심을 0°와 ±36°, ±72°에 놓아서 수평 시청자가 정확히 수평으로 구워진 타일을 받습니다. 같은 부류의 &quot;반 셀 차이&quot; 실수는 다음 편의 패럴랙스 작업에서 또 나타나고, 처방은 같은 질문입니다. 내 이산 샘플 점이 정규 입력에 대해 정말 내가 생각하는 자리에 떨어지는가?</p>
<p>두 가지가 더 중요했습니다. 빌보드는 카메라를 계속 향하는 게 아니라 구간별로 정적이어야 합니다. 임포스터는 특정 베이크 방향에서 찍은 평평한 사진이라서 런타임 quad의 이미지 평면이 그 베이크 카메라의 평면과 맞아야 합니다. 즉 한 셀이 선택된 채로 유지되는 호 구간 동안에는 방향을 유지하다가 경계에서 스냅합니다. 그리고 예산은 플레이어가 실제로 보는 쪽을 따라가야 합니다. 이후 한 패스에서 기울어진 탑다운 행들을 통째로 버리고 15° 간격의 수평 링 슬롯 24개에 정중앙 아래 타일 하나를 더한 구성으로 바꿨습니다. 나무는 거의 언제나 눈높이에서 보이기 때문입니다.</p>
<h2 id="스냅-그리고-블렌딩이-그걸-지운-방법" tabindex="-1">스냅, 그리고 블렌딩이 그걸 지운 방법 <a class="header-anchor" href="#스냅-그리고-블렌딩이-그걸-지운-방법" aria-label="Permalink to &quot;스냅, 그리고 블렌딩이 그걸 지운 방법&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/42-imposter-flicker/" title="Spike 42 Imposter Flicker Comparison" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/42-imposter-flicker/" target="_blank">새 탭에서 Spike 42 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=42-imposter-flicker">소스 보기</a></p>
<p>구간별로 정적인 빌보드는 멀리서는 보이지 않고 가까이서는 튀는데, 이건 궤도를 돌기 전까지는 괜찮습니다. Spike 42는 변형 네 개를 나란히 놓아(원본 프롭, az/el 5×5 기준선, 헤미옥타헤드럴 격자 둘) 깜빡임을 분리하고 없앴습니다. 두 가지 아티팩트가 스냅을 일으킵니다. 셀 팝은 프래그먼트 셰이더가 시점 방향을 25개 셀 중 하나로 양자화하기 때문에 일어납니다. 경계를 넘으면 같은 프레임에서 샘플링하는 타일이 바뀌고 quad가 다시 조준됩니다. 극점 퇴화는 탑다운 시점인데, 거기서는 모든 방위각이 한 점으로 무너지고 링과 상단 타일 사이의 다리가 아틀라스에서 가장 나쁜 전환입니다.</p>
<p>헤미옥타헤드럴 매핑은 둘 다 고칩니다. 상반구를 단위 정사각형 위로 연속적으로 매핑하기 때문에 인접한 3D 방향이 인접한 UV에 떨어지고, 극점 특이점도 없고 특수한 탑다운 타일도 필요 없습니다. 깜빡임의 처방은 양선형 셀 블렌딩입니다. 가장 가까운 타일로 스냅하는 대신, 인코딩된 방향을 감싸는 2×2 타일 묶음을 찾아 넷 모두를 블렌딩합니다. 텍스처 탭은 총 8회입니다(디퓨즈 4, 노멀 4). 인접한 시점들이 이제 팝 대신 크로스페이드합니다. 두 단위 벡터의 노멀 블렌드 자체는 단위 길이가 아니라서 다시 정규화하는데, 이웃 타일 사이의 작은 각도에 대해서는 slerp처럼 동작합니다. 비용은 실제로 듭니다(12×12 아틀라스는 약 9 MB로 az/el의 1.6 MB와 비교되고, 베이크는 288개 렌더 타깃 패스에서 대략 5배 더 오래 걸립니다). 하지만 베이크는 로드 시 한 번뿐이고, 블렌딩은 팝 없는 결과를 사 줍니다. 이게 바로 카메라가 실제로 움직이는 동안 임포스터를 쓸 만하게 만드는 것입니다.</p>
<h2 id="나무-백만-그루-프레임당-카메라-위치-복사-한-번" tabindex="-1">나무 백만 그루, 프레임당 카메라 위치 복사 한 번 <a class="header-anchor" href="#나무-백만-그루-프레임당-카메라-위치-복사-한-번" aria-label="Permalink to &quot;나무 백만 그루, 프레임당 카메라 위치 복사 한 번&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/41-imposter-forest/" title="Spike 41 Imposter Forest" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/41-imposter-forest/" target="_blank">새 탭에서 Spike 41 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=41-imposter-forest">소스 보기</a></p>
<p>Spike 38의 런타임은 프레임마다 quad마다 CPU <code>lookAt</code>을 한 번 합니다. 나무 한 그루엔 괜찮지만 숲엔 치명적입니다. 나무 백만 그루면 프레임당 행렬 갱신과 인스턴스 버퍼 업로드가 모든 걸 압도합니다. Spike 41은 프레임당 파이프라인 전체를 GPU로 옮깁니다. 각 인스턴스의 중심, 요(yaw), 스케일은 빌드 시점에 인스턴스 attribute로 한 번 업로드되고 다시는 바뀌지 않습니다. 버텍스 셰이더는 월드 공간 시점 방향 <code>camPos − center</code>에서 빌보드 기저를 만들고 공유된 단위 quad를 월드 공간으로 펼칩니다. 프래그먼트 셰이더는 픽셀마다 헤미옥타헤드럴 인코딩과 양선형 블렌드를 합니다. 숲 전체에서 프레임당 유일한 CPU 작업은 카메라 위치 uniform을 갱신하는 <code>Vector3.copy</code> 한 번이고, 이건 나무 수에 전혀 비례하지 않습니다.</p>
<p>수학에서 멋진 한 부분은 인스턴스별 요가 노멀 디코드에서 상쇄된다는 것입니다. 베이크는 노멀을 베이크 카메라의 프레임에 저장하는데, 월드 업 축 둘레의 요 회전이 +Y를 보존하고 외적이 회전 등변이기 때문에, 월드 업 기준으로 만든 런타임 기저는 이미 회전된 베이크 기저와 같습니다. 그래서 셰이더는 인스턴스별 요를 전혀 건드리지 않고 런타임 기저 varying을 통해 노멀을 그대로 디코드합니다. 배치는 순수 랜덤 스캐터가 아니라 지터링된 격자를 씁니다. 영역을 셀로 나누고 셀마다 중심에 경계가 있는 오프셋을 더해 나무 하나를 떨어뜨리는데, 이렇게 하면 최소 간격이 보장되어(두 나무가 겹치지 않음) 동시에 여전히 자연스러운 숲으로 읽힙니다. 놓치기 쉬운 한 가지 디테일은 바운딩 스피어입니다. 지오메트리 템플릿은 그냥 단위 quad라서, 카메라가 원점에서 다른 방향을 보는 순간 three.js가 숲 전체를 프러스텀 컬링해 버립니다. 전체 영역에 quad 한 개분의 여유를 더해 덮는 명시적 바운딩 스피어를 설정하면 모서리의 나무들이 비스듬한 각도에서 잘려 나가지 않습니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>옥타헤드럴 및 방위각-고도각 임포스터 아틀라스.</strong> 임포스터는 프롭을 시점 방향 격자에서 디퓨즈 아틀라스 하나와 월드 공간 노멀 아틀라스 하나로 구운 뒤, 맞는 타일을 샘플링하는 단일 빌보드를 렌더링해 삼각형 수천 개를 두 장의 텍스처로 대체합니다. 교과서적인 옥타헤드럴 매핑은 균일한 구면 커버리지를 주지만 폴딩 경계에서 CPU/GPU가 어긋나기 쉽습니다. 단순한 방위각 곱하기 고도각 격자는 덜 균일한 구면을 샘플링하지만 구조적으로 셀 선택기와 셰이더가 일치하도록 보장합니다. 홀수 N을 써서 한 행이 정확히 0° 고도각에 떨어지게 하고, 프롭은 대부분 눈높이에서 보이므로 타일 예산을 수평 링에 쓰세요.</p>
<p><strong>구간별 정적 빌보드 방향.</strong> 임포스터는 특정 베이크 방향에서 찍은 사진이라서 런타임 quad의 이미지 평면이 런타임 카메라를 계속 향하는 게 아니라 베이크 카메라의 평면과 맞아야 합니다. quad는 한 셀이 선택된 채 유지되는 호 구간 동안 방향을 유지하다가 경계에서 스냅하는데, 이건 임포스터 거리에서는 보이지 않고 임포스터를 쓰지 않는 가까운 거리에서만 튑니다.</p>
<p><strong>양선형 셀 블렌드를 적용한 헤미옥타헤드럴 아틀라스.</strong> 상반구를 단위 정사각형 위로 연속적으로 매핑하면 극점 특이점과 특수한 탑다운 타일이 사라집니다. 스냅은 인코딩된 시점 방향을 감싸는 2×2 타일 묶음을 샘플링해 넷 모두를 양선형 블렌딩(8 탭)함으로써 없애므로 인접한 시점들이 크로스페이드합니다. 블렌딩된 노멀은 다시 정규화되어 타일 간의 작은 각도에 대해 slerp를 근사합니다. 비용은 더 큰 아틀라스(12×12에서 약 9 MB)와 더 긴 일회성 베이크이고, 그 대가로 카메라 움직임 아래에서 팝 없는 셰이딩을 얻습니다.</p>
<p><strong>GPU 구동 인스턴스화 임포스터.</strong> 인스턴스별 중심, 요, 스케일은 인스턴스 attribute로 한 번 업로드됩니다. 버텍스 셰이더는 빌보드 기저를 만들고 공유된 단위 quad를 펼치며, 프래그먼트 셰이더는 픽셀마다 인코딩과 블렌딩을 합니다. 숲 전체에 대한 프레임당 CPU 비용은 카메라 위치 uniform 복사 한 번이고 인스턴스 수와 무관합니다. 인스턴스별 요는 노멀 디코드에서 상쇄되는데, 월드 업 둘레의 요가 외적 기저 구성에 의해 보존되기 때문입니다. 명시적인 숲 전역 바운딩 스피어는 카메라가 단위 quad 템플릿의 원점에서 다른 방향을 볼 때 three.js가 인스턴스화 메시 전체를 프러스텀 컬링하는 것을 막습니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">GPU 구동 LOD</a>를 보세요.</p>
<hr>
<p>29부 중 19부.
이전: <a href="/ko/blog/2026-05-02-open-world-browser-part-18-ai-scattering.html">18부 - AI가 배치한 듯한 스캐터 브러시</a>
다음: <a href="/ko/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion.html">20부 - 평평한 면에서 깊이 속이기</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[현대 게임의 볼류메트릭 구름과 날씨 효과]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-04-volumetric-clouds-and-weather</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-04-volumetric-clouds-and-weather</guid>
            <pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[현대 게임이 볼류메트릭 구름, 대기 산란, 안개, 비, 눈, 동적 날씨를 어떻게 렌더링하는지, 그리고 각 기법 뒤에 있는 기초 논문과 엔진 발표 자료를 함께 살펴봅니다.]]></description>
            <content:encoded><![CDATA[<h1 id="현대-게임의-볼류메트릭-구름과-날씨-효과" tabindex="-1">현대 게임의 볼류메트릭 구름과 날씨 효과 <a class="header-anchor" href="#현대-게임의-볼류메트릭-구름과-날씨-효과" aria-label="Permalink to &quot;현대 게임의 볼류메트릭 구름과 날씨 효과&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<img src="/img/blog/clouds_weather_hero.webp" alt="Stylized AAA scene with towering volumetric storm clouds, lightning, rain shafts, and a wet stone road reflecting the sky" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>몇 주 전에 <a href="/ko/blog/2026-05-03-aaa-rendering-techniques.html">현대 AAA 게임이 실제로 출시하는 렌더링 기법</a>에 대해 썼습니다. 그때 얇게 다루고 넘어간 영역 하나가 하늘과 날씨인데, 따로 한 편으로 다룰 만한 주제이기 때문입니다. 구름, 안개, 비, 눈은 지형 데모를 하나의 장소로 바꿔주는 시스템입니다. 그리고 이들은 보기보다 훨씬 많은 코드를 공유합니다. 볼류메트릭 구름, 지면 안개, 갓 레이는 모두 같은 레이 마칭입니다. 젖은 도로, 눈 쌓임, 발자국 흔적은 모두 같은 변위 더하기 PBR 기법입니다. 바람은 장면 안의 모든 것이 읽어 들이는 하나의 방향 벡터입니다.</p>
<p>여기 2026년에 큰 스튜디오들이 이걸 어떻게 만드는지에 대한 짧고 주관적인 둘러보기를 준비했습니다. 각 요소 뒤에 있는 논문과 엔진 발표 자료도 함께 실었습니다.</p>
<h2 id="_1-물리-기반-하늘과-대기" tabindex="-1">1. 물리 기반 하늘과 대기 <a class="header-anchor" href="#_1-물리-기반-하늘과-대기" aria-label="Permalink to &quot;1. 물리 기반 하늘과 대기&quot;"></a></h2>
<p>대기 산란이 기초입니다. 하늘의 색, 지평선의 아지랑이, 먼 산이 파랗게 보이는 이유, 해 질 녘의 주황빛, 이 모든 것이 공기를 통과하는 빛의 산란에서 나옵니다. 현대 엔진은 이걸 물리에서 계산합니다. 파란색을 만드는 레일리 산란, 태양 주위의 아지랑이를 만드는 미 산란, 천정의 짙은 보라색을 만드는 오존 흡수가 그것입니다.</p>
<p>원래 2008년 Bruneton 방식은 모든 것을 4D 룩업 테이블에 미리 구워 넣었는데, 이 때문에 동적 시간 변화가 제약을 받았고 낮은 태양 각도에서 LUT 아티팩트가 생겼습니다. Sébastien Hillaire의 2020년 업데이트는 (UE5의 Sky Atmosphere 컴포넌트가 쓰는 바로 그것입니다) 고차원 LUT를 몇 장의 2D 텍스처와 프레임마다 갱신되는 다중 산란 근사로 대체했습니다. 휴대폰부터 고사양 PC까지 다 돌아갑니다.</p>
<img src="/img/blog/clouds_weather_atmosphere.webp" alt="Physically based sky at golden hour with smooth orange-to-blue gradient over a distant mountain silhouette" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Hillaire, <a href="https://sebh.github.io/publications/egsr2020.pdf" target="_blank" rel="noreferrer">A Scalable and Production Ready Sky and Atmosphere Rendering Technique</a> (EGSR 2020, 현대 표준이며 UE5에서 사용).</li>
<li>Bruneton, Neyret, <a href="https://hal.inria.fr/inria-00288758/document" target="_blank" rel="noreferrer">Precomputed Atmospheric Scattering</a> (EGSR 2008, 원래의 LUT 접근).</li>
<li>Bruneton, <a href="https://ebruneton.github.io/precomputed_atmospheric_scattering/" target="_blank" rel="noreferrer">Precomputed Atmospheric Scattering: a New Implementation</a> (오픈소스 참조 구현, 오존과 다중 행성 지원).</li>
<li>Epic Games, <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/sky-atmosphere-component-in-unreal-engine" target="_blank" rel="noreferrer">Sky Atmosphere Component</a> (UE5 문서).</li>
</ul>
<h2 id="_2-perlin-worley-노이즈로-만드는-볼류메트릭-구름" tabindex="-1">2. Perlin-Worley 노이즈로 만드는 볼류메트릭 구름 <a class="header-anchor" href="#_2-perlin-worley-노이즈로-만드는-볼류메트릭-구름" aria-label="Permalink to &quot;2. Perlin-Worley 노이즈로 만드는 볼류메트릭 구름&quot;"></a></h2>
<p>현대 게임 볼류메트릭 구름의 기초 기법은 Andrew Schneider의 2015년 Horizon Zero Dawn 발표에서 시작됐습니다. 구름은 메시가 아닙니다. 구름은 계층화된 노이즈로 정의된 3D 밀도 함수입니다. 저주파 Perlin-Worley 혼합이 구름의 전체 형태를 만들고, 더 높은 주파수의 Worley 노이즈가 실루엣을 침식해 얇게 흩날리는 가장자리를 만듭니다. 날씨 맵(월드 XZ로 샘플링하는 2D 텍스처)이 지역별로 구름 양, 구름 종류, 강수를 제어합니다. 높이 기반 그래디언트가 고도에 따라 적운, 층운, 권운 프로파일 사이를 블렌딩합니다.</p>
<p>렌더러는 카메라에서 구름 볼륨을 가로질러 레이를 진행시키며 밀도와 산란을 누적합니다. 2017년의 &quot;Nubis&quot; 버전은 지역 규모의 저작과 애니메이션을 추가했고, 원래의 PS4 구현은 하늘 전체를 약 2ms에 처리했습니다. 오늘날 볼류메트릭 구름을 출시하는 대부분의 스튜디오는 여전히 그 혈통이 이 논문으로 거슬러 올라갑니다.</p>
<img src="/img/blog/clouds_weather_noise.webp" alt="A 3D cloud shape decomposed into stacked Perlin and Worley noise patterns showing how detail erodes the silhouette" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/the-real-time-volumetric-cloudscapes-of-horizon-zero-dawn" target="_blank" rel="noreferrer">The Real-Time Volumetric Cloudscapes of Horizon Zero Dawn</a> (SIGGRAPH 2015, 정전이라 할 만한 참고 자료).</li>
<li>Schneider, <a href="https://advances.realtimerendering.com/s2017/Nubis%20-%20Authoring%20Realtime%20Volumetric%20Cloudscapes%20with%20the%20Decima%20Engine%20-%20Final%20.pdf" target="_blank" rel="noreferrer">Nubis: Authoring Real-Time Volumetric Cloudscapes with the Decima Engine</a> (SIGGRAPH 2017, 지역 규모 후속편).</li>
<li>Hillaire, <a href="https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/s2016-pbs-frostbite-sky-clouds-new.pdf" target="_blank" rel="noreferrer">Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite</a> (SIGGRAPH 2016, Frostbite 버전).</li>
<li>Häggström, <a href="https://www.diva-portal.org/smash/get/diva2:1223894/FULLTEXT01.pdf" target="_blank" rel="noreferrer">Real-time rendering of volumetric clouds</a> (전체 셰이더 코드가 담긴 깔끔하고 접근하기 쉬운 논문).</li>
</ul>
<h2 id="_3-복셀-구름과-nubis3" tabindex="-1">3. 복셀 구름과 Nubis³ <a class="header-anchor" href="#_3-복셀-구름과-nubis3" aria-label="Permalink to &quot;3. 복셀 구름과 Nubis³&quot;"></a></h2>
<p>2023년의 Nubis 진화 버전은 2.5D 형상 표현을 완전히 버리고 진정한 3D 복셀을 택했습니다. 각 복셀이 구름 밀도를 직접 저장하므로, 아티스트가 지형을 조각하듯 구름 형태를 깎고 애니메이션할 수 있습니다. 더 조밀한 표현으로 옮겨가는 비용은, 압축된 부호 거리 필드를 이용한 레이 마칭 가속과 희소 복셀 데이터의 영리한 업레저로 되갚습니다.</p>
<p>그 결과는 기저의 트릭이 무너지는 게 보이지 않는 채로 <em>통과해</em> 날아다닐 수 있는 구름 풍경입니다. 대부분의 스튜디오에는 과한 수준이지만, 최상위가 향하고 있는 방향이기는 합니다.</p>
<img src="/img/blog/clouds_weather_voxel_clouds.webp" alt="A cumulus cloud shown decomposed into a 3D voxel grid, with smoothed wispy edges blending the chunky interior" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/nubis-cubed" target="_blank" rel="noreferrer">Nubis³: Methods (and madness) to model and render immersive real-time voxel-based clouds</a> (SIGGRAPH 2023, 복셀 구름 발표).</li>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/nubis-evolved" target="_blank" rel="noreferrer">Nubis, Evolved</a> (SIGGRAPH 2022, 2.5D와 완전한 3D 사이의 다리).</li>
<li>Schneider, <a href="https://www.schneidervfx.com/" target="_blank" rel="noreferrer">Real-time Volumetrics and VFX</a> (Andrew의 개인 사이트, 강의 노트와 분석 포함).</li>
</ul>
<h2 id="_4-계층형-구름-렌더링과-2d-배경" tabindex="-1">4. 계층형 구름 렌더링과 2D 배경 <a class="header-anchor" href="#_4-계층형-구름-렌더링과-2d-배경" aria-label="Permalink to &quot;4. 계층형 구름 렌더링과 2D 배경&quot;"></a></h2>
<p>모든 스튜디오가 풀 볼륨 구름을 감당할 수 있는 건 아니고, 모든 카메라 각도가 그걸 필요로 하는 것도 아닙니다. 많은 게임이 기법을 조합합니다. 고고도 권운은 스크롤하는 2D 레이어로, 중고도 적운은 볼류메트릭 레이로, 저고도 층운은 얇은 참여 매질 슬래브로 렌더링합니다. 지평선은 종종 미리 구워둔 하늘 큐브맵을 받고, 볼류메트릭 패스가 페이드 거리 너머에서 거기로 블렌딩됩니다.</p>
<p>이 계층화가 구름 예산을 정직하게 유지해 줍니다. 풀 퀄리티의 단일 구름 종류는 4~6ms를 먹어버릴 수 있는데, 구름 고도별로 서로 다른 퀄리티를 계층화하면 절반의 비용으로 같은 룩을 유지할 수 있습니다.</p>
<img src="/img/blog/clouds_weather_cloud_layers.webp" alt="Sunset sky split into three cloud layers: high cirrus wisps, mid cumulus puffs, and low stratus haze near the horizon" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Vos, <a href="https://www.gdcvault.com/play/1023327/The-Real-Time-Volumetric-Cloudscapes" target="_blank" rel="noreferrer">The Real-Time Volumetric Cloudscapes of Horizon Zero Dawn</a> (GDC 2016 영상, 계층화 분석은 후반부에).</li>
<li>Bauer, <a href="https://www.youtube.com/watch?v=IYxtqlD1-Ac" target="_blank" rel="noreferrer">Creating the Atmospheric World of Red Dead Redemption 2</a> (SIGGRAPH 2019, RDR2의 하늘/구름/볼류메트릭 통합 파이프라인).</li>
<li>Hillaire, <a href="https://www.gdcvault.com/play/1029105/Volumetric-Clouds-and" target="_blank" rel="noreferrer">Volumetric clouds and mega particles in REDengine 4</a> (GDC 2025, Cyberpunk 2077의 구름 파이프라인).</li>
</ul>
<h2 id="_5-프록셀-그리드를-쓰는-볼류메트릭-안개" tabindex="-1">5. 프록셀 그리드를 쓰는 볼류메트릭 안개 <a class="header-anchor" href="#_5-프록셀-그리드를-쓰는-볼류메트릭-안개" aria-label="Permalink to &quot;5. 프록셀 그리드를 쓰는 볼류메트릭 안개&quot;"></a></h2>
<p>안개는 2D 화면 효과가 아니라 3D 필드입니다. 현대의 표준 접근은 프록셀 그리드입니다. 카메라 뷰 프러스텀에 정렬된 3D 텍스처로, 각 셀(&quot;froxel&quot; = frustum + voxel)이 밀도와 조명된 색을 저장합니다. 컴퓨트 셰이더가 모든 광원으로부터 산란을 그리드에 주입하고, 뷰 레이를 따라 소광을 누적한 다음, 그 결과를 전체 화면 패스로 적용합니다.</p>
<p>이게 창문을 통과하는 광선, 점 광원 주위의 색깔 있는 안개, 폭발 주변의 보이는 볼륨을 만들어 줍니다. 또한 먼 물체를 공기 속으로 흐려지게 하는 &quot;대기 원근&quot;의 기반 기계장치이기도 합니다. 이 기법은 Assassin's Creed 4를 위해 Bart Wronski가 도입했고 Sébastien Hillaire가 Frostbite에서 표준화했습니다.</p>
<img src="/img/blog/clouds_weather_froxel_fog.webp" alt="Camera frustum visualized as a 3D froxel grid with smaller cells near the camera and bigger cells far away, fog particles inside" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Wronski, <a href="https://bartwronski.com/wp-content/uploads/2014/08/bwronski_volumetric_fog_siggraph2014.pdf" target="_blank" rel="noreferrer">Volumetric Fog: Unified Compute Shader Based Solution to Atmospheric Scattering</a> (SIGGRAPH 2014, 원래의 프록셀 그리드 논문).</li>
<li>Hillaire, <a href="http://www.frostbite.com/2015/08/physically-based-unified-volumetric-rendering-in-frostbite/" target="_blank" rel="noreferrer">Physically Based and Unified Volumetric Rendering in Frostbite</a> (SIGGRAPH 2015, 프로덕션 수준 구현).</li>
<li>Kovalovs, <a href="https://history.siggraph.org/wp-content/uploads/2022/08/2020-Talks-Kovalovs_Volumetric-Effects-of-The-Last-of-Us-Part-Two.pdf" target="_blank" rel="noreferrer">Volumetric Effects of The Last of Us Part Two</a> (SIGGRAPH 2020, 시간적 지터와 깊이 정합 합성에 대한 노트 포함).</li>
<li>Wright et al., <a href="https://advances.realtimerendering.com/s2022/SIGGRAPH2022-Advances-Lumen-Wright%20et%20al.pdf" target="_blank" rel="noreferrer">Lumen: Real-Time Global Illumination in Unreal Engine 5</a> (SIGGRAPH 2022, Lumen과 볼류메트릭 안개의 상호작용 포함).</li>
</ul>
<h2 id="_6-갓-레이와-박명-광선" tabindex="-1">6. 갓 레이와 박명 광선 <a class="header-anchor" href="#_6-갓-레이와-박명-광선" aria-label="Permalink to &quot;6. 갓 레이와 박명 광선&quot;"></a></h2>
<p>안개 낀 공기 속에 보이는 햇살 광선은 별개의 효과가 아닙니다. 안개 밀도와 섀도 맵이 둘 다 같은 컴퓨트 셰이더에 제공되기만 하면, 같은 안개 시스템에서 자연스럽게 떨어져 나옵니다. 셰이더가 프록셀에 빛을 주입할 때, 그 프록셀의 월드 위치에서 섀도 맵을 샘플링합니다. 그림자 속 셀은 어둡게 유지되고, 빛 속 셀은 태양 색을 받아들입니다. 그 결과를 따라 카메라 레이를 진행시키면 밝은 셀들이 연속된 광선을 이룹니다.</p>
<p>더 저렴한 스크린 공간 변형(태양 위치에서 깊이 버퍼로의 방사형 블러)도 존재하고, 모바일이나 저사양 하드웨어에서는 여전히 올바른 선택입니다. 화면 밖 태양 위치는 놓치지만 비용이 거의 들지 않습니다.</p>
<img src="/img/blog/clouds_weather_god_rays.webp" alt="Dawn forest with sun rays slicing through tree trunks and ground fog, forming clear god ray shafts" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Mitchell, <a href="https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-13-volumetric-light-scattering-post-process" target="_blank" rel="noreferrer">Volumetric Light Scattering as a Post-Process</a> (GPU Gems 3, 스크린 공간 방사형 블러 접근).</li>
<li>Engelhardt, Dachsbacher, <a href="https://cg.ivd.kit.edu/publications/2010/epipolar/EpipolarSampling.pdf" target="_blank" rel="noreferrer">Epipolar Sampling for Shadows and Crepuscular Rays in Participating Media</a> (I3D 2010, 더 정확한 GPU 기법).</li>
<li>Vos, <a href="https://www.guerrilla-games.com/read/volumetric-light-effects-in-killzone-shadow-fall" target="_blank" rel="noreferrer">Volumetric Light Effects in Killzone: Shadow Fall</a> (SIGGRAPH 2014, 그림자 통합을 포함한 프로덕션 버전).</li>
</ul>
<h2 id="_7-번개와-확률적-날씨-이벤트" tabindex="-1">7. 번개와 확률적 날씨 이벤트 <a class="header-anchor" href="#_7-번개와-확률적-날씨-이벤트" aria-label="Permalink to &quot;7. 번개와 확률적 날씨 이벤트&quot;"></a></h2>
<p>번개는 두 부분으로 이루어진 한 프레임짜리 효과입니다. 번개 줄기 메시, 그리고 장면 전체의 톤매핑과 조명 반응입니다. 줄기 자체는 보통 재귀적 선분 분할 알고리즘으로 만든 절차적 빌보드 메시로, 혼돈을 위해 지터를 주고 땅 쪽으로 갈수록 가늘어지게 합니다. 어떤 엔진은 이걸 스크린 공간 가산 섬광으로 렌더링하고, 어떤 엔진은 한 프레임짜리 점 광원 주입을 통해 세계에 빛을 드리우는 완전히 조명된 발광 지오메트리로 렌더링합니다.</p>
<p>흥미로운 부분은 그 <em>나머지</em> 전부입니다. 구름 밑면이 아래에서부터 밝아지고, 땅이 두 프레임 동안 밝아지며, 자동 노출 측광이 회복하는 데 몇 프레임이 걸리고, 거리에 따라 지연된 천둥 큐가 재생됩니다. 잘하면, 이게 16ms짜리 섬광을 5초짜리 시퀀스로 바꿔서, 날씨를 그저 위에서 일어나는 것이 아니라 세계 안에서 일어나는 무언가로 느끼게 합니다.</p>
<img src="/img/blog/clouds_weather_lightning.webp" alt="Lightning fork striking from a thundercloud at dusk, lighting the cloud bottoms and a small village silhouette" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Reed, Wyvill, <a href="https://dl.acm.org/doi/10.1145/192161.192256" target="_blank" rel="noreferrer">Visual Simulation of Lightning</a> (SIGGRAPH 1994, 다들 여전히 쓰는 재귀적 번개 줄기 알고리즘).</li>
<li>Kim, Lin, <a href="https://gamma.cs.unc.edu/POWER/" target="_blank" rel="noreferrer">Fast Animation of Lightning Using an Adaptive Mesh</a> (IEEE TVCG 2007, 더 물리적으로 뒷받침된 방식).</li>
<li>Bauer, <a href="https://www.youtube.com/watch?v=IYxtqlD1-Ac" target="_blank" rel="noreferrer">Creating the Atmospheric World of Red Dead Redemption 2</a> (SIGGRAPH 2019, 번개 타이밍을 포함한 RDR2의 폭풍 파이프라인).</li>
</ul>
<h2 id="_8-비-파티클-비-메시-스크린-공간-빗방울" tabindex="-1">8. 비 파티클, 비 메시, 스크린 공간 빗방울 <a class="header-anchor" href="#_8-비-파티클-비-메시-스크린-공간-빗방울" aria-label="Permalink to &quot;8. 비 파티클, 비 메시, 스크린 공간 빗방울&quot;"></a></h2>
<p>현대 게임의 떨어지는 비는 단순한 파티클인 경우가 드뭅니다. 저렴하면서도 설득력 있는 해법은, 수직이나 화면 정렬 쿼드에 걸쳐 늘인 소수의 스크롤 텍스처를 다른 모든 것과 같은 태양 및 하늘 프로브로 조명하는 것입니다. 카메라에 더 가까운 곳에서는 개별 줄무늬 파티클이 디테일을 더합니다. 카메라 렌즈 그 자체 위에서는, 물방울 텍스처, 흘러내리는 흔적, 충돌 잔물결이 &quot;당신은 폭풍 속에 있다&quot;는 느낌을 살려 줍니다.</p>
<p>바람이 비의 방향에 영향을 줍니다. 같은 바람 벡터가 구름 날씨 맵을 밀고, 풀을 휘게 하며, 비 쿼드를 기울입니다. 장면 전체에 걸친 하나의 벡터, 수십 개의 소비자입니다.</p>
<img src="/img/blog/clouds_weather_rain_storm.webp" alt="Heavy night rainstorm with sheets of rain illuminated by distant headlights and ripples on a wet road" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Tatarchuk, <a href="https://gpuopen.com/wp-content/uploads/2018/04/Tatarchuk-Rain-Rendering-EGSR2006.pdf" target="_blank" rel="noreferrer">Artist-Directable Real-Time Rain Rendering in City Environments</a> (EGSR 2006, 정전이라 할 만한 계층형 비 참고 자료).</li>
<li>Garg, Nayar, <a href="https://www1.cs.columbia.edu/CAVE/projects/rain_ren/rain_ren.php" target="_blank" rel="noreferrer">Photorealistic Rendering of Rain Streaks</a> (SIGGRAPH 2006, 빗방울을 통과하는 빛의 물리).</li>
<li>Wojciechowski, <a href="https://www.gdcvault.com/play/1027382/Rain-In-Cyberpunk-2077" target="_blank" rel="noreferrer">Rain in Cyberpunk 2077</a> (GDC 2021, 현대 프로덕션 둘러보기).</li>
</ul>
<h2 id="_9-젖은-표면-물웅덩이-잔물결" tabindex="-1">9. 젖은 표면, 물웅덩이, 잔물결 <a class="header-anchor" href="#_9-젖은-표면-물웅덩이-잔물결" aria-label="Permalink to &quot;9. 젖은 표면, 물웅덩이, 잔물결&quot;"></a></h2>
<p>땅을 바꾸지 않는 비는 곧바로 가짜처럼 보입니다. 젖은 표면은 알베도를 어둡게 하고(물이 들어오는 빛을 흡수), 노멀을 평탄하게 하며(물의 막이 미세 표면을 매끄럽게 함), 거칠기를 낮춰서(물은 스치는 각도에서 거의 완벽한 거울임) 반응합니다. 셰이더 변경은 작지만, 시각적 변화는 큽니다.</p>
<p>물웅덩이는 마스크 기반입니다. 높이 기반 또는 버텍스 페인트 마스크가 &quot;젖음&quot; 파라미터가 올라감에 따라 물이 차오르는 낮은 지점을 정의합니다. 잔물결은 빗방울 충돌로 트리거되는 플립북 노멀 맵 텍스처입니다. 정말 좋은 구현은 젖음 상태를 시간에 걸쳐 쌓아 올려서, 긴 폭풍우는 세계를 천천히 적시고 잠깐의 소나기는 높은 지점만 어둡게 만듭니다.</p>
<img src="/img/blog/clouds_weather_wet_surfaces.webp" alt="Wet cobblestone street at night with shallow puddles reflecting neon signs and ripple rings from raindrop impacts" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Lagarde, de Rousiers, <a href="https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/" target="_blank" rel="noreferrer">Moving Frostbite to Physically Based Rendering 3.0, section 5.5</a> (SIGGRAPH 2014, 정전이라 할 만한 젖은 표면 PBR 조정).</li>
<li>Lagarde, <a href="https://seblagarde.wordpress.com/2011/08/17/feeding-a-physical-based-lighting-mode/" target="_blank" rel="noreferrer">Adopting a Physically Based Shading Model</a> (젖은 PBR 수학이 담긴 원래의 블로그 시리즈).</li>
<li>Cyanilux, <a href="https://www.cyanilux.com/tutorials/rain-effects-breakdown/" target="_blank" rel="noreferrer">Rain Effects Breakdown</a> (물웅덩이, 잔물결, 물방울에 대한 접근하기 쉬운 Shader Graph 둘러보기).</li>
</ul>
<h2 id="_10-눈-쌓임과-변형" tabindex="-1">10. 눈 쌓임과 변형 <a class="header-anchor" href="#_10-눈-쌓임과-변형" aria-label="Permalink to &quot;10. 눈 쌓임과 변형&quot;"></a></h2>
<p>눈은 비와 대칭을 이루는 문제입니다. 세계가 눈을 그저 받기만 하는 게 아니라 기억해야 합니다. 표준 접근은 하늘이 보이는 곳마다 시간에 걸쳐 쌓이는 위에서 내려다본 &quot;눈 쌓임&quot; 텍스처를 씁니다(위에서 내려다본 깊이 또는 섀도 맵에 대해 계산). 지형 셰이더가 이 마스크를 샘플링해서, 가려진 영역에는 눈 머티리얼을, 노출된 영역에는 깊은 눈 변위를 블렌딩합니다.</p>
<p>발자국과 타이어 자국은 플레이어를 중심으로 한 슬라이딩 변형 맵에 렌더링됩니다. 카메라가 움직이면 오래된 발자국은 밖으로 스크롤되고 텍스처가 둘러 감깁니다. 지형이나 눈 셰이더가 이 변형 맵을 샘플링해서, 기록된 곳의 버텍스를 아래로 밀어 넣습니다. Battlefield 5의 눈은 이걸 하드웨어 테셀레이션으로 합니다. 더 저렴한 접근은 버텍스 변위만 쓰는 고밀도 지형 메시를 씁니다.</p>
<img src="/img/blog/clouds_weather_snow_deformation.webp" alt="Stylized snowy landscape with fresh footprints, drifts piled against rocks, falling snowflakes, and hazy distant mountains" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Barré-Brisebois, <a href="https://www.digitalfoundry.net/articles/digitalfoundry-2018-hands-on-with-battlefield-5s-closed-alpha" target="_blank" rel="noreferrer">Hands-on with Battlefield 5: how the small things matter</a> (Frostbite 눈의 프로덕션 정리).</li>
<li>St-Amour, <a href="https://is.muni.cz/th/m2v6i/real-time_snow_deformation.txt?lang=cs" target="_blank" rel="noreferrer">Real-time snow deformation</a> (전체 GPU 구현 세부 사항이 담긴 논문).</li>
<li>Andersson, <a href="https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/chapter5-andersson-terrain-rendering-in-frostbite.pdf" target="_blank" rel="noreferrer">Terrain Rendering in Frostbite Using Procedural Shader Splatting</a> (눈 쌓임이 그 위에 올라타는 스플랫 시스템 기반).</li>
</ul>
<h2 id="_11-전역-시스템으로서의-바람" tabindex="-1">11. 전역 시스템으로서의 바람 <a class="header-anchor" href="#_11-전역-시스템으로서의-바람" aria-label="Permalink to &quot;11. 전역 시스템으로서의 바람&quot;"></a></h2>
<p>바람은 파티클 효과가 아닙니다. 프로덕션 엔진에서는 <em>모든</em> 동적 시스템이 자신의 버텍스 셰이더에서 읽어 들이는 하나의 전역 벡터(때로는 저해상도 3D 필드)입니다. 풀잎이 휘고, 나뭇가지가 흔들리고, 천이 펄럭이고, 나뭇잎이 떠다니고, 비가 기울고, 연기가 이류하고, 구름 날씨 맵이 스크롤합니다. 프레임마다 갱신되는 하나의 유니폼, 수십 개의 소비자입니다.</p>
<p>더 풍부한 버전은 월드 위치로 샘플링한 방향과 세기를 저장하는 &quot;바람 그리드&quot;로, 국소적인 돌풍이 부는 폭풍, 바람을 막아주는 골짜기, 건물 뒤의 후류를 가능하게 합니다. 식생은 또한 보통 저작 시점에 구워진 버텍스별 오프셋을 받아서, 똑같은 나무들이 발맞춰 흔들리지 않게 합니다. 그 결과는 같은 박자로 숨 쉬는 세계입니다.</p>
<img src="/img/blog/clouds_weather_wind_foliage.webp" alt="Strong wind blowing grass and trees sideways with leaves swirling in the foreground under stormy clouds" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>McAuley, <a href="https://www.gdcvault.com/play/1022235/Rendering-the-World-of-Far" target="_blank" rel="noreferrer">Rendering the World of Far Cry 4</a> (GDC 2015, Far Cry 4의 식생용 바람 그리드 포함).</li>
<li>Habel, Wimmer, <a href="https://www.cg.tuwien.ac.at/research/publications/2007/HABEL-2007-IIM/" target="_blank" rel="noreferrer">Realistic Real-Time Rendering of Landscapes Using Billboard Clouds</a> (오래됐지만 식생에 대한 바람 수학은 그대로).</li>
<li>Frostbite, <a href="https://www.guerrilla-games.com/read/the-vegetation-of-horizon-zero-dawn" target="_blank" rel="noreferrer">The Vegetation of Horizon Zero Dawn</a> (SIGGRAPH 2017, 바람 시스템 아키텍처 포함).</li>
</ul>
<h2 id="_12-모래폭풍-눈보라-짙은-날씨" tabindex="-1">12. 모래폭풍, 눈보라, 짙은 날씨 <a class="header-anchor" href="#_12-모래폭풍-눈보라-짙은-날씨" aria-label="Permalink to &quot;12. 모래폭풍, 눈보라, 짙은 날씨&quot;"></a></h2>
<p>험한 날씨는 그 자체로 하나의 렌더링 범주입니다. 모래폭풍은 강한 방향 편향과 공격적인 거리 안개를 가진, 두껍고 불투명하며 지면에 정렬된 안개입니다. 눈보라는 카메라 근처 파티클 폭발과 줄어든 가시성을 더합니다. 화산재와 연기는 색만 다른 같은 아키텍처입니다.</p>
<p>이걸 살려 주는 것은 파티클이 아니라 <em>연동</em>입니다. 태양이 어두워지고, 하늘이 물들고, 후처리 컬러 그레이딩이 바뀌고, 환경음이 교체되고, 발소리가 달라지고, 플레이어에게 음성이 있다면 그 음성이 먹먹해집니다. 렌더러는 전령일 뿐이고, 몰입은 게임의 모든 시스템이 동시에 반응하는 데서 옵니다.</p>
<img src="/img/blog/clouds_weather_sandstorm.webp" alt="A wall of orange dust and sand rolling across a desert plain with bruised sky above and clear blue behind" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Burley, <a href="https://www.gdcvault.com/play/1024954/The-Real-time-Sky-and" target="_blank" rel="noreferrer">The Real-Time Sky and Atmosphere of Uncharted: The Lost Legacy</a> (GDC 2018, 짙은 날씨 합성에 대한 노트 포함).</li>
<li>Khalifa, <a href="https://www.gdcvault.com/play/1027587/Atmospheric-Weather-Effects-in-Forza" target="_blank" rel="noreferrer">Atmospheric Weather Effects in Forza Horizon 5</a> (GDC 2022, 현대 오픈월드 날씨).</li>
<li>Karis, <a href="https://advances.realtimerendering.com/s2021/" target="_blank" rel="noreferrer">The Technology Behind the Unreal Engine 5 &quot;Lumen in the Land of Nanite&quot; Demo</a> (SIGGRAPH 2021, 동굴 먼지 장면의 볼류메트릭 스택).</li>
</ul>
<h2 id="_13-하루의-시간대와-동적-하늘" tabindex="-1">13. 하루의 시간대와 동적 하늘 <a class="header-anchor" href="#_13-하루의-시간대와-동적-하늘" aria-label="Permalink to &quot;13. 하루의 시간대와 동적 하늘&quot;"></a></h2>
<p>실시간 하루 시간대는 이 목록의 다른 모든 시스템을 출시할 가치가 있게 만들어 주는 곱셈 인자입니다. 태양 방향과 색이 24분 또는 24시간 주기에 걸쳐 갱신됩니다. 대기 LUT가 태양 각도에 따라 갱신됩니다. 구름 조명이 프레임마다 재계산됩니다. 섀도 캐스케이드가 다시 가리킵니다. 반사 프로브가 새로고침됩니다. 환경광 색이 바뀝니다. 후처리 노출이 적응합니다.</p>
<p>이걸 눈에 띄는 아티팩트 없이 해내는 것은 대체로 텍스처 캐싱과 시간적 안정성에 관한 이야기입니다. 빠른 기법은 고정된 태양 각도에서 하늘을 미리 계산하고 보간합니다. 느린 기법은 매 프레임 재계산합니다. Hillaire 2020 대기 모델은 재계산할 만큼 충분히 빠른데, 그래서 UE5가 그걸 채택했습니다. 구름 날씨 맵은 바람을 따라 스크롤하므로, 아무도 키프레임을 저작하지 않아도 구름 양이 자연스럽게 바뀝니다.</p>
<img src="/img/blog/clouds_weather_time_of_day.webp" alt="Three vertical bands across one landscape: dawn pink, noon blue, sunset red, all sharing the same hill silhouette" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Hillaire, <a href="https://sebh.github.io/publications/egsr2020.pdf" target="_blank" rel="noreferrer">A Scalable and Production Ready Sky and Atmosphere Rendering Technique</a> (EGSR 2020, 동적 하루 시간대 논의 포함).</li>
<li>Pesce, <a href="https://www.realtimerendering.com/raytracinggems/rtg2/index.html" target="_blank" rel="noreferrer">Real-Time Sky Rendering: Techniques and Tradeoffs</a> (Ray Tracing Gems II 챕터, 현대적 개관).</li>
<li>Bauer, <a href="https://www.youtube.com/watch?v=IYxtqlD1-Ac" target="_blank" rel="noreferrer">Creating the Atmospheric World of Red Dead Redemption 2</a> (SIGGRAPH 2019, 24시간 파이프라인 포함).</li>
</ul>
<h2 id="_14-날씨-상태-머신" tabindex="-1">14. 날씨 상태 머신 <a class="header-anchor" href="#_14-날씨-상태-머신" aria-label="Permalink to &quot;14. 날씨 상태 머신&quot;"></a></h2>
<p>이 모든 것의 밑바닥에는 작은 상태 머신이 있습니다. 대부분의 게임은 4개에서 12개 사이의 날씨 상태(맑음, 부분적으로 흐림, 잔뜩 흐림, 약한 비, 강한 비, 뇌우, 안개, 눈, 눈보라, 모래폭풍)를 출시하고, 각각은 한 묶음의 파라미터로 정의됩니다. 구름 양과 종류, 풍속과 풍향, 강수 종류와 강도, 환경광 색조, 오디오 프로파일, 후처리 그레이드가 그것입니다.</p>
<p>전환은 30초에서 120초에 걸쳐 파라미터 묶음 사이를 선형 보간한 것입니다. 전환은 특수한 경우가 아니라, 그저 두 상태가 보간되는 것이며, 각 렌더링 하위 시스템이 그 프레임의 현재 파라미터 값을 읽습니다. 날씨는 스크립트로 짜일 수도 있고(컷신에 폭풍이 필요함), 시드로 정해질 수도 있고(지역별 게임 내 하루마다 결정적이어서 같은 세계의 두 플레이어가 같은 날씨를 봄), 지역 그리드에 완전히 저작될 수도 있습니다. 가장 깔끔한 파이프라인은 이 셋 모두를, 같은 파라미터 버퍼에 기록하는 서로 다른 스케줄러로 다룹니다.</p>
<img src="/img/blog/clouds_weather_state_machine.webp" alt="Side-by-side of the same scene under clear sun on the left and stormy rain on the right with wet glistening surfaces" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>자세히 보기:</p>
<ul>
<li>Bauer, <a href="https://www.youtube.com/watch?v=IYxtqlD1-Ac" target="_blank" rel="noreferrer">Creating the Atmospheric World of Red Dead Redemption 2</a> (SIGGRAPH 2019, 날씨 상태 파이프라인 포함).</li>
<li>Khalifa, <a href="https://www.gdcvault.com/play/1027587/Atmospheric-Weather-Effects-in-Forza" target="_blank" rel="noreferrer">Atmospheric Weather Effects in Forza Horizon 5</a> (GDC 2022, 파라미터 블렌드 접근 포함).</li>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/the-real-time-volumetric-cloudscapes-of-horizon-zero-dawn" target="_blank" rel="noreferrer">The Real-Time Volumetric Cloudscapes of Horizon Zero Dawn</a> (SIGGRAPH 2015, 날씨 맵 기반 구름 진화 포함).</li>
</ul>
<h2 id="_15-영화적인-순간들" tabindex="-1">15. 영화적인 순간들 <a class="header-anchor" href="#_15-영화적인-순간들" aria-label="Permalink to &quot;15. 영화적인 순간들&quot;"></a></h2>
<p>이 모든 스택은 몇몇 상징적인 순간을 위해 존재합니다. 폭풍 전선이 밀려올 때 능선 위에 서 있는 것. 숲지붕 사이 빈 곳을 햇살 광선이 태우며 지나가는 것을 바라보는 것. 동굴에서 나와 눈 속으로 걸어 들어가는 것. 적운 속을 날아 통과하며 그 안쪽의 빛을 보는 것.</p>
<p>이런 것들이 플레이어가 스크린샷을 찍는 순간입니다. 또한 위의 모든 시스템이 동시에 작동해야 하는 순간이기도 합니다. 구름 볼류메트릭, 대기 산란, 그림자 통합 안개, 젖은 PBR, 식생에 부는 바람, 하루 시간대 컬러 그레이딩, 그리고 날씨 상태 사이의 전환이 모두 하나의 프레임으로 합성됩니다. 이 중 하나라도 틀리면 마법이 깨집니다.</p>
<img src="/img/blog/clouds_weather_cloud_sea.webp" alt="Looking down across a sea of clouds onto a single mountain peak rising through, with sunlit cloud tops and shadowed valleys below" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<h2 id="이것이-브라우저에-의미하는-것" tabindex="-1">이것이 브라우저에 의미하는 것 <a class="header-anchor" href="#이것이-브라우저에-의미하는-것" aria-label="Permalink to &quot;이것이 브라우저에 의미하는 것&quot;"></a></h2>
<p>이 기법들 대부분은 WebGPU로 깔끔하게 옮겨집니다. 우리는 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">오픈월드 브라우저 엔진</a>에 기본 대기 안개, 등장방형 스카이박스 블렌딩, 스크린 공간 거리 아지랑이를 이미 출시했습니다. 더 어려운 부분(풀 볼류메트릭 구름, 프록셀 그리드 안개, 동적 물웅덩이가 있는 젖은 PBR, 눈 변형 맵)은 지형 파이프라인이 안정된 지금 명백한 다음 단계입니다. Spike 24의 스카이박스에서 프래그먼트별 안개 색을 샘플링하는 것이 이 퍼즐의 한 조각입니다. 같은 대기 LUT로 흘러 들어가는 컴퓨트 셰이더 구름 레이마처가 그다음입니다.</p>
<p>좋은 소식은 이제 브라우저 하드웨어의 하한선이 충분히 높아졌다는 것입니다. WebGPU 컴퓨트, 3D 텍스처, 간접 디스패치, 타임스탬프 쿼리가 모두 존재합니다. Hillaire 2020 대기는 WebGL로 여러 번 포팅됐습니다. Schneider의 Nubis는 GLSL 오픈소스 참조 구현이 있고, 이는 기계적인 수정만으로 WGSL로 옮겨집니다. 이제 브라우저 게임이 콘솔 게임과 같은 하늘을 가질 수 없는 렌더링상의 이유는 없습니다. 엔지니어링상의 이유만 있을 뿐이고, 엔지니어링상의 이유는 우리가 좋아하는 종류입니다.</p>
<h2 id="스택-전체를-아우르는-더-읽을거리" tabindex="-1">스택 전체를 아우르는 더 읽을거리 <a class="header-anchor" href="#스택-전체를-아우르는-더-읽을거리" aria-label="Permalink to &quot;스택 전체를 아우르는 더 읽을거리&quot;"></a></h2>
<p>이 모든 것을 한데 묶어주는 한 가지 출처를 원한다면, SIGGRAPH &quot;Advances in Real-Time Rendering in Games&quot; 아카이브(<a href="https://advances.realtimerendering.com/" target="_blank" rel="noreferrer">advances.realtimerendering.com</a>)에 2014년까지 거슬러 올라가는 정전이라 할 만한 날씨와 대기 발표 자료가 있습니다. 특정 게임이 하늘과 날씨를 어떻게 렌더링하는지에 대한 프로덕션 분해는 <a href="http://www.adriancourreges.com/blog/" target="_blank" rel="noreferrer">Adrian Courrèges의 GPU 프로파일링 글</a>에 GTA V, Horizon Zero Dawn, Doom Eternal의 프레임 단위 상세 분석이 담겨 있습니다. 하늘과 대기 수학 자체에 관해서는 <a href="https://www.scratchapixel.com/lessons/3d-basic-rendering/volume-rendering-for-developers/intro-volume-rendering.html" target="_blank" rel="noreferrer">scratchapixel.com의 볼륨 렌더링 챕터</a>가 가장 부드러운 입문서이고, Hillaire의 오픈소스 <a href="https://github.com/sebh/UnrealEngineSkyAtmosphere" target="_blank" rel="noreferrer">구현 저장소</a>가 프로덕션 품질의 참조입니다.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[최신 AAA 게임에서 쓰이는 렌더링 기법 짧은 목록]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-03-aaa-rendering-techniques</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-03-aaa-rendering-techniques</guid>
            <pubDate>Sun, 03 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Nanite 가상화 지오메트리부터 ReSTIR 패스 트레이싱, ML 기반 업스케일링까지, 오늘날 AAA 비주얼을 떠받치는 핵심 렌더링 기법을 항목마다 깊이 있는 기술 레퍼런스와 함께 정리했습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="최신-aaa-게임에서-쓰이는-렌더링-기법-짧은-목록" tabindex="-1">최신 AAA 게임에서 쓰이는 렌더링 기법 짧은 목록 <a class="header-anchor" href="#최신-aaa-게임에서-쓰이는-렌더링-기법-짧은-목록" aria-label="Permalink to &quot;최신 AAA 게임에서 쓰이는 렌더링 기법 짧은 목록&quot;"></a></h1>
<p><em>글: <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<img src="/img/blog/aaa_rendering_hero.webp" alt="Composite scene showing PBR materials, virtualized geometry, and ray-traced lighting in a modern AAA game" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>2026년 AAA 게임의 렌더링 파이프라인을 열어보면, 거기 들어있는 것들 대부분은 여러 스튜디오에 두루 쓰이는 한 줌의 기법으로 거슬러 올라갑니다. 엔진마다 이름은 달라도 아이디어는 같습니다. 화면에서 실제로 일을 하고 있는 기법들을 짧게 정리하고, 항목마다 그림 한 장과 깊이 있는 기술 레퍼런스 몇 개를 붙였습니다.</p>
<h2 id="_1-물리-기반-렌더링-pbr" tabindex="-1">1. 물리 기반 렌더링 (PBR) <a class="header-anchor" href="#_1-물리-기반-렌더링-pbr" aria-label="Permalink to &quot;1. 물리 기반 렌더링 (PBR)&quot;"></a></h2>
<p>머티리얼은 albedo, roughness, metallic, normal, ambient occlusion 텍스처로 기술되고, 에너지 보존 셰이더(Cook-Torrance specular, Lambertian 또는 Disney diffuse)로 조명됩니다. 모든 최신 AAA 엔진이 전제로 깔고 가는 기준선입니다. 표면 하나가 햇빛 아래에서도, 램프 빛 아래에서도, 손전등 아래에서도 일관되게 보인다면 그건 PBR 덕분입니다.</p>
<img src="/img/blog/aaa_pbr_materials.webp" alt="Iron helmet rendered with PBR materials, with floating texture swatches showing albedo, roughness, metallic, and normal maps" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Burley, <a href="https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf" target="_blank" rel="noreferrer">Physically-Based Shading at Disney</a> (최초의 &quot;Disney BRDF&quot; 강의 노트, SIGGRAPH 2012).</li>
<li>Karis, <a href="https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf" target="_blank" rel="noreferrer">Real Shading in Unreal Engine 4</a> (SIGGRAPH 2013, UE4 PBR의 정석 같은 발표).</li>
<li>Lagarde and de Rousiers, <a href="https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/" target="_blank" rel="noreferrer">Moving Frostbite to Physically Based Rendering 3.0</a> (SIGGRAPH 2014, Frostbite 파이프라인 전체).</li>
<li><a href="https://www.realtimerendering.com/" target="_blank" rel="noreferrer">Real-Time Rendering, 4th edition, chapter 9</a> (교과서 수준의 참고서).</li>
</ul>
<h2 id="_2-디퍼드-셰이딩과-비저빌리티-버퍼-셰이딩" tabindex="-1">2. 디퍼드 셰이딩과 비저빌리티 버퍼 셰이딩 <a class="header-anchor" href="#_2-디퍼드-셰이딩과-비저빌리티-버퍼-셰이딩" aria-label="Permalink to &quot;2. 디퍼드 셰이딩과 비저빌리티 버퍼 셰이딩&quot;"></a></h2>
<p>지오메트리 단계가 먼저 속성(노멀, 머티리얼 ID, 깊이)을 G-buffer나 visibility buffer에 씁니다. 조명은 그 버퍼들을 읽어 각 픽셀을 한 번만 셰이딩하는 풀스크린 패스로 돌아갑니다. Visibility buffer(Nanite 등이 쓰는 방식)는 여기서 한 발 더 나아가, 삼각형 ID만 저장하고 머티리얼 파라미터는 나중에 픽셀별로 풀어냅니다. 덕분에 밀도 높은 지오메트리에서도 오버드로 비용이 저렴하게 유지됩니다.</p>
<img src="/img/blog/aaa_deferred_gbuffer.webp" alt="Deferred shading G-buffer split into final color, world normals, depth, and material ID panels" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Engel, <a href="https://download.nvidia.com/developer/presentations/2004/6800_Leagues/6800_Leagues_Deferred_Shading.pdf" target="_blank" rel="noreferrer">Deferred Shading</a> (NVIDIA, 토대가 된 발표).</li>
<li>Burns and Hunt, <a href="http://jcgt.org/published/0002/02/04/" target="_blank" rel="noreferrer">The Visibility Buffer: A Cache-Friendly Approach to Deferred Shading</a> (JCGT 2013, 최초의 visibility buffer 논문).</li>
<li>Wihlidal, <a href="http://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/" target="_blank" rel="noreferrer">&quot;Optimizing the Graphics Pipeline with Compute&quot;</a> (GDC 2016, Frostbite의 compute 기반 디퍼드 경로).</li>
<li>Karis, Stubbe, Wihlidal, <a href="https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf" target="_blank" rel="noreferrer">A Deep Dive into Nanite Virtualized Geometry</a> (SIGGRAPH 2021, Nanite의 visibility buffer를 상세히 다룸).</li>
</ul>
<h2 id="_3-가상화-지오메트리-nanite-스타일" tabindex="-1">3. 가상화 지오메트리 (Nanite 스타일) <a class="header-anchor" href="#_3-가상화-지오메트리-nanite-스타일" aria-label="Permalink to &quot;3. 가상화 지오메트리 (Nanite 스타일)&quot;"></a></h2>
<p>메시는 클러스터 계층으로 미리 빌드됩니다. 런타임에 GPU가 각 픽셀에 맞는 해상도로 클러스터를 스트리밍하고 선택하기 때문에, 수동 LOD 없이도 서브픽셀 정밀도의 디테일을 얻습니다. Unreal의 Nanite가 가장 눈에 띄는 예입니다. 다른 엔진들도 이제 자체 변형판을 내놓고 있습니다. 실제 결과는 LOD 작업 없이도 영화 품질의 에셋을 실시간으로 돌리는 것입니다.</p>
<img src="/img/blog/aaa_virtualized_geometry.webp" alt="Smooth render on the left, sub-pixel meshlet clusters in vivid colors on the right" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Karis, Stubbe, Wihlidal, <a href="https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf" target="_blank" rel="noreferrer">A Deep Dive into Nanite Virtualized Geometry</a> (SIGGRAPH 2021).</li>
<li>Brian Karis, <a href="https://www.youtube.com/watch?v=eviSykqSUUw" target="_blank" rel="noreferrer">Nanite GDC 2021 talk</a> (이해하기 쉬운 영상 설명).</li>
<li>Liktor, <a href="https://research.activision.com/publications/2021/09/geometry-rendering-pipeline-architecture-at-activision" target="_blank" rel="noreferrer">Geometry Rendering Pipeline Architecture at Activision</a> (클러스터 기반 렌더링, 2021).</li>
<li>Schied et al., <a href="https://research.nvidia.com/publication/2017-07_spatiotemporal-variance-guided-filtering-real-time-reconstruction-path-traced" target="_blank" rel="noreferrer">Spatiotemporal Variance-Guided Filtering</a> (관련된 클러스터 컬링 기법).</li>
</ul>
<h2 id="_4-그림자-반사-ao를-위한-실시간-레이-트레이싱" tabindex="-1">4. 그림자, 반사, AO를 위한 실시간 레이 트레이싱 <a class="header-anchor" href="#_4-그림자-반사-ao를-위한-실시간-레이-트레이싱" aria-label="Permalink to &quot;4. 그림자, 반사, AO를 위한 실시간 레이 트레이싱&quot;"></a></h2>
<p>하드웨어 레이 트레이싱(DXR, Vulkan RT)은 매 프레임 빌드되는 BVH에 대해 그림자 광선, 미러 및 글로시 반사 광선, ambient occlusion 광선을 쏩니다. 픽셀당 광선이 몇 개에 불과해도 스크린 스페이스 기법이 할 수 있는 것보다 낫습니다. 특히 화면 밖 반사와 접촉 그림자에서 그렇습니다. 대부분의 게임은 이걸 모든 곳에 쓰지 않고 꼭 필요한 데만 외과적으로 씁니다.</p>
<img src="/img/blog/aaa_hardware_raytracing.webp" alt="Glossy red sports car in a luxury showroom with accurate ray-traced reflections and contact shadows" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Microsoft, <a href="https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html" target="_blank" rel="noreferrer">DirectX Raytracing (DXR) Functional Spec</a> (API 레퍼런스).</li>
<li>Wyman, <a href="http://intro-to-dxr.cwyman.org/" target="_blank" rel="noreferrer">Introduction to DirectX Raytracing</a> (SIGGRAPH 강의 노트, 아주 접근하기 쉬움).</li>
<li>Boksansky and Marrs, <a href="https://www.realtimerendering.com/raytracinggems/rtg2/index.html" target="_blank" rel="noreferrer">Ray Tracing Gems II, chapters 17-19</a> (무료 PDF, 최신 DXR 기법).</li>
<li>Stachowiak, <a href="https://www.ea.com/frostbite/news/stochastic-screen-space-reflections" target="_blank" rel="noreferrer">Stochastic Screen-Space Reflections</a> (Frostbite, SSR에서 RT로 넘어가는 다리).</li>
</ul>
<h2 id="_5-소프트웨어-레이-트레이싱-lumen-스타일" tabindex="-1">5. 소프트웨어 레이 트레이싱 (Lumen 스타일) <a class="header-anchor" href="#_5-소프트웨어-레이-트레이싱-lumen-스타일" aria-label="Permalink to &quot;5. 소프트웨어 레이 트레이싱 (Lumen 스타일)&quot;"></a></h2>
<p>모든 플레이어가 RTX 카드를 가진 건 아니기 때문에, 엔진은 distance field나 surface cache 폴백도 함께 제공합니다. 예를 들어 Unreal의 Lumen은 signed distance field와 surface cache에 대해 트레이싱해 저렴한 diffuse GI를 얻고, 필요할 때만 하드웨어 광선으로 격상합니다. AAA 게임이 콘솔에서 &quot;레이 트레이싱 같은 모습&quot;을 내는 방식이 바로 이것입니다.</p>
<img src="/img/blog/aaa_software_rt_lumen.webp" alt="Cathedral interior with stained-glass color bleed and an SDF wireframe overlay revealing approximated geometry" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Wright et al., <a href="https://advances.realtimerendering.com/s2022/SIGGRAPH2022-Advances-Lumen-Wright%20et%20al.pdf" target="_blank" rel="noreferrer">Lumen: Real-Time Global Illumination in Unreal Engine 5</a> (SIGGRAPH 2022, Lumen 논문).</li>
<li>Epic Games, <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/lumen-technical-details-in-unreal-engine" target="_blank" rel="noreferrer">Lumen Technical Details</a> (공식 엔진 문서).</li>
<li>Wright, <a href="https://advances.realtimerendering.com/s2021/Wright%20et%20al%20-%20Radiance%20Caching%20for%20Real-Time%20Global%20Illumination%20-%20SIGGRAPH%202021.pdf" target="_blank" rel="noreferrer">Radiance Caching for Real-Time Global Illumination</a> (SIGGRAPH 2021).</li>
<li>Wright, <a href="https://www.youtube.com/watch?v=2GYXuM10riw" target="_blank" rel="noreferrer">Lumen GDC 2022 talk</a> (영상 버전).</li>
</ul>
<h2 id="_6-restir과-reservoir-샘플링" tabindex="-1">6. ReSTIR과 reservoir 샘플링 <a class="header-anchor" href="#_6-restir과-reservoir-샘플링" aria-label="Permalink to &quot;6. ReSTIR과 reservoir 샘플링&quot;"></a></h2>
<p>수천 개의 광원이 있는 직접 및 간접 조명에서는 ReSTIR(Reservoir Spatio-Temporal Importance Resampling)이 픽셀과 프레임 사이에서 광원 샘플을 재사용합니다. Cyberpunk 2077의 패스 트레이싱 같은 게임이 픽셀당 광선 한두 개로도 노이즈를 낮게 유지하는 방법입니다. 패스 트레이싱이 고사양 목표가 되면서 더 많은 엔진에서 보게 될 겁니다.</p>
<img src="/img/blog/aaa_ray_tracing_restir.webp" alt="Cyberpunk street with ray-traced reflections in wet pavement and visible bounced light paths" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Bitterli et al., <a href="https://research.nvidia.com/sites/default/files/pubs/2020-07_Spatiotemporal-reservoir-resampling/ReSTIR.pdf" target="_blank" rel="noreferrer">Spatiotemporal Reservoir Resampling for Real-Time Ray Tracing with Dynamic Direct Lighting</a> (SIGGRAPH 2020, 최초의 ReSTIR 논문).</li>
<li>Ouyang et al., <a href="https://research.nvidia.com/publication/2021-06_restir-gi-path-resampling-real-time-path-tracing" target="_blank" rel="noreferrer">ReSTIR GI: Path Resampling for Real-Time Path Tracing</a> (HPG 2021, 간접 조명용 ReSTIR).</li>
<li>Lin et al., <a href="https://research.nvidia.com/publication/2022-07_generalized-resampled-importance-sampling-foundations-restir" target="_blank" rel="noreferrer">Generalized Resampled Importance Sampling</a> (SIGGRAPH 2022, 수학적 토대).</li>
<li>NVIDIA, <a href="https://www.nvidia.com/en-us/geforce/news/cyberpunk-2077-ray-tracing-overdrive-technology-preview-on-rtx-4090/" target="_blank" rel="noreferrer">Cyberpunk 2077 Path Tracing Tech Deep Dive</a> (엔지니어링 블로그).</li>
</ul>
<h2 id="_7-볼류메트릭-구름-안개-대기" tabindex="-1">7. 볼류메트릭 구름, 안개, 대기 <a class="header-anchor" href="#_7-볼류메트릭-구름-안개-대기" aria-label="Permalink to &quot;7. 볼류메트릭 구름, 안개, 대기&quot;"></a></h2>
<p>하늘은 3D 노이즈와 밀도 볼륨을 통과하며 ray march됩니다. 대기는 미리 계산한 산란 테이블(Bruneton 스타일)로 태양과 달의 전환을 처리합니다. 안개는 froxel 그리드(뷰 프러스텀에 정렬된 3D 텍스처라고 생각하면 됩니다)로, 국소 조명을 담아냅니다. 이 셋이 합쳐지면 skybox 한 장이 아니라 &quot;하나의 시스템으로서의 날씨&quot;가 됩니다.</p>
<img src="/img/blog/aaa_volumetrics.webp" alt="Mountain valley at sunset with volumetric clouds and god rays piercing through misty air" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/the-real-time-volumetric-cloudscapes-of-horizon-zero-dawn" target="_blank" rel="noreferrer">The Real-Time Volumetric Cloudscapes of Horizon Zero Dawn</a> (SIGGRAPH 2015, 구름의 정석 같은 레퍼런스).</li>
<li>Hillaire, <a href="https://sebh.github.io/publications/egsr2020.pdf" target="_blank" rel="noreferrer">A Scalable and Production Ready Sky and Atmosphere Rendering Technique</a> (EGSR 2020, UE5에서 쓰는 현대판 Bruneton 후계작).</li>
<li>Wronski, <a href="https://bartwronski.com/2014/08/22/volumetric-fog-siggraph-2014/" target="_blank" rel="noreferrer">Volumetric Fog: Unified Compute Shader Based Solution to Atmospheric Scattering</a> (SIGGRAPH 2014, Assassin's Creed 4의 froxel 안개).</li>
<li>Hillaire, <a href="https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite" target="_blank" rel="noreferrer">Physically Based and Unified Volumetric Rendering in Frostbite</a> (SIGGRAPH 2015).</li>
</ul>
<h2 id="_8-캐스케이드-섀도-맵과-가상-섀도-맵" tabindex="-1">8. 캐스케이드 섀도 맵과 가상 섀도 맵 <a class="header-anchor" href="#_8-캐스케이드-섀도-맵과-가상-섀도-맵" aria-label="Permalink to &quot;8. 캐스케이드 섀도 맵과 가상 섀도 맵&quot;"></a></h2>
<p>태양 그림자의 경우, 캐스케이드 섀도 맵은 프러스텀을 여러 구간으로 나누고 각 구간을 적절한 해상도로 렌더링합니다. 가상 섀도 맵은 한 발 더 나아갑니다. 하나의 거대한 섀도 맵을 페이지로 쪼개고, 카메라에서 보이는 페이지만 렌더링합니다. AAA 게임이 막대한 메모리 비용 없이 플레이어 근처에서 또렷한 그림자를 유지하는 방법입니다.</p>
<img src="/img/blog/aaa_cascaded_shadows.webp" alt="Outdoor scene with three colored cascade frustums overlaid showing shadow detail near the camera" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Dimitrov, <a href="https://developer.download.nvidia.com/SDK/10.5/opengl/src/cascaded_shadow_maps/doc/cascaded_shadow_maps.pdf" target="_blank" rel="noreferrer">Cascaded Shadow Maps</a> (NVIDIA 백서, 표준 레퍼런스).</li>
<li>Microsoft, <a href="https://learn.microsoft.com/en-us/windows/win32/dxtecharts/cascaded-shadow-maps" target="_blank" rel="noreferrer">Common Techniques to Improve Shadow Depth Maps</a> (DirectX 문서).</li>
<li>Wright, <a href="https://advances.realtimerendering.com/s2023/index.html#VirtualShadowMaps" target="_blank" rel="noreferrer">Virtual Shadow Maps in Fortnite Battle Royale Chapter 4</a> (SIGGRAPH 2023, UE5 VSM 발표).</li>
<li>Epic Games, <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/virtual-shadow-maps-in-unreal-engine" target="_blank" rel="noreferrer">Virtual Shadow Maps documentation</a>.</li>
</ul>
<h2 id="_9-스크린-스페이스-효과-ssao-ssr-ssgi-sssss" tabindex="-1">9. 스크린 스페이스 효과 (SSAO, SSR, SSGI, SSSSS) <a class="header-anchor" href="#_9-스크린-스페이스-효과-ssao-ssr-ssgi-sssss" aria-label="Permalink to &quot;9. 스크린 스페이스 효과 (SSAO, SSR, SSGI, SSSSS)&quot;"></a></h2>
<p>깊이와 노멀 버퍼를 저렴하게 읽으면 ambient occlusion(SSAO), 반사(SSR), 한 번 반사하는 글로벌 일루미네이션(SSGI), 피부의 서브서피스 스캐터링(SSSSS)을 얻을 수 있습니다. 화면 밖 디테일을 놓치기 때문에 레이 트레이싱이 자리를 넘겨받고 있지만, 빠른 기준선으로는 여전히 어디에나 쓰입니다.</p>
<img src="/img/blog/aaa_screen_space_effects.webp" alt="Side-by-side kitchen scene comparing flat lighting on the left with SSAO, SSR, and SSGI on the right" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Mittring, <a href="https://www.crytek.com/wp-content/uploads/Finding%20Next%20Gen%20-%20CryEngine%202.pdf" target="_blank" rel="noreferrer">Finding Next Gen: CryENGINE 2</a> (SIGGRAPH 2007, 최초의 SSAO 논문).</li>
<li>McGuire et al., <a href="https://research.nvidia.com/publication/scalable-ambient-obscurance" target="_blank" rel="noreferrer">Scalable Ambient Obscurance</a> (HPG 2012, 현대판 SSAO).</li>
<li>Stachowiak and Uludag, <a href="https://www.ea.com/frostbite/news/stochastic-screen-space-reflections" target="_blank" rel="noreferrer">Stochastic Screen-Space Reflections</a> (Frostbite, SSR 레퍼런스).</li>
<li>Jimenez, <a href="https://www.iryoku.com/separable-sss/" target="_blank" rel="noreferrer">Separable Subsurface Scattering</a> (대부분의 AAA 엔진에서 피부에 쓰는 기법).</li>
<li>Mara et al., <a href="https://research.activision.com/publications/2016/09/deep-g-buffers-for-stable-global-illumination-approximation" target="_blank" rel="noreferrer">Deep Screen Space</a> (Activision, SSGI 계보의 하나).</li>
</ul>
<h2 id="_10-시간적-안티앨리어싱과-ml-업스케일링-dlss-fsr-xess" tabindex="-1">10. 시간적 안티앨리어싱과 ML 업스케일링 (DLSS, FSR, XeSS) <a class="header-anchor" href="#_10-시간적-안티앨리어싱과-ml-업스케일링-dlss-fsr-xess" aria-label="Permalink to &quot;10. 시간적 안티앨리어싱과 ML 업스케일링 (DLSS, FSR, XeSS)&quot;"></a></h2>
<p>프레임은 더 낮은 내부 해상도로 렌더링되고, 모션 벡터와 깊이, 히스토리를 이용해 재구성됩니다. ML 기반 업스케일러(DLSS 3/4, FSR 3, XeSS)는 그 위에 프레임 생성을 더해, 옵티컬 플로우로부터 중간 프레임을 보간합니다. 대부분의 AAA 타이틀은 이제 업스케일러가 켜져 있다고 전제하고 출시하며, 이는 프레임의 나머지 예산을 짜는 방식을 바꿔놓습니다.</p>
<img src="/img/blog/aaa_ml_upscaling.webp" alt="Side-by-side of a low-resolution input and a sharp ML-reconstructed output of the same character" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Karis, <a href="http://advances.realtimerendering.com/s2014/index.html#_HIGH-QUALITY_TEMPORAL_SUPERSAMPLING" target="_blank" rel="noreferrer">High Quality Temporal Supersampling</a> (SIGGRAPH 2014, TAA의 정석 같은 발표).</li>
<li>Salvi, <a href="https://research.nvidia.com/sites/default/files/pubs/2016-03_An-Excursion-in/dlss_DTAA-2-2.pdf" target="_blank" rel="noreferrer">An Excursion in Temporal Supersampling</a> (NVIDIA, DLSS로 가는 길목).</li>
<li>Edelsten, <a href="https://www.gdcvault.com/play/1026184/" target="_blank" rel="noreferrer">Truly Next-Gen: Adding Deep Learning to Games and Graphics</a> (GDC 2019, DLSS 아키텍처).</li>
<li>AMD, <a href="https://gpuopen.com/fidelityfx-super-resolution-3/" target="_blank" rel="noreferrer">FidelityFX Super Resolution 3 technical details</a> and Intel, <a href="https://www.intel.com/content/www/us/en/developer/articles/technical/intel-xess-technical-paper.html" target="_blank" rel="noreferrer">XeSS technical paper</a>.</li>
</ul>
<h2 id="_11-gpu-주도-렌더링과-mesh-shader" tabindex="-1">11. GPU 주도 렌더링과 mesh shader <a class="header-anchor" href="#_11-gpu-주도-렌더링과-mesh-shader" aria-label="Permalink to &quot;11. GPU 주도 렌더링과 mesh shader&quot;"></a></h2>
<p>컬링, LOD 선택, 드로 제출이 모두 GPU에서 돌아갑니다. Mesh shader는 vertex/geometry/tessellation 파이프라인을, meshlet을 내보내는 더 유연한 compute 스타일 단계로 대체합니다. multi-draw indirect와 결합하면 오브젝트별 핫 루프에서 CPU를 완전히 빼낼 수 있습니다.</p>
<img src="/img/blog/aaa_gpu_driven_meshlets.webp" alt="Alien spaceport scene with colored meshlet cluster overlay showing GPU-driven rendering" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Haar and Aaltonen, <a href="https://advances.realtimerendering.com/s2015/aaltonenhaar_siggraph2015_combined_final_footer_220dpi.pdf" target="_blank" rel="noreferrer">GPU-Driven Rendering Pipelines</a> (SIGGRAPH 2015, 토대가 된 Assassin's Creed Unity 발표).</li>
<li>Wihlidal, <a href="https://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/" target="_blank" rel="noreferrer">Optimizing the Graphics Pipeline with Compute</a> (GDC 2016, Frostbite의 GPU 주도 컬링).</li>
<li>Kubisch, <a href="https://developer.nvidia.com/blog/introduction-turing-mesh-shaders/" target="_blank" rel="noreferrer">Introduction to Turing Mesh Shaders</a> (NVIDIA, mesh shader 입문서).</li>
<li>Pesce, <a href="https://www.bartwronski.com/" target="_blank" rel="noreferrer">A Whirlwind Tour of Mesh Shaders</a> (그리고 <a href="http://www.adriancourreges.com/blog/" target="_blank" rel="noreferrer">Adrian Courrèges의 RenderDoc 분해</a>에 모인 비슷한 엔지니어링 블로그들).</li>
</ul>
<h2 id="_12-머리카락-옷감-피부-렌더링" tabindex="-1">12. 머리카락, 옷감, 피부 렌더링 <a class="header-anchor" href="#_12-머리카락-옷감-피부-렌더링" aria-label="Permalink to &quot;12. 머리카락, 옷감, 피부 렌더링&quot;"></a></h2>
<p>머리카락은 strand 기반 지오메트리에 Marschner 스타일의 이방성 셰이딩을 씁니다(NVIDIA HairWorks, AMD TressFX, 또는 엔진 자체 시스템). 옷감은 GPU에서 position-based dynamics로 시뮬레이션되고 이방성 스페큘러로 렌더링됩니다. 피부는 스크린 스페이스 서브서피스 스캐터링에 사전 적분된 wrap lighting을 더합니다. AAA와 인디 사이의 예산 격차가 드러나는 곳은 보통 이 세 가지입니다.</p>
<img src="/img/blog/aaa_hair_cloth_skin.webp" alt="Close-up of a warrior with strand-based hair, cloth cloak, and subsurface-scattered skin" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Marschner et al., <a href="https://www.cs.cornell.edu/~srm/publications/SG03-hair.pdf" target="_blank" rel="noreferrer">Light Scattering from Human Hair Fibers</a> (SIGGRAPH 2003, 토대가 된 머리카락 모델).</li>
<li>Chiang et al., <a href="https://benedikt-bitterli.me/pchfm/pchfm.pdf" target="_blank" rel="noreferrer">A Practical and Controllable Hair and Fur Model for Production Path Tracing</a> (Disney 2016, 실시간 근사에 널리 쓰임).</li>
<li>Müller et al., <a href="https://matthias-research.github.io/pages/publications/posBasedDyn.pdf" target="_blank" rel="noreferrer">Position Based Dynamics</a> (옷감 시뮬레이션의 표준 레퍼런스).</li>
<li>Jimenez et al., <a href="https://www.iryoku.com/separable-sss/" target="_blank" rel="noreferrer">Separable Subsurface Scattering</a> and <a href="https://www.iryoku.com/translucency/" target="_blank" rel="noreferrer">Real-Time Realistic Skin Translucency</a>.</li>
</ul>
<h2 id="_13-데칼-가상-텍스처링-머티리얼-레이어링" tabindex="-1">13. 데칼, 가상 텍스처링, 머티리얼 레이어링 <a class="header-anchor" href="#_13-데칼-가상-텍스처링-머티리얼-레이어링" aria-label="Permalink to &quot;13. 데칼, 가상 텍스처링, 머티리얼 레이어링&quot;"></a></h2>
<p>표면 변화는 깊이 버퍼에 투영되는 레이어드 데칼(탄흔, 먼지, 핏자국, 때)과, 고해상도 디테일을 적시에 스트리밍하는 가상 텍스처에서 나옵니다. 머티리얼 레이어링은 마스크와 triplanar 투영을 써서 픽셀마다 여러 PBR 세트를 블렌딩합니다. 바위 하나가 다섯 개처럼 보이는 이유입니다.</p>
<img src="/img/blog/aaa_decals_virtual_textures.webp" alt="Weathered concrete bunker wall with bullet decals, graffiti, and a virtual texture page atlas inset" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Pranckevičius, <a href="https://aras-p.info/blog/2009/02/27/deferred-decals/" target="_blank" rel="noreferrer">Deferred Decals</a>와 후속편들 (Aras의 고전 블로그 시리즈).</li>
<li>Mittring, <a href="http://advances.realtimerendering.com/s2012/Epic/UnrealEngine4_Mittring_SIGGRAPH2012_Final_Cleaned.pdf" target="_blank" rel="noreferrer">The Technology Behind the &quot;Unreal Engine 4 Elemental Demo&quot;</a> (SIGGRAPH 2012, 가상 텍스처링 세부 내용 포함).</li>
<li>van Waveren, <a href="https://www.realtimerendering.com/blog/id-tech-5-challenges-from-texture-virtualization-to-massive-parallelization/" target="_blank" rel="noreferrer">id Tech 5 Challenges: From Texture Virtualization to Massive Parallelization</a> (SIGGRAPH 2009, MegaTexture 발표).</li>
<li>Williams, <a href="https://www.gdcvault.com/play/1022144/Crafting-the-World-of-The" target="_blank" rel="noreferrer">Material Layering in The Order: 1886</a> (GDC 2014, 레이어드 PBR 머티리얼).</li>
</ul>
<h2 id="_14-순서-무관-투명-oit" tabindex="-1">14. 순서 무관 투명 (OIT) <a class="header-anchor" href="#_14-순서-무관-투명-oit" aria-label="Permalink to &quot;14. 순서 무관 투명 (OIT)&quot;"></a></h2>
<p>머리카락, 식생, 파티클, 유리는 깔끔하게 정렬되지 않습니다. AAA 엔진은 weighted blended OIT, depth peeling, per-pixel linked list 같은 기법으로 CPU 정렬 단계 없이도 이들을 올바르게 렌더링합니다. 식생이 많은 장면에서는 한 프레임에서 조용히 가장 비싼 부분 중 하나입니다.</p>
<img src="/img/blog/aaa_oit_transparency.webp" alt="Forest scene with overlapping translucent foliage, smoke, glass droplets, and translucent hair" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>McGuire and Bavoil, <a href="http://jcgt.org/published/0002/02/09/" target="_blank" rel="noreferrer">Weighted Blended Order-Independent Transparency</a> (JCGT 2013, WBOIT 논문).</li>
<li>Bavoil and Myers, <a href="https://developer.download.nvidia.com/SDK/10/opengl/src/dual_depth_peeling/doc/DualDepthPeeling.pdf" target="_blank" rel="noreferrer">Order Independent Transparency with Dual Depth Peeling</a> (NVIDIA 백서).</li>
<li>Yang et al., <a href="https://www.cse.chalmers.se/edu/year/2017/course/TDA362/Per-Pixel%20Linked%20List.pdf" target="_blank" rel="noreferrer">Real-Time Concurrent Linked List Construction on the GPU</a> (per-pixel linked list 레퍼런스).</li>
<li>Wyman, <a href="https://research.nvidia.com/publication/2016-06_exploring-and-expanding-continuum-oit-algorithms" target="_blank" rel="noreferrer">Exploring and Expanding the Continuum of OIT Algorithms</a> (HPG 2016, 비교 서베이).</li>
</ul>
<h2 id="_15-뉴럴-래디언스-캐싱과-ml-디노이저" tabindex="-1">15. 뉴럴 래디언스 캐싱과 ML 디노이저 <a class="header-anchor" href="#_15-뉴럴-래디언스-캐싱과-ml-디노이저" aria-label="Permalink to &quot;15. 뉴럴 래디언스 캐싱과 ML 디노이저&quot;"></a></h2>
<p>가장 최신의 레이어입니다. NVIDIA의 neural radiance cache는 장면별로 간접 조명을 학습하고, 광선을 더 쏘는 대신 그것을 조회합니다. ML 디노이저(OptiX, Intel Open Image Denoise, 자체 개발판)는 희소한 레이 트레이싱 신호를 밀리초 단위로 정리합니다. 이 범주는 앞으로 2년 동안 빠르게 커질 겁니다.</p>
<img src="/img/blog/aaa_neural_radiance_denoise.webp" alt="Noisy 1-spp ray-traced cathedral on the left, clean ML-denoised result on the right" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>더 깊이 보기:</p>
<ul>
<li>Müller et al., <a href="https://research.nvidia.com/publication/2021-06_real-time-neural-radiance-caching-path-tracing" target="_blank" rel="noreferrer">Real-Time Neural Radiance Caching for Path Tracing</a> (SIGGRAPH 2021, NRC 논문).</li>
<li>Schied et al., <a href="https://research.nvidia.com/publication/2017-07_spatiotemporal-variance-guided-filtering-real-time-reconstruction-path-traced" target="_blank" rel="noreferrer">Spatiotemporal Variance-Guided Filtering: Real-Time Reconstruction for Path-Traced Global Illumination</a> (HPG 2017, SVGF).</li>
<li>Chaitanya et al., <a href="https://research.nvidia.com/publication/interactive-reconstruction-monte-carlo-image-sequences-using-recurrent-denoising" target="_blank" rel="noreferrer">Interactive Reconstruction of Monte Carlo Image Sequences using a Recurrent Denoising Autoencoder</a> (SIGGRAPH 2017, 최초의 순환형 ML 디노이저).</li>
<li>Intel, <a href="https://www.openimagedenoise.org/documentation.html" target="_blank" rel="noreferrer">Open Image Denoise documentation</a> (오픈소스 프로덕션 디노이저).</li>
</ul>
<h2 id="이것이-브라우저에-의미하는-것" tabindex="-1">이것이 브라우저에 의미하는 것 <a class="header-anchor" href="#이것이-브라우저에-의미하는-것" aria-label="Permalink to &quot;이것이 브라우저에 의미하는 것&quot;"></a></h2>
<p>우리는 이 기법들 중 몇 가지를 WebGPU로 우리의 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">브라우저 오픈 월드 엔진</a>에 이미 적용했습니다. 캐스케이드 섀도 맵, GPU 주도 인스턴싱, triplanar PBR, 스크린 스페이스 안개, clipmap 기반 가상화 지형이 모두 탭 안에서 120 FPS로 돌아갑니다. 나머지(하드웨어 레이 트레이싱, mesh shader, ML 업스케일링)는 WebGPU 스펙이 따라잡으면서 웹으로 오고 있습니다. 더 깊이 보려면 <a href="/ko/guides/browser-3d-open-world-tech.html">브라우저 오픈 월드 기술</a>과 <a href="/ko/guides/landscape-generation-browser.html">지형 생성</a>에 관한 가이드를 참고하세요.</p>
<h2 id="전체-스택을-아우르는-더-읽을거리" tabindex="-1">전체 스택을 아우르는 더 읽을거리 <a class="header-anchor" href="#전체-스택을-아우르는-더-읽을거리" aria-label="Permalink to &quot;전체 스택을 아우르는 더 읽을거리&quot;"></a></h2>
<p>책 한 권만 읽는다면, <a href="https://www.realtimerendering.com/" target="_blank" rel="noreferrer">Real-Time Rendering, 4th edition</a>이 위 주제 대부분을 다루는 표준 참고서입니다. 진행 중인 연구를 따라가려면, SIGGRAPH의 &quot;Advances in Real-Time Rendering in Games&quot; 강좌 아카이브(<a href="https://advances.realtimerendering.com/" target="_blank" rel="noreferrer">advances.realtimerendering.com</a>)에 2006년까지 거슬러 올라가는 AAA 엔진 심화 분석 PDF가 무료로 있습니다. 특정 게임이 한 프레임을 어떻게 렌더링하는지에 대한 프로덕션 분해를 보려면, <a href="http://www.adriancourreges.com/blog/" target="_blank" rel="noreferrer">Adrian Courrèges의 GPU 프로파일링 글</a>이 필독입니다.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 18부: AI가 배치한 것처럼 느껴지는 스캐터 브러시]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-02-open-world-browser-part-18-ai-scattering</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-02-open-world-browser-part-18-ai-scattering</guid>
            <pubDate>Sat, 02 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 37은 LLM 없이도 나무를 절벽에서 떼어 놓고 자갈을 물가에 멈춰 세우는 휴리스틱 스캐터 브러시를 만들었고, 그다음 인스턴싱, 거리 LOD, 한 무더기의 버그를 거쳐 4ms짜리 페인트 스트로크까지 끌고 갔다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-18부-ai가-배치한-것처럼-느껴지는-스캐터-브러시" tabindex="-1">브라우저에서 오픈 월드 만들기, 18부: AI가 배치한 것처럼 느껴지는 스캐터 브러시 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-18부-ai가-배치한-것처럼-느껴지는-스캐터-브러시" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 18부: AI가 배치한 것처럼 느껴지는 스캐터 브러시&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva의 CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-05-01-open-world-browser-part-17-animations-and-search.html">17부</a>에서는 플레이어에게 전투 수준의 애니메이션 세트와 CC0 모델이라면 무엇이든 월드로 끌어오는 방법을 줬습니다. 이번 부분은 다시 창작자 쪽으로 돌아갑니다. Spike 34의 팔레트는 클릭 한 번에 프롭 하나를 배치하는데, 주인공 오브젝트 하나를 세우는 데는 괜찮지만 숲을 만드는 데는 쓸모가 없습니다. Spike 37은 그 브러시입니다. 지형을 가로질러 드래그하면 나무가 있어야 할 곳에 나무가 채워집니다.</p>
<h2 id="ai-없는-ai-배치" tabindex="-1">AI 없는 &quot;AI 배치&quot; <a class="header-anchor" href="#ai-없는-ai-배치" aria-label="Permalink to &quot;AI 없는 &quot;AI 배치&quot;&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/37-ai-scattering/" title="Spike 37 AI-Assisted Prop Scattering" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/37-ai-scattering/" target="_blank">새 탭에서 Spike 37 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=37-ai-scattering">소스 보기</a></p>
<p>이 spike가 답하려는 질문은, 순수하게 휴리스틱으로 만든 브러시가 LLM을 건너뛸 만큼 충분히 똑똑하게 느껴지는가입니다. &quot;AI 배치&quot;에 대한 검증은 구체적입니다. 나무는 절벽을 피하고, 바위는 경사면 쪽으로 기울고, 해변 자갈은 물가에서 멈춥니다. 전부 첫 스트로크에서요. 우리는 경사와 고도 술어, 가중치 추첨, 패밀리별 간격으로 거기에 도달했고 모델 호출은 단 한 번도 없었습니다.</p>
<p>브러시는 손으로 다듬은 지형 특징을 가진 257×257 CPU 하이트맵 위에서 작동하므로 모든 프리셋이 내려앉을 곳을 갖습니다. 혼합 경사 선택용 북부 산악, 스크리(자갈)용 동쪽 절벽 띠, 해변과 초원용 남쪽 해안 평야, 남서쪽 호수 분지가 있습니다. 지형은 <code>(altitude, slope)</code> 바이옴 분류기로 정점 색을 굽기 때문에, 나무 한 그루를 칠하기도 전에 어떤 프리셋이 어디서 발동할지 볼 수 있습니다. 다섯 개 프리셋이 평면 데이터로 제공되며, 각각은 <code>{ category, weight, slopeMin, slopeMax, altMin, altMax, minSpacing, alignToSlope }</code> 같은 선택 항목의 목록입니다. Cliff와 Scree는 <code>slopeMin: 0.3</code>으로 설정해 바위가 실제 경사면에만 떨어지게 하고, <code>alignToSlope: true</code>로 설정해 각 바위의 up 벡터가 표면 법선을 따르게 합니다.</p>
<p>각 스트로크마다 스캐터 엔진은 브러시 디스크 안에서 <code>densityPerM2 × area</code> 개의 후보 점을 샘플링하고, 후보마다 높이와 경사를 읽고, 프리셋의 선택 항목을 술어를 통과한 것들로 거른 뒤 가중치로 하나를 뽑고, 반경 내 공간 해시에 대해 간격 검사를 돌립니다. 전체가 결정적입니다. 시드를 줄 수 있는 Mulberry32 RNG가 모든 추첨을 소유하므로 <code>(seed, brush events)</code>가 어떤 세션이든 정확히 재현합니다. 부팅 지형에서 평탄한 초원 위 Mixed Forest 스트로크는 후보 158개 중 139개를 5ms에 배치했고, 같은 프리셋이 절벽 위에서는 226개 중 106개만 배치했으며 HUD는 그중 81개가 경사 때문에 거부됐다고 보고했습니다. 그 거부 내역이 곧 UX 전부입니다. 절벽이 <em>왜</em> 나무를 몇 그루만 받았는지 추측하지 않고 볼 수 있으니까요.</p>
<p>프리셋을 평면 데이터로 유지하는 핵심은, LLM 버전이 도착했을 때 그것이 재작성이 아니라 JSON 교체가 된다는 점입니다. <code>paint({ preset })</code>은 <code>preset.picks</code>가 손으로 다듬은 레시피에서 왔는지, &quot;이끼 낀 바위가 있는 활엽수림&quot;을 가중치로 펼친 워커에서 왔는지 신경 쓰지 않습니다. 엔진은 프롭 id도 절대 하드코딩하지 않으므로, 다른 카탈로그를 끼워 넣어도 엔진 변경이 필요 없습니다.</p>
<h2 id="드로우-콜-300개에서-49개로" tabindex="-1">드로우 콜 300개에서 49개로 <a class="header-anchor" href="#드로우-콜-300개에서-49개로" aria-label="Permalink to &quot;드로우 콜 300개에서 49개로&quot;"></a></h2>
<p>첫 번째 버전은 각 배치를 멀티 메시 그룹의 <code>clone(true)</code>로 렌더링했는데, 프롭이 몇백 개일 때는 괜찮지만 2,500개 상한에서는 드로우 콜이 수천 개로 치솟는 벽에 부딪힙니다. 우리는 그 벽에 닿기 전에 <code>(propId, partIndex)</code>당 버킷 하나를 두는 <code>InstancedMesh</code>로 바꿨습니다. 각 버킷은 두 배씩 늘려 성장합니다. 더 큰 <code>InstancedMesh</code>를 할당하고, 살아 있는 행렬을 복사하고, 씬 부모를 교체하고, 옛 속성을 폐기합니다. 지우기는 스왑 리무브라서, 버킷 크기와 상관없이 인스턴스 하나를 제거하는 일은 O(1)입니다. 교체가 전적으로 배치 레코드 아래에 살기 때문에 결정성, 간격, 거부 HUD가 모두 변경 없이 그대로 이어집니다.</p>
<p>MegaKit 팩에 대한 진단이 진짜 아키텍처 질문 하나를 정리해 줬습니다. 멀티 프리미티브 glTF 메시(줄기 + 잎)는 three.js에 두 가지 형태 중 하나로 도착할 수 있습니다. 배열 머티리얼과 <code>geometry.groups</code>를 가진 메시 하나거나, 각각 머티리얼 하나씩을 가진 별도의 형제 메시들이거나입니다. 이 팩에서는 로더가 두 번째 경로를 택합니다. 모든 파트가 빈 그룹을 가진 단일 머티리얼 메시입니다. 그게 스캐터에는 더 나은 형태인데, 프리미티브별로 버킷이 분리되면 줄기 버킷과 잎 버킷의 개수가 갈라질 때 서로 독립적으로 성장할 수 있기 때문입니다. 드로우 콜 수는 어느 쪽이든 같지만, 분리하면 메모리 형태가 더 좋습니다. 측정된 이득은 사실로 드러났습니다. ~300 드로우 콜이던 숲 스트로크가 49개가 됐고, 멀티 스트로크 세션 전체는 51 드로우 콜에서 75 FPS로 3,221개 인스턴스에 도달했습니다. 클론 경로로는 프레임 예산이 붕괴하기 전에 결코 닿을 수 없던 상한이죠.</p>
<h2 id="거리-lod-그리고-그-안에-숨은-버그-네-개" tabindex="-1">거리 LOD, 그리고 그 안에 숨은 버그 네 개 <a class="header-anchor" href="#거리-lod-그리고-그-안에-숨은-버그-네-개" aria-label="Permalink to &quot;거리 LOD, 그리고 그 안에 숨은 버그 네 개&quot;"></a></h2>
<p>인스턴싱이 드로우 콜은 줄였지만, 모든 인스턴스는 여전히 전체 삼각형 개수를 그렸습니다. 90m 밖에서 잎 디테일을 2픽셀 기여하는 나무까지요. 그래서 우리는 meshoptimizer로 프롭 파트마다 LOD 세 단계(full, 50%, 15%)를 굽고, 버킷 키를 <code>(propId, partIndex, lod)</code>로 확장하고, 배치를 형제 버킷 사이로 할당 없이 실어 나르는 <code>move()</code>를 추가했습니다. 거리 밴드는 0~30m, 30~90m, 그 너머이며, 각 경계 주위에 ±4m의 히스테리시스를 둬서 밴드 가장자리 근처를 맴도는 카메라가 배치를 앞뒤로 흔들며 매 프레임 행렬을 다시 업로드하지 않게 했습니다. 재평가는 4Hz로 상한이 걸려 있고 카메라가 실제로 움직였을 때만 게이트되므로, 정지한 카메라는 프레임당 제곱 거리 비교 한 번만 듭니다.</p>
<p>그 LOD 경로가 바로 교훈적인 버그들이 살던 곳입니다. 첫 번째는 카메라가 궤도를 돌 때 배치가 사라지거나 중복되는 모습으로 나타났고, 씬이 채워질수록 심해졌습니다. 원인은 공유 스크래치 행렬이었습니다. <code>move()</code>가 배치의 변환을 모듈 스코프의 <code>_tmpMat</code>로 읽어 들였는데, 원본 버킷의 스왑 리무브가 자기 내부 셔플에 같은 <code>_tmpMat</code>를 쓰면서, 목적지가 쓰기 전에 실어 나르던 행렬을 덮어쓴 것입니다. 이 버그는 옮겨지는 슬롯이 이미 버킷의 마지막일 때만 비켜갔는데, 대략 <code>1/count</code> 확률이고, 이게 정확히 플레이테스트에서 본 &quot;씬이 커질수록 심해지는 드문 깜빡임&quot;입니다. 수정은 <code>move()</code> 전용으로 예약한 <code>_carryMat</code>였습니다. 누적 1,274회 이동으로 스트레스 테스트했을 때 클러스터는 픽셀 단위로 동일하게 유지됐습니다.</p>
<p>두 번째 버그는 더 미묘했습니다. 모든 LOD 전환이 부드럽게 느껴졌는데 <em>첫 번째만</em> 예외였습니다. LOD1으로 넘어가는 나무는 실루엣이 거의 안 변하는데도 음영이 눈에 띄게 바뀐 반면, 사다리 뒤쪽의 더 큰 삼각형 감소는 멀쩡해 보였습니다. <code>LockBorder</code>를 쓰는 단순화기는 정점을 옮기거나 만들어내지 않으므로 살아남은 정점은 법선을 그대로 유지하는데, 그런데도 우리는 단순화 후마다 <code>computeVertexNormals()</code>를 호출하고 있었습니다. LOD0은 아티스트가 만든 원본 법선을 손대지 않고 반환하지만, LOD1 이상은 three.js의 일반적인 면 평균 재계산을 받았습니다. 0에서 1로 가는 경계가 사다리에서 법선 체계가 바뀌는 유일한 지점이었으니, 팝이 살던 곳도 거기였습니다. 그 방어적인 한 줄을 빼니 음영이 고쳐졌고, 덤으로 파트당 네 개 LOD에서 법선을 다시 계산하지 않게 되면서 프롭당 굽기 시간이 대략 절반으로 줄었습니다.</p>
<p>단순화기가 만들어낸 것을 감사하다 세 번째 이득이 떠올랐습니다. 각 LOD는 새 인덱스를 가진 <code>original.clone()</code>이었고, <code>BufferGeometry.clone()</code>은 모든 속성을 깊은 복사하므로, 다섯 개 LOD가 position, normal, UV, color 버퍼의 독립 복사본 다섯 개를 들고 있었고 그 값들은 전부 비트 단위로 동일했습니다. 우리는 속성 참조를 공유하고 LOD마다 전용 인덱스 버퍼만 소유하도록 리팩터링해서, 전형적인 나무 파트를 서로 다른 속성 아이덴티티 20개에서 9개로 줄이고 각 정점 버퍼를 GPU에 한 번만 업로드했습니다. 별칭(aliased) 저장에는 계약 두 가지가 따라옵니다. 어떤 한 LOD를 통해서도 속성 데이터를 변형하지 말 것, 그리고 LOD 하나의 지오메트리를 <code>dispose()</code>하지 말 것. 둘 다 그 버퍼를 공유하는 모든 형제에 영향을 주기 때문입니다.</p>
<p>네 번째 버그는 페인팅과는 아무 상관이 없었습니다. 버튼을 누르지도 않고 지형 위에서 그저 커서를 흔들기만 해도 프레임 레이트가 떨어졌습니다. <code>pointermove</code> 핸들러가 공간 구조가 없는 131,072 삼각형 평면인 지형 메시에 대해 레이캐스트를 했고, 그래서 three.js가 이벤트마다 초당 최대 1,000회까지 전체 인덱스 버퍼를 훑었습니다. 지형이 파라메트릭 하이트맵이라서 그 조회에는 메시가 전혀 필요 없었습니다. <code>sampleHeight</code>에 대한 적응형 레이 마치(표면 위로 높을 때는 큰 보폭, 가까울 때는 0.4m 바닥, 그다음 부호 전환에서 12회 이분법)는 광선당 131,072번의 삼각형 테스트 대신 대략 8~30개 샘플이 드는데, 약 세 자릿수만큼 더 싸고, 호버는 다시 프레임 상한을 유지합니다.</p>
<h2 id="비용은-그냥-옮겨갈-뿐이다-클릭에서-옮겨가게-하라" tabindex="-1">비용은 그냥 옮겨갈 뿐이다. 클릭에서 옮겨가게 하라 <a class="header-anchor" href="#비용은-그냥-옮겨갈-뿐이다-클릭에서-옮겨가게-하라" aria-label="Permalink to &quot;비용은 그냥 옮겨갈 뿐이다. 클릭에서 옮겨가게 하라&quot;"></a></h2>
<p>spike를 프로덕션 타깃인 three r184의 <code>WebGPURenderer</code>로 바꾼 뒤, DevTools 프로파일은 첫 페인트가 265ms 동안 막히고 그중 79%가 meshoptimizer WASM 안에 있다는 것을 보여줬습니다. 굽기는 실제 작업이었습니다. 콜드 프리셋에 대해 약 180회의 simplify 호출이었죠. 하지만 그게 클릭 핸들러 안에서 돌고 있었는데, <code>preloadProps</code>가 씬을 가져와 파싱만 했지 LOD 굽기를 전혀 촉발하지 않았기 때문입니다. 수정은 프리셋 선택이 배경에서 전체 굽기를 하게 만드는 것이었습니다. <code>preloadProps</code>는 이제 파트 해석 경로를 호출하고, 진행 중인 프로미스를 캐시해서 빠른 클릭이 중복을 만들지 않고 그것에 합류하게 하며, 단순화기가 파트당 네 번씩 다시 하던 지오메트리별 전처리를 메모이즈합니다. 첫 페인트는 HUD에서 209ms에서 4ms로 떨어졌습니다. WASM 시간은 사라지지 않았습니다. 그저 사용자의 임계 경로를 떠나, 사용자가 지형을 보며 어디를 칠할지 정하는 동안 돌 뿐입니다.</p>
<p>그게 이 spike의 되풀이되는 교훈입니다. 이 수정들 거의 어느 것도 브러시가 <em>하는 일</em>을 바꾸지 않았습니다. 그것들은 비용이 <em>언제</em> 내려앉는지를 바꿨습니다. 클릭에서, 호버에서, 카메라가 맴도는 경계에서 비용을 떼어냈죠. 즉각적으로 느껴지는 스캐터 도구는 일을 덜 하는 게 아니라, 사용자가 기다리지 않는 곳에서 그 일을 하는 것입니다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>휴리스틱 적합도 스캐터.</strong> 브러시가 디스크 안에서 후보 점을 샘플링하고, 점마다 CPU 하이트맵에서 <code>(height, slope)</code>를 읽고, 경사와 고도 술어로 프리셋의 선택 항목을 거르고, 가중치로 하나를 뽑고, 공간 해시에 추적되는 패밀리별 최소 간격을 위반하면 거부합니다. 경사 정렬 선택은 up 벡터를 표면 법선으로 회전시킵니다. 이렇게 하면 학습된 가중치 없이도 의도적으로 읽히는 배치(나무는 절벽을 피하고, 바위는 경사 쪽으로 기울고, 자갈은 물가에서 멈춤)가 나오고, 프리셋을 평면 데이터로 유지해 LLM이 생성한 선택 목록을 그대로 끼워 넣을 수 있게 합니다.</p>
<p><strong>비동기 로드 하의 결정적 배치.</strong> 시드를 줄 수 있는 Mulberry32 RNG가 모든 추첨을 소유하므로 <code>(seed, brush events)</code>가 세션을 정확히 재현합니다. RNG 추첨은 어떤 <code>await</code>보다 먼저 일어나고, 간격 예약은 glTF 클론이 해석되기 전에 공간 인덱스에 삽입되므로, 동시 후보들은 서로를 존중하고 비동기 에셋 로딩이 시퀀스를 교란할 수 없습니다.</p>
<p><strong>O(1) 편집이 가능한 버킷형 InstancedMesh.</strong> <code>(propId, partIndex, lod)</code>당 <code>InstancedMesh</code> 하나이며, 살아 있는 행렬을 더 큰 버퍼로 복사해 요청에 따라 용량을 두 배로 늘립니다. 지우기와 FIFO 축출은 옮겨진 인스턴스의 인덱스를 패치하는 역참조 배열을 동반한 스왑 리무브라서, 버킷 크기와 상관없이 제거가 O(1)입니다. 한 진단이 glTF 파트가 단일 머티리얼 메시로 도착함을 확인했고, 이로써 프리미티브당 버킷 하나가 활성 경로가 되어 각 프리미티브에 독립적으로 성장 가능한 버킷을 줍니다.</p>
<p><strong>히스테리시스와 공유 속성 버퍼를 쓰는 거리 LOD.</strong> 파트당 meshopt로 단순화한 세 단계를 ±4m 히스테리시스가 있는 거리 밴드로 선택해 경계 근처 카메라가 흔들리지 않게 하고, 상한이 걸린 비율로, 실제 카메라 움직임에 게이트해 재평가합니다. <code>LockBorder</code> 단순화는 정점을 절대 옮기지 않기 때문에, 모든 LOD가 하나의 position/normal/UV/color 버퍼 세트를 공유하고 전용 인덱스 버퍼만 다르며, 이로써 서로 다른 GPU 정점 버퍼를 대략 절반으로 줄입니다. 방어적인 <code>computeVertexNormals</code> 하나를 건너뛰면 아티스트 법선이 LOD 전반에 동일하게 유지되고 사다리에서 유일한 음영 불연속이 사라집니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">LOD와 meshoptimizer</a>를 보세요.</p>
<p><strong>고빈도 조회를 위한 해석적 하이트맵 레이캐스트.</strong> 131k 삼각형 평면 메시에 대한 <code>pointermove</code> 빈도의 커서 조회는 이벤트마다 전체 인덱스 버퍼를 훑습니다. 이것을 해석적 높이 함수에 대한 적응형 레이 마치(표면에서 멀 때는 큰 보폭, 가까울 때는 작은 바닥, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.869ex;" xmlns="http://www.w3.org/2000/svg" width="16.358ex" height="2.566ex" role="img" focusable="false" viewBox="0 -750 7230.4 1134.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(389,0)"><g data-mml-node="mtext"><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(392,0)" style="stroke-width: 3;"/><path data-c="79" d="M69 -66Q91 -66 104 -80T118 -116Q118 -134 109 -145T91 -160Q84 -163 97 -166Q104 -168 111 -168Q131 -168 148 -159T175 -138T197 -106T213 -75T225 -43L242 0L170 183Q150 233 125 297Q101 358 96 368T80 381Q79 382 78 382Q66 385 34 385H19V431H26L46 430Q65 430 88 429T122 428Q129 428 142 428T171 429T200 430T224 430L233 431H241V385H232Q183 385 185 366L286 112Q286 113 332 227L376 341V350Q376 365 366 373T348 383T334 385H331V431H337H344Q351 431 361 431T382 430T405 429T422 429Q477 429 503 431H508V385H497Q441 380 422 345Q420 343 378 235T289 9T227 -131Q180 -204 113 -204Q69 -204 44 -177T19 -116Q19 -89 35 -78T69 -66Z" transform="translate(892,0)" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1453,-239.4) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2460.7,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3460.9,0)"><g data-mml-node="mtext"><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(389,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1225,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(1617,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(2117,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2395,0)" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2984,-150) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(6841.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><msub><mtext>ray</mtext><mi>y</mi></msub><mo>−</mo><msub><mtext>terrain</mtext><mi>y</mi></msub><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>의 부호 전환에서 이분법)로 바꾸면 수만 번의 삼각형 테스트 대신 수십 개 샘플이 들어 약 세 자릿수만큼 더 싸고, 미리 할당한 출력 벡터가 핫 패스를 할당 없이 유지합니다.</p>
<p><strong>상호작용의 임계 경로에서 작업을 떼어내라.</strong> 비싼 일회성 작업(meshopt LOD 굽기, WGSL 파이프라인 컴파일)은 클릭 핸들러 안이 아니라 유휴 틈에 돌아야 합니다. 프리셋 선택 시 활성 프리셋의 전체 굽기를 미리 로드하고, 진행 중인 프로미스를 캐시해 빠른 클릭이 포크가 아니라 합류하게 하고, 지오메트리별 전처리를 메모이즈한 결과, 전체 작업량을 전혀 줄이지 않고도 첫 페인트 지연을 209ms에서 4ms로 떨어뜨렸습니다.</p>
<hr>
<p>29부 중 18부.
이전: <a href="/ko/blog/2026-05-01-open-world-browser-part-17-animations-and-search.html">17부 - 리타기팅이 필요 없던 애니메이션, 그리고 실시간 에셋 검색</a>
다음: <a href="/ko/blog/2026-05-04-open-world-browser-part-19-imposters.html">19부 - 숲에서 살아남아야 하는 임포스터</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 17부: 리타기팅이 필요 없던 애니메이션, 그리고 실시간 에셋 검색]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-05-01-open-world-browser-part-17-animations-and-search</link>
            <guid>https://app.cinevva.com/ko/blog/2026-05-01-open-world-browser-part-17-animations-and-search</guid>
            <pubDate>Fri, 01 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 35는 262개의 전투와 이동 클립을 플레이어 릭에 리타기팅하고, 그것들을 정직하게 유지할 오프라인 일치 테스트를 만들었다. Spike 36은 빌드 단계 없이 실시간 Polyhaven 모델 검색을 연결했다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-17부-리타기팅이-필요-없던-애니메이션-그리고-실시간-에셋-검색" tabindex="-1">브라우저에서 오픈 월드 만들기, 17부: 리타기팅이 필요 없던 애니메이션, 그리고 실시간 에셋 검색 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-17부-리타기팅이-필요-없던-애니메이션-그리고-실시간-에셋-검색" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 17부: 리타기팅이 필요 없던 애니메이션, 그리고 실시간 에셋 검색&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring.html">16부</a>에서 우리는 물체를 배치할 수 있는 세계를 얻었습니다. 이번 부분은 그 안에서 플레이어가 할 수 있는 더 나은 것을 줍니다. 전투급 애니메이션 세트, 그리고 검색을 입력해서 수천 개의 CC0 모델 중 무엇이든 세계로 끌어오는 방법입니다.</p>
<h2 id="_262개-클립-하나의-스켈레톤-세-개의-리타기팅-수정" tabindex="-1">262개 클립, 하나의 스켈레톤, 세 개의 리타기팅 수정 <a class="header-anchor" href="#_262개-클립-하나의-스켈레톤-세-개의-리타기팅-수정" aria-label="Permalink to &quot;262개 클립, 하나의 스켈레톤, 세 개의 리타기팅 수정&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/35-combat-animations/" title="Spike 35 Combat Animations" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/35-combat-animations/" target="_blank">새 탭에서 Spike 35 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=35-combat-animations">소스 보기</a></p>
<p>플레이어 릭은 CC4 스타일의 <code>3MIKE</code> 스켈레톤으로 213개의 본을 가지고 있고, 80개가 넘는 본의 얼굴 릭과 완전한 손가락 관절을 포함합니다. 애니메이션 소스는 여기에 맞지 않습니다. 첫 번째 버전은 손으로 고른 Mixamo 전투 클립을 리타기팅했지만, 소스 풀이 얇았고 이동 애니메이션은 Mixamo와 몇 개의 Kimodo BVH 대기 동작 사이에 어색하게 쪼개져 있었습니다. 진짜 성과는 소스 라이브러리를 Quaternius의 Universal Animation Library 두 팩으로 바꿨을 때 나왔습니다. 하나의 일관된 UE5 스타일 65본 마네킹 위에 총 262개의 클립입니다. 검 콤보, 활쏘기, 등반, 벽 달리기, 회피, 피격 반응, 이모트, 그리고 훨씬 깔끔한 이동 애니메이션 세트가 있습니다.</p>
<p>이건 65본 소스에서 213본 타깃으로 가는 것이고, 공유된 본 이름도, T-포즈 방향도, 팔다리 비율도 없습니다. 모든 클립은 세 단계로 리매핑됩니다. 본 이름 맵, 두 릭이 기준 방향을 공유하도록 하는 바인드 포즈 정렬, 그리고 더 짧은 소스 릭이 캐릭터를 바닥에 무릎까지 박아버리지 않도록 하는 위치 트랙 스케일링입니다. 이걸 제대로 맞추는 일은 각각 구체적인 무언가를 가르쳐 준 일련의 버그를 쫓는 것을 뜻했습니다.</p>
<p>캐릭터가 너무 비틀린 채로 나왔고, 모든 어깨와 팔꿈치가 약 30° 정도 과하게 회전했습니다. 원인은 포즈 불일치였습니다. UAL 소스는 진짜 T-포즈로 배포되고, CC4의 바인드는 A-포즈인데, 리타기터는 두 릭이 일치하는 기준 포즈에 있다고 가정했습니다. 그래서 A에서 T로의 차이가 매 프레임 델타마다 더해졌습니다. 수정은 바인드를 잡기 위해 CC4의 팔 체인을 진짜 T-포즈로 강제한 다음 리타기팅하는 것입니다. 그러면 델타가 작게 유지됩니다.</p>
<p>그다음에는 몸이 이동을 멈췄습니다. 넉백이 상체를 뒤로 젖혔지만 발은 바닥에 박힌 채로 남았습니다. UAL은 변위를 골반이 아니라 <code>root</code> 본에 둡니다. 그래서 골반 위치를 읽으면 거의 0에 가까운 움직임이 나왔습니다. 수정은 <code>root.position</code>과 <code>pelvis.position</code>을 더하고, 수평 부분을 스케일링한 다음, 하나의 엉덩이 위치 트랙으로 쓰는 것입니다. 이걸 하면서 우리는 수직 오프셋이 약 12% 어긋나 있는 것을 발견했습니다. 골반 높이는 엉덩이-바닥 비율이 필요한데 Y축에 전역 팔다리 비율을 썼기 때문이었습니다. 두 개의 비율, 두 개의 축입니다. Y에는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="40.854ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 18057.6 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mtext"><path data-c="76" d="M338 431Q344 429 422 429Q479 429 503 431H508V385H497Q439 381 423 345Q421 341 356 172T288 -2Q283 -11 263 -11Q244 -11 239 -2Q99 359 98 364Q93 378 82 381T43 385H19V431H25L33 430Q41 430 53 430T79 430T104 429T122 428Q217 428 232 431H240V385H226Q187 384 184 370Q184 366 235 234L286 102L377 341V349Q377 363 367 372T349 383T335 385H331V431H338Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(528,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(972,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1364,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(1753,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(2031,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(2475,0)" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(2975,0)" style="stroke-width: 3;"/><path data-c="52" d="M130 622Q123 629 119 631T103 634T60 637H27V683H202H236H300Q376 683 417 677T500 648Q595 600 609 517Q610 512 610 501Q610 468 594 439T556 392T511 361T472 343L456 338Q459 335 467 332Q497 316 516 298T545 254T559 211T568 155T578 94Q588 46 602 31T640 16H645Q660 16 674 32T692 87Q692 98 696 101T712 105T728 103T732 90Q732 59 716 27T672 -16Q656 -22 630 -22Q481 -16 458 90Q456 101 456 163T449 246Q430 304 373 320L363 322L297 323H231V192L232 61Q238 51 249 49T301 46H334V0H323Q302 3 181 3Q59 3 38 0H27V46H60Q102 47 111 49T130 61V622ZM491 499V509Q491 527 490 539T481 570T462 601T424 623T362 636Q360 636 340 636T304 637H283Q238 637 234 628Q231 624 231 492V360H289Q390 360 434 378T489 456Q491 467 491 499Z" transform="translate(3253,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(3989,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(4489,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(4878,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(5156,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(5933.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6989.6,0) translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(7267.6,0)"><g data-mml-node="mtext"><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(389,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(889,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(1281,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1781,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(2225,0)" style="stroke-width: 3;"/><path data-c="48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z" transform="translate(2614,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(3364,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(3642,0)" style="stroke-width: 3;"/><path data-c="59" d="M518 0Q497 3 374 3Q253 3 232 0H221V46H254Q313 47 321 58Q324 62 324 167V273L221 446Q117 620 114 623Q106 631 91 634T31 637H11V683H20Q29 680 148 680Q273 680 294 683H305V637H287Q239 636 236 621Q236 619 321 475L407 332L483 460Q502 492 527 534Q563 594 563 604Q563 632 517 637H508V683H517H525Q533 683 545 683T571 682T600 681T626 681Q695 681 731 683H738V637H723Q640 633 613 588Q612 587 517 427L425 273V169V95Q425 66 428 59T444 49Q459 46 506 46H528V0H518Z" transform="translate(4198,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(12215.6,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z" style="stroke-width: 3;"/></g></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(12715.6,0)"><g data-mml-node="mtext"><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(394,0)" style="stroke-width: 3;"/><path data-c="75" d="M383 58Q327 -10 256 -10H249Q124 -10 105 89Q104 96 103 226Q102 335 102 348T96 369Q86 385 36 385H25V408Q25 431 27 431L38 432Q48 433 67 434T105 436Q122 437 142 438T172 441T184 442H187V261Q188 77 190 64Q193 49 204 40Q224 26 264 26Q290 26 311 35T343 58T363 90T375 120T379 144Q379 145 379 161T380 201T380 248V315Q380 361 370 372T320 385H302V431Q304 431 378 436T457 442H464V264Q464 84 465 81Q468 61 479 55T524 46H542V0Q540 0 467 -5T390 -11H383V58Z" transform="translate(894,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1450,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(1842,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2286,0)" style="stroke-width: 3;"/><path data-c="48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z" transform="translate(2730,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(3480,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(3758,0)" style="stroke-width: 3;"/><path data-c="59" d="M518 0Q497 3 374 3Q253 3 232 0H221V46H254Q313 47 321 58Q324 62 324 167V273L221 446Q117 620 114 623Q106 631 91 634T31 637H11V683H20Q29 680 148 680Q273 680 294 683H305V637H287Q239 636 236 621Q236 619 321 475L407 332L483 460Q502 492 527 534Q563 594 563 604Q563 632 517 637H508V683H517H525Q533 683 545 683T571 682T600 681T626 681Q695 681 731 683H738V637H723Q640 633 613 588Q612 587 517 427L425 273V169V95Q425 66 428 59T444 49Q459 46 506 46H528V0H518Z" transform="translate(4314,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(17779.6,0) translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mtext>verticalRatio</mtext><mo>=</mo><mo data-mjx-texclass="ORD" stretchy="false">|</mo><mrow data-mjx-texclass="ORD"><mtext>targetHipY</mtext></mrow><mrow data-mjx-texclass="ORD"><mo>/</mo></mrow><mrow data-mjx-texclass="ORD"><mtext>sourceHipY</mtext></mrow><mo data-mjx-texclass="ORD" stretchy="false">|</mo></math></mjx-assistive-mml></mjx-container>, 수평에는 비율 자체를 씁니다. 오버슈트가 사라졌습니다. 그리고 <code>RL_BoneRoot.position</code> NaN 경고가 줄줄이 나왔는데, UAL의 <code>root</code>(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="5.875ex" height="1.731ex" role="img" focusable="false" viewBox="0 -683 2596.6 765" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D44C" d="M66 637Q54 637 49 637T39 638T32 641T30 647T33 664T42 682Q44 683 56 683Q104 680 165 680Q288 680 306 683H316Q322 677 322 674T320 656Q316 643 310 637H298Q242 637 242 624Q242 619 292 477T343 333L346 336Q350 340 358 349T379 373T411 410T454 461Q546 568 561 587T577 618Q577 634 545 637Q528 637 528 647Q528 649 530 661Q533 676 535 679T549 683Q551 683 578 682T657 680Q684 680 713 681T746 682Q763 682 763 673Q763 669 760 657T755 643Q753 637 734 637Q662 632 617 587Q608 578 477 424L348 273L322 169Q295 62 295 57Q295 46 363 46Q379 46 384 45T390 35Q390 33 388 23Q384 6 382 4T366 1Q361 1 324 1T232 2Q170 2 138 2T102 1Q84 1 84 9Q84 14 87 24Q88 27 89 30T90 35T91 39T93 42T96 44T101 45T107 45T116 46T129 46Q168 47 180 50T198 63Q201 68 227 171L252 274L129 623Q128 624 127 625T125 627T122 629T118 631T113 633T105 634T96 635T83 636T66 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1040.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2096.6,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>Y</mi><mo>=</mo><mn>0</mn></math></mjx-assistive-mml></mjx-container>에 있음)를, 바인드 Y로 나눠서 정규화되는 위치 트랙을 가진 타깃 본에 매핑한 것이 원인이었습니다. 0으로 나누기, NaN, 조용히 버려지는 트랙입니다. 수정은 root 매핑을 통째로 빼는 것이었습니다. 그 평행이동은 이미 엉덩이 트랙 안에 살고 있기 때문입니다.</p>
<p>가장 작은 수정이 보기에는 가장 만족스러웠습니다. 캐릭터가 축 늘어진 바인드 포즈 손가락으로 검을 쥐고 있었는데, 본 맵에 손가락 항목이 없었고 리타기터는 매핑된 본에 대해서만 트랙을 쓰기 때문이었습니다. 손가락 본 30개(다섯 손가락, 세 마디, 두 손, 변형되지 않는 UAL의 네 번째 손끝 헬퍼는 제외)를 추가하니 손이 손잡이를 잡을 때 오므라지고 놓을 때 펴졌습니다.</p>
<h2 id="_262개-클립을-보지-않고-262개-클립을-증명하기" tabindex="-1">262개 클립을 보지 않고 262개 클립을 증명하기 <a class="header-anchor" href="#_262개-클립을-보지-않고-262개-클립을-증명하기" aria-label="Permalink to &quot;262개 클립을 보지 않고 262개 클립을 증명하기&quot;"></a></h2>
<p>262개 클립 라이브러리를 눈으로 검증할 수는 없습니다. 그래서 우리는 오프라인 궤적 일치 테스트를 만들었습니다. 각 팩을 로드하고, 소스 스켈레톤을 60Hz로 샘플링하고, 리타기팅 파이프라인을 돌린 다음, 스케일링 후의 본별 월드 위치와 회전을 소스와 비교하는 헤드리스 Node 스크립트입니다. 골반 Y 드리프트는 최대 0.003 m로 나왔습니다. 손은 일정한 2.5° 오프셋을 보였는데, 처음에는 &quot;손가락이 추적되지 않는다&quot;로 읽혔습니다. 하지만 일정한 오프셋은 평평한 UAL 손과 약간 오므라진 CC4 바인드 사이의 바인드 델타이고, 클립 전체에서 변하지 않습니다. 진짜 애니메이션 오류는 프레임마다 달라지는 드리프트로 나타납니다. 이게 분명해지자 테스트는 한 방 회귀 검사가 되었습니다. 어떤 클립의 드리프트가 그 일정한 기준선을 유지하지 못하면, 최근의 변경이 리타기팅을 망가뜨린 것입니다.</p>
<p>나란히 놓인 참조 마네킹은 디버깅의 시각적 절반을 결정적으로 만들었습니다. 백슬래시를 누르면 현재 클립을 소유한 소스 릭이 플레이어 옆에 나타납니다. 그래서 &quot;어깨가 비틀렸다&quot;라는 질문이 &quot;비틀림이 소스에 있나, 아니면 리타기팅이 더한 건가?&quot;로 바뀝니다. 수치 테스트는 회귀를 잡고, 시각 참조는 숫자로 드러나지 않는 바인드 포즈 실수를 잡습니다. 둘이 함께 추측 게임을 은퇴시켰습니다.</p>
<p>파이프라인이 단단해지자, WASD/점프/수영 기준선을 Mixamo에서 UAL로 바꾸는 것은 얇은 별칭 맵에 불과했습니다. FSM은 여전히 <code>idle</code>이나 <code>walk</code> 같은 일반 상태 이름을 말하고, 재생 시점에 UAL 클립 이름으로 해석됩니다. 수영은 클립별 릭 오프셋이 필요했습니다. 자유형과 선헤엄 포즈가 골반을 서로 다른 해부학적 높이에 고정하기 때문입니다. 그래서 능동적으로 수영할 때는 릭을 반 미터 가라앉히고 선헤엄칠 때는 더 깊게 가라앉히면서, 부드러운 5Hz로 둘 사이를 블렌딩합니다.</p>
<h2 id="단어를-입력하면-모델이-나온다" tabindex="-1">단어를 입력하면 모델이 나온다 <a class="header-anchor" href="#단어를-입력하면-모델이-나온다" aria-label="Permalink to &quot;단어를 입력하면 모델이 나온다&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/36-polyhaven-models/" title="Spike 36 Polyhaven Models" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/36-polyhaven-models/" target="_blank">새 탭에서 Spike 36 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=36-polyhaven-models">소스 보기</a></p>
<p>Spike 34는 CC0 팩을 손으로 큐레이션하느라 하루를 잡아먹었습니다. 장기적인 답은 검색 상자입니다. Polyhaven은 너그러운 JSON API와 결정론적 CDN 뒤에 약 1,100개의 CC0 모델을 게시합니다. 그리고 이 spike는 빌드 단계 없이 정적 페이지에서 전체 경로(쿼리, 썸네일, 로드, 렌더)를 약 300줄의 바닐라 JS에 three.js를 더해 연결합니다.</p>
<p>부팅할 때 전체 카탈로그를 한 번 가져옵니다. 약 600 KB입니다. 검색은 순수 클라이언트 측 점수 매기기(이름이 id를 이기고, id가 카테고리를 이기고, 카테고리가 태그를 이김)에 120 ms 디바운스를 걸고 상위 60개 카드를 렌더링합니다. 썸네일은 <code>IntersectionObserver</code>를 통해 지연 로드되므로 타이핑이 한 번에 60개 요청을 쏘지 않습니다. 흥미로운 부분은 로딩입니다. Polyhaven의 파일 엔드포인트는 GLB가 아니라 멀티파일 glTF를 노출하고, 텍스처는 해상도 간에 공유되며 별도 파일로 쪼개져 있고, 상대 경로에서 절대 CDN URL로 가는 <code>include</code> 맵을 돌려줍니다. JSON을 우리가 직접 내려받아 패치하는 대신, 그 맵을 <code>LoadingManager.setURLModifier</code>에 먹입니다. 이건 로더가 필요로 하는 모든 의존성(<code>.bin</code>, 각 텍스처)마다 발동되어 CDN을 통해 해석합니다. 한 번의 클릭, 겉보기엔 하나의 파일입니다. API와 CDN 둘 다 너그러운 CORS를 설정했고, 어떤 클라이언트 코드보다 먼저 <code>curl</code>로 검증했습니다. 그래서 프록시가 필요 없습니다. PBR 머티리얼은 <code>RoomEnvironment</code>와 ACES 톤 매핑 기본값으로 에셋별 보정 없이 올바르게 렌더링되고, 1k 텍스처는 일반적인 모델을 4k의 20에서 40 MB 대신 2에서 5 MB로 유지합니다.</p>
<p>meshoptimizer WASM 패스가 비파괴적 리듀서로 마무리합니다. 각 메시는 원본 지오메트리의 복제본을 보관하고, 비율을 바꾸면 누적적으로 단순화하는 대신 그 복제본에서 인덱스 버퍼를 다시 빌드합니다. 멀티 머티리얼 지오메트리는 그룹별로 단순화하고 <code>geometry.groups</code>를 다시 빌드해서 머티리얼 슬롯이 무너지지 않습니다. 안락의자 하나가 전체 정밀도 5,626 삼각형에서 절반 정밀도 2,812로 갑니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>바인드 포즈 정렬을 동반한 스켈레톤 리타기팅.</strong> 본 이름, 비율, 기준 포즈가 다른 한 스켈레톤에서 다른 스켈레톤으로 애니메이션을 매핑하려면 세 가지 보정이 필요합니다. 본 이름 맵, 두 릭이 기준 방향을 공유하도록 하는 바인드 포즈 정렬(타깃의 A-포즈 팔 체인을 소스의 T-포즈로 강제), 그리고 위치 트랙 스케일링입니다. 포즈 불일치는 A에서 T로의 회전을 매 프레임 델타에 더해 관절 회전을 두 배로 만듭니다. 매핑되지 않은 헬퍼 본은 반드시 버려야 합니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="5.875ex" height="1.731ex" role="img" focusable="false" viewBox="0 -683 2596.6 765" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D44C" d="M66 637Q54 637 49 637T39 638T32 641T30 647T33 664T42 682Q44 683 56 683Q104 680 165 680Q288 680 306 683H316Q322 677 322 674T320 656Q316 643 310 637H298Q242 637 242 624Q242 619 292 477T343 333L346 336Q350 340 358 349T379 373T411 410T454 461Q546 568 561 587T577 618Q577 634 545 637Q528 637 528 647Q528 649 530 661Q533 676 535 679T549 683Q551 683 578 682T657 680Q684 680 713 681T746 682Q763 682 763 673Q763 669 760 657T755 643Q753 637 734 637Q662 632 617 587Q608 578 477 424L348 273L322 169Q295 62 295 57Q295 46 363 46Q379 46 384 45T390 35Q390 33 388 23Q384 6 382 4T366 1Q361 1 324 1T232 2Q170 2 138 2T102 1Q84 1 84 9Q84 14 87 24Q88 27 89 30T90 35T91 39T93 42T96 44T101 45T107 45T116 46T129 46Q168 47 180 50T198 63Q201 68 227 171L252 274L129 623Q128 624 127 625T125 627T122 629T118 631T113 633T105 634T96 635T83 636T66 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1040.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2096.6,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>Y</mi><mo>=</mo><mn>0</mn></math></mjx-assistive-mml></mjx-container>에 있는 root 본은 위치 트랙 정규화에서 조용한 0으로 나누기를 일으키기 때문입니다.</p>
<p><strong>한 릭을 위한 두 개의 스케일 비율.</strong> 수평 변위는 전역 팔다리 비율(전체 스켈레톤 크기)을 쓰지만, 수직 골반 오프셋은 엉덩이-바닥 비율 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="25.041ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 11068 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(278,0)"><g data-mml-node="mtext"><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(389,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(889,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(1281,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1781,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(2225,0)" style="stroke-width: 3;"/><path data-c="48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z" transform="translate(2614,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(3364,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(3642,0)" style="stroke-width: 3;"/><path data-c="59" d="M518 0Q497 3 374 3Q253 3 232 0H221V46H254Q313 47 321 58Q324 62 324 167V273L221 446Q117 620 114 623Q106 631 91 634T31 637H11V683H20Q29 680 148 680Q273 680 294 683H305V637H287Q239 636 236 621Q236 619 321 475L407 332L483 460Q502 492 527 534Q563 594 563 604Q563 632 517 637H508V683H517H525Q533 683 545 683T571 682T600 681T626 681Q695 681 731 683H738V637H723Q640 633 613 588Q612 587 517 427L425 273V169V95Q425 66 428 59T444 49Q459 46 506 46H528V0H518Z" transform="translate(4198,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(5226,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z" style="stroke-width: 3;"/></g></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(5726,0)"><g data-mml-node="mtext"><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(394,0)" style="stroke-width: 3;"/><path data-c="75" d="M383 58Q327 -10 256 -10H249Q124 -10 105 89Q104 96 103 226Q102 335 102 348T96 369Q86 385 36 385H25V408Q25 431 27 431L38 432Q48 433 67 434T105 436Q122 437 142 438T172 441T184 442H187V261Q188 77 190 64Q193 49 204 40Q224 26 264 26Q290 26 311 35T343 58T363 90T375 120T379 144Q379 145 379 161T380 201T380 248V315Q380 361 370 372T320 385H302V431Q304 431 378 436T457 442H464V264Q464 84 465 81Q468 61 479 55T524 46H542V0Q540 0 467 -5T390 -11H383V58Z" transform="translate(894,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1450,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(1842,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2286,0)" style="stroke-width: 3;"/><path data-c="48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z" transform="translate(2730,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(3480,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(3758,0)" style="stroke-width: 3;"/><path data-c="59" d="M518 0Q497 3 374 3Q253 3 232 0H221V46H254Q313 47 321 58Q324 62 324 167V273L221 446Q117 620 114 623Q106 631 91 634T31 637H11V683H20Q29 680 148 680Q273 680 294 683H305V637H287Q239 636 236 621Q236 619 321 475L407 332L483 460Q502 492 527 534Q563 594 563 604Q563 632 517 637H508V683H517H525Q533 683 545 683T571 682T600 681T626 681Q695 681 731 683H738V637H723Q640 633 613 588Q612 587 517 427L425 273V169V95Q425 66 428 59T444 49Q459 46 506 46H528V0H518Z" transform="translate(4314,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(10790,0) translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo data-mjx-texclass="ORD" stretchy="false">|</mo><mrow data-mjx-texclass="ORD"><mtext>targetHipY</mtext></mrow><mrow data-mjx-texclass="ORD"><mo>/</mo></mrow><mrow data-mjx-texclass="ORD"><mtext>sourceHipY</mtext></mrow><mo data-mjx-texclass="ORD" stretchy="false">|</mo></math></mjx-assistive-mml></mjx-container>를 씁니다. 다리 대 몸통 비율이 두 릭 사이에서 다르기 때문입니다. 두 축에 하나의 비율을 쓰면 등반은 오버슈트하고 회복은 바닥 아래로 가라앉습니다. UAL 변위도 골반이 아니라 <code>root</code> 본에 살기 때문에, 넉백, 등반, 이동 클립 전반에서 움직임을 보존하려면 둘 다 하나의 엉덩이 위치 트랙으로 더해야 합니다.</p>
<p><strong>오프라인 궤적 일치 테스트.</strong> 헤드리스 스크립트가 소스 스켈레톤을 60Hz로 샘플링하고, 리타기팅 파이프라인을 돌리고, 본별 월드 변환을 소스와 비교합니다. 일정한 프레임별 오프셋은 무해한 바인드 델타이고, 프레임마다 달라지는 드리프트는 진짜 오류입니다. 그래서 테스트는 변경이 트랙을 떨어뜨리거나 왜곡할 때 발동되는 회귀 검사가 됩니다. 팩별 GLB 격리(새로 로드하고, 다음 것 전에 해제)는 전체 스윕에 걸친 캐시 경합을 피합니다.</p>
<p><strong>CDN glTF 그래프를 위한 LoadingManager.setURLModifier.</strong> CDN이 glTF를 상대 URI 그래프로, 동반하는 include 맵(상대 경로에서 절대 URL로)과 함께 배포할 때, <code>setURLModifier</code>는 JSON을 다시 쓰지 않고도 로더가 요청하는 모든 의존성을 CDN을 통해 해석합니다. 이것은 멀티파일, 멀티해상도 배포를 한 번의 클릭 로드로 접어 넣습니다. 다음 로드 전에 이전 모델의 지오메트리, 머티리얼, 텍스처 맵을 해제하면 탐색 세션 동안 수백 MB의 GPU 메모리가 쌓이는 것을 막습니다.</p>
<p><strong>비파괴적 메시 단순화.</strong> 각 메시의 원본 지오메트리 복제본을 저장하고 단순화 비율마다 인덱스 버퍼만 다시 빌드하면 변경이 빠르게 유지되고 반복 단순화로 인한 누적 손상을 피합니다. <code>geometry.groups</code> 슬라이스별로 돌리고 그룹을 재구성하면 멀티 머티리얼 할당이 보존됩니다. 이것이 거리 기반 LOD에 어떻게 공급되는지는 <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">LOD와 meshoptimizer</a>를 보세요.</p>
<hr>
<p>29부 중 17부.
이전: <a href="/ko/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring.html">16부 - 계속 자라나는 세계를 위한 구조</a>
다음: <a href="/ko/blog/2026-05-02-open-world-browser-part-18-ai-scattering.html">18부 - AI가 배치한 듯한 스캐터 브러시</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AI 게임 엔진의 해부: 프롬프트 안에 실제로 들어 있는 것]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-04-30-anatomy-of-an-ai-game-engine</link>
            <guid>https://app.cinevva.com/ko/blog/2026-04-30-anatomy-of-an-ai-game-engine</guid>
            <pubDate>Thu, 30 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Cinevva는 텍스트 상자 하나처럼 보입니다. 그 뒤에는 오케스트레이터, 타입이 정의된 26개의 도구, 11개의 에셋 제공처, 에이전트가 직접 플레이할 수 있는 실시간 게임 iframe, 그리고 게임플레이 릴과 연결된 스토어프런트가 있습니다. 이 기계 전체를 하나씩 뜯어봅니다.]]></description>
            <content:encoded><![CDATA[<h1 id="ai-게임-엔진의-해부-프롬프트-안에-실제로-들어-있는-것" tabindex="-1">AI 게임 엔진의 해부: 프롬프트 안에 실제로 들어 있는 것 <a class="header-anchor" href="#ai-게임-엔진의-해부-프롬프트-안에-실제로-들어-있는-것" aria-label="Permalink to &quot;AI 게임 엔진의 해부: 프롬프트 안에 실제로 들어 있는 것&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Mariana Muntean</a>, Cinevva CEO</em></p>
<p>낯선 사람들이 Cinevva에 대해 가장 흔히 하는 말은 그냥 AI 래퍼라는 것입니다. 홈페이지에 들어와서 &quot;Describe your game&quot;이라고 적힌 입력 상자 하나를 보고는 제품을 다 이해했다고 결론 내립니다. 그들이 이해한 건 정문입니다. 제품은 그 문장을 입력할 때 보이지 않는 모든 것이고, 이번 주부터는 거기에 더해 플레이어들이 당신의 게임을 찾으러 걸어 들어오는 오픈 월드까지입니다.</p>
<p>그 입력 뒤에는 완전한 게임 엔진이 있습니다. 타입이 정의된 26개의 도구를 가진 오케스트레이터, 생성 모델 한 무리, 11개 제공처에 걸친 통합 에셋 검색, 에이전트가 읽고 쓸 수 있는 실시간 게임 iframe, 그리고 같은 에이전트가 완성된 당신의 게임을 넘겨볼 수 있는 게임플레이 릴로 출시해 주는 스토어프런트가 있죠. 이 중 별난 건 하나도 없습니다. 전부 배관 작업입니다. 흥미로운 일은 무엇을 무엇에 연결할지 정하는 것이었습니다.</p>
<p>이 글은 그 기계를 위에서 아래로 훑습니다. 기술 투자자에게 들려주는 설명이자, 기여를 고민하는 개발자에게 들려주는 설명이기도 합니다. 둘 다 같은 답을 원합니다.</p>
<h2 id="_1-프롬프트는-표면이지-시스템이-아니다" tabindex="-1">1. 프롬프트는 표면이지 시스템이 아니다 <a class="header-anchor" href="#_1-프롬프트는-표면이지-시스템이-아니다" aria-label="Permalink to &quot;1. 프롬프트는 표면이지 시스템이 아니다&quot;"></a></h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-prompt.png" alt="The Cinevva prompt input on the homepage. A single text field reads 'Make a neon space shooter with asteroids, power-ups, and a synth soundtrack.' Below it are three suggestion chips and the Cinevva logo." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>첫 번째 설계 결정은 사용자가 직접 발을 들이기 전까지 모든 걸 숨기는 것이었습니다. 홈페이지의 일은 하나뿐입니다. 문장 하나를 프로젝트로 바꾸는 것이죠. 우리는 경험을 공개되는 쪽(프롬프트, 쇼케이스, 스토어프런트 피드)과 창작자 쪽(IDE, 에셋 도구, 게시 흐름)으로 나눴습니다. 그냥 놀고 싶은 사람들은 조종석을 들여다볼 필요가 없도록요.</p>
<p>그래서 플레이스홀더가 &quot;Make a snake game with neon graphics&quot;나 &quot;Top-down zombie shooter&quot; 같은 문구로 돌아가는 것입니다. 이건 튜토리얼이 아닙니다. 허가증입니다. 사용자는 &quot;이상한 아케이드 아이디어&quot;도 합법적인 입력이라는 걸 알게 됩니다.</p>
<p>제출하는 순간 세 가지 일이 일어납니다. 시스템이 안정적인 ID를 가진 새 게임 프로젝트를 만듭니다. 빈 파일 트리(<code>index.html</code>, <code>game.js</code>, <code>style.css</code>, <code>assets/</code>, <code>GDD.md</code>)를 심습니다. 그리고 당신의 문장을, 그 빈 파일들을 가리키는 프로젝트 컨텍스트 창과 함께 오케스트레이터로 보냅니다. 이 순간부터 당신은 손을 가진 에이전트와 대화하게 됩니다.</p>
<h2 id="_2-입력-뒤에는-완전한-브라우저-ide" tabindex="-1">2. 입력 뒤에는 완전한 브라우저 IDE <a class="header-anchor" href="#_2-입력-뒤에는-완전한-브라우저-ide" aria-label="Permalink to &quot;2. 입력 뒤에는 완전한 브라우저 IDE&quot;"></a></h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-ide.png" alt="The Cinevva creator IDE in dark mode. Three panels: a file tree on the left with GDD.md, index.html, game.js, style.css and an assets folder; a syntax-highlighted code editor in the middle showing a Three.js renderer setup; and a live game preview on the right showing a top-down neon space shooter with a SCORE and LIVES HUD." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>창작자 작업 공간은 전적으로 브라우저 안에서 돌아가는 3분할 IDE입니다. 왼쪽에 파일 트리, 가운데에 코드 편집기, 오른쪽에 실시간 게임 iframe, 아래쪽을 가로지르는 채팅 입력. 이 배치는 일부러 고른 것입니다. 이미 코드를 쓰는 사람은 한눈에 알아봅니다. 코드를 쓰지 않는 사람은 가운데 패널을 무시하고 채팅하고만 대화하면 됩니다.</p>
<p>파일 트리는 비유가 아닙니다. 모든 프로젝트는 실제로 HTML, JS, CSS, 생성된 이미지, GLB 모델, 오디오 파일로 이루어진 작은 정적 사이트이고, R2에서 Cloudflare Worker를 거쳐 바로 서빙됩니다. 빌드 단계가 없습니다. 이 점이 중요합니다. 에이전트가 당신이 실제로 출시할 파일들을 읽고 쓸 수 있다는 뜻이고, 같은 산출물이 iframe 안에서도, Capacitor로 감싼 휴대폰에서도, Tauri로 감싼 Steam에서도, Discord 안에서 Embedded Activity로도 돌아간다는 뜻입니다. 하나의 파일 시스템, 여섯 개의 배포 대상입니다.</p>
<p>우리가 생성하는 모든 게임은 <code>window</code>에 두 개의 함수를 노출해야 합니다. <code>getGameState()</code>는 실행 중인 게임을 설명하는 평범한 객체(플레이어 위치, 점수, 생명, 적, 타이머)를 반환합니다. <code>setGameState(patch)</code>는 부분 업데이트를 실시간 게임에 다시 적용합니다. 이 작은 API가 바로 에이전트가 다시 로드하지 않고도 실행 중인 게임을 들여다보고 수정하게 해 주는 계약입니다. 왜 그런지는 6절에서 다시 다룹니다.</p>
<h2 id="_3-오케스트레이터-진짜-엔진이-사는-곳" tabindex="-1">3. 오케스트레이터, 진짜 엔진이 사는 곳 <a class="header-anchor" href="#_3-오케스트레이터-진짜-엔진이-사는-곳" aria-label="Permalink to &quot;3. 오케스트레이터, 진짜 엔진이 사는 곳&quot;"></a></h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-orchestrator.png" alt="A diagram of the Cinevva orchestrator. A central node labeled 'Orchestrator (LLM)' is connected to eight tool nodes arranged around it: list_game_files, read_files, edit_files, write_files, generate_image (Flux), generate_skybox (Blockade), generate_music (ElevenLabs), and rig_model (Tripo). A dotted line connects the orchestrator to a 'Game iframe' node labeled 'screenshots + console.'" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>이걸 &quot;AI 래퍼&quot;라고 부르는 사람들이 놓치는 부분은, AI가 코드를 쓴다기보다는 작은 오케스트라를 지휘한다는 점입니다. 오케스트레이터는 프런티어 모델을 상대로 도는 tool-calling 루프로, 약 천 줄짜리 시스템 프롬프트와 26개 함수로 이루어진 타입 정의 도구 표면을 갖추고 있습니다. 그 도구 정의가 엔진입니다. 모델은 지휘자입니다.</p>
<p>26개의 도구는 다섯 가지 계열로 나뉩니다. 파일 시스템 도구(<code>list_game_files</code>, <code>read_files</code>, <code>search_game_file</code>, <code>edit_files</code>, <code>write_files</code>, <code>delete_files</code>, <code>rename_files</code>)는 에이전트가 당신의 게임을 다른 코드베이스처럼 다루게 해 줍니다. 프로젝트 도구(<code>create_new_game</code>, <code>list_games</code>, <code>open_game</code>, <code>ask_user</code>, <code>game_ready</code>)는 프로젝트의 수명 주기와 사람에게 다시 넘기는 단계를 처리합니다. 생성 도구(<code>generate_image</code>, <code>generate_skybox</code>, <code>generate_music</code>, <code>generate_sfx</code>, <code>rig_model</code>, <code>apply_animation</code>, <code>list_animations</code>, <code>list_skybox_styles</code>)는 다음 절에서 다룰 전용 모델들을 호출합니다. 지식 도구(<code>search_fonts</code>, <code>list_library_docs</code>, <code>search_library_docs</code>, <code>list_generations</code>)는 에이전트에게 환각이 아닌, 믿을 수 있고 색인된 사실의 출처를 줍니다. 그리고 런타임 도구(<code>read_console_logs</code>, <code>execute_js</code>)는 에이전트가 실시간 게임을 보고 만지게 해 줍니다.</p>
<p>전형적인 첫 턴은 대략 이렇습니다. 사용자가 &quot;Make a neon space shooter&quot;를 입력합니다. 모델은 설계를 설명하는 <code>GDD.md</code>와 함께 <code>write_files</code> 호출을 내보내고, 그다음 다시 <code>write_files</code>로 <code>index.html</code>, <code>game.js</code>, <code>style.css</code>를 내보냅니다. <code>prompt=&quot;synthwave space shooter, 120 BPM, driving bassline&quot;</code>으로 <code>generate_music</code>을 호출하면 ElevenLabs Music에 대한 작업이 시작되고 R2 안의 MP3 URL이 돌아옵니다. 별이 빛나는 배경을 위해 Blockade Labs의 model 3 스타일로 <code>generate_skybox</code>를 호출합니다. <code>game_ready(title, message)</code>를 호출해 iframe을 새 빌드로 전환하고, 마지막으로 <code>read_console_logs</code>를 호출해 게임이 오류 없이 부팅됐는지 확인합니다. 스택 트레이스가 보이면, 사용자가 무언가를 보고하기 전에 <code>edit_files</code>로 돌아가 고칩니다.</p>
<p>이 설계의 흥미로운 속성은, 시스템 프롬프트와 도구 스키마만이 제품에 특화된 유일한 부분이라는 점입니다. 모델을 바꿔도 전부 그대로 작동합니다. 우리는 지난 한 해 동안 표면을 바꾸지 않고 세 개의 프런티어 모델 사이를 옮겨 다녔습니다. 그 표면이 우리 것이기 때문입니다.</p>
<h2 id="_4-에셋-쪽-모델-팬아웃" tabindex="-1">4. 에셋 쪽: 모델 팬아웃 <a class="header-anchor" href="#_4-에셋-쪽-모델-팬아웃" aria-label="Permalink to &quot;4. 에셋 쪽: 모델 팬아웃&quot;"></a></h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-assets.png" alt="A three-panel asset generation dashboard. The left panel is a music generator with a prompt 'synthwave space shooter, 120 BPM, driving bassline,' a 60-second duration slider, and a Generate button, plus a playing waveform card titled 'Asteroid Drift Theme.' The middle panel is a skybox generator with the prompt 'deep space, distant nebula, two moons' and a grid of four 360 degree environment thumbnails. The right panel shows a rotating 3D model preview of a low-poly purple spaceship with a 'Rig + Walk' button and a status indicator that reads 'Rigging... 1m 42s left.'" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>에이전트는 이미지, 음악, 사운드, 3D를 직접 생성하지 않습니다. 전문가들을 호출합니다. Cinevva의 에셋 쪽은 분야별 최고 모델들로 팬아웃한 다음, 하나의 출력이 다음 것의 유효한 입력이 되도록 붙여 놓은 구조입니다.</p>
<p>이미지와 스프라이트의 경우 <code>generate_image</code>가 Flux Pro 1.1을 호출하는데, 너비와 높이는 항상 32의 배수이고, 프롬프트가 투명도를 요구하면 출력 형식이 PNG로 전환됩니다. 곡 전체는 에이전트가 스타일 프롬프트와 초 단위 길이로 ElevenLabs Music을 호출합니다. 일회성 효과음은 ElevenLabs SFX가 &quot;laser gun firing, sci-fi blaster&quot; 같은 텍스트에서 5초에서 15초 사이의 클립을 만들어 냅니다. 360도 환경은 <code>generate_skybox</code>가 약 90가지 스타일 중 하나로 Blockade Labs를 호출하며, 기본값은 model 3 Digital Painting입니다. 3D 캐릭터의 경우 <code>rig_model</code>이 GLB를 Tripo로 보내 이족, 사족, 육족, 팔족, 뱀형, 또는 수생 생물로 스키닝하고 리깅하며, 그다음 <code>apply_animation</code>이 15개 프리셋(idle, walk, run, jump, climb, dive, slash, shoot, hurt, fall, turn, 그리고 비이족용 행진 동작) 중 아무거나 재생합니다.</p>
<p>이것들은 하나하나가 동기 호출이 아니라 작업입니다. 짧으면 몇 초, 길면 몇 분이 걸립니다. 오케스트레이터는 이들을 띄우고 곧바로 <code>jobId</code>와 함께 반환하며, 별도의 채널이 에셋이 준비되면 결과를 대화로 다시 흘려보냅니다. 이게 느낌을 완전히 바꿉니다. 3D 모델이 백그라운드에서 리깅을 끝내는 동안 에이전트는 계속 게임 로직을 만들 수 있습니다. 사용자는 단일 임계 경로에서 기다릴 일이 없습니다.</p>
<p>산출물은 모두 같은 곳에 떨어집니다. <code>cdn.cinevva.com</code> 뒤의 R2이고, 평범한 URL로 주소를 지정할 수 있습니다. 이 말은 에이전트의 다음 <code>write_files</code> 호출이 그냥 <code>&lt;audio src=&quot;https://cdn.cinevva.com/audio/abc.mp3&quot;&gt;</code>를 임베드하면 게임이 바로 작동한다는 뜻입니다. SDK도, asset bundler도, manifest도 없습니다.</p>
<h2 id="_5-11개-제공처에-걸친-에셋-검색" tabindex="-1">5. 11개 제공처에 걸친 에셋 검색 <a class="header-anchor" href="#_5-11개-제공처에-걸친-에셋-검색" aria-label="Permalink to &quot;5. 11개 제공처에 걸친 에셋 검색&quot;"></a></h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-asset-search.png" alt="The Cinevva asset search page in dark mode. A search bar at the top contains the query 'asteroid rock' and a row of provider filter pills shows All, PolyHaven, Sketchfab, Kenney, Quaternius, AmbientCG, OpenGameArt, Freesound, Smithsonian, Synty, and Jamendo, with Sketchfab highlighted. Below is a four-column grid of asteroid model thumbnails, each card showing its provider badge, a CC0 or CC-BY license tag, and a 'Use in game' button. A small caption in the upper right corner shows a chat bubble that reads 'ChatGPT: one of the best free asset tools for game devs.'" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>생성은 특정한 무언가가 필요할 때 훌륭합니다. 검색은 이미 존재하는 무언가가 있을 때 더 빠릅니다. <a href="/ko/assets.html">에셋 라이브러리</a>는 무료 및 라이선스 제공처 11곳에 걸친 연합 검색으로, 하나의 순위가 매겨진 피드로 반환됩니다.</p>
<p>제공처 레지스트리는 worker 안에 있으며, 각 쿼리를 PolyHaven, Sketchfab, Freesound, Kenney, AmbientCG, Quaternius, OpenGameArt, Smithsonian 3D 컬렉션, TurboSquid, Synty, Jamendo에 병렬로 던집니다. 각 제공처는 공통 인터페이스(<code>search</code>, <code>getMetadata</code>, <code>isBrowsable</code>, <code>getSupportedTypes</code>)를 구현하므로, 새 제공처를 추가하는 일은 TypeScript 파일 하나입니다. 집계 계층은 제공처마다 다른 페이지네이션 방식을 커서 기반으로 처리하고, 라이선스를 중복 제거하며, 에셋 타입을 공통 분류 체계(model, texture, audio, hdri, sprite)로 정규화하고, 각 에셋에 라이선스를 태그로 붙입니다. 그래서 에이전트는 재배포할 수 없는 것을 절대 고르지 않습니다.</p>
<p>지난 분기에 ChatGPT가 이 도구를 게임 개발자를 위한 최고의 무료 에셋 검색 도구 중 하나로 추천했을 때, 우리는 그 추천을 직접 읽어 봤습니다. 핵심에 대해서는 옳았습니다. 요점은 우리가 단일 라이브러리 위에 검색창을 얹었다는 게 아닙니다. 요점은 &quot;stone wall texture&quot;를 검색하는 인디 개발자가 PolyHaven과 AmbientCG의 결과를 나란히 받고, 그 옆에 Kenney의 양식화된 버전과 Smithsonian의 사진 측량 옵션까지 받는다는 것입니다. 쿼리 한 번에, 일관된 라이선스 메타데이터와 함께요. 에이전트도 같은 엔드포인트를 호출해서 사람과 똑같은 방식으로 에셋을 고를 수 있습니다.</p>
<p>엔진에서 자주 과소평가되는 부분이 바로 여기입니다. 대부분의 게임 AI 데모는 모든 걸 처음부터 생성해서, 결국 균일하고 번들거리며 살짝 기이한 룩으로 끝납니다. Cinevva에서 흥미로운 게임들은 생성된 에셋을 Smithsonian의 진짜 CC0 사진 측량물, 그리고 Quaternius의 손으로 만든 로우폴리 나무와 섞습니다. 오케스트레이터는 그걸 한 턴에 해낼 수 있습니다.</p>
<h2 id="_6-에이전트가-게임을-플레이한다" tabindex="-1">6. 에이전트가 게임을 플레이한다 <a class="header-anchor" href="#_6-에이전트가-게임을-플레이한다" aria-label="Permalink to &quot;6. 에이전트가 게임을 플레이한다&quot;"></a></h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-debug.png" alt="A live debugging view. On the left, a running neon space shooter showing the player ship dodging asteroids with a SCORE of 4820 and 2 lives remaining. On the right, two stacked panels: an execute_js panel showing the call JSON.stringify(getGameState()) and a returned JSON object with player position, velocity, health, score, lives, and asteroid count, and a read_console_logs panel showing the most recent log lines including spawn asteroid, powerup picked, a texture load warning, and an FPS reading of 58." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>우리가 보여 줄 때 대부분의 엔지니어를 놀라게 하는 부분이 바로 이것입니다. 에이전트는 단지 코드를 파일에 쓰는 데 그치지 않습니다. 샌드박스 iframe에서 게임을 실행하고, 콘솔을 읽고, UI와 3D 장면을 층으로 나눠 스크린샷을 찍고, 실시간 런타임 안에서 JavaScript를 실행해 상태를 검사하거나 바꿉니다.</p>
<p><code>read_console_logs</code>는 iframe에서 나온 <code>console.log</code>, <code>console.warn</code>, <code>console.error</code> 그리고 잡히지 않은 예외의 마지막 50줄을 반환합니다. 모든 <code>game_ready</code> 호출 후에, 에이전트는 시스템 프롬프트에 의해 <code>read_console_logs</code>를 호출하고 사용자에게 다시 넘기기 전에 모든 오류를 고치도록 요구받습니다. 이 규칙 하나가 다른 도구들에 있는 &quot;AI는 다 됐다고 했는데 화면이 까맣다&quot; 류의 실패 대부분을 없앱니다.</p>
<p><code>execute_js</code>는 더 강력한 쪽입니다. 게임의 전역 스코프 안에서 임의의 JavaScript를 실행합니다. 모든 게임이 <code>getGameState</code>와 <code>setGameState</code>를 구현하도록 요구받기 때문에, 에이전트는 <code>JSON.stringify(getGameState())</code>를 실행해 실행 중인 게임의 전체 상태를 읽고, <code>setGameState({player: {x: 500, y: 100}})</code>로 플레이어를 순간 이동시키거나, <code>setGameState({lives: 99})</code>로 무적을 부여하거나, <code>setGameState({level: 3})</code>로 앞으로 건너뛸 수 있습니다. 더 낮은 수준도 찔러 볼 수 있는데, <code>scene.children.map(c =&gt; c.type)</code>로 Three.js 장면 그래프를 검사하거나 <code>document.querySelectorAll('canvas').length</code>로 렌더러가 마운트됐는지 확인하는 식입니다.</p>
<p>이게 왜 중요한지 보일 겁니다. 사용자가 &quot;2단계에서 플레이어가 벽에 끼인다&quot;고 말하면, 에이전트는 추측할 필요가 없습니다. 2단계를 열고, <code>getGameState()</code>를 실행하고, 충돌 데이터를 살펴보고, <code>execute_js</code> 패치를 돌려 수정안을 테스트한 다음, 그제야 수정안을 디스크에 씁니다. 당신이 디버그하는 방식 그대로 디버그합니다. 우리는 iframe을 대상이 아니라 동료로 다룹니다.</p>
<h2 id="_7-라이브러리-문서-지루한-사실의-출처" tabindex="-1">7. 라이브러리 문서, 지루한 사실의 출처 <a class="header-anchor" href="#_7-라이브러리-문서-지루한-사실의-출처" aria-label="Permalink to &quot;7. 라이브러리 문서, 지루한 사실의 출처&quot;"></a></h2>
<p>우리는 게임이 실제로 쓰는 라이브러리(Three.js, Tone.js, Cannon, 그리고 늘어나는 중)의 공식 문서를 구조화되고 검색 가능한 JSON 저장소로 색인합니다. 에이전트는 열린 웹에 손을 뻗기 전에 <code>search_library_docs(&quot;threejs&quot;, &quot;Mesh&quot;)</code>에 손을 뻗습니다. 더 빠르고, 버전이 관리되며, 두 마이너 릴리스 전에 이름이 바뀐 메서드를 절대 환각하지 않습니다.</p>
<p>이건 화려한 일이 아닙니다. 하지만 작동하는 코드를 만드는 AI와, 그럴듯해 보이지만 40번째 줄에서 죽는 코드를 만드는 AI의 차이입니다. Cinevva로 만든 게임의 눈에 보이는 품질 대부분이 이 한 가지 결정에서 나옵니다.</p>
<h2 id="_8-플레이-가능에서-발견-가능으로-릴과-스토어프런트" tabindex="-1">8. 플레이 가능에서 발견 가능으로: 릴과 스토어프런트 <a class="header-anchor" href="#_8-플레이-가능에서-발견-가능으로-릴과-스토어프런트" aria-label="Permalink to &quot;8. 플레이 가능에서 발견 가능으로: 릴과 스토어프런트&quot;"></a></h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-reels.png" alt="A short-form gameplay reels storefront. In the center, a phone-shaped card plays a portrait video of a neon space shooter mid-combat with social UI icons stacked on the right (a heart with 14k, a chat bubble with 3.2k, a share arrow with 1.8k, and a 'Play Now' button). The reel label at the bottom reads 'Asteroid Drift • by @indiedev • 3.1M views.' To the left, a small chat snippet titled 'From the creator's chat' shows the assistant message 'Game is live. Reel auto-published to your storefront.' To the right, a Storefront panel lists three trending games: Asteroid Drift, Roadhawk Runner, and Birb Clicker, each with a view count and a 'Trending' badge." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>아무도 플레이하지 않는 게임은 개인 취미입니다. 인디 개발에서 풀리지 않은 가장 어려운 문제는 이제 게임을 만드는 게 아닙니다. 배포입니다. 그래서 엔진은 &quot;플레이 가능&quot;에서 멈추지 않습니다. &quot;플레이어 앞에 있음&quot;에서 멈춥니다.</p>
<p>Cinevva의 모든 프로젝트는 <code>play.cinevva.com/{game-id}</code> 같은 안정적인 공유 URL을 가지며, 이 URL은 게임의 최신 빌드를 전체 페이지 iframe으로 열고 좋아요와 공유를 위한 작은 오버레이를 띄웁니다. 에이전트가 <code>game_ready</code>를 호출하면, IDE 안의 미리보기만 전환하는 게 아닙니다. 15초짜리 게임플레이 릴을 <a href="/ko/play.html">Cinevva 스토어프런트</a>에 게시하겠다고 제안하기도 합니다. 릴은 게임이 플레이되는 실제 녹화로, iframe에서 직접 캡처됩니다(우리는 에이전트가 게임 런타임에 주입하는 작은 레코더 스크립트를 함께 보냅니다). 그래서 시청자가 스크롤로 지나치는 것은 마케팅 편집물이 아니라 진짜 게임플레이입니다.</p>
<p>이게 개발자가 사는 루프를 바꿉니다. 옛 루프는 코드 작성, 빌드, 패키징, 업로드, Steam 페이지 작성, 알고리즘과 싸우기, 위시리스트 카운터 지켜보기였습니다. 새 루프는 문장 하나 입력, 에이전트가 만드는 걸 지켜보기, 게시 누르기, 당신의 게임이 다른 모든 것과 함께 같은 스와이프 피드에 나타나는 걸 지켜보기입니다. 발견은 창작이 일어나는 같은 제품 안에서, 같은 URL에서, 같은 로그인으로 일어납니다.</p>
<p>개발자 커뮤니티 독자라면 이 부분을 살펴보세요. 배포는 언제나 게임 엔진이 함께 출시하지 않는 해자였습니다. Unity는 에디터를 출시하고, 당신은 게임을 Steam에 출시합니다. Unreal은 에디터를 출시하고, 당신은 Epic Store에 출시합니다. Cinevva는 양쪽 다 출시합니다. 엔진과 스토어프런트는 게임을 만든 바로 그 오케스트레이터를 통해 서로 대화합니다.</p>
<h2 id="_9-top-performers-발견의-플라이휠" tabindex="-1">9. Top Performers: 발견의 플라이휠 <a class="header-anchor" href="#_9-top-performers-발견의-플라이휠" aria-label="Permalink to &quot;9. Top Performers: 발견의 플라이휠&quot;"></a></h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-charts.png" alt="The Cinevva Top Performers chart. Three tabs at the top read Trending, Recent, and Top, with Top selected. Below, a podium row of three featured games: number one The Breaker Belt with 42.1k plays, number two Roadhawk Runner with 27.7k plays, and number three Asteroid Drift with 37.1k plays. Below the podium, a denser grid of six smaller game cards including Pixel Platformer, Zombie Shooter, Fruit Ninja Clone, Tower Defense, Card Battler, and Zombie Builder, each with thumbnails, creator handles, and play counts." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>릴 피드는 플라이휠의 절반입니다. <a href="/ko/charts.html">Top Performers 차트</a>가 나머지 절반입니다. 이 차트는 게임을 trending, recent, all-time top으로 순위 매기는데, 가중치는 원시 클릭이 아니라 완주율(플레이어가 한 세션을 끝냈는가)로 둡니다. 완주율은 설치 수보다 조작하기 어렵습니다. 60초 동안 주의를 붙드는 게임이 열었다 닫히는 게임을 이깁니다.</p>
<p>모든 신호는 오케스트레이터의 다음 턴으로 되먹임됩니다. 에이전트가 &quot;파워업을 추가하자&quot;고 말할 때, 고정된 패턴 라이브러리에서 끌어오는 게 아닙니다. 이번 달 Cinevva에서 어떤 메커니즘이 실제로 플레이어를 붙잡는지 지켜본 모델에서 끌어옵니다. 플라이휠은 페이지 하단의 차트가 아닙니다. 엔진 전체의 학습 신호입니다.</p>
<p>투자자라면, 이것이 데이터 해자입니다. 우리는 단지 생성된 게임만 가진 게 아닙니다. 실제 세션 수준 참여 지표가 붙은 생성 게임을 가졌고, 그것을 만들어 낸 프롬프트에 붙어 있고, 에이전트가 내린 에셋 선택에 붙어 있고, 그걸 좋아한 플레이어에게 붙어 있습니다. 한 바퀴를 돌 때마다 다음 바퀴가 더 단단해집니다.</p>
<h2 id="_10-엔진이-게임이-되다" tabindex="-1">10. 엔진이 게임이 되다 <a class="header-anchor" href="#_10-엔진이-게임이-되다" aria-label="Permalink to &quot;10. 엔진이 게임이 되다&quot;"></a></h2>
<p>여기가 제가 몇 달째 소셜에서 흘려 온 부분입니다. 1절부터 9절까지는 게임을 만드는 시스템을 설명합니다. 직접 보기 전까지 설명하기 더 어려운 것은, 그 시스템 자체가 하나의 장소가 될 때 무슨 일이 일어나는가입니다.</p>
<p>게임을 만드는 일은, 우리가 지금까지 출시한 모든 것을 가지고도 고된 작업입니다. 한 번도 게임을 만들어 본 적이 없다면, 당신은 갑자기 줄거리, 캐릭터, 세계, 메커니즘, 누가 무엇을 언제 하는지, 빛이 어떻게 움직이는지, 특수 효과가 어떻게 층층이 쌓이는지, 음악, 음향 효과, 카메라 움직임을 책임지게 됩니다. 양이 많습니다. 게다가 그 모든 것 위에, 결과물이 누군가 다른 사람의 도구가 뱉어낸 템플릿이 아니라 당신 것처럼 느껴지길 원하죠. 프롬프트와 오케스트레이터는 기계적인 작업 대부분을 당신 대신 해 줍니다. 그것들이 혼자서 못 하는 건, 완성된 당신의 것에 다른 사람들이 지켜보는 무대를 마련해 주는 일입니다.</p>
<p>그래서 우리는 무대를 지었습니다. 올해 대부분 동안 <a href="/ko/about.html">Oleg</a>와 엔진 팀은 오픈 월드를 브라우저에 넣는 일에 대한 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">14부작 시리즈</a>를 발행해 왔습니다. 실시간으로 깎을 수 있는 조각된 지형. 경사와 고도에 따라 스스로를 바위나 풀로 칠하는 바이옴. 컴퓨트로 생성된 지형 위에서 바람에 휘는 8만 개의 풀잎. 하이트맵 지형과 볼류메트릭 지형을 같은 발걸음으로 걷고, 질주하고, 점프하고, 활공하는 캐릭터. 그 무엇도 그 자체를 위한 기술 데모가 아니었습니다. 이것을 위한 기반이었습니다.</p>
<p>오늘 오픈 월드가 초기 형태로 라이브 상태입니다. 아바타를 입고 걸어 들어갑니다. 당신이 게시한 게임들이 당신 주변에 방문 가능한 공간으로 나타납니다. <a href="/ko/play.html">스토어프런트 릴</a>과 <a href="/ko/charts.html">Top Performers 차트</a>가 지금 그것들을 보여 주는 방식과 같지만, 이번엔 스와이프가 아니라 두 발로 도착합니다. 세계를 떠나지 않고도 낯선 사람의 게임 안으로 들어갈 수 있습니다. 방금 플레이한 것을 만든 사람 옆에 서서 다음에 무엇을 더하면 좋을지 말해 줄 수 있습니다. 방금 만난 사람과 함께 지형 한 조각을 깎아 새 프로젝트의 씨앗으로 만들 수 있습니다. 발견은 더 이상 피드가 아닙니다. 산책이 됩니다.</p>
<p>우리 엔진은 언제나 기술적 의미에서 게임 엔진이었습니다. 오늘은 문자 그대로의 의미에서도 게임 엔진이 됩니다. 당신의 게임을 만드는 그것이 이제 그 자체로 하나의 게임이고, 3절의 같은 오케스트레이터, 4절의 같은 에셋 레일, 6절의 같은 <code>getGameState</code> 계약, 8절의 같은 릴, 9절의 같은 차트가 모두 당신의 플레이어들이 걸어 다니는 하나의 장소로 합쳐집니다. 만드는 것과 노는 것 사이의 경계는 언제나 인위적이었습니다. 이제 그 경계는 사라졌습니다.</p>
<h2 id="우리가-잘했다고-생각하는-것" tabindex="-1">우리가 잘했다고 생각하는 것 <a class="header-anchor" href="#우리가-잘했다고-생각하는-것" aria-label="Permalink to &quot;우리가 잘했다고 생각하는 것&quot;"></a></h2>
<p>첫 번째로 잘한 것은 프롬프트를 제품이 아니라 UI 어포던스로 다룬 것입니다. 제품은 오케스트레이터, 도구 표면, 에셋 레일, 그리고 스토어프런트입니다. 프롬프트는 사용자를 시스템 안으로 들이는 가장 값싼 방법입니다.</p>
<p>두 번째는 빌드 단계가 없는 평평한 브라우저 네이티브 파일 시스템을 고집한 것입니다. Cinevva 게임이 하나의 사실 출처에서 모바일, 데스크톱, Steam, Discord로 출시되는 이유가 이것입니다. 에이전트가 자기가 쓴 것을 읽을 수 있는 이유도 이것입니다.</p>
<p>세 번째는 모든 생성 게임이 <code>getGameState</code>와 <code>setGameState</code>를 구현한다는 계약입니다. 시스템 프롬프트의 그 한 줄이 에이전트를 코드 생성기가 아니라 협력자처럼 느껴지게 만드는 것입니다. 에이전트는 플레이할 수 있고, 플레이할 수 있는 시스템은 디버그할 수 있습니다.</p>
<p>네 번째는 스토어프런트를 엔진과 같은 루프에 연결한 것입니다. 우리는 원시 모델 품질로는 이기지 않을 겁니다. 오픈 웨이트 생성기보다 두 달 앞선다는 데에는 지킬 만한 우위가 없습니다. 우리는 당신의 게임을 만드는 바로 그 에이전트가 그것을 게시하고, 측정하고, 낯선 사람들이 어떻게 플레이했는지에서 배울 때 이깁니다.</p>
<p>기계 전체가 돌아가는 모습을 보고 싶다면, 홈페이지 프롬프트가 여전히 정문입니다. 문장 하나를 입력하세요. 그 뒤에서 무슨 일이 일어나는지 지켜보세요. 그런 다음 여기로 돌아와서 엔진의 어느 부분을 다음에 써 주면 좋을지 알려 주세요.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 16부: 계속 자라나는 세계를 위한 구조]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring</link>
            <guid>https://app.cinevva.com/ko/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring</guid>
            <pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 33은 6,285줄짜리 모놀리스를 모듈로 쪼개면서 숨어 있던 초기화 순서 버그 세 개를 드러냈습니다. Spike 34는 그 구조를 활용해 무엇도 부풀리지 않고 100개가 넘는 배치형 소품을 추가했습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-16부-계속-자라나는-세계를-위한-구조" tabindex="-1">브라우저에서 오픈 월드 만들기, 16부: 계속 자라나는 세계를 위한 구조 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-16부-계속-자라나는-세계를-위한-구조" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 16부: 계속 자라나는 세계를 위한 구조&quot;"></a></h1>
<p><em>글: <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p><a href="/ko/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting.html">13부</a> 이후 모든 spike는 같은 방식을 따랐습니다. 이전 모놀리스를 복사하고, 기능 하나를 더한다. <a href="/ko/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water.html">spike 32</a>가 끝날 무렵 그 모놀리스는 단일 <code>&lt;script type=&quot;module&quot;&gt;</code> 안에 들어 있는 6,285줄짜리 <code>index.html</code>이었습니다. 코드 검색은 시끄러웠고, 기능을 어디에 추가할지 찾는 게 쓰는 것보다 오래 걸렸으며, 어떤 아키텍처 변경이든 머릿속으로 diff하기엔 너무 큰 파일을 건드려야 했습니다. 다음 기능을 추가하기 전에 우리는 구조라는 빚을 갚았습니다.</p>
<h2 id="동작-변화-없이-모놀리스-쪼개기" tabindex="-1">동작 변화 없이 모놀리스 쪼개기 <a class="header-anchor" href="#동작-변화-없이-모놀리스-쪼개기" aria-label="Permalink to &quot;동작 변화 없이 모놀리스 쪼개기&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/33-code-structure/" title="Spike 33 Code Structure Refactor" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/33-code-structure/" target="_blank">Spike 33을 새 탭에서 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=33-code-structure">소스 보기</a></p>
<p>제약은 엄격했습니다. 모든 분리는 재설계가 아니라 순수한 리팩터링이어야 했습니다. 모놀리스는 19개의 <code>.mjs</code> 파일과 151줄짜리 호스트 셸이 되었습니다. scene, water, grass, character, physics, multiplayer, UI를 위한 최상위 모듈들, 모든 WGSL 소스 문자열을 GPU 진실의 단일 출처로 쥐고 있는 <code>wgsl.mjs</code>, 그리고 heightmap, SDF, chunk, GPU buffer 래퍼, 브러시, LOD, 영속화를 담은 <code>terrain/</code> 하위 트리로 나뉘었습니다. 전체 코드는 6,555줄이 나왔는데, 기본적으로 모놀리스에 import 보일러플레이트를 더한 것입니다. 분량의 순변화는 없었지만, 탐색 편의성의 변화는 컸습니다.</p>
<p>그런데 페이지가 검은 화면으로 로드됐습니다. 에러 메시지 두 개, 서로 무관한 근본 원인 두 개. 첫 번째는 0바이트 buffer 바인딩에 대한 WebGPU의 불평이었습니다. 모놀리스에서는 SDF 브러시 buffer가 첫 marching-cubes chunk가 나타날 때 지연 할당됐고, bind-group 팩토리는 마침 그 뒤, buffer가 존재한 다음에 돌았습니다. <code>terrain/gpu.mjs</code>를 <code>terrain/brush.mjs</code>에서 분리하면서 모듈 평가 순서가 바뀌었고, 이제 팩토리가 먼저 돌아 <code>null</code> 자리표시자를 바인딩하려 했습니다. 해법은 bind-group 생성을 첫 dispatch까지 미루는 <code>getOrCreateBindGroup(chunk)</code> 헬퍼였습니다. &quot;모든 것을 미리 만들어 두는&quot; 패턴은 모놀리스의 단일 초기화 경로가 남긴 흔적이었습니다.</p>
<p>두 번째 메시지는 무섭게 생긴 FBX 스켈레톤 경고였는데, 알고 보니 헛다리였습니다. spike 25부터 계속 찍혀 왔고 무해했습니다. 캐릭터가 사라진 건 단지 첫 번째 버그가 연쇄됐기 때문입니다. 모든 compute dispatch가 예외를 던졌고, heightmap이 끝내 쓰이지 않았으며, 높이 샘플이 0을 반환했고, 캐릭터가 원점에 스폰돼 세계를 뚫고 떨어졌습니다. buffer를 고치면 캐릭터는 경고를 다 달고도 멀쩡히 애니메이션됩니다.</p>
<p>이게 리팩터링의 진짜 교훈입니다. 모놀리스는 &quot;X는 Y가 만들어지기 전에 존재해야 한다&quot;는 모든 관계를 위에서 아래로 흐르는 스크립트 순서 안에 숨겼습니다. 모듈화가 그 순서를 뒤섞으면서 잠복해 있던 순서 버그 세 개가 더 드러났습니다. 풀이 heightmap 업로드 전에 흩뿌려지는 문제, 물 평면이 환경 맵 디코딩이 끝나기 전에 추가되는 문제, 영속화 로드가 첫 프레임 이후에야 완료되는 문제였습니다. 셋 다 한 줄 수정이었고, 분리하지 않았다면 하나도 잡히지 않았을 것입니다.</p>
<h2 id="무엇도-키우지-않고-소품-백-개-추가하기" tabindex="-1">무엇도 키우지 않고 소품 백 개 추가하기 <a class="header-anchor" href="#무엇도-키우지-않고-소품-백-개-추가하기" aria-label="Permalink to &quot;무엇도 키우지 않고 소품 백 개 추가하기&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/34-world-authoring/" title="Spike 34 World Authoring" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/34-world-authoring/" target="_blank">Spike 34를 새 탭에서 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=34-world-authoring">소스 보기</a></p>
<p>Spike 34는 그 구조가 값을 했는지 확인하는 시험이었습니다. 목표는 CC0 모델 팩에서 나무, 바위, 덤불, 버섯, 길을 배치하는 1인칭 팔레트였고, 지형 인식 정렬, 영속화, 멀티플레이어 동기화, 물리 콜라이더를 모두 조작을 벗어나지 않고 처리하는 것이었습니다. 새 코드는 한 줄도 빠짐없이 <code>src/props/</code> 아래 다섯 개의 새 파일에 들어갔고, 기존 모듈은 어느 것도 연결용 코드 열 줄을 넘게 늘지 않았습니다.</p>
<p>에셋 작업은 기록해 둘 만한 우회로를 거쳤습니다. 이런 일은 하루를 통째로 잡아먹기 때문입니다. 우리는 Quaternius의 Ultimate Nature 팩으로 시작했는데, 텍스처가 내장되지 않은 FBX 라이브러리였습니다. FBX 머티리얼은 map 없는 <code>MeshPhong</code>으로 들어와서, 머티리얼 이름을 PNG에 매핑하는 표를 손으로 연결하고, Phong을 Standard로 변환하고, 색 공간을 일일이 설정했습니다. 머티리얼의 약 30%는 맞는 PNG가 없었고, 비슷한 나무들 사이에서 이름이 모호한 것도 몇 개 있었습니다. 두 번째 FBX 팩도 같은 구멍이 있었습니다. 해법은 매핑 표를 더 늘리는 게 아니라 더 잘 만들어진 팩이었습니다. Quaternius의 Stylized Nature MegaKit은 내장 PBR 머티리얼과 베이크된 노멀을 갖춘 완전한 glTF 116개를 제공합니다. <code>FBXLoader</code>를 <code>GLTFLoader</code>로 바꾸자 cm-to-meters 스케일링, 텍스처 표, Phong 변환이 사라졌고 <code>library.mjs</code>가 약 80줄 줄었습니다. 결론은 이렇습니다. PBR이 담긴 glTF는 그것을 제공하는 CC0 팩에 맞는 파이프라인이고, 수동 텍스처 매핑이 붙은 FBX는 코드는 두 배에 품질은 절반이었습니다.</p>
<p>glTF 경로에는 까다로운 부분 몇 가지가 따라왔습니다. 팔레트는 썸네일 116개를 렌더링하는데, WebGPU의 <code>canvas.toDataURL()</code>은 <code>GPUCanvasContext</code> 표면에 대해 빈 값을 반환합니다. 그래서 썸네일은 <code>RenderTarget</code>에 렌더링한 뒤 <code>readRenderTargetPixelsAsync</code>로 다시 읽어 와 2D canvas에 blit하면서 WebGPU의 256바이트 행 정렬을 챙깁니다. 고스트 프리뷰는 각 머티리얼을 복제해 초록색으로 물들이는데, <code>material</code>이 배열인 mesh에서 깨졌고 <code>Array.isArray</code> 분기로 고쳤습니다. 그리고 약 200 MB로 들어온 16비트 노멀 맵은 일회성 <code>mogrify -depth 8</code>로 약 32 MB까지 줄였는데, 어차피 브라우저가 업로드 시 다운샘플링하므로 시각적으로는 똑같습니다.</p>
<h2 id="렌더링되는-지오메트리가-gpu에만-존재할-때" tabindex="-1">렌더링되는 지오메트리가 GPU에만 존재할 때 <a class="header-anchor" href="#렌더링되는-지오메트리가-gpu에만-존재할-때" aria-label="Permalink to &quot;렌더링되는 지오메트리가 GPU에만 존재할 때&quot;"></a></h2>
<p>가장 배울 게 많았던 버그는 커서가 움직일 때 고스트 프리뷰가 1~2미터 단위로 툭툭 끊겨 붙는 것이었습니다. 지형 mesh는 정점 위치를 <code>StorageBufferAttribute</code>에 저장합니다. compute 파이프라인이 GPU에서 직접 그것들을 쓰기 때문에 three.js의 CPU <code>Raycaster</code>는 그것들을 볼 수 없고 아무것도 반환하지 않습니다. 폴백은 해석적 heightmap에 대한 거친 1.5 m 레이 마치였고, 그 고정 간격이 바로 사용자가 본 격자였습니다. 우리는 그것을 적응형 마치로 바꿨습니다. 표면 위로 높이 떨어져 있을 땐 간격 2.5 m, 표면 5 m 이내로 들어오면 0.4 m로 줄이고, 그다음 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.869ex;" xmlns="http://www.w3.org/2000/svg" width="16.358ex" height="2.566ex" role="img" focusable="false" viewBox="0 -750 7230.4 1134.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(389,0)"><g data-mml-node="mtext"><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(392,0)" style="stroke-width: 3;"/><path data-c="79" d="M69 -66Q91 -66 104 -80T118 -116Q118 -134 109 -145T91 -160Q84 -163 97 -166Q104 -168 111 -168Q131 -168 148 -159T175 -138T197 -106T213 -75T225 -43L242 0L170 183Q150 233 125 297Q101 358 96 368T80 381Q79 382 78 382Q66 385 34 385H19V431H26L46 430Q65 430 88 429T122 428Q129 428 142 428T171 429T200 430T224 430L233 431H241V385H232Q183 385 185 366L286 112Q286 113 332 227L376 341V350Q376 365 366 373T348 383T334 385H331V431H337H344Q351 431 361 431T382 430T405 429T422 429Q477 429 503 431H508V385H497Q441 380 422 345Q420 343 378 235T289 9T227 -131Q180 -204 113 -204Q69 -204 44 -177T19 -116Q19 -89 35 -78T69 -66Z" transform="translate(892,0)" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1453,-239.4) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2460.7,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3460.9,0)"><g data-mml-node="mtext"><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(389,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1225,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(1617,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(2117,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2395,0)" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2984,-150) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(6841.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><msub><mtext>ray</mtext><mi>y</mi></msub><mo>−</mo><msub><mtext>terrain</mtext><mi>y</mi></msub><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>의 부호가 바뀌면 14번 이분합니다. 이렇게 하면 한 번의 캐스트당 대략 넓은 스텝 30번에 이분 14번으로 1밀리미터 미만 정밀도에 도달합니다. 렌더링되는 지오메트리가 GPU에만 살 때는 raycaster와 싸우지 말고, 해석적 출처에 대고 마치하세요.</p>
<h2 id="편집을-거쳐도-정직하게-남는-콜라이더" tabindex="-1">편집을 거쳐도 정직하게 남는 콜라이더 <a class="header-anchor" href="#편집을-거쳐도-정직하게-남는-콜라이더" aria-label="Permalink to &quot;편집을 거쳐도 정직하게 남는 콜라이더&quot;"></a></h2>
<p>우리는 볼록 껍질이나 mesh 콜라이더 대신 프리미티브 프록시를 골랐습니다. Quaternius 소품은 둥글둥글하고 로우폴리이며 의미 있는 오목부가 없어서, 껍질을 쓰면 같은 플레이 경험을 위해 코드는 약 50배, 런타임 비용은 약 10배가 듭니다. 각 소품은 바운딩 박스에서 유도한 하나의 형태로 줄어듭니다. 나무와 선인장은 수직 캡슐, 바위는 구, 통나무는 긴 축을 따라 놓인 수평 캡슐, 장식용 덤불과 꽃은 아무것도 없음입니다. 바위와 통나무는 걸어다닐 수 있고(수직으로만 밀어내서 위에 올라설 수 있음), 나무와 선인장은 막힙니다(완전 3D 밀어내기라 줄기를 타고 오를 수 없음). 8 m 공간 해시가 프레임당 테스트를 플레이어의 3×3 이웃으로, 보통 소품 0~6개로 제한합니다.</p>
<p>두 가지 설계 결정이 시스템을 일관되게 유지했습니다. 지형 정렬은 코드에 하드코딩된 카테고리 열거형이 아니라 매니페스트 플래그입니다. 그래서 고스트 프리뷰와 확정된 배치가 같은 <code>placement.alignToTerrain</code> 값을 읽고 서로 어긋날 수 없습니다. 그리고 이미 배치된 소품은 헬퍼 하나를 통해 지형 편집에 반응합니다. 브러시 스트로크(로컬이든 피어에서 재생된 것이든) 이후 <code>refreshPlacementsInRadius</code>가 영향받은 원판 안에 있는 모든 소품 아래의 지면을 다시 샘플링하고, 정렬을 다시 적용하고, 콜라이더 끝점을 다시 유도합니다. 나무 아래에 언덕을 깎으면 나무가 함께 솟아오릅니다. 영속화와 멀티플레이어는 spike 31의 패턴을 그대로 재사용해, <code>{uid, propId, x, y, z, rotY, scale}</code>의 평탄한 목록을 저장하고 배치, 제거, 미세 조정 이벤트를 BroadcastChannel로 미러링합니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>WebGPU에서의 ES 모듈 분해.</strong> 모놀리식 <code>&lt;script type=&quot;module&quot;&gt;</code>을 베어 경로 <code>.mjs</code> import로 쪼개는 건, 모듈을 정적 에셋으로 제공할 때 번들러가 필요 없고, three.js TSL도 모듈 경계를 넘나들며 잘 작동합니다. 숨은 비용은 초기화 순서입니다. 모놀리스는 &quot;X를 Y보다 먼저 만든다&quot;를 위에서 아래로 흐르는 스크립트 순서에 인코딩하지만, 모듈은 import 순서로 평가되어 GPU bind-group 팩토리를 그 buffer가 존재하기 전에 돌릴 수 있습니다. 수정 패턴은 지연 초기화(첫 사용 시 <code>getOrCreate...</code>)와 선언 순서에 기대는 대신 올바른 promise를 await하는 것입니다.</p>
<p><strong>내장 PBR이 담긴 glTF vs 수동 매핑이 붙은 FBX.</strong> glTF는 미터 단위로 들어오고, 자기 텍스처를 참조하며, <code>MeshStandardMaterial</code>을 곧바로 줍니다. 그래서 glTF로 만들어진 CC0 팩은 PBR 파이프라인에 바로 들어갑니다. 텍스처 바인딩 메타데이터가 없는 FBX 팩은 팩이 업데이트될 때마다 어긋나는, 손으로 유지하는 머티리얼 이름-PNG 표가 필요하고, 거기에 Phong-Standard 변환과 수동 색 공간 태깅까지 붙습니다. 식생 안전망은 <code>alphaTest</code>가 없는 <code>transparent</code> 머티리얼을 <code>alphaTest: 0.5</code> 컷아웃 카드로 승격시켜, 불투명 지오메트리 뒤에서 제대로 정렬되게 합니다.</p>
<p><strong>WebGPU 오프스크린 썸네일.</strong> <code>canvas.toDataURL()</code>은 <code>GPUCanvasContext</code> 기반 canvas에 대해 빈 값을 반환합니다. 프레젠테이션 표면에서 2D 컨텍스트로 돌아오는 경로가 없기 때문입니다. <code>RenderTarget</code>에 렌더링하고, <code>readRenderTargetPixelsAsync</code>로 픽셀을 읽고, 2D canvas에 blit하는 방식은, blit이 WebGPU의 256바이트 정렬 읽기 간격을 따르는 한 잘 작동합니다. 결과는 버전 번호가 붙은 키 아래 <code>localStorage</code>에 캐시되므로 팩이 바뀌면 오래된 렌더가 무효화됩니다.</p>
<p><strong>해석적 heightmap에 대한 적응형 레이 마치.</strong> 지형 정점이 GPU <code>StorageBufferAttribute</code>에 살 때 CPU raycaster는 그것들을 볼 수 없습니다. 해석적 높이 함수를 따라, 표면에서 멀 땐 큰 간격으로, 가까울 땐 작은 간격으로 마치하고, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.869ex;" xmlns="http://www.w3.org/2000/svg" width="16.358ex" height="2.566ex" role="img" focusable="false" viewBox="0 -750 7230.4 1134.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(389,0)"><g data-mml-node="mtext"><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(392,0)" style="stroke-width: 3;"/><path data-c="79" d="M69 -66Q91 -66 104 -80T118 -116Q118 -134 109 -145T91 -160Q84 -163 97 -166Q104 -168 111 -168Q131 -168 148 -159T175 -138T197 -106T213 -75T225 -43L242 0L170 183Q150 233 125 297Q101 358 96 368T80 381Q79 382 78 382Q66 385 34 385H19V431H26L46 430Q65 430 88 429T122 428Q129 428 142 428T171 429T200 430T224 430L233 431H241V385H232Q183 385 185 366L286 112Q286 113 332 227L376 341V350Q376 365 366 373T348 383T334 385H331V431H337H344Q351 431 361 431T382 430T405 429T422 429Q477 429 503 431H508V385H497Q441 380 422 345Q420 343 378 235T289 9T227 -131Q180 -204 113 -204Q69 -204 44 -177T19 -116Q19 -89 35 -78T69 -66Z" transform="translate(892,0)" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1453,-239.4) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2460.7,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3460.9,0)"><g data-mml-node="mtext"><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(389,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1225,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(1617,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(2117,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2395,0)" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2984,-150) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(6841.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><msub><mtext>ray</mtext><mi>y</mi></msub><mo>−</mo><msub><mtext>terrain</mtext><mi>y</mi></msub><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>의 부호 전환에서 이진 탐색으로 정밀화하면, 정해진 샘플 수 안에서 1밀리미터 미만의 커서 정밀도를 얻습니다. 같은 프리미티브가 브러시 커서와 소품 고스트를 모두 구동합니다.</p>
<p><strong>공간 해시를 곁들인 프리미티브 캡슐 콜라이더.</strong> 각 소품은 바운딩 박스에서 카테고리 기반의 캡슐이나 구로 줄어들어 <code>{kind, walkable, radius, p1, p2}</code>로 기록되고, 겹치는 8 m 해시 버킷마다 등록됩니다. 프레임당 플레이어는 자신의 3×3 버킷 이웃에 있는 소품만 테스트하고, 각각 캡슐 대 캡슐 해소를 한 번씩 합니다. 걸어다닐 수 있는 프록시(바위, 통나무)는 수직으로만 밀어내고, 막는 프록시(나무)는 완전 3D 밀어내기를 받습니다. 이것이 기반으로 삼는 캡슐 수식은 <a href="/ko/guides/landscape-generation-browser.html#physics-on-sdf-terrain">SDF 지형 충돌</a>을 참고하세요.</p>
<hr>
<p>29부 중 16부.
이전: <a href="/ko/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water.html">15부 - 베이스라인을 교체한 다음, 동기화하기</a>
다음: <a href="/ko/blog/2026-05-01-open-world-browser-part-17-animations-and-search.html">17부 - 리타기팅이 필요 없던 애니메이션, 그리고 실시간 에셋 검색</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2022년에 게임에 대해 걸었던 네 가지 베팅. 지금 어떻게 늙어가고 있나.]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-04-24-2022-predictions-aging-well</link>
            <guid>https://app.cinevva.com/ko/blog/2026-04-24-2022-predictions-aging-well</guid>
            <pubDate>Fri, 24 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[2022년 한 인터뷰에서 나는 WebGL 게임 엔진, 대화용 GPT-3, 실시간 창작 협업, 그리고 인디의 부상에 베팅했다. 4년이 지난 지금, 각 베팅이 어디에 도착했는지 정리한다.]]></description>
            <content:encoded><![CDATA[<h1 id="_2022년에-게임에-대해-걸었던-네-가지-베팅-지금-어떻게-늙어가고-있나" tabindex="-1">2022년에 게임에 대해 걸었던 네 가지 베팅. 지금 어떻게 늙어가고 있나. <a class="header-anchor" href="#_2022년에-게임에-대해-걸었던-네-가지-베팅-지금-어떻게-늙어가고-있나" aria-label="Permalink to &quot;2022년에 게임에 대해 걸었던 네 가지 베팅. 지금 어떻게 늙어가고 있나.&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Mariana Muntean</a>, Cinevva CEO</em></p>
<img src="/img/blog/tech-done-different.jpg" alt="Tech Done Different podcast interview, May 2022" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>2022년 5월, 나는 Ted Harrington의 팟캐스트 <em>Tech Done Different</em>과 인터뷰를 했다. 당시 정리된 글은 <a href="https://medium.com/@vio-202020/interview-with-tech-done-different-3b9bf74d99c2" target="_blank" rel="noreferrer">지금도 Medium에 살아 있다</a>. 그때 나는 Cinevva를 한 2년쯤 운영하고 있었다. 다섯 명, 20만 달러 투자 유치, 벽에 걸린 Mozilla Builders 상, 그리고 게임 개발이 어디로 가고 있는지에 대한 잔뜩 쌓인 의견.</p>
<p>그 의견들은 2022년에 대부분 유행하던 생각이 아니었다. Web3가 시끄러웠고, AAA 스튜디오가 대화를 장악했고, GPT-3는 연구용 장난감이었고, WebGL은 취미로 잼 게임을 만드는 사람들이 쓰는 거였다. &quot;어떤 창작자든 게임 개발자가 될 것이다&quot;라고 소리 내어 말하면 정중한 끄덕임만 돌아왔고 수표는 없었다.</p>
<p>지난주에 나는 그 인터뷰를 다시 읽었다. 일부는 희망 섞인 망상처럼 읽힌다. 일부는 내가 타임머신을 가졌던 것처럼 읽힌다. 가장 잘 늙은 네 가지 베팅과, 그 옆에 놓인 2026년의 실제 모습을 정리한다.</p>
<h2 id="베팅-1-게임-엔진은-브라우저에-속한다" tabindex="-1">베팅 1: 게임 엔진은 브라우저에 속한다 <a class="header-anchor" href="#베팅-1-게임-엔진은-브라우저에-속한다" aria-label="Permalink to &quot;베팅 1: 게임 엔진은 브라우저에 속한다&quot;"></a></h2>
<p>2022년에 내가 한 말:</p>
<blockquote>
<p>WebGL 기술은 모바일 기기를 포함해 여러 플랫폼에서 쓸 수 있다. PC에만 제한될 수 있는 다른 API와 다르다. 그래서 집에서 편하게 있든 이동 중이든, 여전히 만들고 게시할 수 있다. WebGL 게임은 전통적인 PC 게임이 필요로 하는 CPU와 GPU 성능의 일부만 쓴다.</p>
</blockquote>
<p>2022년에 이건 통념을 거스르는 베팅이었다. 큰 엔진들은 전부 다운로드, 설치, 패치 사이클을 전제했다. 브라우저 게임은 Flash 향수와 Friv를 뜻했다.</p>
<p>2026년에 우리 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">오픈 월드 엔진은 브라우저 탭에서 120 FPS로 돌아간다</a>. 지형, 나무, 물리, 멀티플레이어 동기화, 전부 하나의 URL 안에서. 다운로드도, 앱 스토어도, 설치도 없다.</p>
<img src="/img/blog/open-world-browser-120fps.png" alt="The Cinevva open-world running at 120 FPS in a browser tab, with terrain, trees, physics, and a player capsule rendered in a single tab" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>브라우저가 따라잡은 건 세 가지가 한꺼번에 자리를 잡았기 때문이다. WebGPU가 모든 주요 브라우저에 출시됐다. SharedArrayBuffer와 교차 출처 격리가 안정적으로 작동하게 됐다. WebAssembly가 Rust에서 컴파일한 진짜 물리 엔진을 돌릴 만큼 빨라졌다. 우리 팀은 그 각 단계가 실제로 무엇을 치르게 했는지 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">12부작 현장 일지로 발행했다</a>. 요약하자면, 이제 브라우저는 진짜 게임 런타임이지, 진짜 게임의 데모를 올려놓는 곳이 아니다.</p>
<p>이 베팅 안에서 내가 놓친 베팅: 작업의 얼마나 많은 부분이 엔지니어링 문화 쪽에 있을지를 과소평가했다. 브라우저 게임 엔진은 더 이상 브라우저에 발목 잡히지 않는다. 진짜 게임에는 런처가 있어야 한다는 가정에 발목 잡힌다.</p>
<h2 id="베팅-2-ai는-파이프라인의-일부지-부가-기능이-아니다" tabindex="-1">베팅 2: AI는 파이프라인의 일부지, 부가 기능이 아니다 <a class="header-anchor" href="#베팅-2-ai는-파이프라인의-일부지-부가-기능이-아니다" aria-label="Permalink to &quot;베팅 2: AI는 파이프라인의 일부지, 부가 기능이 아니다&quot;"></a></h2>
<p>2022년에 내가 한 말:</p>
<blockquote>
<p>우리 플랫폼이 매끄럽게 작동하려면 오픈소스 게임 도구를 쓰지만, 동시에 자연어 처리, 컴퓨터 비전, 그리고 대화용 GPT3와 텍스트-이미지 생성용 DALL:E 같은 Open AI 솔루션을 활용해 우리만의 기술도 개발한다.</p>
</blockquote>
<p>2022년 5월에 GPT-3는 대부분의 사람이 한 번도 써본 적 없는 유료 API였다. DALL·E는 나온 지 겨우 1년 넘었고 대기 명단이 있었다. 그것들을 프로덕션 게임 개발 도구로 쓰겠다고 말한 건, 잘 봐줘야 야심 찬 코스프레였다.</p>
<p>2026년에 진지한 창작 파이프라인에는 전부 언어 모델과 이미지 생성이 들어가 있다. 우리 것도 마찬가지다. 오늘 Cinevva 내부에는 사운드트랙용 ElevenLabs Music, 효과음용 ElevenLabs SFX, 에셋용 Hunyuan3D와 SAM3D, 비주얼용 Flux, 적응형 오디오용 Mubert, 악기 편성용 AceStep이 있다. 프롬프트가 들어가면 쓸 수 있는 에셋이 나오고, 이 모든 게 에디터 안에서 일어난다.</p>
<img src="/img/blog/prompting-3d-games.png" alt="Prompt-driven 3D asset generation inside the Cinevva editor" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>이 베팅의 증거는 GDC 2026 <em>State of the Game Industry</em> 보고서에 있다. <a href="/ko/signals/2026-03-28-the-52-52-split.html">게임 회사의 52%가 생성형 AI가 프로덕션에서 쓰이고 있다고 말한다</a>. 같은 52%의 개발자가 AI 사용이 업계에 부정적인 영향을 주고 있다고 말한다. 두 숫자 다 사실이다. 핵심은, 그 기반 기술이 누구도 인정하고 싶어 한 것보다 더 빨리 기본기가 됐다는 거다.</p>
<p>내가 틀린 것: 저항은 품질을 걱정하는 엔지니어에게서 올 거라고 생각했다. 대부분은 일자리를 걱정하는 아티스트에게서 왔다. 그 대화는 <a href="/ko/signals/2026-03-16-when-ai-overrides-the-artist.html">내가 예상한 것보다 훨씬 더 엉망이고</a>, 이걸 깔끔한 승리로 취급하는 사람들은 제대로 보고 있지 않다.</p>
<h2 id="베팅-3-게임-개발에는-google-docs-스타일의-협업이-필요하다" tabindex="-1">베팅 3: 게임 개발에는 Google Docs 스타일의 협업이 필요하다 <a class="header-anchor" href="#베팅-3-게임-개발에는-google-docs-스타일의-협업이-필요하다" aria-label="Permalink to &quot;베팅 3: 게임 개발에는 Google Docs 스타일의 협업이 필요하다&quot;"></a></h2>
<p>2022년에 내가 한 말:</p>
<blockquote>
<p>소스 컨트롤과 앱 버전 작업은 흔히 원격 협업과 엮인다. 오늘 그걸 하려면 어디로 가야 하는지, 어떤 버전의 애플리케이션을 받아야 하는지 알아야 하고, 모두와 동기화돼 있어야 하고, 혹시라도 팀원 한 명이 잘못된 버전의 앱을 쓰고 있으면 문제가 된다. 우리는 Google doc 같은 거의 실시간에 가까운 경험을 목표로 한다. 간단하고, 힘들지 않고, 그러면서 재미있게.</p>
</blockquote>
<p>코드 도구에서의 실시간 협업은 2022년에 변두리 아이디어였다. Replit은 그게 있었다. VS Code Live Share도 있었다. 대부분의 전문 엔진은 Perforce, VPN, 그리고 네 브랜치를 옆에서 봐주는 시니어 엔지니어를 필요로 했다.</p>
<p>2026년에 실시간 협업은 진지하게 받아들여지고 싶은 어떤 창작 도구든 기본값이다. Figma는 디자인에서 그걸 당연하게 만들었다. Cursor와 Bolt는 코드에서 그걸 당연하게 만들었다. Lovable은 앱 프로토타이핑에서 그걸 당연하게 만들었다. 게임 엔진은 선두가 아니라 뒤처진 쪽이었다.</p>
<img src="/img/blog/open-world-chunk-streaming.png" alt="Streaming chunks of an open-world game between players in real time" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>우리 자체 엔진 안에서는 이제 멀티플레이어 동기화가 <a href="/ko/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy.html">일급 스파이크로 작동한다</a>. 브라우저 안에서 청크 스트리밍, 프레즌스, 공유 상태까지. 그 경험은 &quot;Perforce 설정하고, Slack에 어떤 버전이 맞는지 물어보고, 런처 설치하기&quot;보다 &quot;링크 열고, 바로 들어가기&quot;에 가깝다.</p>
<p>내가 과소평가한 부분: 게임에서 실시간 협업의 가장 어려운 부분은 네트워킹이 아니다. 창작 의도의 충돌 해소다. 두 사람이 같은 레벨을 동시에 편집하는 건 동기화 문제이기 전에 UX 문제이고, 대부분의 도구는 아직 이걸 풀지 못했다.</p>
<h2 id="베팅-4-미래는-인디다" tabindex="-1">베팅 4: 미래는 인디다 <a class="header-anchor" href="#베팅-4-미래는-인디다" aria-label="Permalink to &quot;베팅 4: 미래는 인디다&quot;"></a></h2>
<p>2022년에 내가 한 말:</p>
<blockquote>
<p>게임 콘텐츠를 만들지 못했던 창작자들이 만들 수 있게 될 것이다. 우리는 사람들이 창의성을 인식하고 표현하는 풍부한 새로운 방식을 발견하게 될 것이다. 이번엔 그 과정이 기업이나 대형 AAA 스튜디오만의 통제 아래 있지 않을 것이다. 미래는 인디다.</p>
</blockquote>
<p>이건 그 인터뷰에서 가장 낭만적인 문장이었고, 2022년에 가장 무시하기 쉬운 문장이었다. AAA 예산은 그 어느 때보다 높았다. 인디 프로젝트는 그 어느 때보다 가시성을 얻기 어려웠다. 계산은 반대 방향으로 가는 것처럼 보였다.</p>
<p>2026년에 계산이 뒤집혔다. 우리는 <a href="/ko/blog/2026-02-18-a-breaker-belt.html">A Breaker Belt</a>를 사흘 만에, 두 사람이, 하나의 코드베이스로 웹, 모바일, PC에서 만들었다. 예전엔 작은 팀이 한 분기를 써야 했던 일이다. <a href="/ko/signals/2026-03-23-solo-devs-shipping-not-vibing.html">솔로 개발자들이 vibing만 하는 게 아니라 진짜로 게임을 내고 있고</a>, Steam Next Fest 2026에는 1인 팀의 출품이 역대 최다였다.</p>
<img src="/img/social/industry-solo-dev-shipping.png" alt="Solo developers shipping production-quality games using AI tooling and browser engines" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>이상한 아이디어가 통하는지 알아내는 비용이 무너졌다. 그게 진짜 변화이고, 나머지 모든 것, 즉 파이프라인 속 AI, 런타임으로서의 브라우저, 실시간 협업은 그것에 봉사한다. 제대로 된 도구를 가진 솔로 개발자는 이제 2018년에 20명짜리 스튜디오가 가졌던 생산 역량을 가진다.</p>
<p>2022년에 내가 충분히 또렷하게 보지 못한 것: 병목이 생산에서 발견으로 옮겨간다. 누구나 게임을 낼 수 있게 되면, 찾아지는 게 어려운 문제가 된다. 그게 다음 베팅들이고, 우리는 그걸 거는 한가운데에 있다.</p>
<h2 id="내가-일부러-틀린-것들" tabindex="-1">내가 일부러 틀린 것들 <a class="header-anchor" href="#내가-일부러-틀린-것들" aria-label="Permalink to &quot;내가 일부러 틀린 것들&quot;"></a></h2>
<p>2022년의 몇몇 베팅은 아직 보류 중이거나 수정이 필요하다.</p>
<p>그 인터뷰에서 Web3 쪽은 그래야 했던 것보다 더 시끄러웠다. 암호화와 영지식 증명 부분은 콘텐츠 권리의 기본 요소로서 여전히 유효하다. 토큰과 마켓플레이스 식의 틀은 나쁘게 늙었고, 2022년에 거기에 쏟은 에너지의 많은 부분은 진짜 상승 여지가 있던 AI 도구 쪽에 쓰는 게 나았을 것이다.</p>
<p>나는 또한 &quot;누구나 게임을 만들 수 있다&quot;의 많은 부분이 도구 문제가 아니라 발견과 분배 문제라는 걸 과소평가했다. 만드는 건 이제 쉽다. 찾아지고 돈을 버는 건 여전히 어렵고, 오늘 우리 작업의 대부분은 거기로 간다.</p>
<p>그게 우리가 지금 걸고 있는 베팅이다. 우리는 <a href="/ko/play.html">cinevva.com/play</a>에 TikTok 스타일의 릴스 피드를 막 출시했다. 실제 게임플레이의 세로 스와이프 클립, 각 15초, 예고편도 마케팅 영상도 없다. 뭔가 눈에 들어오면, 한 번 탭하면 브라우저에서 바로 플레이하게 된다. 다운로드도, 설치도, 너와 게임 사이를 막는 튜토리얼도 없다.</p>
<p>이게 인디 개발자에게 중요한 이유는 잔혹한 계산이다. Steam Next Fest 2026에는 역대 최다 출품이 있었는데, 게임당 주의력 예산을 따져보기 전까지는 멋지게 들린다. 대부분의 데모는 노출 1천 회 미만을 얻었다. 스토어 페이지 퍼널은 AI가 더 나쁘게 만들기 전에 이미 망가져 있었다. 게임플레이 자체가 광고인 스크롤-앤-스와이프 표면은 발견 루프를 하나의 동작으로 압축한다. 그건 TikTok이 무명 뮤지션을 청취자 앞에 놓는 것과 똑같은 방식으로 솔로 개발자를 플레이어 앞에 놓는다. 그게 &quot;누구나 낼 수 있다&quot;와 &quot;누구나 성공할 수 있다&quot; 사이에 빠져 있던 조각이다.</p>
<p>원본 인터뷰 전문을 보고 싶다면, <a href="https://medium.com/@vio-202020/interview-with-tech-done-different-3b9bf74d99c2" target="_blank" rel="noreferrer">여기 있다</a>. 다시 읽어보니 유용했다. 2022년에 우리가 소리 내어 말한 것의 대부분은 작동하는 로드맵으로 드러났다. 우리가 생각한 것보다 더 빠른 시계 위에서였을 뿐이다.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 13부: 지형 조각과 수학 함수의 죽음]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting</link>
            <guid>https://app.cinevva.com/ko/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting</guid>
            <pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[잘못된 출발 세 번, 폭발한 메시 하나, 그리고 지형 데이터가 어떻게 동작해야 하는지를 다시 생각하게 만든 이음새 버그 하나.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-13부-지형-조각과-수학-함수의-죽음" tabindex="-1">브라우저에서 오픈 월드 만들기, 13부: 지형 조각과 수학 함수의 죽음 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-13부-지형-조각과-수학-함수의-죽음" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 13부: 지형 조각과 수학 함수의 죽음&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p>열두 부분 동안 우리는 바라볼 수 있는 지형 엔진을 만들었습니다. 그 위를 날아다닐 수 있고, 이음새가 갈라지지 않는 걸 감상할 수 있었죠. 이번에는 그걸 직접 만져보고 싶었습니다.</p>
<p>목표는 간단하게 들렸습니다. 플레이어가 브러시로 지형을 실시간으로 조각하되, 24개의 spike를 들여 쌓아 올린 어떤 시스템도 망가뜨리지 않게 하자. 결국 세 번의 시도, 렌더링 실패처럼 보였지만 사실은 데이터 모델 실패였던 버그 두 개, 그리고 지형 데이터가 어떻게 동작해야 하는지에 대한 근본적인 재고가 필요했습니다.</p>
<h2 id="잘못된-출발-세-번" tabindex="-1">잘못된 출발 세 번 <a class="header-anchor" href="#잘못된-출발-세-번" aria-label="Permalink to &quot;잘못된 출발 세 번&quot;"></a></h2>
<p>Spike 25는 쉬운 작업이어야 했습니다. 프로덕션 코드베이스에는 이미 지형 메시에 닿는 레이캐스터가 있었습니다. 배치 도구가 그걸로 오브젝트를 떨어뜨리죠. 브러시 도구도 같은 형태를 따르되, prefab을 생성하는 대신 heightmap 값을 수정할 뿐입니다. 간단합니다.</p>
<p>첫 번째 시도: 프로덕션 <code>world/client/</code> TypeScript 코드에 직접 만들어 넣었습니다. 새 <code>terrain-brush.ts</code>, <code>chunk.ts</code> 수정, 프로토콜 변경, Vue 컴포넌트 업데이트. 한 시간 안에 어느 정도 동작하는 브러시가 생겼지만, chunk 경계에서 눈에 보이는 법선 불연속이 나타났습니다. 이 버그가 내 브러시 코드인지, 기존 chunk 봉합인지, 아니면 전체 렌더 루프와의 어떤 상호작용인지 구분할 수 없었습니다. spike 방법론이 막으려고 존재하는 게 바로 이 상황입니다. 규칙을 건너뛰었고 그 대가를 바로 치렀습니다. 전부 되돌렸습니다.</p>
<p>두 번째 시도: 독립 spike였지만, Three.js 0.170.0과 WebGL을 집어 들었습니다. 프로덕션 코드가 WebGL을 쓰니 자연스러워 보였죠. 하지만 Spike 13-24는 모두 WebGPU로 옮겨가 있었습니다. WebGL 브러시 spike를 만들면 우리가 옮겨가려는 렌더러가 아니라 레거시 렌더러에서 동작한다는 걸 증명하는 셈입니다. 방향이 틀렸습니다. 다시 시작했습니다.</p>
<p>세 번째 시도: WebGPU, <code>WebGPURenderer</code>, 정점 생성용 컴퓨트 셰이더, Spike 22 스택에 맞춤. 이번엔 아키텍처가 맞았습니다. 브러시 동작 다섯 개가 작동했습니다. 올리기, 내리기, 매끄럽게, 평탄화, 노이즈. 브러시 한 사이클 P95가 M1에서 4ms 아래였습니다.</p>
<p>그리고 이음새 버그는 여전히 있었습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/25-heightmap-brush/" title="Spike 25 Heightmap Brush" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/25-heightmap-brush/" target="_blank">새 탭에서 Spike 25 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=25-heightmap-brush">소스 보기</a></p>
<h2 id="죽지-않는-이음새-버그" tabindex="-1">죽지 않는 이음새 버그 <a class="header-anchor" href="#죽지-않는-이음새-버그" aria-label="Permalink to &quot;죽지 않는 이음새 버그&quot;"></a></h2>
<p>chunk 간 법선 계산의 표준 해법은 경계 중첩입니다. 각 chunk가 이웃의 데이터를 한 줄 더 저장해서, 경계에서의 법선 계산이 양쪽을 모두 샘플링할 수 있게 하는 거죠. 그렇게 구현했습니다. 이웃의 가장자리 데이터를 확장된 버퍼로 복사했죠. 이음새는 여전히 갈라졌습니다.</p>
<p>수학을 파고들었습니다. chunk A(cx=-1)와 chunk B(cx=0)의 경계에서, 두 chunk 모두 공유 정점에서 같은 법선을 계산해야 합니다. chunk A의 셰이더는 <code>mix(own_col31, own_col32, 0.85)</code>를 샘플링했습니다. chunk B는 <code>mix(neighbor_edge, own_col0, 0.85)</code>를 샘플링했죠. 이건 서로 다른 데이터를 지나는 서로 다른 쌍선형 보간 경로입니다. 경계 데이터가 정확해도, 두 chunk는 같은 점에서 다른 법선을 계산합니다.</p>
<p>바로 이 순간 경계 복사가 진짜 버그가 아니라는 걸 깨달았습니다. 진짜 버그는 데이터 모델이었습니다.</p>
<p>1번부터 24번까지 모든 spike는 <code>height_at()</code>라는 절차적 수학 함수를 썼습니다. 월드 좌표를 넣으면 높이가 나오죠. 깔끔하고, 전역적이고, 상태가 없습니다. 브러시는 수학 함수를 수정할 수 없어서, 그 위에 <code>displacement</code> 버퍼를 얹었습니다. 지형은 이제 <code>height_at(x,z) + displacement[i]</code>가 됐습니다. GPU 셰이더에는 기본 지형용 노이즈 함수 30줄과 변위 오버레이용 쌍선형 보간 코드가 박혀 있었습니다. 평탄화 브러시는 목표 높이를 만들어낼 변위 값을 알아내려고 <code>height_at()</code>를 빼야 했습니다. 두 시스템이 서로 위에 쌓여서, 서로 다른 샘플링 전략으로 서로 다른 걸 계산하고 있었던 겁니다.</p>
<p>이건 실제 게임이 동작하는 방식이 아닙니다. 프로덕션에서는 제작된 지형이 버퍼에 저장된 샘플 데이터입니다. 절차적 함수는 초기 spike에서 편하게 쓴 대역일 뿐이었습니다. 제 역할은 다 했죠. 이제는 적극적으로 버그를 만들어내고 있었습니다.</p>
<p>그걸 죽였습니다.</p>
<p>이제 각 chunk는 실제 높이 값을 담은 <code>heightmap</code> Float32Array를 직접 소유합니다. 생성 시 절차적 노이즈가 그걸 채웁니다. 그 후로 노이즈 함수는 다시는 호출되지 않습니다. 브러시는 저장된 높이를 직접 수정합니다. GPU 셰이더는 하나의 버퍼에서 하나의 함수로 읽습니다. <code>hm_at(i,j)</code>. 법선은 같은 데이터에 격자 정렬 중심 차분을 써서 구합니다. 쌍선형 보간의 모호함도 없고, 두 시스템 간 불일치도 없습니다. 셰이더가 90줄에서 40줄로 줄었습니다.</p>
<p>이음새는 저절로 고쳐졌습니다. 공유 가장자리에 있는 두 chunk가 이제 각자의 버퍼에서 같은 이산 높이 값을 읽습니다(경계 중첩에 정확한 이웃 내부 점을 담아서). 같은 데이터가 들어가면 같은 법선이 나옵니다.</p>
<p>이건 브러시에 관한 교훈이 아니었습니다. 브러시가 드러낸 데이터 아키텍처에 관한 교훈이었습니다.</p>
<h2 id="폭발한-메시" tabindex="-1">폭발한 메시 <a class="header-anchor" href="#폭발한-메시" aria-label="Permalink to &quot;폭발한 메시&quot;"></a></h2>
<p>Spike 26은 볼류메트릭 쪽 대응물이었습니다. 64세제곱 SDF 볼륨을 브러시로 수정하고, marching cubes로 다시 메싱하기. Spike 25와 같은 질문이지만 3D에서요.</p>
<p>처음 실행했을 때 메시가 폭발했습니다. 긴 가시들이 사방으로 뻗어 나갔죠. 하루를 망친 성게 같았습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/26-sdf-brush/" title="Spike 26 SDF Brush" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/26-sdf-brush/" target="_blank">새 탭에서 Spike 26 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=26-sdf-brush">소스 보기</a></p>
<p>내가 생성한 MC 케이스 테이블에는 4096개 대신 3840개의 항목이 있었습니다. 전체 테이블은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="26.441ex" height="1.756ex" role="img" focusable="false" viewBox="0 -694 11687 776" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(1500,0)"><path data-c="A0" d="" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(1750,0)"><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(444,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(944,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1338,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(1782,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4148.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(5148.4,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(6148.4,0)"><path data-c="A0" d="" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(6398.4,0)"><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(394,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(672,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1172,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(1561,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(8631.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(9687,0)"><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="39" d="M352 287Q304 211 232 211Q154 211 104 270T44 396Q42 412 42 436V444Q42 537 111 606Q171 666 243 666Q245 666 249 666T257 665H261Q273 665 286 663T323 651T370 619T413 560Q456 472 456 334Q456 194 396 97Q361 41 312 10T208 -22Q147 -22 108 7T68 93T121 149Q143 149 158 135T173 96Q173 78 164 65T148 49T135 44L131 43Q131 41 138 37T164 27T206 22H212Q272 22 313 86Q352 142 352 280V287ZM244 248Q292 248 321 297T351 430Q351 508 343 542Q341 552 337 562T323 588T293 615T246 625Q208 625 181 598Q160 576 154 546T147 441Q147 358 152 329T172 282Q197 248 244 248Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(1500,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>256</mn><mtext> </mtext><mtext>cases</mtext><mo>×</mo><mn>16</mn><mtext> </mtext><mtext>slots</mtext><mo>=</mo><mn>4096</mn></math></mjx-assistive-mml></mjx-container>인데, 나는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="15.964ex" height="1.717ex" role="img" focusable="false" viewBox="0 -677 7056 759" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1722.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2722.4,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4000.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(5056,0)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1500,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>256</mn><mo>×</mo><mn>15</mn><mo>=</mo><mn>3840</mn></math></mjx-assistive-mml></mjx-container>만 가지고 있었습니다. case 112부터 시작해서 16개 행이 빠진 거죠. 그 인덱스 이후의 모든 조회가 어긋나서, case 번호가 삼각화 데이터와 더는 맞지 않았습니다. marching cubes가 잘못된 항목을 읽으면, 두 끝점이 표면의 같은 쪽에 있는 엣지를 만들어냅니다. 실제로 교차하는 엣지에서는 보간 매개변수</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -1.909ex;" xmlns="http://www.w3.org/2000/svg" width="11.698ex" height="4.757ex" role="img" focusable="false" viewBox="0 -1259 5170.4 2102.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(638.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(1694.6,0)"><g data-mml-node="mrow" transform="translate(877.9,676)"><g data-mml-node="mo"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(778,0)"><g data-mml-node="mi"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(518,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mrow" transform="translate(220,-686)"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(518,-150) scale(0.707)"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1093.6,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2093.8,0)"><g data-mml-node="mi"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(518,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g><rect width="3235.9" height="60" x="120" y="220"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi>t</mi><mo>=</mo><mfrac><mrow><mo>−</mo><msub><mi>v</mi><mi>a</mi></msub></mrow><mrow><msub><mi>v</mi><mi>b</mi></msub><mo>−</mo><msub><mi>v</mi><mi>a</mi></msub></mrow></mfrac></math></mjx-assistive-mml></mjx-container><p>가 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="4.526ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 2000.7 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="5B" d="M118 -250V750H255V710H158V-210H255V-250H118Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(278,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(778,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1222.7,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1722.7,0)"><path data-c="5D" d="M22 710V750H159V-250H22V-210H119V710H22Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mn>0</mn><mo>,</mo><mn>1</mn><mo stretchy="false">]</mo></math></mjx-assistive-mml></mjx-container> 안에 떨어집니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.355ex;" xmlns="http://www.w3.org/2000/svg" width="2.131ex" height="1.358ex" role="img" focusable="false" viewBox="0 -443 942.1 600.1" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(518,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>v</mi><mi>a</mi></msub></math></mjx-assistive-mml></mjx-container>와 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="1.971ex" height="1.359ex" role="img" focusable="false" viewBox="0 -443 871.3 600.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(518,-150) scale(0.707)"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>v</mi><mi>b</mi></msub></math></mjx-assistive-mml></mjx-container>의 부호가 반대이기 때문이죠. 가짜 엣지에서는 둘의 부호가 같아서 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="6.868ex" height="1.676ex" role="img" focusable="false" viewBox="0 -583 3035.9 740.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(518,-150) scale(0.707)"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1093.6,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2093.8,0)"><g data-mml-node="mi"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(518,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>v</mi><mi>b</mi></msub><mo>−</mo><msub><mi>v</mi><mi>a</mi></msub></math></mjx-assistive-mml></mjx-container>가 0에 가깝거나 부호가 뒤집히고, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="0.817ex" height="1.441ex" role="img" focusable="false" viewBox="0 -626 361 637" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>t</mi></math></mjx-assistive-mml></mjx-container>가 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="4.526ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 2000.7 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="5B" d="M118 -250V750H255V710H158V-210H255V-250H118Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(278,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(778,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1222.7,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1722.7,0)"><path data-c="5D" d="M22 710V750H159V-250H22V-210H119V710H22Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mn>0</mn><mo>,</mo><mn>1</mn><mo stretchy="false">]</mo></math></mjx-assistive-mml></mjx-container> 밖으로 튀어 정점을 볼륨 한참 바깥에 둡니다. 거기에 잘못된 셀 수백 개를 곱하면 고슴도치가 나오는 겁니다.</p>
<p>해법은 어이없을 만큼 단순했습니다. Spike 12에서 검증된 테이블을 바이트 단위로 그대로 복사하기. 교훈을 얻었습니다. 검증된 사본이 있을 때는 절대 룩업 테이블을 다시 생성하지 마라.</p>
<p>두 번째 버그는 더 미묘했습니다. 매끄럽게 다듬는 브러시는 지형 특징을 부드럽게 만들어야 했습니다. 그런데 날카로운 주름을 만들어냈죠. 문제는 이거였습니다. 나는 모든 SDF 값을 0(등위면)을 향해 끌어당기고 있었습니다. 그러면 매끄러워질 것 같지만, 사실은 거리장을 붕괴시킵니다. 표면 위아래의 복셀이 모두 0으로 몰려서, 브러시 반경 안의 모든 걸 평평하게 눌러버립니다. 경계에서는 매끄럽게 다듬어진 복셀이 다듬어지지 않은 복셀을 만나 단단한 계단이 생깁니다. &quot;매끄럽게&quot; 브러시가 주름 생성기였던 겁니다.</p>
<p>해법은 제대로 된 라플라시안 평활화였습니다. 각 값을 0으로 끌어당기는 대신, 직접 이웃한 6개의 평균을 향해 끌어당기는 거죠.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -3.222ex;" xmlns="http://www.w3.org/2000/svg" width="30.99ex" height="7.575ex" role="img" focusable="false" viewBox="0 -1924.1 13697.6 3348.2" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(629,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1200.7,0)"><path data-c="2190" d="M944 261T944 250T929 230H165Q167 228 182 216T211 189T244 152T277 96T303 25Q308 7 308 0Q308 -11 288 -11Q281 -11 278 -11T272 -7T267 2T263 21Q245 94 195 151T73 236Q58 242 55 247Q55 254 59 257T73 264Q121 283 158 314T215 375T247 434T264 480L267 497Q269 503 270 505T275 509T288 511Q308 511 308 500Q308 493 303 475Q293 438 278 406T246 352T215 315T185 287T165 270H929Q944 261 944 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2478.5,0)"><g data-mml-node="mi"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(629,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3623.7,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(4623.9,0)"><path data-c="1D706" d="M166 673Q166 685 183 694H202Q292 691 316 644Q322 629 373 486T474 207T524 67Q531 47 537 34T546 15T551 6T555 2T556 -2T550 -11H482Q457 3 450 18T399 152L354 277L340 262Q327 246 293 207T236 141Q211 112 174 69Q123 9 111 -1T83 -12Q47 -12 47 20Q47 37 61 52T199 187Q229 216 266 252T321 306L338 322Q338 323 288 462T234 612Q214 657 183 657Q166 657 166 673Z" style="stroke-width: 3;"/></g><g data-mml-node="mrow" transform="translate(5373.6,0)"><g data-mml-node="mo"><path data-c="239B" d="M837 1154Q843 1148 843 1145Q843 1141 818 1106T753 1002T667 841T574 604T494 299Q417 -84 417 -609Q417 -641 416 -647T411 -654Q409 -655 366 -655Q299 -655 297 -654Q292 -652 292 -643T291 -583Q293 -400 304 -242T347 110T432 470T574 813T785 1136Q787 1139 790 1142T794 1147T796 1150T799 1152T802 1153T807 1154T813 1154H819H837Z" transform="translate(0,770.1)" style="stroke-width: 3;"/><path data-c="239D" d="M843 -635Q843 -638 837 -644H820Q801 -644 800 -643Q792 -635 785 -626Q684 -503 605 -363T473 -75T385 216T330 518T302 809T291 1093Q291 1144 291 1153T296 1164Q298 1165 366 1165Q409 1165 411 1164Q415 1163 416 1157T417 1119Q417 529 517 109T833 -617Q843 -631 843 -635Z" transform="translate(0,-780.1)" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(875,0)"><g data-mml-node="mn" transform="translate(220,676)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(220,-686)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g><rect width="700" height="60" x="120" y="220"/></g><g data-mml-node="munder" transform="translate(1981.7,0)"><g data-mml-node="mo" transform="translate(370.5,0)"><path data-c="2211" d="M60 948Q63 950 665 950H1267L1325 815Q1384 677 1388 669H1348L1341 683Q1320 724 1285 761Q1235 809 1174 838T1033 881T882 898T699 902H574H543H251L259 891Q722 258 724 252Q725 250 724 246Q721 243 460 -56L196 -356Q196 -357 407 -357Q459 -357 548 -357T676 -358Q812 -358 896 -353T1063 -332T1204 -283T1307 -196Q1328 -170 1348 -124H1388Q1388 -125 1381 -145T1356 -210T1325 -294L1267 -449L666 -450Q64 -450 61 -448Q55 -446 55 -439Q55 -437 57 -433L590 177Q590 178 557 222T452 366T322 544L56 909L55 924Q55 945 60 948Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(0,-1147.3) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D457" d="M297 596Q297 627 318 644T361 661Q378 661 389 651T403 623Q403 595 384 576T340 557Q322 557 310 567T297 596ZM288 376Q288 405 262 405Q240 405 220 393T185 362T161 325T144 293L137 279Q135 278 121 278H107Q101 284 101 286T105 299Q126 348 164 391T252 441Q253 441 260 441T272 442Q296 441 316 432Q341 418 354 401T367 348V332L318 133Q267 -67 264 -75Q246 -125 194 -164T75 -204Q25 -204 7 -183T-12 -137Q-12 -110 7 -91T53 -71Q70 -71 82 -81T95 -112Q95 -148 63 -167Q69 -168 77 -168Q111 -168 139 -140T182 -74L193 -32Q204 11 219 72T251 197T278 308T289 365Q289 372 288 376Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(412,0)"><path data-c="2208" d="M84 250Q84 372 166 450T360 539Q361 539 377 539T419 540T469 540H568Q583 532 583 520Q583 511 570 501L466 500Q355 499 329 494Q280 482 242 458T183 409T147 354T129 306T124 272V270H568Q583 262 583 250T568 230H124V228Q124 207 134 177T167 112T231 48T328 7Q355 1 466 0H570Q583 -10 583 -20Q583 -32 568 -40H471Q464 -40 446 -40T417 -41Q262 -41 172 45Q84 127 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1079,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1967,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2356,0)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2701,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="msub" transform="translate(4333.3,0)"><g data-mml-node="mi"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(629,-150) scale(0.707)"><path data-c="1D457" d="M297 596Q297 627 318 644T361 661Q378 661 389 651T403 623Q403 595 384 576T340 557Q322 557 310 567T297 596ZM288 376Q288 405 262 405Q240 405 220 393T185 362T161 325T144 293L137 279Q135 278 121 278H107Q101 284 101 286T105 299Q126 348 164 391T252 441Q253 441 260 441T272 442Q296 441 316 432Q341 418 354 401T367 348V332L318 133Q267 -67 264 -75Q246 -125 194 -164T75 -204Q25 -204 7 -183T-12 -137Q-12 -110 7 -91T53 -71Q70 -71 82 -81T95 -112Q95 -148 63 -167Q69 -168 77 -168Q111 -168 139 -140T182 -74L193 -32Q204 11 219 72T251 197T278 308T289 365Q289 372 288 376Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5525.8,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(6526.1,0)"><g data-mml-node="mi"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(629,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(7449,0)"><path data-c="239E" d="M31 1143Q31 1154 49 1154H59Q72 1154 75 1152T89 1136Q190 1013 269 873T401 585T489 294T544 -8T572 -299T583 -583Q583 -634 583 -643T577 -654Q575 -655 508 -655Q465 -655 463 -654Q459 -653 458 -647T457 -609Q457 -58 371 340T100 1037Q87 1059 61 1098T31 1143Z" transform="translate(0,770.1)" style="stroke-width: 3;"/><path data-c="23A0" d="M56 -644H50Q31 -644 31 -635Q31 -632 37 -622Q69 -579 100 -527Q286 -228 371 170T457 1119Q457 1161 462 1164Q464 1165 520 1165Q575 1165 577 1164Q582 1162 582 1153T583 1093Q581 910 570 752T527 400T442 40T300 -303T89 -626Q78 -640 75 -642T61 -644H56Z" transform="translate(0,-780.1)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><msub><mi>ϕ</mi><mi>i</mi></msub><mo stretchy="false">←</mo><msub><mi>ϕ</mi><mi>i</mi></msub><mo>+</mo><mi>λ</mi><mrow data-mjx-texclass="INNER"><mo data-mjx-texclass="OPEN">(</mo><mfrac><mn>1</mn><mn>6</mn></mfrac><munder><mo data-mjx-texclass="OP">∑</mo><mrow data-mjx-texclass="ORD"><mi>j</mi><mo>∈</mo><mi>N</mi><mo stretchy="false">(</mo><mi>i</mi><mo stretchy="false">)</mo></mrow></munder><msub><mi>ϕ</mi><mi>j</mi></msub><mo>−</mo><msub><mi>ϕ</mi><mi>i</mi></msub><mo data-mjx-texclass="CLOSE">)</mo></mrow></math></mjx-assistive-mml></mjx-container><p>괄호 안의 항은 이산 라플라시안이고, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="8.862ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 3917.2 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D706" d="M166 673Q166 685 183 694H202Q292 691 316 644Q322 629 373 486T474 207T524 67Q531 47 537 34T546 15T551 6T555 2T556 -2T550 -11H482Q457 3 450 18T399 152L354 277L340 262Q327 246 293 207T236 141Q211 112 174 69Q123 9 111 -1T83 -12Q47 -12 47 20Q47 37 61 52T199 187Q229 216 266 252T321 306L338 322Q338 323 288 462T234 612Q214 657 183 657Q166 657 166 673Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(860.8,0)"><path data-c="2208" d="M84 250Q84 372 166 450T360 539Q361 539 377 539T419 540T469 540H568Q583 532 583 520Q583 511 570 501L466 500Q355 499 329 494Q280 482 242 458T183 409T147 354T129 306T124 272V270H568Q583 262 583 250T568 230H124V228Q124 207 134 177T167 112T231 48T328 7Q355 1 466 0H570Q583 -10 583 -20Q583 -32 568 -40H471Q464 -40 446 -40T417 -41Q262 -41 172 45Q84 127 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1805.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2194.6,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2694.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3139.2,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3639.2,0)"><path data-c="5D" d="M22 710V750H159V-250H22V-210H119V710H22Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>λ</mi><mo>∈</mo><mo stretchy="false">(</mo><mn>0</mn><mo>,</mo><mn>1</mn><mo stretchy="false">]</mo></math></mjx-assistive-mml></mjx-container>는 평활화 강도입니다. 이건 가까운 지오메트리를 평균 내어 표면 형태를 부드럽게 만들면서, 거리장을 붕괴시키는 대신 그 기울기를 보존합니다.</p>
<h2 id="전부-한꺼번에" tabindex="-1">전부 한꺼번에 <a class="header-anchor" href="#전부-한꺼번에" aria-label="Permalink to &quot;전부 한꺼번에&quot;"></a></h2>
<p>Spike 27은 통합 관문이었습니다. Spike 24의 전체 파이프라인(heightmap 패치, MC chunk, Transvoxel 이음새, geomorph LOD)을 Spike 25의 샘플 데이터 모델, 그리고 두 가지 브러시 타입과 결합하기.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/27-hm-mc-brush/" title="Spike 27 HM + MC + Brush Integration" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/27-hm-mc-brush/" target="_blank">새 탭에서 Spike 27 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=27-hm-mc-brush">소스 보기</a></p>
<p>제일 먼저 한 일은 모든 셰이더에서 <code>height_at()</code>를 뜯어내는 것이었습니다. 세 개의 컴퓨트 셰이더(SDF 채우기, heightmap 패치, Transvoxel 이음새)가 이제 같은 129x129 heightmap GPU 버퍼를 바인딩하고, 공유 WGSL 프리앰블을 통해 같은 <code>hm_sample()</code> 쌍선형 보간 함수를 씁니다. 하나의 데이터 소스, 여러 소비자. Spike 1부터 모든 셰이더에 살고 있던 절차적 노이즈 함수가 사라졌습니다.</p>
<p>그러고 나서 흥미로운 문제들이 시작됐습니다.</p>
<p>SDF 브러시가 한 chunk를 MC 모드로 잠그면, 그 chunk와 heightmap 이웃 사이의 Transvoxel 이음새는 heightmap이 아니라 SDF 볼륨에서 샘플링해야 합니다. 이음새 셰이더에 추가 스토리지 버퍼 바인딩과 chunk별 MC 플래그를 더했습니다. 처리할 경계 조합은 네 가지였습니다. HM-HM, HM-MC, MC-HM, MC-MC.</p>
<p>LOD는 또 다른 퍼즐이었습니다. 앞선 spike에서는 MC chunk를 더 낮은 LOD로 전환한다는 게 더 거친 해상도로 SDF를 다시 채운다는 뜻이었습니다. 그걸 스트라이드 기반 샘플링으로 바꿨습니다. SDF 데이터는 전체 해상도(격자 점 65개)를 유지합니다. MC 셰이더는 격자 크기와 셀 개수의 비율로 스트라이드를 계산합니다. LOD0에서는 스트라이드가 1입니다. LOD1에서는 스트라이드가 2가 되어 한 칸 건너 복셀을 샘플링합니다. chunk는 SDF 데이터를 건드리지 않고 자유롭게 LOD를 바꿀 수 있습니다.</p>
<p>가장 만족스러웠던 해법은 동적 수직 chunk 생성이었습니다. chunk 꼭대기 위로 위쪽으로 조각하면, 그 위에 MC 전용 chunk가 새로 나타나고 그 SDF는 아래 chunk의 경계면에서 초기화됩니다. 아래쪽으로 조각해도 마찬가지입니다. 월드가 편집에 맞게 자라납니다.</p>
<p>마지막 함정은 heightmap 브러시가 MC로 잠긴 chunk에 아무 일도 안 하면서 조용히 넘어가는 것이었습니다. HM 브러시는 <code>heightmapCPU</code>를 수정하고 다시 업로드합니다. MC chunk는 더 이상 heightmap에서 읽지 않습니다. 그 SDF가 heightmap으로 채워진 뒤에 따로 갈라졌기 때문이죠. <code>syncHeightmapToSdf()</code>를 추가했습니다. heightmap이 바뀐 뒤, 브러시 반경 안의 MC chunk에 대해 SDF 열을 다시 파생시키고 새 값을 업로드합니다. 이제 두 브러시 타입 모두 두 chunk 타입에서 동작합니다.</p>
<h2 id="우리가-실제로-배운-것" tabindex="-1">우리가 실제로 배운 것 <a class="header-anchor" href="#우리가-실제로-배운-것" aria-label="Permalink to &quot;우리가 실제로 배운 것&quot;"></a></h2>
<p>브러시 spike들은 성능 질문에 답하려는 것이었습니다. 조각이 프레임 예산 안에서 돌아갈 수 있는가? 가능합니다. 그게 쉬운 부분이었습니다.</p>
<p>어려운 부분은, 24개 spike 동안 <code>height_at()</code>를 지형의 진실로 써온 게 보이지 않는 의존성을 만들어냈고, 우리가 뭔가를 편집하려는 순간 그게 깨진다는 걸 발견한 것이었습니다. 그 절차적 함수는 깨끗하고 전역적이고 상태가 없었습니다. 더는 지형이 아니게 되기 직전까지는요.</p>
<p>우리가 적어두었고 잊지 않을 규칙들:</p>
<ol>
<li>지형 높이는 샘플 데이터에서 나온다. chunk가 자신의 버퍼를 소유한다.</li>
<li>절차적 생성은 초기 데이터를 채운다. 그것은 런타임의 진실이 아니다.</li>
<li>브러시는 chunk 데이터를 직접 수정한다. 변위 오버레이를 쓰지 않는다.</li>
<li>법선은 같은 데이터에서 격자 정렬 중심 차분으로 나온다.</li>
<li>경계 중첩(이웃 내부에서 1셀)이 chunk 간 법선을 처리한다.</li>
<li>검증된 사본이 있을 때는 절대 룩업 테이블을 다시 생성하지 않는다.</li>
</ol>
<p><a href="/ko/blog/2026-04-13-open-world-browser-part-14-world-comes-alive.html">14부</a>에서는 디버그 지오메트리를 조각하는 걸 멈추고, 그것을 실제 장소처럼 보이고 느껴지게 만들기 시작합니다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>샘플 heightmap 아키텍처.</strong> 지형을 런타임에 절차적 함수로 평가하는 대신, chunk별로 소유하는 데이터로 저장합니다. 각 chunk는 실제 높이 값이 담긴 <code>Float32Array</code>를 가집니다. 절차적 노이즈가 생성 시점에 초기 데이터를 채우고, 그 후로 함수는 다시 호출되지 않습니다. 이로써 수학 기반 지형과 편집 오버레이 사이의 이중 시스템 불일치가 사라지고, 브러시 동작이 단순해지며(저장된 값을 직접 편집), GPU 셰이더가 아주 단순해집니다(버퍼에서 읽고, 격자 정렬 중심 차분으로 법선 계산). 스트리밍이 있는 오픈 월드에서는 이웃에서 1셀 경계 중첩을 가진 chunk별 소유가 표준 방식입니다. 우리의 <a href="/ko/guides/landscape-generation-browser.html#terrain-data-representation">지형 생성 가이드</a>를 보세요.</p>
<p><strong>SDF 브러시 동작.</strong> 부호 있는 거리장을 수정해서 지형을 조각합니다. 더하기(팽창)는 구 주위의 스무스 스텝 감쇠를 씁니다. 빼기(파내기)는 같은 형태를 음수로 합니다. 매끄럽게 다듬기는 라플라시안 평균을 씁니다. 직접 이웃 6개를 읽고 평균을 계산해 그 평균을 향해 끌어당깁니다. 0을 향해 끌어당기는 단순한 방식은 거리장을 붕괴시켜 날카로운 모서리를 만듭니다. 라플라시안 평활화는 특징을 부드럽게 하면서 장의 기울기를 보존합니다. <a href="/ko/guides/landscape-generation-browser.html#signed-distance-fields-sdfs">SDF 지형 표현</a>을 보세요.</p>
<p><strong>혼합 데이터 소스를 가진 Transvoxel.</strong> MC chunk와 heightmap chunk 경계의 전환 셀은 양쪽에서 서로 다른 데이터를 샘플링해야 합니다. 이음새 셰이더는 네 가지 조합(HM-HM, HM-MC, MC-HM, MC-MC)을 모두 처리하기 위해 chunk별 플래그와 버퍼 바인딩을 가집니다. 한쪽이 MC로 잠겨 있으면, 셰이더는 heightmap을 샘플링하는 대신 SDF 버퍼를 삼선형 보간합니다.</p>
<p><strong>marching cubes를 위한 스트라이드 기반 LOD.</strong> chunk의 현재 LOD 레벨과 상관없이 SDF 데이터는 전체 해상도로 저장합니다. MC 셰이더는 SDF 격자 점 수와 MC 셀 수의 비율로 샘플링 스트라이드를 계산합니다. 전체 해상도에서는 스트라이드가 1, 절반 해상도에서는 2입니다. 이로써 SDF 데이터가 LOD 변경에서 분리되어, chunk는 SDF를 다시 만들지 않고 자유롭게 LOD를 전환할 수 있습니다.</p>
<hr>
<p>14부 중 13부.
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-12-lessons.html">12부 - 링, 하늘 안개, 그리고 다시 해볼 것들</a>
다음: <a href="/ko/blog/2026-04-13-open-world-browser-part-14-world-comes-alive.html">14부 - 세계가 살아난다</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 14부: 세계가 살아나다]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-04-13-open-world-browser-part-14-world-comes-alive</link>
            <guid>https://app.cinevva.com/ko/blog/2026-04-13-open-world-browser-part-14-world-comes-alive</guid>
            <pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[당신의 조각에 반응하는 머티리얼, 동굴 천장에 자라는 풀, 그리고 지금 브라우저 탭 안에 있다는 사실을 잊게 만드는 글라이더.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-14부-세계가-살아나다" tabindex="-1">브라우저에서 오픈 월드 만들기, 14부: 세계가 살아나다 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-14부-세계가-살아나다" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 14부: 세계가 살아나다&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 파트로 연결됩니다.</p>
<p><a href="/ko/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting.html">13부</a> 이후 우리에겐 조각 기능이 생겼습니다. 지형을 올리고, 동굴을 파고, 절벽을 매끄럽게 다듬는 일을 전부 실시간으로, 이음새가 멀쩡한 채로 할 수 있었죠. 하지만 세계는 기술 데모처럼 보였습니다. 디버그 색으로 칠해진 플랫 셰이딩, 와이어프레임 오버레이, 청크를 구분하려고 LOD 색을 입힌 회색 지오메트리. 편집은 할 수 있었습니다. 느낄 수는 없었죠.</p>
<p>세 개의 spike가 그것을 바꿨습니다. 아키텍처가 바뀐 게 아닙니다. 13부와 똑같은 파이프라인, 버퍼, 이음새 스티칭을 그대로 썼습니다. 우리는 그저 지형이 하나의 장소처럼 느껴지게 하는 레이어를 더했을 뿐입니다. 형태에 반응하는 표면, 그 표면 위에서 자라나는 생명, 그리고 그 위를 걷는 몸 말입니다.</p>
<p>&quot;기술적으로 작동한다&quot;와 &quot;여기 계속 있고 싶다&quot; 사이의 차이는 놀라울 만큼 작았습니다.</p>
<h2 id="절벽을-조각하면-바위로-변하는-걸-지켜보세요" tabindex="-1">절벽을 조각하면 바위로 변하는 걸 지켜보세요 <a class="header-anchor" href="#절벽을-조각하면-바위로-변하는-걸-지켜보세요" aria-label="Permalink to &quot;절벽을 조각하면 바위로 변하는 걸 지켜보세요&quot;"></a></h2>
<p>Spike 28은 좁은 질문 하나를 던졌습니다. 트라이플래너 매핑을 쓰는 4레이어 머티리얼이 컴퓨트로 생성한 지형 위에서 프레임 예산을 잡아먹지 않고 돌아갈 수 있을까? 답은 그렇다였지만, 흥미로운 부분은 그다음에 벌어진 일이었습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/28-multi-material/" title="Spike 28 Multi-Material Texturing" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/28-multi-material/" target="_blank">새 탭에서 Spike 28 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=28-multi-material">소스 보기</a></p>
<p>네 개의 절차적 텍스처(풀, 바위, 모래, 눈)를 시작 시점에 FBM 노이즈로 생성합니다. 외부 파일도, 에셋 파이프라인도 없이 그냥 수학과 <code>DataTexture</code> 하나만 씁니다. 머티리얼 가중치는 표면 자체에서 나옵니다. 경사와 고도죠. 수목한계선 아래의 평평한 지역은 풀이 됩니다. 가파른 면은 바위가 됩니다. 낮은 땅은 모래가 됩니다. 높은 봉우리는 눈이 됩니다. 각 원시 가중치는 경사와 고도에 <code>smoothstep</code>을 적용해 나오고, 그다음 프래그먼트마다 정규화되어 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.663ex;" xmlns="http://www.w3.org/2000/svg" width="10.014ex" height="2.36ex" role="img" focusable="false" viewBox="0 -750 4426.1 1043.1" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="munder"><g data-mml-node="mo"><path data-c="2211" d="M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1089,-285.4) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="msub" transform="translate(1549.6,0)"><g data-mml-node="mi"><path data-c="1D464" d="M580 385Q580 406 599 424T641 443Q659 443 674 425T690 368Q690 339 671 253Q656 197 644 161T609 80T554 12T482 -11Q438 -11 404 5T355 48Q354 47 352 44Q311 -11 252 -11Q226 -11 202 -5T155 14T118 53T104 116Q104 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Q21 293 29 315T52 366T96 418T161 441Q204 441 227 416T250 358Q250 340 217 250T184 111Q184 65 205 46T258 26Q301 26 334 87L339 96V119Q339 122 339 128T340 136T341 143T342 152T345 165T348 182T354 206T362 238T373 281Q402 395 406 404Q419 431 449 431Q468 431 475 421T483 402Q483 389 454 274T422 142Q420 131 420 107V100Q420 85 423 71T442 42T487 26Q558 26 600 148Q609 171 620 213T632 273Q632 306 619 325T593 357T580 385Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(749,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2870.3,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3926.1,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><munder><mo data-mjx-texclass="OP">∑</mo><mi>i</mi></munder><msub><mi>w</mi><mi>i</mi></msub><mo>=</mo><mn>1</mn></math></mjx-assistive-mml></mjx-container> 이 되며, 최종 색은 가중 혼합 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.663ex;" xmlns="http://www.w3.org/2000/svg" width="7.963ex" height="2.36ex" role="img" focusable="false" viewBox="0 -750 3519.5 1043.1" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="munder"><g data-mml-node="mo"><path data-c="2211" d="M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1089,-285.4) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="msub" transform="translate(1549.6,0)"><g data-mml-node="mi"><path data-c="1D464" d="M580 385Q580 406 599 424T641 443Q659 443 674 425T690 368Q690 339 671 253Q656 197 644 161T609 80T554 12T482 -11Q438 -11 404 5T355 48Q354 47 352 44Q311 -11 252 -11Q226 -11 202 -5T155 14T118 53T104 116Q104 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Q21 293 29 315T52 366T96 418T161 441Q204 441 227 416T250 358Q250 340 217 250T184 111Q184 65 205 46T258 26Q301 26 334 87L339 96V119Q339 122 339 128T340 136T341 143T342 152T345 165T348 182T354 206T362 238T373 281Q402 395 406 404Q419 431 449 431Q468 431 475 421T483 402Q483 389 454 274T422 142Q420 131 420 107V100Q420 85 423 71T442 42T487 26Q558 26 600 148Q609 171 620 213T632 273Q632 306 619 325T593 357T580 385Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(749,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mstyle" transform="translate(2592.6,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(2759.6,0)"><g data-mml-node="mi"><path data-c="1D450" d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(466,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><munder><mo data-mjx-texclass="OP">∑</mo><mi>i</mi></munder><msub><mi>w</mi><mi>i</mi></msub><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><msub><mi>c</mi><mi>i</mi></msub></math></mjx-assistive-mml></mjx-container> 일 뿐입니다. 정규화는 바이옴이 겹치는 곳에서 표면이 어두워지거나 과하게 밝아지는 걸 막아줍니다. 트라이플래너 매핑은 삼각형에 의미 있는 UV 좌표가 없는 MC 청크의 UV 투영을 처리합니다.</p>
<p>확신을 준 순간은 이랬습니다. 브러시로 지형을 올려 가파른 절벽을 만들면, 같은 프레임 안에 새 면 위로 바위 텍스처가 나타납니다. 다시 평평하게 누르면 풀이 그 표면을 되찾습니다. 머티리얼은 브러시에 대해 알지 못합니다. 그저 월드 좌표와 표면 법선을 읽을 뿐이고, 그건 지오메트리가 만들어질 때 쓴 것과 같은 데이터입니다. 조각에서 시각으로 이어지는 피드백 루프는 즉각적이고 스크립트로 짠 게 아닙니다.</p>
<p>Spike 8은 한 달 반 전에 WebGL 위의 정적 메시로 지형 머티리얼 비용을 테스트했습니다. Spike 28은 그것이 전체 조각 파이프라인을 깔고 있는 동적 컴퓨트 생성 지형 위에서도 작동한다는 걸 증명합니다. 우리는 이걸 예산에 잡아뒀지만, 모든 게 돌아가는 상태에서 60fps를 유지하는 걸 보는 건 그래도 안심이 됐습니다.</p>
<h2 id="풀-더미-8만-개와-동굴-천장-하나" tabindex="-1">풀 더미 8만 개와 동굴 천장 하나 <a class="header-anchor" href="#풀-더미-8만-개와-동굴-천장-하나" aria-label="Permalink to &quot;풀 더미 8만 개와 동굴 천장 하나&quot;"></a></h2>
<p>Spike 29는 게임 개발 본능이 발동한 지점입니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/29-vegetation/" title="Spike 29 Vegetation / Shader Grass" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/29-vegetation/" target="_blank">새 탭에서 Spike 29 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=29-vegetation">소스 보기</a></p>
<p>우리는 젤다의 전설 야생의 숨결 같은 풀을 원했습니다. 폴리곤 수가 아니라 그 느낌이요. 적절한 곳을 덮고, 바람에 흔들리고, 그 사이를 뛰어가고 싶게 만드는 풀 말입니다.</p>
<p>풀 더미 하나는 60도 각도로 교차하는 세 개의 쿼드로 이루어지고, 휘어짐을 위해 수직 세그먼트가 네 개 들어갑니다. 어느 각도에서 봐도 입체적으로 보이는 십자 모양이고 빌보드 트릭은 쓰지 않습니다. 청크당 <code>InstancedMesh</code> 하나, 세계 전체에 8만 더미, 통틀어 대략 240만 개의 풀 정점입니다.</p>
<p>중요한 건 배치입니다. CPU가 각 청크에 걸쳐 흔들린 격자(jittered grid)를 훑으면서 GPU 머티리얼 셰이더가 쓰는 것과 똑같은 경사/고도 로직을 평가합니다. 머티리얼 시스템이 &quot;풀&quot;이라고 하는 곳에 풀이 자랍니다. 바위나 모래가 우세한 곳에서는 밀도가 0으로 떨어집니다. 바닥에 깔린 <code>smoothstep</code> 가중치가 바이옴 경계에서 연속적인 그라데이션을 만들기 때문에 감쇠가 매끈합니다. 경계가 없으니 경계를 알아채지 못합니다.</p>
<p>그다음 작동할지 확신하지 못했던 일을 했습니다. SDF 표면 위의 풀이요. 스캐터 함수는 SDF 볼륨의 각 컬럼을 훑으면서 인접 복셀 사이의 영점 교차를 찾습니다. SDF가 음수에서 양수로 넘어가는 곳에 표면이 있습니다. 표면 법선은 필드의 정규화된 그래디언트 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -1.238ex;" xmlns="http://www.w3.org/2000/svg" width="9.256ex" height="3.445ex" role="img" focusable="false" viewBox="0 -975.7 4091.1 1522.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mover"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(300,16) translate(-250 0)"><path data-c="5E" d="M112 560L249 694L257 686Q387 562 387 560L361 531Q359 532 303 581L250 627L195 580Q182 569 169 557T148 538L140 532Q138 530 125 546L112 560Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(877.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(1933.6,0)"><g data-mml-node="mrow" transform="translate(573.6,485) scale(0.707)"><g data-mml-node="mi"><path data-c="2207" d="M46 676Q46 679 51 683H781Q786 679 786 676Q786 674 617 326T444 -26Q439 -33 416 -33T388 -26Q385 -22 216 326T46 676ZM697 596Q697 597 445 597T193 596Q195 591 319 336T445 80L697 596Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(833,0)"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mrow" transform="translate(220,-370.3) scale(0.707)"><g data-mml-node="mo"><path data-c="2016" d="M133 736Q138 750 153 750Q164 750 170 739Q172 735 172 250T170 -239Q164 -250 152 -250Q144 -250 138 -244L137 -243Q133 -241 133 -179T132 250Q132 731 133 736ZM329 739Q334 750 346 750Q353 750 361 744L362 743Q366 741 366 679T367 250T367 -178T362 -243L361 -244Q355 -250 347 -250Q335 -250 329 -239Q327 -235 327 250T329 739Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(500,0)"><path data-c="2207" d="M46 676Q46 679 51 683H781Q786 679 786 676Q786 674 617 326T444 -26Q439 -33 416 -33T388 -26Q385 -22 216 326T46 676ZM697 596Q697 597 445 597T193 596Q195 591 319 336T445 80L697 596Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1333,0)"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1929,0)"><path data-c="2016" d="M133 736Q138 750 153 750Q164 750 170 739Q172 735 172 250T170 -239Q164 -250 152 -250Q144 -250 138 -244L137 -243Q133 -241 133 -179T132 250Q132 731 133 736ZM329 739Q334 750 346 750Q353 750 361 744L362 743Q366 741 366 679T367 250T367 -178T362 -243L361 -244Q355 -250 347 -250Q335 -250 329 -239Q327 -235 327 250T329 739Z" style="stroke-width: 3;"/></g></g><rect width="1917.6" height="60" x="120" y="220"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mrow data-mjx-texclass="ORD"><mover><mi>n</mi><mo stretchy="false">^</mo></mover></mrow><mo>=</mo><mfrac><mrow><mi mathvariant="normal">∇</mi><mi>ϕ</mi></mrow><mrow><mo data-mjx-texclass="OPEN" fence="false" stretchy="false">‖</mo><mi mathvariant="normal">∇</mi><mi>ϕ</mi><mo data-mjx-texclass="CLOSE" fence="false" stretchy="false">‖</mo></mrow></mfrac></math></mjx-assistive-mml></mjx-container> 일 뿐이고, 복셀 차이로 계산합니다. 경사는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="11.911ex" height="2.398ex" role="img" focusable="false" viewBox="0 -810 5264.4 1060" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(892,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(1336,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(1780,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(2280,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2674,0)"><path data-c="2061" d="" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2674,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(3063,0)"><g data-mml-node="mover"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(300,16) translate(-250 0)"><path data-c="5E" d="M112 560L249 694L257 686Q387 562 387 560L361 531Q359 532 303 581L250 627L195 580Q182 569 169 557T148 538L140 532Q138 530 125 546L112 560Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(3885.2,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(4385.4,0)"><g data-mml-node="mover"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(300.6,16) translate(-250 0)"><path data-c="5E" d="M112 560L249 694L257 686Q387 562 387 560L361 531Q359 532 303 581L250 627L195 580Q182 569 169 557T148 538L140 532Q138 530 125 546L112 560Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(4875.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>arccos</mi><mo data-mjx-texclass="NONE">⁡</mo><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mover><mi>n</mi><mo stretchy="false">^</mo></mover></mrow><mo>⋅</mo><mrow data-mjx-texclass="ORD"><mover><mi>y</mi><mo stretchy="false">^</mo></mover></mrow><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>, 즉 수직으로부터의 각도입니다. 그게 충분히 완만하면 풀을 놓습니다.</p>
<p>Spike 27에서 SDF 브러시로 동굴을 팝니다. Spike 29로 돌아오면 동굴 천장 위에 풀이 자라고 있습니다. 스캐터 코드는 동굴이 뭔지 모릅니다. 그저 적절한 고도에서 적절한 경사를 가진 표면을 볼 뿐입니다. 그게 오픈 월드 시스템을 만드는 일을 만족스럽게 하는 종류의 창발적 동작입니다.</p>
<p>바람은 TSL 버텍스 셰이더 안의 사인파이고, 잎의 V 좌표로 변조되어 끝은 흔들리고 뿌리는 박혀 있습니다. V를 토글하면 약하게, 강하게, 끄기를 순환합니다. 바람은 전적으로 버텍스 셰이더 안에서 돌기 때문에 8만 더미 전부에서 동시에, CPU 비용 없이 작동합니다.</p>
<p>Spike 7은 5만 개의 풀 인스턴스를 테스트했고 우리는 한계에 부딪힐까 봐 긴장했습니다. Spike 29는 컴퓨트 지형, 이음새 스티칭, 멀티 머티리얼 텍스처링, 브러시 위에 8만 개를 돌립니다. 잎당 정점 수를 줄이는 것보다 <code>InstancedMesh</code> 드로우를 더 적게 묶는 게 여전히 더 중요합니다. Spike 7의 교훈은 그대로 통했습니다.</p>
<p>미뤄둔 게 하나 있습니다. 풀 아래를 조각해도 풀은 갱신되지 않습니다. 인스턴스 행렬은 스캐터 시점에 설정됩니다. 언덕을 골짜기로 조각하면 G를 눌러 다시 스캐터할 때까지 풀이 공중에 떠 있습니다. spike로는 충분합니다. 프로덕션에서는 더티 청크 재스캐터가 필요할 겁니다.</p>
<h2 id="첫-발자국" tabindex="-1">첫 발자국 <a class="header-anchor" href="#첫-발자국" aria-label="Permalink to &quot;첫 발자국&quot;"></a></h2>
<p>Spike 30은 제가 계속 다시 찾게 되는 것입니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/30-physics/" title="Spike 30 Terrain Physics" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/30-physics/" target="_blank">새 탭에서 Spike 30 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=30-physics">소스 보기</a></p>
<p>물리 라이브러리는 쓰지 않습니다. 120Hz 고정 타임스텝의 커스텀 캡슐입니다. 프로덕션 코드베이스는 웹 워커에서 Rapier를 씁니다(Spike 2가 지연 시간이 괜찮다는 걸 증명했죠). 하지만 이 spike는 충돌 쿼리 자체를 증명해야 했습니다. 캐릭터가 하이트맵 지형을 가로질러 걷고, 조각한 SDF 지형으로 올라서고, 바닥을 뚫고 떨어지지 않을 수 있을까?</p>
<p>핵심은 <code>terrainQuery(x, y, z)</code> 라는 함수입니다. 그 위치가 MC로 잠긴 청크 안에 들어가는지 확인합니다. 그렇다면 CPU SDF 미러를 삼선형 보간하고 그래디언트를 표면 법선으로 반환합니다. 아니라면 중앙 차분 법선을 쓰는 하이트맵 조회로 갑니다. 캐릭터는 자기가 어떤 지형 시스템 위에 서 있는지 모릅니다. 그저 바닥을 묻고 답을 받을 뿐입니다.</p>
<p>SDF 충돌은 어려울 거라 예상했던 부분입니다. 캡슐 둘레의 일곱 개 프로브 포인트(바닥, 중심, 위, 네 개의 기본 방향 오프셋). 위치 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.373ex" height="1.005ex" role="img" focusable="false" viewBox="0 -444 607 444" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D431" d="M227 0Q212 3 121 3Q40 3 28 0H21V62H117L245 213L109 382H26V444H34Q49 441 143 441Q247 441 265 444H274V382H246L281 339Q315 297 316 297Q320 297 354 341L389 382H352V444H360Q375 441 466 441Q547 441 559 444H566V382H471L355 246L504 63L545 62H586V0H578Q563 3 469 3Q365 3 347 0H338V62H366Q366 63 326 112T285 163L198 63L217 62H235V0H227Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">x</mi></mrow></math></mjx-assistive-mml></mjx-container> 의 프로브는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="8.519ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 3765.6 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(596,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(985,0)"><g data-mml-node="mi"><path data-c="1D431" d="M227 0Q212 3 121 3Q40 3 28 0H21V62H117L245 213L109 382H26V444H34Q49 441 143 441Q247 441 265 444H274V382H246L281 339Q315 297 316 297Q320 297 354 341L389 382H352V444H360Q375 441 466 441Q547 441 559 444H566V382H471L355 246L504 63L545 62H586V0H578Q563 3 469 3Q365 3 347 0H338V62H366Q366 63 326 112T285 163L198 63L217 62H235V0H227Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1592,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2258.8,0)"><path data-c="3C" d="M694 -11T694 -19T688 -33T678 -40Q671 -40 524 29T234 166L90 235Q83 240 83 250Q83 261 91 266Q664 540 678 540Q681 540 687 534T694 519T687 505Q686 504 417 376L151 250L417 124Q686 -4 687 -5Q694 -11 694 -19Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(3314.6,0)"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>ϕ</mi><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">x</mi></mrow><mo stretchy="false">)</mo><mo>&lt;</mo><mi>r</mi></math></mjx-assistive-mml></mjx-container> 일 때 침투하고 있으며, 침투 깊이는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="12.423ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 5491 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(780.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1836.6,0)"><path data-c="1D45F" d="M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2509.8,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(3510,0)"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4106,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(4495,0)"><g data-mml-node="mi"><path data-c="1D431" d="M227 0Q212 3 121 3Q40 3 28 0H21V62H117L245 213L109 382H26V444H34Q49 441 143 441Q247 441 265 444H274V382H246L281 339Q315 297 316 297Q320 297 354 341L389 382H352V444H360Q375 441 466 441Q547 441 559 444H566V382H471L355 246L504 63L545 62H586V0H578Q563 3 469 3Q365 3 347 0H338V62H366Q366 63 326 112T285 163L198 63L217 62H235V0H227Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5102,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>p</mi><mo>=</mo><mi>r</mi><mo>−</mo><mi>ϕ</mi><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">x</mi></mrow><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>, 밀어내는 방향은 필드 그래디언트 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -1.238ex;" xmlns="http://www.w3.org/2000/svg" width="9.256ex" height="3.445ex" role="img" focusable="false" viewBox="0 -975.7 4091.1 1522.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mover"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(300,16) translate(-250 0)"><path data-c="5E" d="M112 560L249 694L257 686Q387 562 387 560L361 531Q359 532 303 581L250 627L195 580Q182 569 169 557T148 538L140 532Q138 530 125 546L112 560Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(877.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(1933.6,0)"><g data-mml-node="mrow" transform="translate(573.6,485) scale(0.707)"><g data-mml-node="mi"><path data-c="2207" d="M46 676Q46 679 51 683H781Q786 679 786 676Q786 674 617 326T444 -26Q439 -33 416 -33T388 -26Q385 -22 216 326T46 676ZM697 596Q697 597 445 597T193 596Q195 591 319 336T445 80L697 596Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(833,0)"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mrow" transform="translate(220,-370.3) scale(0.707)"><g data-mml-node="mo"><path data-c="2016" d="M133 736Q138 750 153 750Q164 750 170 739Q172 735 172 250T170 -239Q164 -250 152 -250Q144 -250 138 -244L137 -243Q133 -241 133 -179T132 250Q132 731 133 736ZM329 739Q334 750 346 750Q353 750 361 744L362 743Q366 741 366 679T367 250T367 -178T362 -243L361 -244Q355 -250 347 -250Q335 -250 329 -239Q327 -235 327 250T329 739Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(500,0)"><path data-c="2207" d="M46 676Q46 679 51 683H781Q786 679 786 676Q786 674 617 326T444 -26Q439 -33 416 -33T388 -26Q385 -22 216 326T46 676ZM697 596Q697 597 445 597T193 596Q195 591 319 336T445 80L697 596Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1333,0)"><path data-c="1D719" d="M409 688Q413 694 421 694H429H442Q448 688 448 686Q448 679 418 563Q411 535 404 504T392 458L388 442Q388 441 397 441T429 435T477 418Q521 397 550 357T579 260T548 151T471 65T374 11T279 -10H275L251 -105Q245 -128 238 -160Q230 -192 227 -198T215 -205H209Q189 -205 189 -198Q189 -193 211 -103L234 -11Q234 -10 226 -10Q221 -10 206 -8T161 6T107 36T62 89T43 171Q43 231 76 284T157 370T254 422T342 441Q347 441 348 445L378 567Q409 686 409 688ZM122 150Q122 116 134 91T167 53T203 35T237 27H244L337 404Q333 404 326 403T297 395T255 379T211 350T170 304Q152 276 137 237Q122 191 122 150ZM500 282Q500 320 484 347T444 385T405 400T381 404H378L332 217L284 29Q284 27 285 27Q293 27 317 33T357 47Q400 66 431 100T475 170T494 234T500 282Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1929,0)"><path data-c="2016" d="M133 736Q138 750 153 750Q164 750 170 739Q172 735 172 250T170 -239Q164 -250 152 -250Q144 -250 138 -244L137 -243Q133 -241 133 -179T132 250Q132 731 133 736ZM329 739Q334 750 346 750Q353 750 361 744L362 743Q366 741 366 679T367 250T367 -178T362 -243L361 -244Q355 -250 347 -250Q335 -250 329 -239Q327 -235 327 250T329 739Z" style="stroke-width: 3;"/></g></g><rect width="1917.6" height="60" x="120" y="220"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mrow data-mjx-texclass="ORD"><mover><mi>n</mi><mo stretchy="false">^</mo></mover></mrow><mo>=</mo><mfrac><mrow><mi mathvariant="normal">∇</mi><mi>ϕ</mi></mrow><mrow><mo data-mjx-texclass="OPEN" fence="false" stretchy="false">‖</mo><mi mathvariant="normal">∇</mi><mi>ϕ</mi><mo data-mjx-texclass="CLOSE" fence="false" stretchy="false">‖</mo></mrow></mfrac></math></mjx-assistive-mml></mjx-container> 입니다. 캡슐이 표면으로 다시 들어가는 걸 막기 위해, 속도를 투영해 안쪽 성분을 상쇄합니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="17.018ex" height="2.398ex" role="img" focusable="false" viewBox="0 -810 7521.9 1060" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D42F" d="M401 444Q413 441 495 441Q568 441 574 444H580V382H510L409 156Q348 18 339 6Q331 -4 320 -4Q318 -4 313 -4T303 -3H288Q273 -3 264 12T221 102Q206 135 197 156L96 382H26V444H34Q49 441 145 441Q252 441 270 444H279V382H231L284 264Q335 149 338 149Q338 150 389 264T442 381Q442 382 418 382H394V444H401Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(640,413) scale(0.707)"><path data-c="2032" d="M79 43Q73 43 52 49T30 61Q30 68 85 293T146 528Q161 560 198 560Q218 560 240 545T262 501Q262 496 260 486Q259 479 173 263T84 45T79 43Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1162.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(2218,0)"><g data-mml-node="mi"><path data-c="1D42F" d="M401 444Q413 441 495 441Q568 441 574 444H580V382H510L409 156Q348 18 339 6Q331 -4 320 -4Q318 -4 313 -4T303 -3H288Q273 -3 264 12T221 102Q206 135 197 156L96 382H26V444H34Q49 441 145 441Q252 441 270 444H279V382H231L284 264Q335 149 338 149Q338 150 389 264T442 381Q442 382 418 382H394V444H401Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3047.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4047.5,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(4436.5,0)"><g data-mml-node="mi"><path data-c="1D42F" d="M401 444Q413 441 495 441Q568 441 574 444H580V382H510L409 156Q348 18 339 6Q331 -4 320 -4Q318 -4 313 -4T303 -3H288Q273 -3 264 12T221 102Q206 135 197 156L96 382H26V444H34Q49 441 145 441Q252 441 270 444H279V382H231L284 264Q335 149 338 149Q338 150 389 264T442 381Q442 382 418 382H394V444H401Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5265.7,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(5765.9,0)"><g data-mml-node="mover"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(300,16) translate(-250 0)"><path data-c="5E" d="M112 560L249 694L257 686Q387 562 387 560L361 531Q359 532 303 581L250 627L195 580Q182 569 169 557T148 538L140 532Q138 530 125 546L112 560Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(6365.9,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(6754.9,0)"><g data-mml-node="mspace"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(6921.9,0)"><g data-mml-node="mover"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(300,16) translate(-250 0)"><path data-c="5E" d="M112 560L249 694L257 686Q387 562 387 560L361 531Q359 532 303 581L250 627L195 580Q182 569 169 557T148 538L140 532Q138 530 125 546L112 560Z" style="stroke-width: 3;"/></g></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><msup><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">v</mi></mrow><mo data-mjx-alternate="1">′</mo></msup><mo>=</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">v</mi></mrow><mo>−</mo><mo stretchy="false">(</mo><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">v</mi></mrow><mo>⋅</mo><mrow data-mjx-texclass="ORD"><mover><mi>n</mi><mo stretchy="false">^</mo></mover></mrow><mo stretchy="false">)</mo><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mrow data-mjx-texclass="ORD"><mover><mi>n</mi><mo stretchy="false">^</mo></mover></mrow></math></mjx-assistive-mml></mjx-container><p>이렇게 하면 표면을 따라 미끄러지는 성분만 남습니다. 물리 엔진이 아닙니다. 지오메트리 쿼리와 단순한 반응입니다. 하지만 형태마다 특수 케이스 코드를 하나도 안 쓰고 동굴, 돌출부, 조각한 터널을 다 처리합니다. 10초 전에 판 동굴로 걸어 들어가면 캡슐이 천장 윤곽을 정확히 따라갑니다.</p>
<p>이동 모델은 실용적으로 시작했다가 재미있어졌습니다. 걷기, 달리기, 전력 질주, 점프, 45도 이상에서의 경사 미끄러짐. 그다음 야생의 숨결식 패러글라이더를 넣었더니 spike가 닫고 싶지 않은 무언가로 변했습니다.</p>
<p>공중에서 스페이스를 누릅니다. 중력이 -30에서 -4로 떨어집니다. 낙하 속도는 -3에서 한계가 잡힙니다. 캡슐에서 델타윙 메시가 스케일 보간으로 펼쳐집니다. 왼쪽으로 기울이면 날개가 기웁니다. 캡슐이 향하는 방향이 속도 벡터 쪽으로 자동 정렬되어 항상 가는 곳을 바라봅니다. 스페이스를 놓으면 떨어집니다. 땅에 닿으면 다시 달리고 있습니다.</p>
<p>카메라는 3인칭으로 당겨집니다(P로 토글). 요(yaw) 스무딩과 함께 플레이어 뒤를 따라옵니다. 플레이어에서 카메라까지 레이마치가 20스텝으로 지형을 테스트합니다. 동굴로 날아 들어가면 카메라 암이 바위를 뚫고 들어가는 대신 매끄럽게 짧아집니다. 반대편으로 나오면 다시 늘어납니다.</p>
<p>이 spike를 가치 있게 만든 순간이 여기 있습니다. 하이트맵 브러시로 높은 절벽을 조각합니다. 3인칭 카메라로 전환합니다. 가장자리까지 달립니다. 점프합니다. 글라이더를 펼칩니다. 방금 조각한 지형 위로 왼쪽으로 기울이는데, 아래에는 Spike 29에서 키운 풀이 흔들리고, 절벽 면에는 Spike 28의 바위 텍스처가 깔려 있고, 모든 청크 경계에서 Transvoxel 이음새가 버티고 있습니다. 반대편에 착지합니다. 하나의 브라우저 탭 안에서 모든 게 함께 작동합니다.</p>
<h2 id="내-발밑을-조각하기" tabindex="-1">내 발밑을 조각하기 <a class="header-anchor" href="#내-발밑을-조각하기" aria-label="Permalink to &quot;내 발밑을 조각하기&quot;"></a></h2>
<p>확신하지 못했던 게 하나 있습니다. 캐릭터가 서 있는 지형을 조각하면 어떻게 될까? 하이트맵 변경은 <code>terrainQuery()</code>가 CPU 버퍼를 직접 읽기 때문에 즉시 전파됩니다. SDF 변경은 CPU SDF 미러를 통해 전파됩니다. 캡슐은 다음 물리 틱에 침투를 해소하는데, 120Hz에서 그건 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.816ex;" xmlns="http://www.w3.org/2000/svg" width="9.304ex" height="2.773ex" role="img" focusable="false" viewBox="0 -864.9 4112.2 1225.5" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="mn" transform="translate(573.6,394) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g><rect width="1260.7" height="60" x="120" y="220"/></g><g data-mml-node="mo" transform="translate(1778.4,0)"><path data-c="2248" d="M55 319Q55 360 72 393T114 444T163 472T205 482Q207 482 213 482T223 483Q262 483 296 468T393 413L443 381Q502 346 553 346Q609 346 649 375T694 454Q694 465 698 474T708 483Q722 483 722 452Q722 386 675 338T555 289Q514 289 468 310T388 357T308 404T224 426Q164 426 125 393T83 318Q81 289 69 289Q55 289 55 319ZM55 85Q55 126 72 159T114 210T163 238T205 248Q207 248 213 248T223 249Q262 249 296 234T393 179L443 147Q502 112 553 112Q609 112 649 141T694 220Q694 249 708 249T722 217Q722 153 675 104T555 55Q514 55 468 76T388 123T308 170T224 192Q164 192 125 159T83 84Q80 55 69 55Q55 55 55 85Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2834.2,0)"><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" style="stroke-width: 3;"/><path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" transform="translate(778,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mfrac><mn>1</mn><mn>120</mn></mfrac><mo>≈</mo><mn>8.3</mn></math></mjx-assistive-mml></mjx-container> ms 안입니다.</p>
<p>그냥 작동합니다. 플레이어 아래 땅을 올리면 함께 올라갑니다. 땅을 파내면 떨어집니다. 특별한 처리는 없습니다. 물리가 충분히 빠르게 돌아서 단일 프레임의 지형 변경이 큰 침투를 만들지 않습니다. 이건 타임스텝을 120Hz로 고른 데서 온 행복한 우연이었습니다. 우리는 매끄러운 이동을 위해 그걸 골랐는데, 덤으로 지형 편집이 안전해졌습니다.</p>
<h2 id="spike-30개를-지나" tabindex="-1">spike 30개를 지나 <a class="header-anchor" href="#spike-30개를-지나" aria-label="Permalink to &quot;spike 30개를 지나&quot;"></a></h2>
<p>우리는 이 시리즈를 평평한 하이트맵과 큐브 500개로 시작했습니다. 이제는 입체적인 동굴이 있는 조각된 지형, Transvoxel 이음새 스티칭, 표면 형태에 반응하는 멀티 머티리얼 텍스처링, 바람에 흔들리는 풀 더미 8만 개, 그리고 그 위를 걷고 전력 질주하고 점프하고 활공하는 캐릭터를 갖췄습니다.</p>
<p>이 중 무엇도 아직 프로덕션에 들어가지 않았습니다. <code>world/client/</code> 코드베이스는 여전히 단순한 하이트맵 청크로 WebGL을 돌립니다. 이 30개 spike의 모든 것은 독립적인 HTML 페이지 안에 살고 있습니다. 다음은 통합 작업입니다. <code>WebGPURenderer</code>로 마이그레이션하고, 하이브리드 HM/MC 정책을 청크 매니저에 연결하고, 브러시와 머티리얼 시스템을 멀티플레이어에 잇는 일이요.</p>
<p>하지만 이제 렌더링 시스템은 위험이 아닙니다. 열린 질문은 데이터 흐름에 관한 것입니다. 편집 영속성, 브러시 스트로크의 네트워크 동기화, 협업 조각. 삼각형 사이가 아니라 플레이어 사이에서 벌어지는 것들이죠.</p>
<p>1부부터 이 시리즈를 따라오셨다면, 지저분한 부분까지 함께해 주셔서 고맙습니다. 방금 발견하셨다면 <a href="/ko/blog/2026-02-25-open-world-browser-part-01-risk-first.html">1부</a>로 돌아가세요. 잘못 든 길에 교훈이 있습니다.</p>
<h2 id="이-챕터에서-언급한-기술" tabindex="-1">이 챕터에서 언급한 기술 <a class="header-anchor" href="#이-챕터에서-언급한-기술" aria-label="Permalink to &quot;이 챕터에서 언급한 기술&quot;"></a></h2>
<p><strong>TSL (Three Shading Language).</strong> WebGPU 렌더러를 위한 Three.js의 노드 기반 셰이더 시스템입니다. 머티리얼은 자바스크립트의 함수 합성을 써서 노드(<code>positionWorld</code>, <code>normalWorld</code>, <code>smoothstep</code>, <code>triplanarTexture</code>)로 구성됩니다. 셰이더 그래프는 런타임에 WGSL로 컴파일됩니다. TSL은 WebGPU 타깃에서 원시 GLSL <code>ShaderMaterial</code>을 대체하고, 표준 Three.js 머티리얼 기능(라이트, 그림자, 안개)과 커스텀 프래그먼트별 로직 사이의 상호 운용을 제공합니다.</p>
<p><strong>트라이플래너 매핑.</strong> 텍스처를 세 번(XY, XZ, YZ 평면) 샘플링하고 표면 법선 방향에 따라 혼합하는 텍스처 투영 기법입니다. 임의의 메시 지오메트리에서 UV 늘어짐을 없애는데, 이는 삼각형에 의미 있는 UV 좌표가 없는 마칭 큐브 출력에 핵심적입니다. TSL은 <code>triplanarTexture()</code>를 내장 노드로 제공합니다.</p>
<p><strong>교차 쿼드 잎으로 만든 인스턴스 식생.</strong> 풀 더미 하나는 60도 각도로 교차하는 쿼드 3개로, 어느 시점에서 봐도 입체적으로 보이게 합니다. 쿼드당 수직 세그먼트 4개가 바람 애니메이션을 위한 매끄러운 휘어짐을 가능하게 합니다. 전체 필드는 청크당 단일 <code>InstancedMesh</code>로 렌더링됩니다. 용량은 25% 초과 할당되어, 지형을 편집할 때 GPU 버퍼를 재할당하지 않고도 새 인스턴스가 예약된 슬롯을 채울 수 있습니다. <a href="/ko/guides/landscape-generation-browser.html#vegetation-and-foliage">식생에 관한 우리 랜드스케이프 생성 가이드</a>를 보세요.</p>
<p><strong>캡슐 대 SDF 충돌.</strong> 물리 엔진 없이 입체 지형에 대한 캐릭터 충돌입니다. 캡슐을 SDF에 대해 여러 지점에서 프로브합니다. 필드 값이 캡슐 반지름보다 작은 곳에서, 그래디언트가 바깥쪽 법선을 주고 그 차이가 침투 깊이를 줍니다. 이는 형태별 코드 없이 동굴, 돌출부, 터널을 처리합니다. <a href="/ko/guides/landscape-generation-browser.html#physics-on-sdf-terrain">SDF 지형 충돌</a>을 보세요.</p>
<p><strong>고정 타임스텝 캐릭터 컨트롤러.</strong> 물리는 프레임 레이트와 무관하게 120Hz로 스텝을 밟으며, 실제 시간을 누적해 고정 크기 스텝으로 소비합니다. 최대 서브스텝 횟수가 느린 프레임에서 죽음의 나선(spiral-of-death)을 막습니다. 그라운드 스내핑이 경사 이동 중에 캡슐을 붙여둡니다. 고정 타임스텝은 향후 멀티플레이어 리플레이를 위한 결정론적 동작을 보장합니다.</p>
<hr>
<p>29부 중 14부.
이전: <a href="/ko/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting.html">13부 - 지형 조각과 수학 함수의 죽음</a>
다음: <a href="/ko/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water.html">15부 - 베이스라인을 교체한 다음 동기화하기</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 15부: 기준선을 교체하고, 그다음 동기화하기]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water</link>
            <guid>https://app.cinevva.com/ko/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water</guid>
            <pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[스파이크 31-32는 기존 월드를 가장 좋은 스파이크로 교체하기로 결정하고, 브러시 파라미터 재생 방식 멀티플레이를 증명한 뒤 수영이 가능한 바다를 추가했습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-15부-기준선을-교체하고-그다음-동기화하기" tabindex="-1">브라우저에서 오픈 월드 만들기, 15부: 기준선을 교체하고, 그다음 동기화하기 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-15부-기준선을-교체하고-그다음-동기화하기" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 15부: 기준선을 교체하고, 그다음 동기화하기&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 보시나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. 스파이크가 무엇인지 설명하고 모든 부분을 링크해 두었습니다.</p>
<p>앞선 열네 개 부분은 스파이크 1부터 30까지를 다뤘습니다. 그 흐름은 실시간으로 조각할 수 있는 지형 시스템과, 그 위를 걷고 활공하고 떨어질 수 있는 캐릭터로 마무리됐습니다. 이번 부분은 스파이크 31에서 시리즈를 다시 이어갑니다. 그리고 우리가 가장 먼저 결정해야 했던 건 기술적인 게 아니었습니다. 그 수많은 스파이크 코드를 어떻게 할 것인가였습니다.</p>
<h2 id="교체하라-백포트하지-마라-는-결정" tabindex="-1">&quot;교체하라, 백포트하지 마라&quot;는 결정 <a class="header-anchor" href="#교체하라-백포트하지-마라-는-결정" aria-label="Permalink to &quot;&quot;교체하라, 백포트하지 마라&quot;는 결정&quot;"></a></h2>
<p>우리에겐 각각 하나의 고립된 개념을 증명하는 독립 HTML 파일 30개가 있었고, 통합은 전혀 되어 있지 않았습니다. 프로덕션의 <code>world/client/</code>는 여전히 옛 스택이었습니다. WebGL, 단순한 heightmap, 75줄짜리 캐릭터 컨트롤러, 메시지 타입이 아홉 개인 MessagePack 프로토콜. 편집도, WebGPU도, 머티리얼도, 식생도 없었습니다.</p>
<p>뻔한 계획은 스파이크 결과물을 그 프로덕션 코드베이스에 하나씩 백포트하는 것이었습니다. 우리는 그걸 버렸습니다. 스파이크 30은 이미 <code>world/client/</code>가 도달했던 그 어떤 것보다도 나은 지형, 물리, 머티리얼, 식생, 카메라를 갖고 있었습니다. 옛 WebGL 코드에 백포트한다는 건 처음부터 끝까지 그 코드와 싸운다는 뜻이었습니다. 그래서 우리는 결정을 내렸습니다. 가장 성공적인 스파이크로 월드 구현을 교체하고 거기서부터 앞으로 만들어가기로요. 스파이크 30이 새 기준선이 되었고, <code>world/client/</code>는 죽은 코드가 됐습니다.</p>
<p>이 결정이 남은 작업을 다시 짰습니다. &quot;멋진 싱글플레이어 기술 데모&quot;에서 &quot;제품&quot;으로 가려면 멀티플레이, 영속성, 무한 월드 스트리밍, 오브젝트 배치가 필요했습니다. 멀티플레이 지형 동기화를 먼저 했습니다. 그것이 아키텍처를 강제하는 작업이기 때문입니다. 그것이 답하는 질문은 묻기는 쉽고 틀리면 비싼 질문입니다. 플레이어 A가 조각할 때, 실제로 회선을 타고 가는 건 무엇인가?</p>
<h2 id="픽셀-동기화가-아닌-브러시-파라미터-재생" tabindex="-1">픽셀 동기화가 아닌 브러시 파라미터 재생 <a class="header-anchor" href="#픽셀-동기화가-아닌-브러시-파라미터-재생" aria-label="Permalink to &quot;픽셀 동기화가 아닌 브러시 파라미터 재생&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/31-multiplayer-sync/" title="Spike 31 Multiplayer Terrain Sync" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/31-multiplayer-sync/" target="_blank">새 탭에서 Spike 31 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=31-multiplayer-sync">소스 보기</a></p>
<p>네트워크 코드를 한 줄 쓰기 전에, 우리는 브러시 스트로크 하나가 정확히 무엇을 하는지 따라가 봤습니다. heightmap 브러시는 커서 주변 반경을 CPU의 <code>Float32Array</code>에서 돌면서 smoothstep 감쇠를 적용하고, 더하거나 빼거나 부드럽게 하거나 평평하게 만듭니다. SDF 브러시는 복셀 구체 위에서 3D로 같은 일을 합니다. 두 경로 모두 순수한 CPU 배열 연산입니다. 루프 안에 GPU 컴퓨트도 없고, 무작위성도 없고, 비결정적 부동소수점도 없습니다. 같은 입력 배열에 같은 파라미터면 모든 기계에서 같은 출력입니다.</p>
<p>이게 비결의 전부입니다. 우리는 편집된 지형을 보내지 않습니다. 브러시 파라미터를, 스트로크 틱당 56바이트를 보내고, 모든 클라이언트가 같은 결정적 함수를 재생합니다. 동기화 프로토콜은 네 가지 메시지 타입입니다. 피어 발견, 브러시 메시지 <code>{op, wx, wy, wz, radius, strength, flattenTarget}</code>, 그리고 20Hz의 플레이어 위치 메시지.</p>
<p>이 스파이크에서는 서버를 아예 건너뛰고 <code>BroadcastChannel</code>을 썼습니다. 동일 출처 탭 간 메시징을 위한 브라우저 API입니다. 탭 두 개를 열면 서로 통신합니다. 인프라는 전혀 없습니다. 이렇게 하면 동기화 문제를 지연, 인증, Durable Object 배선에서 떼어내 격리할 수 있습니다. 파라미터 재생이 탭 사이에서 수렴한다면, WebSocket 너머에서도 수렴할 겁니다.</p>
<p>재생이 어긋날 수 있는 유일한 지점은 순서에 의존하는 연산입니다. 올리기와 내리기는 교환 가능해서, <code>val + strength * falloff</code>는 누가 먼저 적용했든 같은 자리에 떨어집니다. 부드럽게 하기와 평평하게 하기는 이웃 값을 읽기 때문에, 두 클라이언트가 정확히 같은 지점을 같은 순간에 부드럽게 하면 틱당 수천분의 1밀리미터씩 어긋날 수 있습니다. 실제로는 그런 일이 절대 발생하지 않고, 프로덕션에서의 수정 방법은 이미 분명합니다. 편집을 DO로 라우팅하고, DO가 단조 증가하는 시퀀스 번호를 할당하게 하고, 클라이언트에서는 낙관적으로 적용하고, 권위 있는 시퀀스가 다르면 순서를 바로잡으면 됩니다. 전형적인 낙관적 동시성 제어이고, 어차피 DO는 자연스러운 직렬화 지점입니다.</p>
<h2 id="계속-사라지던-피어-캡슐" tabindex="-1">계속 사라지던 피어 캡슐 <a class="header-anchor" href="#계속-사라지던-피어-캡슐" aria-label="Permalink to &quot;계속 사라지던 피어 캡슐&quot;"></a></h2>
<p>편집은 첫 시도에 동기화됐습니다. 원격 플레이어의 캡슐은 아니었습니다. 다른 탭에서 있다가 없다가 깜빡였고, 그것이 견고하게 남도록 만드는 데 서로 다른 버그 세 개를 잡아야 했습니다.</p>
<p>캡슐은 월드 원점에서 스폰됐는데, 그곳은 지형 아래에 묻혀 있습니다. <code>join</code> 메시지가 어떤 위치 데이터보다도 먼저 도착하기 때문입니다. 수정: 숨긴 상태로 시작하고 첫 위치 업데이트에서 드러나게 합니다. 위치 브로드캐스트는 렌더 루프 안에 있었는데, Chrome은 포커스가 없는 탭에서 <code>requestAnimationFrame</code>을 스로틀링합니다. 그래서 다른 탭의 만료 검사가 피어를 거둬가고 다음 메시지가 그것을 다시 만들어냈습니다. 수정: 브로드캐스트를 <code>setInterval</code>로 옮깁니다. 이건 보이는 탭에 대해 스로틀링되지 않습니다. 그리고 만료 타임아웃이 5초로 너무 공격적이어서 어떤 GC 일시정지에도 걸렸습니다. 수정: 30초로 올리고 정상 종료에는 깔끔한 <code>leave</code> 메시지에 의존합니다.</p>
<h2 id="영속성과-늦은-합류-같은-포맷" tabindex="-1">영속성과 늦은 합류, 같은 포맷 <a class="header-anchor" href="#영속성과-늦은-합류-같은-포맷" aria-label="Permalink to &quot;영속성과 늦은 합류, 같은 포맷&quot;"></a></h2>
<p>우리는 영속성을 새 스파이크를 띄우는 대신 같은 스파이크 안에 접어 넣었습니다. 목적지가 IndexedDB든 다른 탭이든 직렬화 포맷이 동일하기 때문입니다. 스냅샷 하나는 전체 heightmap(129×129 <code>Float32Array</code>, 약 66 KB)에, 편집된 SDF 청크(각 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="3.25ex" height="2.003ex" role="img" focusable="false" viewBox="0 -863.3 1436.6 885.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>65</mn><mn>3</mn></msup></math></mjx-assistive-mml></mjx-container>, 약 1.1 MB)만, 그리고 marching-cubes 모드로 잠긴 청크 ID 목록을 더한 것입니다. 디바운스된 저장이 마지막 편집 2초 뒤에 IndexedDB에 씁니다. 로드 시에는 절차적 지형이 동기적으로 생성되고, 그다음 저장된 상태가 첫 의미 있는 프레임 전에 그것을 덮어씁니다. 늦은 합류는 정확히 같은 바이트를 재사용합니다. 새 탭이 합류하면 편집이 있는 기존 탭이 자기 상태를 직렬화해 새로 온 쪽을 겨냥해 보내고, 5분 전에 당신이 조각한 산이 그들의 화면에 나타납니다.</p>
<p>첫 영속성 테스트가 괜찮은 순서 버그를 드러냈습니다. 풀은 초기화 때 절차적 높이를 써서 동기적으로 흩뿌려지는데, IndexedDB 복원은 비동기이고 그 후에 heightmap을 덮어씁니다. 그래서 모든 풀잎이 공중에 뜨거나 가라앉았습니다. 수정은 <code>refreshAllGrass()</code> 패스로, 각 인스턴스 아래의 높이를 다시 샘플링하고 이제 나쁜 경사나 고도에 놓인 풀잎을 숨깁니다. 같은 함수가 로드와 늦은 합류 둘 다를 맡습니다.</p>
<h2 id="경사-연속극" tabindex="-1">경사 연속극 <a class="header-anchor" href="#경사-연속극" aria-label="Permalink to &quot;경사 연속극&quot;"></a></h2>
<p>조각된 지형은 매끈한 절차적 기준선보다 거칠어서, 옛 지형이 절대 일으킬 수 없던 물리 버그 세 개를 드러냈습니다. 똑바로 언덕을 올라가면 캡슐이 옆으로 미끄러졌습니다. 원인은 이동을 지면에 접하도록 유지하려던 속도 투영이었는데, 법선의 수평 성분만으로 작성되어 있었습니다. 법선이 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="15.967ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 7057.3 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(389,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1167,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/><path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" transform="translate(778,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2445,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2889.7,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/><path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="39" d="M352 287Q304 211 232 211Q154 211 104 270T44 396Q42 412 42 436V444Q42 537 111 606Q171 666 243 666Q245 666 249 666T257 665H261Q273 665 286 663T323 651T370 619T413 560Q456 472 456 334Q456 194 396 97Q361 41 312 10T208 -22Q147 -22 108 7T68 93T121 149Q143 149 158 135T173 96Q173 78 164 65T148 49T135 44L131 43Q131 41 138 37T164 27T206 22H212Q272 22 313 86Q352 142 352 280V287ZM244 248Q292 248 321 297T351 430Q351 508 343 542Q341 552 337 562T323 588T293 615T246 625Q208 625 181 598Q160 576 154 546T147 441Q147 358 152 329T172 282Q197 248 244 248Z" transform="translate(778,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4167.7,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4612.3,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(5390.3,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/><path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" transform="translate(778,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6668.3,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mo>−</mo><mn>0.3</mn><mo>,</mo><mn>0.9</mn><mo>,</mo><mo>−</mo><mn>0.3</mn><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>인 대각선 경사에서 북쪽으로 걸으면 난데없이 옆 방향 속도가 주입됐습니다. 지면 스냅이 이미 플레이어를 표면에 붙여두기 때문에, 우리는 그냥 그 투영을 지웠습니다.</p>
<p>드리프트는 두 번째 원인에서 계속 이어졌습니다. SDF 충돌 프로브는 침투 깊이만큼 그래디언트 방향으로 몸을 밀어냅니다. 어떤 경사에서든 그래디언트는 수평 성분을 가지므로, 15° 경사에서 0.1 m 침투는 한 스텝당 옆으로 약 0.026 m를 밀고, 120Hz에서는 대략 3 m/s의 보이지 않는 드리프트가 됩니다. 수정: 경사에 따라 반응을 나눕니다. 걸을 수 있는 지면(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.874ex;" xmlns="http://www.w3.org/2000/svg" width="5.379ex" height="2.444ex" role="img" focusable="false" viewBox="0 -694 2377.5 1080.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mtext"><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(892,0)" style="stroke-width: 3;"/><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(1392,0)" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1981,-241.4) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mtext>grad</mtext><mi>y</mi></msub></math></mjx-assistive-mml></mjx-container>가 걷기 임계값 위)에서는 밀어내기가 수직 방향만입니다. 벽과 절벽에서는 완전한 3D 밀어내기를 유지합니다. 거기가 바로 튕겨나가고 싶은 곳이기 때문입니다. 우리는 또 걸을 수 있는 한계를 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="6.798ex" height="1.667ex" role="img" focusable="false" viewBox="0 -715 3004.7 737" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(444,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(944,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1338,0)"><path data-c="2061" d="" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1504.7,0)"><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(2504.7,0)"><g data-mml-node="mo"><path data-c="B0" d="M147 628Q147 669 179 692T244 715Q298 715 325 689T352 629Q352 592 323 567T249 542Q202 542 175 567T147 628ZM313 628Q313 660 300 669T259 678H253Q248 678 242 678T234 679Q217 679 207 674T192 659T188 644T187 629Q187 600 198 590Q210 579 250 579H265Q279 579 288 581T305 595T313 628Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>cos</mi><mo data-mjx-texclass="NONE">⁡</mo><mn>45</mn><mrow data-mjx-texclass="ORD"><mo data-mjx-pseudoscript="true">°</mo></mrow></math></mjx-assistive-mml></mjx-container>에서 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="6.798ex" height="1.667ex" role="img" focusable="false" viewBox="0 -715 3004.7 737" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(444,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(944,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1338,0)"><path data-c="2061" d="" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1504.7,0)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(2504.7,0)"><g data-mml-node="mo"><path data-c="B0" d="M147 628Q147 669 179 692T244 715Q298 715 325 689T352 629Q352 592 323 567T249 542Q202 542 175 567T147 628ZM313 628Q313 660 300 669T259 678H253Q248 678 242 678T234 679Q217 679 207 674T192 659T188 644T187 629Q187 600 198 590Q210 579 250 579H265Q279 579 288 581T305 595T313 628Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>cos</mi><mo data-mjx-texclass="NONE">⁡</mo><mn>60</mn><mrow data-mjx-texclass="ORD"><mo data-mjx-pseudoscript="true">°</mo></mrow></math></mjx-assistive-mml></mjx-container>로 올려서, 브러시로 만든 언덕이 젤다 야생의 숨결에서처럼 오를 만하게 느껴지도록 했습니다.</p>
<p>세 번째 버그는 청크 경계에서 캡슐을 얼어붙게 했습니다. 충돌 프로브가 단일 청크의 SDF만 샘플링하다가 프로브가 이웃으로 넘어가면 &quot;공중 깊숙이&quot;라는 센티넬 값을 받았기 때문입니다. 수정은 <code>sdfSampleWorld(wx, wy, wz)</code>와 <code>sdfGradientWorld(...)</code>였습니다. 이들은 임의의 월드 위치에 대해 올바른 청크를 찾고, SDF가 없는 곳에서는 heightmap 거리 추정으로 폴백합니다. 이제 SDF에서 heightmap으로의 충돌 전환은 연속적입니다.</p>
<h2 id="물이-월드를-완성한다" tabindex="-1">물이 월드를 완성한다 <a class="header-anchor" href="#물이-월드를-완성한다" aria-label="Permalink to &quot;물이 월드를 완성한다&quot;"></a></h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/32-water-swimming/" title="Spike 32 Water and Swimming" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/32-water-swimming/" target="_blank">새 탭에서 Spike 32 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=32-water-swimming">소스 보기</a></p>
<p>여기까지의 모든 스파이크는 &quot;물 위의 땅&quot;이었습니다. 스파이크 32는 바다를 추가했고, 그와 함께 새 이동 동사를 추가했습니다. 우리는 대략 8에서 58까지 범위인 지형에서 수위를 22로 설정했습니다. 이렇게 하면 낮은 골짜기가 잠기고, 물가에 해변이 남고, 놀기에 충분한 마른 땅이 남습니다.</p>
<p>수면은 TSL로 만든 <code>MeshStandardNodeMaterial</code>로, 지형과 같은 노드 방식입니다. 서로 다른 주파수의 겹쳐진 사인파 세 개가 정점을 변위시키고, 표면 법선은 메시 법선이 아니라 그 파동들의 해석적 코사인 도함수에서 나옵니다. 색은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="4.526ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 2000.7 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="5B" d="M118 -250V750H255V710H158V-210H255V-250H118Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(278,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(778,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1222.7,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1722.7,0)"><path data-c="5D" d="M22 710V750H159V-250H22V-210H119V710H22Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mn>0</mn><mo>,</mo><mn>1</mn><mo stretchy="false">]</mo></math></mjx-assistive-mml></mjx-container>로 클램프된 깊이 추정값 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="24.614ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 10879.3 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(389,0)"><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(278,0)" style="stroke-width: 3;"/><path data-c="76" d="M338 431Q344 429 422 429Q479 429 503 431H508V385H497Q439 381 423 345Q421 341 356 172T288 -2Q283 -11 263 -11Q244 -11 239 -2Q99 359 98 364Q93 378 82 381T43 385H19V431H25L33 430Q41 430 53 430T79 430T104 429T122 428Q217 428 232 431H240V385H226Q187 384 184 370Q184 366 235 234L286 102L377 341V349Q377 363 367 372T349 383T335 385H331V431H338Z" transform="translate(722,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1250,0)" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(1694,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2583.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(3583.4,0)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4295.7,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(5295.9,0)"><path data-c="77" d="M90 368Q84 378 76 380T40 385H18V431H24L43 430Q62 430 84 429T116 428Q206 428 221 431H229V385H215Q177 383 177 368Q177 367 221 239L265 113L339 328L333 345Q323 374 316 379Q308 384 278 385H258V431H264Q270 428 348 428Q439 428 454 431H461V385H452Q404 385 404 369Q404 366 418 324T449 234T481 143L496 100L537 219Q579 341 579 347Q579 363 564 373T530 385H522V431H529Q541 428 624 428Q692 428 698 431H703V385H697Q696 385 691 385T682 384Q635 377 619 334L559 161Q546 124 528 71Q508 12 503 1T487 -11H479Q460 -11 456 -4Q455 -3 407 133L361 267Q359 263 266 -4Q261 -11 243 -11H238Q225 -11 220 -3L90 368Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(722,0)" style="stroke-width: 3;"/><path data-c="76" d="M338 431Q344 429 422 429Q479 429 503 431H508V385H497Q439 381 423 345Q421 341 356 172T288 -2Q283 -11 263 -11Q244 -11 239 -2Q99 359 98 364Q93 378 82 381T43 385H19V431H25L33 430Q41 430 53 430T79 430T104 429T122 428Q217 428 232 431H240V385H226Q187 384 184 370Q184 366 235 234L286 102L377 341V349Q377 363 367 372T349 383T335 385H331V431H338Z" transform="translate(1222,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1750,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(7489.9,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(8101.1,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(9101.3,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/><path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" transform="translate(778,0)" style="stroke-width: 3;"/><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" transform="translate(1278,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mtext>level</mtext><mo>−</mo><mi>y</mi><mo>+</mo><mtext>wave</mtext><mo stretchy="false">)</mo><mo>×</mo><mn>0.12</mn></math></mjx-assistive-mml></mjx-container>를 써서 청록색 얕은 물에서 짙은 틸색 깊은 물로 섞이고, 그 추정값이 물가에서 0에 가까워지는 곳에서 거품이 일어나며, 알파는 깊이를 따라가서 얕은 물은 투명하게 깊은 물은 거의 불투명하게 보입니다.</p>
<p>수영은 부력 스프링입니다. 발이 수위 아래로 내려가고 몸 중심이 표면으로부터 캡슐 반높이 이내에 있을 때 플레이어가 수영 모드에 들어갑니다. 스프링이 몸을 표면 바로 아래의 목표로 끌어당기고, 부력 상수 12 대 물 감쇠 4면 플레이어가 머리를 내놓은 채 흔들림 없이 안정적으로 둥실거립니다. 수영 속도는 걷기보다 느리고 둥실거리는 가속과 항력이 붙으며, 수면 근처에서 점프하면 정상 점프 속도의 60%로 물 밖으로 솟구치고, 입수 시 하강 속도를 -5 m/s로 막아 곤두박질치지 않게 합니다. 지형 충돌은 물속에서도 여전히 작동하므로, 호수 바닥이 수영 목표보다 위로 올라온 곳에서는 걸을 수 있습니다. 수영 플래그는 위치 브로드캐스트에 함께 실려서 피어들이 당신이 수영하는 걸 볼 수 있고, 카메라가 수면 아래로 잠기면 HTML 그래디언트 오버레이가 화면을 물들입니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>결정적 브러시 파라미터 재생.</strong> 편집된 지형을 스트리밍하는 대신, 각 클라이언트는 브러시 파라미터만 보내고 같은 CPU 함수를 재생합니다. heightmap과 SDF 브러시 둘 다 무작위성이나 GPU 비결정성이 없는 순수한 <code>Float32Array</code> 연산이라서 동일한 입력이 어디서나 비트 단위로 동일한 출력을 만들어내기 때문에 가능합니다. 페이로드는 스트로크 틱당 56바이트입니다. 교환 가능한 연산(올리기, 내리기)은 순서와 무관하게 수렴하고, 이웃을 읽는 연산(부드럽게 하기, 평평하게 하기)은 수렴을 보장하기 위해 직렬화 지점이 필요한데, 이는 프로덕션의 Durable Object가 단조 시퀀스 번호로 제공합니다.</p>
<p><strong>WebSocket 대역의 BroadcastChannel.</strong> 서버가 전혀 없는, 동일 출처 탭 간 메시징용 브라우저 API입니다. 여기서는 동기화 프로토콜을 네트워크 지연과 인증에서 격리해 테스트하는 데 썼습니다. 직렬화 포맷(원본 <code>Float32Array</code> heightmap 더하기 편집된 SDF 청크 더하기 MC로 잠긴 청크 ID)은 IndexedDB 영속성과 늦은 합류 상태 전송에 쓰이는 바로 그 바이트라서, 한 포맷이 세 가지 일을 담당합니다.</p>
<p><strong>경사 분할 SDF 충돌 반응.</strong> 캡슐 프로브가 볼류메트릭 지형을 침투할 때, 순진한 수정은 침투 깊이만큼 SDF 그래디언트 방향으로 몸을 밀어냅니다. 경사에서는 그 그래디언트가 수평 성분을 가져 측면 드리프트를 주입합니다. 반응을 나눠서 걸을 수 있는 표면(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.874ex;" xmlns="http://www.w3.org/2000/svg" width="5.379ex" height="2.444ex" role="img" focusable="false" viewBox="0 -694 2377.5 1080.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mtext"><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(892,0)" style="stroke-width: 3;"/><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(1392,0)" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1981,-241.4) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mtext>grad</mtext><mi>y</mi></msub></math></mjx-assistive-mml></mjx-container>가 임계값 위)은 수직 방향만 밀어내고, 가파른 표면은 완전한 3D 밀어내기에 속도 투영까지 유지하면, 벽 충돌을 잃지 않으면서 드리프트를 제거합니다. <a href="/ko/guides/landscape-generation-browser.html#physics-on-sdf-terrain">SDF 지형 충돌</a>을 보세요.</p>
<p><strong>해석적 파동 법선을 쓰는 TSL 물.</strong> 바다는 정점이 합산된 사인파 세 개로 변위되는 노드 머티리얼입니다. 변위 후 메시 법선을 다시 계산하는 대신, 표면 법선은 파동 함수의 코사인 도함수에서 해석적으로 유도합니다. 이게 더 저렴하고, 거친 그리드에서 유한 차분 법선이 만드는 아티팩트를 피합니다. 깊이 기반 색, 물가 거품, 깊이 기반 투명도는 모두 단 하나의 깊이 추정값에 기반합니다.</p>
<p><strong>부력 스프링 수영.</strong> 수영 물리는 몸을 표면 바로 아래의 목표로 끌리는 감쇠 스프링으로 모델링합니다. 부력 상수 12, 감쇠 4면 플레이어가 흔들림 없이 수면에 자리를 잡습니다. 별도의 이동 상수(더 느린 속도, 둥실거리는 가속, 무거운 항력)가 수영에 걷기와 다른 느낌을 주고, 기존의 캡슐 대 지형 충돌이 물속에서도 계속 작동합니다.</p>
<hr>
<p>29부 중 15부.
이전: <a href="/ko/blog/2026-04-13-open-world-browser-part-14-world-comes-alive.html">14부 - 세계가 살아난다</a>
다음: <a href="/ko/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring.html">16부 - 계속 자라는 세계를 위한 구조</a>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cubcoats × Cinevva: 게임 콘셉트 원페이저]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-03-19-cubcoats-game-concepts-one-pager</link>
            <guid>https://app.cinevva.com/ko/blog/2026-03-19-cubcoats-game-concepts-one-pager</guid>
            <pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[스케치-비디오-3D 파이프라인과 Kali the Kitty를 기반으로 한 세 가지 교육용 게임 콘셉트(Golden Tree, Kali's Word Island, Island Stories). 라이선싱 또는 파트너 피칭용.]]></description>
            <content:encoded><![CDATA[<h1 id="cubcoats-×-cinevva-게임-콘셉트-원페이저" tabindex="-1">Cubcoats × Cinevva: 게임 콘셉트 원페이저 <a class="header-anchor" href="#cubcoats-×-cinevva-게임-콘셉트-원페이저" aria-label="Permalink to &quot;Cubcoats × Cinevva: 게임 콘셉트 원페이저&quot;"></a></h1>
<p><em>스케치-비디오-3D 파이프라인과 Kali the Kitty(Cubcoats)를 기반으로 합니다. 라이선싱, 블로그, 또는 파트너 피칭용.</em></p>
<p><strong>PDF로 공유하기:</strong> 이 페이지를 연 다음 브라우저의 <strong>파일 → 인쇄 → PDF로 저장</strong>을 사용하세요.</p>
<hr>
<h2 id="golden-tree-—-전체-원페이저" tabindex="-1">Golden Tree — 전체 원페이저 <a class="header-anchor" href="#golden-tree-—-전체-원페이저" aria-label="Permalink to &quot;Golden Tree — 전체 원페이저&quot;"></a></h2>
<p><strong>태그라인:</strong> <em>당신과 함께 자라는 세계. 방문하고, 물을 주고, 지켜보세요. 레벨도 없고, 부담도 없습니다.</em></p>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>연령</strong></td>
<td>3–13세 (폭넓음)</td>
</tr>
<tr>
<td><strong>형식</strong></td>
<td>에피소드형 공유 3D 세계 + 매주 짧은 &quot;순간&quot;</td>
</tr>
<tr>
<td><strong>플랫폼</strong></td>
<td>웹 (이후 모바일도); 진입 장벽이 낮고 설치가 필요 없음</td>
</tr>
<tr>
<td><strong>바이럴 후크</strong></td>
<td>&quot;친구에게 씨앗을 보내세요.&quot; 함께 키우는 성장, 공유하기 좋은 차분한 클립.</td>
</tr>
</tbody>
</table>
<h3 id="무엇인가" tabindex="-1">무엇인가 <a class="header-anchor" href="#무엇인가" aria-label="Permalink to &quot;무엇인가&quot;"></a></h3>
<p><strong>현실 세계의 시간</strong>에 맞춰 변화하는 차분하고 수집 가능한 세계입니다. 하나의 공유된 &quot;시즌&quot;(예: 봄 섬): 아이들이 돌아다닐 수 있는 단일 3D 섬입니다(플레이 가능한 Kali 데모처럼). 전통적인 레벨이나 점수는 없습니다. 진행은 <strong>당신의 나무에 새 가지가 자랐어요</strong>, <strong>12개의 순간을 봤어요</strong>, <strong>누군가 당신의 씨앗에 물을 줬어요</strong> 같은 식입니다.</p>
<p>방문할 때마다 아이는 다음을 할 수 있습니다. <strong>식물 하나에 물 주기</strong>, <strong>소원 하나 남기기</strong>(텍스트나 이모지), <strong>숨어 있는 Cubcoats 캐릭터 하나 찾기</strong>, 또는 <strong>30초짜리 &quot;순간&quot; 하나 보기</strong>(예: 황금 나무 아래의 Kali). 새로운 순간과 작은 이야기 단락은 <strong>매주</strong> 공개됩니다(에피소드형). 선택적인 은은한 언어: &quot;오늘 Kali가 말했어요: [영어와 중국어로 한 줄].&quot;</p>
<p>학습과 성장은 <strong>잠재적으로</strong> 이루어집니다. 주제(친절, 인내, 다시 도전하기)는 수업이 아니라 글과 그림 속에 담겨 있습니다. 이 경험은 학교가 아니라 장난감이나 함께하는 공간처럼 느껴집니다.</p>
<h3 id="핵심-루프" tabindex="-1">핵심 루프 <a class="header-anchor" href="#핵심-루프" aria-label="Permalink to &quot;핵심 루프&quot;"></a></h3>
<ol>
<li>섬을 <strong>방문</strong>합니다(브라우저나 앱).</li>
<li>방문할 때마다 <strong>부드러운 행동 하나</strong>를 합니다. 물 주기, 소원 빌기, 캐릭터 찾기, 또는 순간 보기.</li>
<li>며칠에서 몇 주에 걸쳐 <strong>세계가 변하는 것을 봅니다</strong>(새로운 꽃, 새로운 캐릭터 포즈, 새로운 짧은 클립).</li>
<li>친구에게 씨앗을 <strong>공유</strong>하거나 &quot;친구의 섬을 방문&quot;해서 성장이 사회적으로 느껴지게 합니다.</li>
</ol>
<h3 id="이-글의-파이프라인과-캐릭터를-어떻게-활용하는가" tabindex="-1">이 글의 파이프라인과 캐릭터를 어떻게 활용하는가 <a class="header-anchor" href="#이-글의-파이프라인과-캐릭터를-어떻게-활용하는가" aria-label="Permalink to &quot;이 글의 파이프라인과 캐릭터를 어떻게 활용하는가&quot;"></a></h3>
<ul>
<li><strong>3D 플레이 가능한 세계:</strong> Kali 데모와 같은 파이프라인입니다. T-pose → 3D Model Generator → 리깅 → Cinevva Engine. 섬과 캐릭터는 탐험 가능하고, 3인칭이며, 부담이 적습니다.</li>
<li><strong>황금 나무:</strong> 글에서 직접 가져왔습니다(Kali의 &quot;두려움에서 희망으로&quot; 단락과 마법 같은 황금 나무). 이 나무는 시즌의 감정적이고 시각적인 중심입니다.</li>
<li><strong>짧은 &quot;순간&quot;:</strong> 글의 세로형 숏폼처럼 제작합니다. 시작 프레임 + 끝 프레임 + 모션 프롬프트 → Video Generator (Kling 3.0 Pro), 9:16, 약 15초. 매주 공개되는 각 콘텐츠는 하나의 작은 이야기 단락입니다.</li>
<li><strong>Cubcoats IP:</strong> Kali와 나머지 일곱 캐릭터, 섬 세계, 그리고 따뜻하고 둥근 아트 스타일. 디지털 에피소드형 제품과 함께 라이선싱 중심의 재출시(2026)에 잘 맞습니다.</li>
</ul>
<h3 id="왜-바이럴이-될-수-있는가" tabindex="-1">왜 바이럴이 될 수 있는가 <a class="header-anchor" href="#왜-바이럴이-될-수-있는가" aria-label="Permalink to &quot;왜 바이럴이 될 수 있는가&quot;"></a></h3>
<ul>
<li><strong>낮은 진입 장벽:</strong> 링크 하나, 복잡한 온보딩 없음. &quot;친구에게 씨앗을 보내세요&quot;는 간단한 공유입니다.</li>
<li><strong>차분하고 아름다운 클립:</strong> 짧은 순간들은 그 자체로 공유하기 좋습니다(소셜, &quot;이 15초만 봐&quot;). 긍정적인 방식으로 밈이 되기 좋습니다.</li>
<li><strong>에피소드형:</strong> &quot;이번 주에 뭐가 새로 나왔지?&quot;가 재방문과 대화를 만듭니다.</li>
<li><strong>잠재적:</strong> 부모는 &quot;차분하고, 창의적이고, 광고 없고, 스트레스 없음&quot;을 봅니다. 아이는 명시적으로 배우지 않으면서도 루틴, 인내, 그리고 잔잔한 놀라움을 얻습니다.</li>
</ul>
<h3 id="가능한-cinevva-블로그-앵글" tabindex="-1">가능한 Cinevva 블로그 앵글 <a class="header-anchor" href="#가능한-cinevva-블로그-앵글" aria-label="Permalink to &quot;가능한 Cinevva 블로그 앵글&quot;"></a></h3>
<p><em>&quot;우리는 Kali를 스케치에서 비디오로, 그리고 돌아다닐 수 있는 캐릭터로 만들었습니다. Golden Tree는 다음 단계입니다. 실시간으로 자라는 세계에서 아이들이 방문하고, 물을 주고, 짧은 순간을 봅니다. 레벨도 없고, 부담도 없습니다. 같은 파이프라인. 새로운 형식.&quot;</em></p>
<hr>
<h2 id="kali-s-word-island-—-한눈에-보기" tabindex="-1">Kali's Word Island — 한눈에 보기 <a class="header-anchor" href="#kali-s-word-island-—-한눈에-보기" aria-label="Permalink to &quot;Kali's Word Island — 한눈에 보기&quot;"></a></h2>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>태그라인</strong></td>
<td>Kali와 친구들이 섬을 키우는 걸 도와주세요. 그 과정에서 영어와 중국어를 배웁니다.</td>
</tr>
<tr>
<td><strong>연령</strong></td>
<td>5–11세</td>
</tr>
<tr>
<td><strong>초점</strong></td>
<td>아이들을 위한 영어 ↔ 중국어; 강한 게임화와 진행 요소.</td>
</tr>
</tbody>
</table>
<p><strong>핵심 아이디어:</strong> Cubcoats 섬은 캐릭터 구역으로 나뉩니다(Kali의 숲, 다른 캐릭터의 해변). 아이들은 영어/중국어를 이해하고 만들어내야 하는 짧은 과제를 하며 캐릭터를 돕습니다. 진행은 &quot;씨앗 → 묘목 → 나무 → 황금 나무&quot;입니다(구역의 나무가 다 자라면 다음 구역이 열림). 매일 하는 &quot;랜턴&quot; 런, 수집 가능한 문구 카드, 캐릭터 &quot;기분&quot; 바, 선택적인 부모 대시보드. 짧은 이야기 순간(시작/끝 프레임 스타일)은 구역을 완성하면 열립니다. <strong>파이프라인:</strong> 캐릭터와 감정적 단락을 위한 동일한 3D + 비디오 파이프라인.</p>
<hr>
<h2 id="cubcoats-island-stories-—-한눈에-보기" tabindex="-1">Cubcoats: Island Stories — 한눈에 보기 <a class="header-anchor" href="#cubcoats-island-stories-—-한눈에-보기" aria-label="Permalink to &quot;Cubcoats: Island Stories — 한눈에 보기&quot;"></a></h2>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>태그라인</strong></td>
<td>나만의 Cubcoats 에피소드를 만드세요. 이야기를 리믹스하세요. 당신의 버전을 공유하세요.</td>
</tr>
<tr>
<td><strong>연령</strong></td>
<td>3–13세 (구간: 3–6세, 7–10세, 11–13세)</td>
</tr>
<tr>
<td><strong>초점</strong></td>
<td>이야기 창작과 리믹스; 교육은 녹아 있지만 메인 피치는 아님.</td>
</tr>
</tbody>
</table>
<p><strong>핵심 아이디어:</strong> 아이들이 분기를 선택하는 에피소드형 내러티브(Kali는 뭐라고 말할까? 어디로 갈까?). 주된 활동은 <strong>리믹스</strong>입니다. 캐릭터, 장소, 2–3개의 단락을 골라서 짧은 &quot;에피소드&quot;를 만듭니다(대본 + 간단한 비주얼, 또는 이후에는 AI 생성 숏폼). 학습은 잠재적입니다(대사와 선택 속의 어휘와 패턴). 소셜: 당신의 에피소드를 공유하고, 다른 사람의 버전을 플레이하고, &quot;친절함 / 재미 / 의외성&quot;을 평가합니다. <strong>파이프라인:</strong> 사용자가 만든 &quot;순간&quot;을 위한 동일한 캐릭터 룩 + 두 프레임 비디오 파이프라인; 캐릭터/세계 일관성을 위한 3D.</p>
<hr>
<p><em>참조한 Cinevva 도구: Image Generator, Video Generator (Kling 3.0 Pro), 3D Model Generator, 자동 리깅, Cinevva Engine. &quot;스케치에서 비디오, 그리고 플레이 가능한 3D까지&quot;(2026-03-04)에서 설명한 파이프라인을 반영합니다.</em></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드를 만들려면 실제로 무엇이 필요한가]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-03-14-open-world-browser-medium-article</link>
            <guid>https://app.cinevva.com/ko/blog/2026-03-14-open-world-browser-medium-article</guid>
            <pubDate>Sat, 14 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Cinevva의 12부작 엔지니어링 시리즈를 저널리즘 방식으로 풀어낸 글. 투박한 지형 베이스라인부터 GPU marching cubes, 스트리밍 LOD, Transvoxel 이음매 디버깅까지 이어진 24개의 spike 실험.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드를-만들려면-실제로-무엇이-필요한가" tabindex="-1">브라우저에서 오픈 월드를 만들려면 실제로 무엇이 필요한가 <a class="header-anchor" href="#브라우저에서-오픈-월드를-만들려면-실제로-무엇이-필요한가" aria-label="Permalink to &quot;브라우저에서 오픈 월드를 만들려면 실제로 무엇이 필요한가&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Mariana Muntean</a>, Cinevva CEO</em></p>
<img src="/img/blog/open-world-browser-120fps.png" alt="The open world running in a browser at 120 FPS — terrain, trees, physics, and a player capsule, all rendered in a single tab" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Cinevva 팀은 최근 게임 개발 분야에서 보기 드물게 투명한 엔지니어링 일지 중 하나를 공개했습니다. 멀티플레이어 오픈 월드를 전적으로 브라우저 안에서 돌리려는 우리의 시도를 기록한 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">12부작 시리즈</a>입니다. 다운로드도 없고, 앱스토어도 없습니다. 그냥 URL 하나면 됩니다.</p>
<p>이 프로젝트는 우리가 &quot;spike&quot;라고 부르는 24개의 기술 실험으로 이어졌습니다. 각각은 위험한 질문 하나에 답하도록 설계된 짧고 집중적인 프로토타입입니다. 모든 spike는 지금 당장 브라우저에서 열어 실행할 수 있는 실제 소스 코드와 함께 공개되었습니다. 이 시리즈는 Cinevva의 CTO이자 공동 창업자인 <a href="/ko/about.html">Oleg Sidorkin</a>이 썼고, 마케팅 글이라기보다 2026년의 브라우저가 실제로 무엇을 할 수 있는지를 최전선에서 적은 현장 일지에 가깝습니다.</p>
<p>이 시리즈가 읽을 가치가 있는 이유는, 설령 지형 시스템을 만들 계획이 전혀 없더라도, 그 밑에 깔린 방법에 있습니다. 비싼 데 발을 들이기 전에 야심 찬 프로젝트의 위험을 어떻게 줄일 수 있는지 보여 주는 사례 연구입니다.</p>
<h2 id="가장-어려운-질문부터-시작하기" tabindex="-1">가장 어려운 질문부터 시작하기 <a class="header-anchor" href="#가장-어려운-질문부터-시작하기" aria-label="Permalink to &quot;가장 어려운 질문부터 시작하기&quot;"></a></h2>
<p>대부분의 오픈 월드 프로젝트는 예측 가능한 순서로 죽습니다. 먼저 멋진 콘셉트가 나옵니다. 그다음 예쁜 장면이 나옵니다. 그러고 나서 게임플레이가 존재하기도 전에 프레임 예산이 이미 다 소진됐다는 걸 발견합니다.</p>
<p>우리 팀은 순서를 뒤집었습니다. <a href="/ko/blog/2026-02-25-open-world-browser-part-01-risk-first.html">첫 번째 spike</a>는 일부러 투박하게 만들었습니다. 512미터 지형 메시, 인스턴스화된 오브젝트 500개, 절차적 높이 노이즈, 물 평면, 그리고 안개. 그림자도 없고 미술 패스도 없었습니다. 유일한 질문은 카메라가 그 안을 이동하는 동안 브라우저가 안정적인 프레임 레이트를 유지할 수 있는가였습니다.</p>
<p>가능했습니다. 그리고 그 &quot;예&quot;는 Oleg가 &quot;베이스라인 계약&quot;이라고 부르는 것을 확립했습니다. 최소한의 장면에 대한 측정된 기준 비용으로, 이후의 모든 기능은 이에 비추어 스스로를 정당화해야 했습니다. 새로운 효과가 멋져 보여도 프레임 예산을 터뜨리면, 그건 출시되지 않았습니다. 적어도 아직은 아니었죠.</p>
<p>이런 종류의 규율은 당연한 소리처럼 들립니다. 하지만 실제로는, 모두가 다음 시각적 성과에 들떠 있는 빠르게 움직이는 프로토타입 환경에서는 드뭅니다.</p>
<h2 id="물리라는-도박" tabindex="-1">물리라는 도박 <a class="header-anchor" href="#물리라는-도박" aria-label="Permalink to &quot;물리라는 도박&quot;"></a></h2>
<p><a href="/ko/blog/2026-02-25-open-world-browser-part-02-worker-physics.html">두 번째 실험</a>은 브라우저 게임 개발자들 사이에서 의견이 갈리는 아키텍처 논쟁을 다뤘습니다. 물리는 더 간단한 메인 스레드에서 돌려야 할까요, 아니면 렌더링을 막지 않는 Web Worker에서 돌려야 할까요?</p>
<p>Worker 기반 물리는 서류상으로는 더 깔끔합니다. 실제로 두려운 건 지연입니다. 모든 입력 이벤트는 메시지 경계를 두 번 넘어야 합니다. 한 번은 Worker에 도달하기 위해, 한 번은 결과를 가져오기 위해. 그 왕복이 너무 느리면, 키를 누르고 캐릭터가 움직이는 걸 보는 것이 굼뜨게 느껴질 겁니다.</p>
<p>팀은 Rapier 물리 엔진(Rust에서 WebAssembly로 컴파일됨)을 전용 Worker에 통합하고, 메시지 파이프라인을 연결한 뒤 측정했습니다. 오버헤드는 무시할 만한 수준이었습니다. 조작은 여전히 즉각적으로 느껴졌습니다. 하지만 우리는 보편적인 규칙이 아니라 특정한 시나리오 하나를 검증한 것이라는 점을 신중히 기록해 두었습니다. 나중에 GPU 부하와 스트리밍 복잡도가 바뀌면, 그 가정들은 다시 점검해야 할 터였죠.</p>
<h2 id="프로젝트를-구한-따분한-spike들" tabindex="-1">프로젝트를 구한 따분한 spike들 <a class="header-anchor" href="#프로젝트를-구한-따분한-spike들" aria-label="Permalink to &quot;프로젝트를 구한 따분한 spike들&quot;"></a></h2>
<p>시리즈의 <a href="/ko/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes.html">3부</a>에는 스크린샷이 하나도 없습니다. 화려해 보이지 않지만 제품 수준의 결과를 안고 있던 세 가지 실험을 다룹니다.</p>
<p>첫 번째는 Cloudflare Durable Objects가 게임 수준의 틱 레이트로 실시간 위치 브로드캐스트를 처리할 수 있는지 시험했습니다. 멀티플레이어의 근간이죠. 이것이 실패했다면, 전체 네트워크 아키텍처는 단일 아일랜드 소유 방식 대신 일찌감치 샤딩이 필요했을 겁니다.</p>
<p>두 번째는 모바일 품질 프로파일을 검증했습니다. 이름만 바꾼 데스크톱 프리셋이 아니라, 같은 지형 베이스라인에서 나온 명시적인 저비용 렌더링 경로였습니다. 질문은 렌더러를 다시 쓰지 않고도 모바일 GPU 제약 아래에서 월드가 읽기 좋고 반응성 있게 유지될 수 있는가였습니다.</p>
<p>세 번째는 크리에이터 워크플로를 위한 AI 생성 동작 스크립트가 프로덕션에 쓸 만큼 신뢰할 수 있는지 평가했습니다.</p>
<p>이 중 어느 것도 데모 영상을 만들어내지 않았습니다. 셋 다 이후의 모든 아키텍처 결정을 형성한 단단한 경계를 세웠습니다. Oleg는 이 &quot;화려하지 않은 spike들이 시각적 spike들보다 더 빠르게 아키텍처를 바꿨다&quot;고 씁니다.</p>
<h2 id="스트리밍-예쁜-프로젝트가-무너지는-지점" tabindex="-1">스트리밍: 예쁜 프로젝트가 무너지는 지점 <a class="header-anchor" href="#스트리밍-예쁜-프로젝트가-무너지는-지점" aria-label="Permalink to &quot;스트리밍: 예쁜 프로젝트가 무너지는 지점&quot;"></a></h2>
<img src="/img/blog/open-world-chunk-streaming.png" alt="Spike 6: Chunk streaming in action — each colored area is a terrain chunk that loads and unloads dynamically as the camera moves" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>정지된 한 프레임에는 많은 것을 숨길 수 있습니다. 하지만 달리는 도중 청크 경계를 넘을 때 생기는 40밀리초의 끊김은 숨길 수 없습니다.</p>
<p>팀은 <a href="/ko/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy.html">고급 지형을 만들기 전에 스트리밍을 시험</a>하며 관심사를 의도적으로 분리했습니다. Spike 6은 단순한 콘텐츠로 이웃 청크 로딩을 검증했습니다. 그 깨끗한 신호를 얻은 뒤에야 Spike 11이 점진적 정제 방식의 압축 하이트맵 스트리밍을 도입했습니다. 먼저 17 샘플 해상도로 지형을 로드하고, 그다음 33, 그다음 전체 65 샘플 그리드 순서로요.</p>
<p>순서가 예상보다 더 중요했습니다. 만약 압축 높이 청크부터 곧장 시작했다면, 모든 끊김이 모호했을 겁니다. 디코드 문제였을까, 텍스처 업로드 지연이었을까, 아니면 지오메트리 업데이트 문제였을까? 단순한 스트리밍을 먼저 시험한 덕분에 불확실성의 한 범주 전체를 제거할 수 있었습니다.</p>
<p>실용적인 교훈 하나가 나왔습니다. 업로드 지연은 평균 FPS를 통해서가 아니라 직접 측정하라는 것입니다. 평균은 프레임 스파이크를 숨기고, 플레이어가 실제로 느끼는 건 바로 그 프레임 스파이크입니다.</p>
<h2 id="비주얼-예산-전쟁" tabindex="-1">비주얼 예산 전쟁 <a class="header-anchor" href="#비주얼-예산-전쟁" aria-label="Permalink to &quot;비주얼 예산 전쟁&quot;"></a></h2>
<p>세 개의 별도 실험이 렌더링 비용을 한데 묶지 않고 따로따로 공략했습니다. <a href="/ko/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty.html">식생</a> 밀도와 바람 애니메이션. 절벽 면을 위한 삼면 매핑(triplanar mapping)이 적용된 멀티 레이어 지형 머티리얼. 현실적인 지형 부하 아래의 캐스케이드 섀도 맵.</p>
<p>식생 spike는 인스턴스를 더 적은 메시로 배칭하는 것이 잎 하나당 폴리곤 수를 줄이는 것보다 더 중요하다는 점을 드러냈습니다. 머티리얼 spike는 수직면에 대한 삼면 투영이 GPU 비용을 들일 가치가 있지만, 다섯 번째 텍스처 스플랫 레이어를 추가하는 건 그렇지 않다는 걸 알아냈습니다. 섀도 spike는 1024 해상도의 캐스케이드 3개가 2밀리초의 GPU 시간을 넘기지 않으면서 받아들일 만한 접촉 그림자를 제공한다고 판단했습니다.</p>
<p>팀은 단도직입적인 규칙을 채택했습니다. 어떤 기능은 측정된 프레임 타임 데이터로 자기 비용을 설명할 수 있을 때만 앞으로 나아간다는 것이죠. 초기에 정해 둔 그 제약 덕분에, 볼류메트릭 지형과 클립맵을 둘러싼 이후의 아키텍처 결정이 훨씬 깔끔해졌습니다.</p>
<h2 id="프로젝트의-궤도를-바꾼-전환점" tabindex="-1">프로젝트의 궤도를 바꾼 전환점 <a class="header-anchor" href="#프로젝트의-궤도를-바꾼-전환점" aria-label="Permalink to &quot;프로젝트의 궤도를 바꾼 전환점&quot;"></a></h2>
<p>Spike 10 이전까지 우리의 머릿속 모델은 &quot;더 큰 월드는 더 많은 지오메트리를 뜻한다&quot;였습니다. <a href="/ko/blog/2026-02-25-open-world-browser-part-06-clipmaps.html">Spike 10</a> 이후에는 &quot;일정한 지오메트리 예산, 카메라 중심의 링 업데이트&quot;가 됐습니다.</p>
<p>지오메트리 클립맵, 즉 카메라를 중심으로 한 동심원 형태의 지형 링들이고 각 링은 점점 거칠어지는데, 이는 그리기 거리와 상관없이 삼각형 수가 대체로 일정하게 유지된다는 뜻이었습니다. 실용적인 요령은 링 경계에서의 지오모핑이었습니다. 셰이더에서 정점 높이를 부드럽게 섞어, 해상도 레벨 간의 전환이 움직이는 중에는 보이지 않게 하는 거죠.</p>
<p>미묘한 교훈은 테스트 방법에서 나왔습니다. 클립맵은 스크린샷에서는 멀쩡해 보입니다. 그 아티팩트는 링 경계를 가로지르는 지속적인 카메라 이동 아래에서만 드러납니다. 팀은 일정한 속도로 이동하며 시간적 노이즈를 살피는 데 시간을 들였습니다. &quot;스크린샷은 거짓말을 했다&quot;고 Oleg는 씁니다. &quot;진실을 말한 건 움직임이었다.&quot;</p>
<h2 id="지하로-내려가기" tabindex="-1">지하로 내려가기 <a class="header-anchor" href="#지하로-내려가기" aria-label="Permalink to &quot;지하로 내려가기&quot;"></a></h2>
<p>하이트맵은 동굴을 표현할 수 없습니다. 그리드의 한 점마다 하나의 고도 값만 저장하니까요. 터널, 돌출부, 깎인 암벽이 필요한 순간, 볼류메트릭 지형이 필요해집니다.</p>
<p><a href="/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes.html">Spike 12</a>는 WebGPU 컴퓨트 셰이더를 사용해 GPU에서 marching cubes를 구현했고, 3D 부호 거리장(signed distance field)에서 삼각형 메시를 추출했습니다. 64 큐브 청크 네 개가 애니메이션되는 SDF 편집으로부터 프레임마다 메시를 갱신하며 동시에 돌아갔습니다. 컴퓨트 셰이더가 모든 것을 처리했습니다. 필드 평가, 셀 분류, 정점 방출까지, CPU 리드백 없이요.</p>
<p>도전은 그걸 동작시키는 게 아니었습니다. 다른 모든 것과 함께 동작시키는 것이었습니다. Three.js 씬 그래프와의 통합, 버퍼 수명 관리(WebGPU 버퍼는 크기를 변경할 수 없습니다), 아직 처리 중인 GPU 리소스를 파괴하지 않기 위한 펜스 처리. 시리즈는 우리가 &quot;점진적 강화(incremental hardening)&quot;라고 부르는 것에 <a href="/ko/blog/2026-02-25-open-world-browser-part-08-webgpu-integration.html">두 개의</a> 전체 부를 할애합니다. 한 번에 하나의 기능을 추가하고, 추가할 때마다 이전 레이어가 여전히 동작하는지 확인하는, 화려하지 않은 과정 말이죠.</p>
<h2 id="이음매-악몽" tabindex="-1">이음매 악몽 <a class="header-anchor" href="#이음매-악몽" aria-label="Permalink to &quot;이음매 악몽&quot;"></a></h2>
<p>시리즈에서 기술적으로 가장 험난한 부분은 <a href="/ko/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut.html">9부에서 11부</a>에 걸쳐 있고, 서로 다른 해상도의 지형 청크가 만날 때 무슨 일이 벌어지는지를 다룹니다.</p>
<p>고해상도 청크가 저해상도 청크 옆에 놓이면, 독립적으로 생성된 두 메시는 경계에서 맞아떨어지지 않습니다. 그 결과 눈에 보이는 균열, 깜빡이는 가장자리, 그리고 빛이 새어 드는 T자 접합이 생깁니다. Transvoxel 알고리즘은 해상도 차이를 잇는 특수한 전환 셀로 이를 해결합니다. 하지만 모든 청크 구성에 걸쳐, 일관된 와인딩 순서, 적절한 버퍼 관리, 정확한 그리기 범위로 그것을 올바르게 구현하는 일은 여섯 개의 별도 실험을 잡아먹었습니다.</p>
<p>팀에서 가장 기억에 남는 디버깅 이야기는 이렇습니다. 이틀 동안 우리가 전환 로직 탓이라고 믿었던 이음매 아티팩트를 쫓았습니다. 진짜 범인은 오래된 데이터였습니다. GPU 컴퓨트 셰이더가 버퍼에 N개의 정점을 썼는데, 그리기 호출은 여전히 이전 프레임의 N+M개 정점을 렌더링하도록 설정돼 있었습니다. 그 여분의 정점들이 쓰레기 값을 담고 있어서 면도날처럼 얇은 삼각형들이 깜빡였던 거죠. 한 줄 수정으로 해결됐습니다. 그리기 범위를 원자 카운터의 활성 정점 수로 잘라낸 것입니다.</p>
<p>&quot;렌더링 버그는 흔히 메싱 버그인 척한다&quot;고 Oleg는 짚습니다. &quot;지오메트리는 처음부터 내내 맞았다.&quot;</p>
<h2 id="혼돈에서-거버넌스로" tabindex="-1">혼돈에서 거버넌스로 <a class="header-anchor" href="#혼돈에서-거버넌스로" aria-label="Permalink to &quot;혼돈에서 거버넌스로&quot;"></a></h2>
<p>이음매 전투를 치른 뒤, 팀은 임시방편의 청크 동작을 <a href="/ko/blog/2026-02-25-open-world-browser-part-11-policy-modes.html">명시적인 정책 시스템</a>으로 대체했습니다. 이제 중앙 함수가 각 청크의 LOD 레벨, 렌더링 모드(하이트맵인지 marching cubes인지), 그리고 어느 면에 전환 셀이 필요한지를 결정합니다. 거리 링이 기본 LOD를 정했습니다. 인접성 제약이 이웃한 두 청크가 해상도 레벨에서 하나 이상 차이 나지 않도록 보장했습니다. 편집 비트맵은 크리에이터 수정이 담긴 볼류메트릭 청크를 거리와 상관없이 marching-cubes 모드로 유지했습니다.</p>
<p>색으로 구분한 디버그 오버레이, 즉 하이트맵 청크는 초록, marching cubes는 파랑, 전환 면은 주황으로 표시한 것은 &quot;저 능선 근처 어딘가에서 버그를 봤다&quot;를 &quot;버그가 북서쪽을 향한 (142, 12, -67) 위치에서 나타난다&quot;로 바꿔 놓았습니다.</p>
<p>&quot;정책이 복잡도를 줄이지는 않았다&quot;고 Oleg는 씁니다. &quot;복잡도를 정리했다.&quot;</p>
<h2 id="이-모든-것이-만들어낸-결과" tabindex="-1">이 모든 것이 만들어낸 결과 <a class="header-anchor" href="#이-모든-것이-만들어낸-결과" aria-label="Permalink to &quot;이 모든 것이 만들어낸 결과&quot;"></a></h2>
<p>마지막 spike는 클립맵 링, 프래그먼트별 하늘 안개(각 지형 프래그먼트 방향의 실제 스카이박스 색을 샘플링), 그리고 Three.js 모듈 배선을 하나의 통합된 데모로 결합했습니다. 그 결과는, 근거리 볼류메트릭 편집, 중거리 하이트맵 청크, 원거리 클립맵 링을 모드와 LOD와 전환을 다스리는 정책 레이어 아래에 겹쳐 놓은 지형 시스템입니다.</p>
<p>시리즈는 Oleg가 앞으로 어떤 프로젝트에서든 반복하겠다고 말하는 <a href="/ko/blog/2026-02-25-open-world-browser-part-12-lessons.html">교훈들</a>로 마무리됩니다.</p>
<ul>
<li><strong>기능 작업에 앞서 위험 spike부터 시작하라.</strong> 콘텐츠 파이프라인에 투자하기 전에 &quot;우리가 이걸 할 수나 있나?&quot;라는 질문부터 처리하라.</li>
<li><strong>통합 점프 전에 검증된 베이스라인을 동결하라.</strong> 깨끗한 체크포인트를 세우는 데 들인 하루는, 나중에 회귀를 이분 탐색하는 여러 날을 아껴 준다.</li>
<li><strong>최적화 마라톤 전에 정책과 관측 가능성을 강제하라.</strong> 트리거 규칙이 있는 이름 붙은 조건은 매번 정체불명의 버그를 이긴다.</li>
<li><strong>스크린샷이 아니라 움직임 속에서 테스트하라.</strong> 팝, 깜빡임, 스트리밍 끊김은 모두 정지된 프레임 안에 숨는다.</li>
<li><strong>평균 FPS가 아니라 기능별 프레임 타임을 측정하라.</strong> 평균은 사용자가 실제로 느끼는 스파이크를 숨긴다.</li>
<li><strong>지저분한 부분을 공개하라.</strong> 잘못 든 길, 헛다리, 엉뚱한 시스템을 탓한 이틀. 사람들이 실제로 배울 수 있는 건 바로 그런 부분이다.</li>
</ul>
<h2 id="이것이-cinevva를-넘어-왜-중요한가" tabindex="-1">이것이 Cinevva를 넘어 왜 중요한가 <a class="header-anchor" href="#이것이-cinevva를-넘어-왜-중요한가" aria-label="Permalink to &quot;이것이 Cinevva를 넘어 왜 중요한가&quot;"></a></h2>
<p>이 시리즈는 한 회사의 지형 파이프라인을 넘어서는 세 가지 이유로 의미가 있습니다.</p>
<p>첫째, WebGPU 컴퓨트 셰이더, WebAssembly 물리, 그리고 엣지에 배포된 Durable Objects가 어떤 문턱을 넘었음을 보여 줍니다. 볼류메트릭 지형, 실시간 편집, 스트리밍 LOD를 갖춘 멀티플레이어 오픈 월드가 2026년에 브라우저 탭 안에서 아키텍처적으로 실현 가능합니다. 2년 전에는 사실이 아니었습니다.</p>
<p>둘째, spike 방법론, 즉 각각이 위험한 질문 하나를 살아 있고 측정 가능한 결과로 답하는 작고 집중된 실험들은, 잘 안 될 수도 있는 무언가를 시도하는 어느 팀에게나 하나의 템플릿을 제공합니다. 투자하기 전에 측정하고, 통합하기 전에 베이스라인을 세우고, 최적화하기 전에 엣지 케이스에 이름을 붙이는 규율은 지형 시스템을 훌쩍 넘어서 적용됩니다.</p>
<p>셋째, 그 과감한 투명성이 바로 핵심입니다. 막다른 길과 이틀짜리 디버깅 우회로까지 포함해 24개 실험 전부의 소스 코드를 공개한 것은, 이것을 단순한 기술 블로그 이상으로 만듭니다. 독자를 고객이 아니라 동료로 대하는 공개 엔지니어링 노트인 셈이죠.</p>
<p>전체 시리즈는 우리 <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>에서 볼 수 있고, 모든 spike가 브라우저에서 실시간으로 돌아갑니다.</p>
<hr>
<p><em>이 글은 원래 <a href="https://vio-202020.medium.com/de-risking-an-ambitious-project-before-committing-to-anything-big-like-an-online-open-world-c94a7c05ee06" target="_blank" rel="noreferrer">Medium</a>에 게시되었습니다.</em></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[스케치에서 영상, 그리고 플레이 가능한 3D까지: 캐릭터, 스토리 프레임, 리그]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-03-04-sketch-to-animated-3d-character</link>
            <guid>https://app.cinevva.com/ko/blog/2026-03-04-sketch-to-animated-3d-character</guid>
            <pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[거친 캐릭터 스케치 한 장을 Cinevva의 이미지 생성기, 영상 생성기, 3D 모델 생성기로 AI 생성 세로형 숏폼과 브라우저에서 직접 움직일 수 있는 리깅된 3D 모델로 바꾼 과정.]]></description>
            <content:encoded><![CDATA[<h1 id="스케치에서-영상-그리고-플레이-가능한-3d까지" tabindex="-1">스케치에서 영상, 그리고 플레이 가능한 3D까지 <a class="header-anchor" href="#스케치에서-영상-그리고-플레이-가능한-3d까지" aria-label="Permalink to &quot;스케치에서 영상, 그리고 플레이 가능한 3D까지&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO</em></p>
<p>평면 스케치 속 캐릭터를 플레이 가능한 3D 게임으로 만들려면 예전에는 콘셉트 아티스트, 3D 모델러, 리거, 애니메이터, 그리고 그 모든 걸 엔진에서 엮어 줄 사람이 필요했습니다. 우리는 그 파이프라인 중 얼마만큼을 <a href="/ko/tools/">Cinevva의 창작 도구</a>가 스스로 처리할 수 있는지 보고 싶었습니다. 그 결과는 다음과 같습니다.</p>
<p>캐릭터는 <a href="https://thecubcoats.com" target="_blank" rel="noreferrer">Cubcoats</a>의 <strong>Kali the Kitty</strong>입니다. Cubcoats는 Nordstrom, Amazon, Disney Store를 통해 100만 개가 넘는 봉제 인형 후디를 판 어린이 브랜드입니다. Cubcoats에는 뚜렷한 성격을 가진 여덟 명의 오리지널 캐릭터와 가상의 섬 세계, 그리고 14건의 특허가 있습니다. 이들은 2026년에 라이선싱 우선 플랫폼으로 다시 출발하는데, 우리는 그 IP가 실물 제품을 넘어설 때 어떤 모습이 되는지 보여 주고 싶었습니다. 세로형 영상 숏폼과 브라우저에서 직접 걸어 다닐 수 있는 리깅된 3D 캐릭터죠. 아래의 모든 것은 그 탐색에서 나온 실제 결과물입니다.</p>
<p>3D 뷰어를 드래그하면 캐릭터 주위를 돌려 볼 수 있습니다. 필름 스트립을 스크롤하면 세로형 숏폼이 첫 프레임에서 마지막 프레임까지 어떻게 움직이는지 볼 수 있습니다.</p>
<h2 id="평면-책-아트에서-돌려-볼-수-있는-캐릭터로" tabindex="-1">평면 책 아트에서 돌려 볼 수 있는 캐릭터로 <a class="header-anchor" href="#평면-책-아트에서-돌려-볼-수-있는-캐릭터로" aria-label="Permalink to &quot;평면 책 아트에서 돌려 볼 수 있는 캐릭터로&quot;"></a></h2>
<p>Cubcoats에는 이미 아름다운 2D 일러스트가 있었습니다. Mimi Chao의 아트 디렉션은 모든 캐릭터에 따뜻하고 둥글고 손으로 그린 듯한 느낌을 주었고, 이는 후디나 그림책에 완벽하게 어울립니다. 하지만 평면 아트는 3D 파이프라인에 먹이로 들어가지 못합니다. 우리는 영상 생성, 메시 제작, 리깅을 위한 참고용으로 버틸 수 있는 고품질 캐릭터가 필요했고, 그 모든 것을 같은 얼굴 하나에서 뽑아내야 했습니다.</p>
<p>먼저 원본 책 일러스트를 <a href="/ko/tools/flux.html">이미지 생성기</a>에 넣고 같은 캐릭터의 3D 렌더링 버전을 만들어 달라고 했습니다.</p>
<figure class="pipeline-media pipeline-media--single">
<img src="/blog/sketch-to-3d-pipeline/kali-flat-book-art.png" alt="Original flat Cubcoats illustrations of Kali the Kitty" loading="lazy">
<figcaption><strong>출발점.</strong> Kali의 원본 2D 책 일러스트. 따뜻하고, 표정이 풍부하고, 완전히 평면입니다.</figcaption>
</figure>
<p>비율이 유지되고, 성격이 살아나고, 부드러운 3D 카툰 느낌이 이후 모든 도구에 일관된 기준점을 주었습니다. 거기서부터 정확한 포즈와 구도를 반복해 다듬어, 고정된 히어로 레퍼런스를 확보했습니다.</p>
<div class="pipeline-media pipeline-media--two">
<figure>
<img src="/blog/sketch-to-3d-pipeline/kali-3d-chatgpt.png" alt="Locked 3D-style character reference for Kali" loading="lazy">
<figcaption><strong>고정된 히어로 레퍼런스.</strong> 영상에 쓰이고 메시의 시각적 기준이 된 전신 3D 카툰 느낌.</figcaption>
</figure>
<figure>
<img src="/blog/sketch-to-3d-pipeline/kali-3d-tpose.png" alt="T-pose reference for 3D generation and rigging" loading="lazy">
<figcaption><strong>T-포즈 시트.</strong> 같은 캐릭터, 팔을 벌린 모습. 이 이미지가 [3D 모델 생성기](/ko/tools/hunyuan3d)와 자동 리거 양쪽에 들어갔습니다.</figcaption>
</figure>
</div>
<p>T-포즈가 중요한 이유는 리깅이 팔이 몸통에서 떨어져 있기를 기대하기 때문입니다. 이걸 건너뛰면 자동 리거가 팔을 몸에 붙여 버리고 포기합니다. 우리는 고정한 같은 캐릭터 룩에서 T-포즈를 생성해, 모든 단계에서 실루엣과 비율이 일관되게 유지되도록 했습니다.</p>
<h2 id="무엇이든-생성하기-전에-먼저-스토리를-써라" tabindex="-1">무엇이든 생성하기 전에 먼저 스토리를 써라 <a class="header-anchor" href="#무엇이든-생성하기-전에-먼저-스토리를-써라" aria-label="Permalink to &quot;무엇이든 생성하기 전에 먼저 스토리를 써라&quot;"></a></h2>
<p>영상 도구를 건드리기 전에 우리는 쉬운 말로 비트 시트를 썼습니다. Cubcoats 세계관에서 Kali의 성격 특성은 &quot;긍정적&quot;입니다. 모두가 소속감을 느끼게 해 주고, 상황이 어려워져도 밝음을 잃지 않는 캐릭터죠. 그래서 그 특성을 중심으로 10초짜리 흐름을 짰습니다.</p>
<blockquote>
<p>Kali가 작고 빛나는 랜턴을 들고 밤의 어둡고 안개 낀 숲으로 걸어 들어간다. 겁이 난 Kali는 혼자 주저앉아 거의 포기하려 한다. 그때 뒤에서 마법 같은 황금빛 나무가 빛나기 시작하는 것을 발견한다. 경이로움, 기쁨, 쏟아져 내리는 황금빛 입자들. 한 호흡 사이에 두려움에서 희망으로.</p>
</blockquote>
<p>전체 줄거리는 이게 다입니다. 복잡할 필요가 없습니다. 하나의 감정 전환을 하나의 연속된 샷에 담아내야 시작 프레임과 끝 프레임이 실제로 이어질 수 있습니다.</p>
<h2 id="전체를-양-끝에서-받쳐-주는-두-프레임" tabindex="-1">전체를 양 끝에서 받쳐 주는 두 프레임 <a class="header-anchor" href="#전체를-양-끝에서-받쳐-주는-두-프레임" aria-label="Permalink to &quot;전체를 양 끝에서 받쳐 주는 두 프레임&quot;"></a></h2>
<p>그 줄거리에서 <a href="/ko/tools/flux.html">이미지 생성기</a>로 핵심 스틸 두 장을 생성했습니다. 세로형 숏폼에 맞춘 세로 비율로요. 프롬프트는 같은 캐릭터를 서로 다른 두 순간에 묘사합니다.</p>
<p><strong>시작 프레임 프롬프트:</strong></p>
<blockquote>
<p>3D animated Pixar-style render of Kali, a small pink kitty character with large round dark eyes, pink pointed ears, a light pink belly, and a cheerful round face. She is standing at the edge of a dark misty forest at night, holding a tiny glowing lantern in both paws. Her ears are slightly flattened and her expression is nervous but determined. Cinematic lighting with cool blue moonlight from above and warm orange glow from the lantern. Dense fog between dark tree trunks in the background. Camera angle: medium shot, slightly low looking up at her. No text, no watermark.</p>
</blockquote>
<p><strong>끝 프레임 프롬프트:</strong></p>
<blockquote>
<p>3D animated Pixar-style render of Kali, a small pink kitty character with large round dark eyes, pink pointed ears, and a light pink belly. She is standing in front of a massive magical tree covered in glowing golden flowers, arms outstretched wide, beaming with a huge joyful smile. Golden petals float in the air around her. The tree radiates warm golden light that illuminates the entire forest clearing. Starry night sky visible above. Camera angle: wide shot from slightly below, epic reveal composition. No text, no watermark.</p>
</blockquote>
<div class="pipeline-media pipeline-media--two">
<figure>
<img src="/blog/sketch-to-3d-pipeline/kali-start-frame.png" alt="Start frame for vertical AI video" loading="lazy">
<figcaption><strong>시작 프레임.</strong> 랜턴을 든 채 숲 가장자리에서 긴장한 Kali.</figcaption>
</figure>
<figure>
<img src="/blog/sketch-to-3d-pipeline/kali-end-frame.png" alt="End frame for vertical AI video" loading="lazy">
<figcaption><strong>끝 프레임.</strong> 황금빛 나무 앞에서 기뻐하는 Kali.</figcaption>
</figure>
</div>
<p>Seedance가 이 두 양 끝점 사이를 보간합니다. 캐릭터 묘사를 두 프롬프트에서 동일하게 유지해, 모델이 같은 인물임을 알도록 했습니다. 바뀌는 것은 장면, 감정, 카메라뿐입니다.</p>
<h2 id="영상은-예상보다-더-잘-나왔다" tabindex="-1">영상은 예상보다 더 잘 나왔다 <a class="header-anchor" href="#영상은-예상보다-더-잘-나왔다" aria-label="Permalink to &quot;영상은 예상보다 더 잘 나왔다&quot;"></a></h2>
<p>두 프레임을 모두 Cinevva의 <a href="/ko/tools/video.html">영상 생성기</a>에 불러오고, Seedance 1.5 Pro를 골라, 9:16 비율과 15초로 설정하고, 줄거리를 모션 프롬프트에 입력한 다음 Generate를 눌렀습니다.</p>
<figure class="pipeline-media pipeline-media--single">
<img src="/blog/sketch-to-3d-pipeline/video-generator-setup.png" alt="Cinevva Video Generator with start and end frames loaded" loading="lazy">
<figcaption><strong>실제 설정.</strong> 시작 프레임, 끝 프레임, 모션 프롬프트, 9:16 세로, 15초, 오디오 켜짐.</figcaption>
</figure>
<p>클립은 두 양 끝점 사이를 보간합니다. 네이티브 오디오는 같은 패스에서 함께 생성됐습니다. 타임라인을 따라 샘플링한 프레임들입니다.</p>
<div class="pipeline-filmstrip" aria-label="Frames from generated vertical video">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_01.jpg" alt="Video frame 1" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_02.jpg" alt="Video frame 2" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_03.jpg" alt="Video frame 3" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_04.jpg" alt="Video frame 4" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_05.jpg" alt="Video frame 5" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_06.jpg" alt="Video frame 6" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_07.jpg" alt="Video frame 7" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_08.jpg" alt="Video frame 8" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_09.jpg" alt="Video frame 9" loading="lazy">
</div>
<p class="pipeline-caption">왼쪽에서 오른쪽으로: 생성된 세로형 숏폼의 진행.</p>
<p>정확한 마무리 포즈를 맞추는 게 중요할 때는 시작 프레임에 끝 프레임을 더하는 방식이 맞았습니다. 더 긴 감정 흐름에는 <a href="/ko/tools/video.html">영상 생성기</a>의 Kling 3.0 Pro 스토리보드 모드에서 단일 레퍼런스에 프롬프트를 더하는 방식이 잘 통했습니다. 작업마다 다른 설정을 쓰는 거죠.</p>
<h2 id="같은-캐릭터-이번엔-3d로" tabindex="-1">같은 캐릭터, 이번엔 3D로 <a class="header-anchor" href="#같은-캐릭터-이번엔-3d로" aria-label="Permalink to &quot;같은 캐릭터, 이번엔 3D로&quot;"></a></h2>
<p>여기서부터 흥미로워집니다. 영상 레퍼런스와 같은 계열의 T-포즈 스틸을 우리의 <a href="/ko/tools/hunyuan3d.html">3D 모델 생성기</a>에 넣어 이미지-투-3D 생성을 돌렸습니다. 게임 메시를 영상과 픽셀 단위로 맞추는 게 아닙니다. 맞추는 건 플레이어의 기억입니다. 게임 속 캐릭터가 릴 속 캐릭터와 같은 성격으로 느껴져야 합니다. 그리고 시작 단계에서 하나의 시각적 정체성을 고정해 두었기 때문에, 실제로 그렇게 됐습니다.</p>
<figure class="pipeline-media pipeline-media--single">
<img src="/blog/sketch-to-3d-pipeline/kali-preview.png" alt="Rendered preview of Hunyuan3D mesh" loading="lazy">
<figcaption>생성된 메시의 미리보기 렌더. 리깅 전의 텍스처와 비율입니다.</figcaption>
</figure>
<p><a href="/ko/tools/hunyuan3d.html">3D 모델 생성기</a>는 텍스처가 입혀진 GLB를 출력합니다. 게임에 바로 쓸 수준은 아니지만 누가 봐도 Kali입니다. 실루엣이 맞았습니다. 재질도 비슷했습니다. 다음 단계로 넘어가기에 충분했습니다.</p>
<h2 id="직접-돌려-보세요" tabindex="-1">직접 돌려 보세요 <a class="header-anchor" href="#직접-돌려-보세요" aria-label="Permalink to &quot;직접 돌려 보세요&quot;"></a></h2>
<p><a href="/ko/tools/hunyuan3d.html">3D 모델 생성기</a>의 원본 출력입니다. 리그 없이 텍스처가 입혀진 메시뿐입니다. 그 옆은 같은 캐릭터를 자동 리깅하고 걷기 애니메이션을 베이크한 결과입니다.</p>
<ClientOnly>
  <SketchPipelineModels />
</ClientOnly>
<h2 id="리깅과-애니메이션" tabindex="-1">리깅과 애니메이션 <a class="header-anchor" href="#리깅과-애니메이션" aria-label="Permalink to &quot;리깅과 애니메이션&quot;"></a></h2>
<p><a href="/ko/tools/hunyuan3d.html">3D 모델 생성기</a>는 메시를 줍니다. 그 메시를 움직이게 하려면 스켈레톤과 애니메이션이 필요합니다. 우리 플랫폼은 리깅을 자동으로 처리합니다. GLB를 업로드하면 전체 애니메이션 라이브러리가 딸린 리깅된 모델을 돌려받습니다. 걷기 사이클, 가만히 숨 쉬기, 점프 등 게임 캐릭터에 필요한 모든 것이요.</p>
<p>기본 걷기 애니메이션은 거의 맞아 보였지만, 완전하지는 않았습니다. Kali의 팔이 몸에 너무 가까이 붙었고 머리가 살짝 어긋난 각도로 기울었습니다. 둘 다 일반적인 휴머노이드에는 말이 되지만 둥근 카툰 고양이에게는 어색했습니다. 그래서 게임 코드에 런타임 본 보정을 추가했습니다. 팔을 바깥으로 밀어내는 어깨 오프셋과 기울기를 펴 주는 머리 회전 보정이요. 작은 손질이지만 차이가 컸습니다. 이게 없으면 Kali는 뻣뻣하고 로봇 같아 보였습니다. 적용하니 다시 Kali처럼 보였습니다.</p>
<h2 id="브라우저에서-캐릭터-플레이하기" tabindex="-1">브라우저에서 캐릭터 플레이하기 <a class="header-anchor" href="#브라우저에서-캐릭터-플레이하기" aria-label="Permalink to &quot;브라우저에서 캐릭터 플레이하기&quot;"></a></h2>
<p>리깅된 모델을 <a href="/ko/engine.html">Cinevva Engine</a>에 떨어뜨렸습니다. 3인칭 카메라, WASD 이동, 곳곳에 흩어진 수집 아이템, 가만히 있을 때 도는 오빗 카메라. 애니메이션 블렌딩을 제대로 맞추는 데는 반복이 필요했습니다. 대기와 걷기 사이 크로스페이드, 높이 정규화, 전방 축 수정, 본 오프셋 조정이요. 캐릭터 뒤를 따르는 3인칭 카메라가 스케치에서 직접 걸어 다닐 수 있는 무언가까지의 고리를 닫아 줍니다.</p>
<p>직접 해 보세요. WASD로 이동합니다.</p>
<div class="pipeline-game-embed">
<iframe src="https://api.cinevva.com/games/game-mmbijtzp-d63d/" allow="fullscreen" loading="lazy"></iframe>
</div>
<h2 id="내일-이걸-해-볼-사람에게-해-주고-싶은-말" tabindex="-1">내일 이걸 해 볼 사람에게 해 주고 싶은 말 <a class="header-anchor" href="#내일-이걸-해-볼-사람에게-해-주고-싶은-말" aria-label="Permalink to &quot;내일 이걸 해 볼 사람에게 해 주고 싶은 말&quot;"></a></h2>
<p>생성 도구를 건드리기 전에 캐릭터 룩 하나를 먼저 고정하세요. 그 레퍼런스를 제대로 잡는 데 쓰는 1분이 나중에 일관성을 쫓느라 쓸 한 시간을 아껴 줍니다.</p>
<p>먼저 짧은 줄거리를 쓰세요. 그런 다음 <a href="/ko/tools/flux.html">이미지 생성기</a>로 시작 프레임과 끝 프레임을 생성하세요. 레퍼런스 이미지는 API 크기 제한 안에 두세요. <a href="/ko/tools/hunyuan3d.html">3D 모델 생성기</a>에 넣을 때는 같은 디자인 체계에서 나온 T-포즈를 쓰세요.</p>
<p>두 프레임을 모두 <a href="/ko/tools/video.html">영상 생성기</a>에 넣고 보간하게 하세요. 게임 메시는 플랫폼을 통해 모델을 리깅하고, 기본 애니메이션이 캐릭터 비율에 잘 맞지 않으면 런타임에 본 오프셋을 손보세요.</p>
<p>2년 전에는 이 파이프라인이 존재하지 않았습니다. 팀과 예산이 필요했죠. 지금은 스케치 한 장과 Cinevva의 <a href="/ko/tools/">창작 도구</a>만 있으면 됩니다. 누가 캐릭터에 생명을 불어넣을 수 있는가에 있어 의미 있는 변화라고 생각합니다.</p>
<hr>
<p><em>사용한 Cinevva 도구: <a href="/ko/tools/flux.html">이미지 생성기</a>, <a href="/ko/tools/video.html">영상 생성기</a>, <a href="/ko/tools/hunyuan3d.html">3D 모델 생성기</a>, 자동 리깅, 그리고 <a href="/ko/engine.html">Cinevva Engine</a>. 2026년 초 기준입니다.</em></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 1부: 우리는 그것을 부숴보는 일부터 시작했다]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-01-risk-first</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-01-risk-first</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[동굴이나 화려한 셰이더를 만들기 전에, 우리는 한 가지 불편한 질문에 답해야 했다. 이게 브라우저에서 돌아가기는 할까?]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-1부-우리는-그것을-부숴보는-일부터-시작했다" tabindex="-1">브라우저에서 오픈 월드 만들기, 1부: 우리는 그것을 부숴보는 일부터 시작했다 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-1부-우리는-그것을-부숴보는-일부터-시작했다" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 1부: 우리는 그것을 부숴보는 일부터 시작했다&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p>우리는 전적으로 브라우저에서 돌아가는 멀티플레이어 오픈 월드를 만들고 있습니다. 설치도 없고, 앱 스토어도 없고, 그냥 URL 하나뿐입니다. 처음부터 가장 큰 위험은 분명했습니다. 브라우저가 게임플레이, 물리, 네트워킹을 위한 여유를 남겨두면서 지속적인 3D 월드를 플레이 가능한 프레임 레이트로 렌더링할 수 있을까?</p>
<p>대부분의 오픈 월드 프로젝트는 예측 가능한 순서로 실패합니다. 먼저 괜찮은 콘셉트가 나옵니다. 그다음 예쁜 장면이 나옵니다. 그러다 게임플레이가 존재하기도 전에 프레임 예산이 이미 다 떨어졌다는 걸 깨닫습니다.</p>
<p>우리는 다른 어떤 것에도 투자하기 전에 렌더 예산이라는 질문에 먼저 답하고 싶었습니다. 그래서 Spike 1은 예쁜 트레일러를 건너뛰고 곧장 측정으로 갔습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/01-terrain/" title="Spike 1 Terrain and Instancing" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/01-terrain/" target="_blank">새 탭에서 Spike 1 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=01-terrain">소스 보기</a></p>
<p>설정은 의도적으로 단순하게 했습니다. 512미터 지형 mesh, 층을 쌓은 sine 노이즈에 섬 감쇠를 더한 절차적 높이, 수면 평면, 대기 안개, 그리고 인스턴스화된 객체 500개. 평범한 WebGL과 Three.js, ACES 톤 매핑을 썼고, 그림자는 켜지 않았습니다.</p>
<p>우리는 그것이 어떻게 보이는지에는 관심이 없었습니다. 카메라가 장면 안을 움직일 때 장면이 안정적으로 유지되는지에 관심이 있었습니다.</p>
<p>이 spike에서 두 가지가 나왔고, 그것이 프로젝트 전체를 만들었습니다.</p>
<p>첫째, 첫 패스를 절제 있게 유지하면 데스크톱에서는 진짜 여유가 있다는 걸 확인했습니다. 덕분에 나중에 더 어려운 지형 아키텍처를 시도할 자신감이 생겼습니다.</p>
<p>둘째, 기준선 계약을 만들었습니다. 이후의 모든 spike는 이 장면 대비 자신의 비용을 설명해야 했습니다. 새 기능이 보기에는 좋아도 비용이 너무 크면 승격되지 못했습니다.</p>
<p>그 기준선 규율은 나중에 우리가 이음새 아티팩트, 혼합 LOD 전환, 컴퓨트 기반 메싱에 부딪혔을 때 결정적인 역할을 했습니다. 안정적인 기준이 없으면 모든 버그가 실제보다 더 커 보입니다.</p>
<p>2부에서는 렌더링에서 입력 감각으로 넘어갑니다. Worker 물리는 아키텍처 문서에서는 멋지게 들립니다. 하지만 그건 키를 눌렀을 때 캐릭터가 여전히 즉각적으로 느껴질 때에만 의미가 있습니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>Heightmap 지형.</strong> 각 셀이 높이 값 하나를 저장하는 2D 격자입니다. GPU가 버텍스 셰이더에서 평평한 mesh를 변위시켜 지형 표면을 만듭니다. Heightmap은 작고(65x65 chunk가 16비트에서 약 8 KB), GPU 친화적이며 렌더링이 빠릅니다. 한계는 동굴, 돌출부, 또는 자기 위로 접히는 어떤 표면도 표현할 수 없다는 점입니다. heightmap 제약과 그 이후에 무엇이 오는지에 대한 배경은 <a href="/ko/guides/landscape-generation-browser.html#why-heightmaps-arent-enough">지형 생성 가이드</a>를 보세요.</p>
<p><strong>Three.js.</strong> 이 프로젝트 전반에서 사용한 렌더링 라이브러리입니다. Three.js는 WebGL 2(이후에는 WebGPU)를 카메라, 조명, 머티리얼, 지오메트리 객체가 있는 씬 그래프로 추상화합니다. 같은 지오메트리의 여러 복사본을 단일 draw call로 렌더링하는 <code>InstancedMesh</code>, 프러스텀 컬링, PBR 머티리얼, 후처리를 제공합니다. <a href="https://github.com/mrdoob/three.js" target="_blank" rel="noreferrer">GitHub의 Three.js</a>를 보세요. Three.js가 브라우저 오픈 월드 스택에 어떻게 들어맞는지는 <a href="/ko/guides/browser-3d-open-world-tech.html#three-js">브라우저 3D 기술 가이드</a>를 보세요.</p>
<p><strong>InstancedMesh.</strong> 같은 지오메트리의 복사본 N개를 단일 draw call로 렌더링하는 Three.js 기능으로, 각각 다른 위치/회전/스케일을 갖습니다. 인스턴스별 변환은 행렬 속성 버퍼에 저장됩니다. 이것이 Spike 1에서 별도의 draw call 500개 없이 객체 500개를 렌더링한 방식입니다. 대규모 식생을 위해서는 GPU 기반 인스턴스 컬링이 이를 한 단계 더 밀어붙입니다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-vegetation-culling">GPU 식생 컬링에 관한 지형 가이드</a>를 보세요.</p>
<p><strong>프레임 예산.</strong> 60 fps에서 각 프레임은 모든 것을 위해 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.816ex;" xmlns="http://www.w3.org/2000/svg" width="13.598ex" height="2.773ex" role="img" focusable="false" viewBox="0 -864.9 6010.2 1225.5" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mfrac"><g data-mml-node="mrow" transform="translate(220,394) scale(0.707)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(2000,0)"><path data-c="A0" d="" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(2250,0)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(833,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mn" transform="translate(1095.8,-345) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><rect width="2658.6" height="60" x="120" y="220"/></g><g data-mml-node="mo" transform="translate(3176.4,0)"><path data-c="2248" d="M55 319Q55 360 72 393T114 444T163 472T205 482Q207 482 213 482T223 483Q262 483 296 468T393 413L443 381Q502 346 553 346Q609 346 649 375T694 454Q694 465 698 474T708 483Q722 483 722 452Q722 386 675 338T555 289Q514 289 468 310T388 357T308 404T224 426Q164 426 125 393T83 318Q81 289 69 289Q55 289 55 319ZM55 85Q55 126 72 159T114 210T163 238T205 248Q207 248 213 248T223 249Q262 249 296 234T393 179L443 147Q502 112 553 112Q609 112 649 141T694 220Q694 249 708 249T722 217Q722 153 675 104T555 55Q514 55 468 76T388 123T308 170T224 192Q164 192 125 159T83 84Q80 55 69 55Q55 55 55 85Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(4232.2,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="37" d="M55 458Q56 460 72 567L88 674Q88 676 108 676H128V672Q128 662 143 655T195 646T364 644H485V605L417 512Q408 500 387 472T360 435T339 403T319 367T305 330T292 284T284 230T278 162T275 80Q275 66 275 52T274 28V19Q270 2 255 -10T221 -22Q210 -22 200 -19T179 0T168 40Q168 198 265 368Q285 400 349 489L395 552H302Q128 552 119 546Q113 543 108 522T98 479L95 458V455H55V458Z" transform="translate(1278,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mfrac><mrow><mn>1000</mn><mtext> </mtext><mtext>ms</mtext></mrow><mn>60</mn></mfrac><mo>≈</mo><mn>16.7</mn></math></mjx-assistive-mml></mjx-container> ms를 가집니다. JavaScript 로직, 물리, 렌더링, 합성까지요. &quot;예산 점검&quot; spike는 기준 장면이 그중 얼마를 소비하는지 측정합니다. 그래서 이후에 추가하는 모든 것에 남는 여유는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="22.813ex" height="1.886ex" role="img" focusable="false" viewBox="0 -676 10083.4 833.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(306,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(750,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1250,0)" style="stroke-width: 3;"/><path data-c="75" d="M383 58Q327 -10 256 -10H249Q124 -10 105 89Q104 96 103 226Q102 335 102 348T96 369Q86 385 36 385H25V408Q25 431 27 431L38 432Q48 433 67 434T105 436Q122 437 142 438T172 441T184 442H187V261Q188 77 190 64Q193 49 204 40Q224 26 264 26Q290 26 311 35T343 58T363 90T375 120T379 144Q379 145 379 161T380 201T380 248V315Q380 361 370 372T320 385H302V431Q304 431 378 436T457 442H464V264Q464 84 465 81Q468 61 479 55T524 46H542V0Q540 0 467 -5T390 -11H383V58Z" transform="translate(1639,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(2195,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2587,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(3031,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3143.6,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(4199.4,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="37" d="M55 458Q56 460 72 567L88 674Q88 676 108 676H128V672Q128 662 143 655T195 646T364 644H485V605L417 512Q408 500 387 472T360 435T339 403T319 367T305 330T292 284T284 230T278 162T275 80Q275 66 275 52T274 28V19Q270 2 255 -10T221 -22Q210 -22 200 -19T179 0T168 40Q168 198 265 368Q285 400 349 489L395 552H302Q128 552 119 546Q113 543 108 522T98 479L95 458V455H55V458Z" transform="translate(1278,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6199.6,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(7199.8,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="62" d="M307 -11Q234 -11 168 55L158 37Q156 34 153 28T147 17T143 10L138 1L118 0H98V298Q98 599 97 603Q94 622 83 628T38 637H20V660Q20 683 22 683L32 684Q42 685 61 686T98 688Q115 689 135 690T165 693T176 694H179V543Q179 391 180 391L183 394Q186 397 192 401T207 411T228 421T254 431T286 439T323 442Q401 442 461 379T522 216Q522 115 458 52T307 -11ZM182 98Q182 97 187 90T196 79T206 67T218 55T233 44T250 35T271 29T295 26Q330 26 363 46T412 113Q424 148 424 212Q424 287 412 323Q385 405 300 405Q270 405 239 390T188 347L182 339V98Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(1056,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1450,0)" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(1894,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(2172,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2450,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(3006,0)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>t</mi><mtext>features</mtext></msub><mo>=</mo><mn>16.7</mn><mo>−</mo><msub><mi>t</mi><mtext>baseline</mtext></msub></math></mjx-assistive-mml></mjx-container>가 됩니다. 기준선이 이미 12 ms를 먹는다면, 게임플레이와 물리, 네트워킹을 모두 합쳐 약 4.7 ms만 남습니다. 이 접근은 AAA 오픈 월드 개발에서 왔으며 <a href="/ko/guides/browser-3d-open-world-tech.html#what-we-can-learn-from-skyrim-and-the-witcher">GTA V, Skyrim, Elden Ring</a> 모두 고정된 프레임 예산 안에 머물기 위해 공격적인 LOD와 스트리밍을 사용합니다.</p>
<hr>
<p>12부 중 1부.<br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-02-worker-physics.html">2부 - Worker 물리와 입력 지연에 대한 두려움</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 2부: Worker 물리와 입력 지연에 대한 두려움]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-02-worker-physics</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-02-worker-physics</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Rapier를 Web Worker로 옮긴 다음, 모두가 가장 먼저 걱정하는 그것을 측정했습니다. 움직임이 늦게 느껴질까요?]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-2부-worker-물리와-입력-지연에-대한-두려움" tabindex="-1">브라우저에서 오픈 월드 만들기, 2부: Worker 물리와 입력 지연에 대한 두려움 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-2부-worker-물리와-입력-지연에-대한-두려움" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 2부: Worker 물리와 입력 지연에 대한 두려움&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 파트를 링크해 둡니다.</p>
<p>브라우저 멀티플레이어를 충분히 오래 만들다 보면 결국 이 논쟁을 만나게 됩니다.</p>
<p>&quot;물리를 worker에 두면 아키텍처가 깔끔하다. 물리를 메인 스레드에 두면 더 안전하게 느껴진다.&quot;</p>
<p>둘 다 맞을 수 있습니다. 정말 중요한 건 실제 입력에서의 조작감과 지연입니다.</p>
<p>Spike 2는 의견이 아니라 측정으로 그 질문에 답하기 위해 만들었습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/02-rapier-worker/" title="Spike 2 Rapier Worker" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/02-rapier-worker/" target="_blank">새 탭에서 Spike 2 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=02-rapier-worker">소스 보기</a></p>
<p>우리는 Spike 1의 지형을 재사용하고 Rapier를 전용 module worker에 통합했습니다. 입력 상태를 매 프레임 worker로 보내고, 시뮬레이션은 그쪽에서 한 스텝 진행했으며, 권위 있는 위치를 렌더러로 다시 받아왔습니다.</p>
<p>핵심 지표는 입력부터 눈에 보이는 움직임까지의 지연, 그리고 물리 스텝 타이밍이었습니다. 또한 일반 이동, 스프린트 버스트, 점프 케이던스에서 지터가 생기는지도 지켜봤습니다.</p>
<p>결과는 예상보다 좋았습니다. 우리의 메시지 형태와 케이던스에서는 worker 경계가 지연을 좌우하지 않았습니다. 조작은 여전히 즉각적으로 느껴졌고, 그것이 플레이어가 신경 쓰는 유일한 부분이었습니다.</p>
<p>이 단계에서 한 가지 어려움은 해석의 위험이었습니다. 성공적인 결과가 나오면, 팀은 종종 지나치게 일반화해서 아키텍처 질문이 영원히 끝났다고 가정합니다. 그렇지 않습니다. 우리는 구체적인 시나리오 하나와 하드웨어 프로필 하나만 검증했을 뿐입니다. 이후의 spike들은 GPU와 스트리밍 압력이 바뀌었을 때 여전히 가정을 다시 점검해야 했습니다.</p>
<p>이 spike는 또한 프로세스를 한 단계 끌어올려 주었습니다. 우리는 인터랙티브 spike에서 기본으로 HUD에 타이밍 텔레메트리를 노출하기 시작했습니다. 그 덕분에 팀 대화가 &quot;뭔가 이상하다&quot;에서 &quot;이 경로가 1.2 ms를 더했다&quot;로 바뀌었습니다.</p>
<p>3부에서는 나중에 값비싼 사고를 막아준, 덜 화려한 실험들을 다룹니다. 브로드캐스트 부하, 모바일 제약, 행동 생성 신뢰성입니다.</p>
<h2 id="이-장에서-언급된-기술" tabindex="-1">이 장에서 언급된 기술 <a class="header-anchor" href="#이-장에서-언급된-기술" aria-label="Permalink to &quot;이 장에서 언급된 기술&quot;"></a></h2>
<p><strong>Rapier.</strong> Rust로 작성되어 브라우저 사용을 위해 WebAssembly로 컴파일되는 물리 엔진입니다. 리지드 바디, 콜라이더, 조인트, 캐릭터 컨트롤러, 레이캐스팅을 네이티브 대비 2-3배 성능으로 처리합니다. 오픈 월드에서 Rapier는 플레이어 캐릭터 컨트롤러(지형 위 걷기, 계단 오르기, 경사면 미끄러지기), 오브젝트 충돌, 상호작용을 위한 레이캐스팅, 트리거 볼륨을 제공합니다. <a href="https://rapier.rs/" target="_blank" rel="noreferrer">Rapier 문서</a>와 <a href="/ko/guides/browser-3d-open-world-tech.html#rapier-rust-wasm">물리에 관한 브라우저 3D 기술 가이드</a>를 보세요.</p>
<p><strong>Web Workers.</strong> 메인 스레드와 별개로 JavaScript(또는 Wasm)를 실행하는 브라우저 스레드입니다. 물리 시뮬레이션을 worker에 두면 무거운 <code>world.step()</code> 호출이 렌더링을 막지 않습니다. 메인 스레드는 매 프레임 <code>postMessage</code>로 입력 상태를 worker에 보내고 권위 있는 위치를 돌려받습니다. 지연 비용은 두 번의 메시지 홉입니다(데스크톱에서 각각 약 0.1-0.5 ms). 이점은 렌더 스레드가 충돌 감지에서 절대 멈추지 않는다는 것입니다. Transferable 객체(<code>ArrayBuffer</code> 전송)는 큰 위치 배열의 복사 오버헤드를 없앱니다.</p>
<p><strong>WebAssembly (Wasm).</strong> 브라우저에서 네이티브에 가까운 속도로 실행되는 바이너리 명령 형식입니다. Rapier, Havok, Recast 모두 Wasm으로 컴파일됩니다. Rapier-Wasm의 물리 스텝은 수백 개의 바디에 대해 보통 0.5-2 ms인데, 같은 작업을 JavaScript로 하면 5-15 ms입니다. Wasm 모듈은 JavaScript 글루 코드와 함께 <code>.wasm</code> 파일로 가져옵니다. <a href="https://webassembly.org/" target="_blank" rel="noreferrer">WebAssembly 명세</a>를 보세요.</p>
<p><strong>입력부터 화면까지의 지연.</strong> 키 입력과 그 결과로 화면에 나타나는 시각적 변화 사이의 시간입니다. 움직임이 &quot;즉각적&quot;으로 느껴지려면 이 값이 약 80 ms 아래로 유지되어야 합니다. worker 물리 구성에서 이 사슬은 누적됩니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.669ex;" xmlns="http://www.w3.org/2000/svg" width="39.876ex" height="2.214ex" role="img" focusable="false" viewBox="0 -683 17625.4 978.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(958.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2014.6,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(278,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(834,0)" style="stroke-width: 3;"/><path data-c="75" d="M383 58Q327 -10 256 -10H249Q124 -10 105 89Q104 96 103 226Q102 335 102 348T96 369Q86 385 36 385H25V408Q25 431 27 431L38 432Q48 433 67 434T105 436Q122 437 142 438T172 441T184 442H187V261Q188 77 190 64Q193 49 204 40Q224 26 264 26Q290 26 311 35T343 58T363 90T375 120T379 144Q379 145 379 161T380 201T380 248V315Q380 361 370 372T320 385H302V431Q304 431 378 436T457 442H464V264Q464 84 465 81Q468 61 479 55T524 46H542V0Q540 0 467 -5T390 -11H383V58Z" transform="translate(1390,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1946,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(4331.9,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(5332.1,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(5832.1,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(5999.1,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(1227,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(7886.5,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(8886.7,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(394,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(783,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(1227,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(10813.7,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(11813.9,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(392,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(836,0)" style="stroke-width: 3;"/><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(1392,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1948,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(2392,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(14448.7,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(15449,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="76" d="M338 431Q344 429 422 429Q479 429 503 431H508V385H497Q439 381 423 345Q421 341 356 172T288 -2Q283 -11 263 -11Q244 -11 239 -2Q99 359 98 364Q93 378 82 381T43 385H19V431H25L33 430Q41 430 53 430T79 430T104 429T122 428Q217 428 232 431H240V385H226Q187 384 184 370Q184 366 235 234L286 102L377 341V349Q377 363 367 372T349 383T335 385H331V431H338Z" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(528,0)" style="stroke-width: 3;"/><path data-c="79" d="M69 -66Q91 -66 104 -80T118 -116Q118 -134 109 -145T91 -160Q84 -163 97 -166Q104 -168 111 -168Q131 -168 148 -159T175 -138T197 -106T213 -75T225 -43L242 0L170 183Q150 233 125 297Q101 358 96 368T80 381Q79 382 78 382Q66 385 34 385H19V431H26L46 430Q65 430 88 429T122 428Q129 428 142 428T171 429T200 430T224 430L233 431H241V385H232Q183 385 185 366L286 112Q286 113 332 227L376 341V350Q376 365 366 373T348 383T334 385H331V431H337H344Q351 431 361 431T382 430T405 429T422 429Q477 429 503 431H508V385H497Q441 380 422 345Q420 343 378 235T289 9T227 -131Q180 -204 113 -204Q69 -204 44 -177T19 -116Q19 -89 35 -78T69 -66Z" transform="translate(922,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1450,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(2006,0)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi>L</mi><mo>=</mo><msub><mi>t</mi><mtext>input</mtext></msub><mo>+</mo><mn>2</mn><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><msub><mi>t</mi><mtext>msg</mtext></msub><mo>+</mo><msub><mi>t</mi><mtext>step</mtext></msub><mo>+</mo><msub><mi>t</mi><mtext>render</mtext></msub><mo>+</mo><msub><mi>t</mi><mtext>vsync</mtext></msub></math></mjx-assistive-mml></mjx-container><p>keydown 이벤트(메인 스레드), worker로 갔다 오는 <code>postMessage</code>(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.669ex;" xmlns="http://www.w3.org/2000/svg" width="5.276ex" height="2.176ex" role="img" focusable="false" viewBox="0 -666 2332.2 961.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(500,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(667,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(1227,0)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>2</mn><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><msub><mi>t</mi><mtext>msg</mtext></msub></math></mjx-assistive-mml></mjx-container>), 물리 스텝, 렌더러가 새 위치를 적용하는 단계, 그다음 다음 vsync입니다. 각 항은 그 자체로는 작지만(데스크톱에서 메시지 홉당 약 0.1-0.5 ms) 쌓입니다. 그래서 아키텍처 다이어그램을 믿는 대신 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.541ex" height="1.545ex" role="img" focusable="false" viewBox="0 -683 681 683" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>L</mi></math></mjx-assistive-mml></mjx-container>을 직접 측정했습니다.</p>
<hr>
<p>12부 중 2부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-01-risk-first.html">1부 - 우리는 그것을 부수려는 시도부터 시작했다</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes.html">3부 - 우리를 구한 화려하지 않은 spike들</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈월드 만들기, 3부: 우리를 구한 화려하지 않은 spike들]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Durable Object 브로드캐스트 부하, 모바일 품질 제약, 행동 생성 신뢰성은 화려하지 않았지만 값비싼 사고를 막아 줬습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈월드-만들기-3부-우리를-구한-화려하지-않은-spike들" tabindex="-1">브라우저에서 오픈월드 만들기, 3부: 우리를 구한 화려하지 않은 spike들 <a class="header-anchor" href="#브라우저에서-오픈월드-만들기-3부-우리를-구한-화려하지-않은-spike들" aria-label="Permalink to &quot;브라우저에서 오픈월드 만들기, 3부: 우리를 구한 화려하지 않은 spike들&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 편을 링크해 둡니다.</p>
<p>이번 편은 번쩍이는 스크린샷이 더 적고 아키텍처 보험이 더 많습니다.</p>
<p>Spike 1과 2를 마친 뒤, 우리는 작아 보이지만 제품 수준의 영향이 있는 위험 점검 세 가지를 돌렸습니다.</p>
<p>첫 번째는 Durable Objects를 이용한 브로드캐스트 fan-out이었습니다. 게임 수준의 tick 비율에서 여러 클라이언트로 위치를 분배하는 것을 테스트하고 지연 분포, tick당 CPU, 전달 무결성을 추적했습니다. 이게 실패했다면 우리는 단일 섬 소유권 대신 이른 샤딩으로 옮겼을 겁니다.</p>
<p>두 번째는 모바일 제약 검증이었습니다. 데스크톱 프리셋의 이름만 모바일로 바꾼 게 아니라, 같은 기준 지형에서 출발한 명확한 저비용 프로필이었습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/01-terrain/?quality=mobile" title="Mobile quality profile based on Spike 1" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/01-terrain/?quality=mobile" target="_blank">새 탭에서 모바일 프로필 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=01-terrain">소스 보기</a></p>
<p>우리는 세그먼트 밀도, 오브젝트 수, 렌더 해상도 부담, 안개 범위를 줄였습니다. 질문은 단순했습니다. 렌더러 전체를 다시 쓰지 않고도 이 세계가 모바일 수준의 제약에서 읽히고 반응할 수 있을까.</p>
<p>세 번째는 창작자 워크플로를 위한 행동 생성 신뢰성이었습니다. 유효한 JSON 비율, 기대하는 primitive에 대한 의미적 정확성, 응답 지연을 평가했습니다. 이게 실패했다면 우리는 엄격한 폼 기반 행동 작성으로 옮겼을 겁니다.</p>
<p>이 장의 핵심 통찰은 이런 화려하지 않은 spike들이 시각적 spike보다 더 빠르게 아키텍처를 바꿨다는 점입니다. 그것들은 네트워크 토폴로지, 모바일 약속, 도구 UX에 단단한 경계를 세웠습니다.</p>
<p>4부에서는 다시 눈에 보이는 지형 작업으로 돌아가, 정적인 로딩 스크린샷이 아니라 이동 중 스트리밍 동작을 테스트합니다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>Cloudflare Durable Objects.</strong> 내장 영속성과 WebSocket 지원을 갖춘, 엣지에 배포되는 상태 보존형 서버리스 인스턴스입니다. 각 Durable Object는 하나의 월드 shard(또는 chunk)에 대한 권위 있는 상태를 보관합니다. 플레이어는 WebSocket으로 연결해 같은 shard에 있는 다른 플레이어들로부터 위치 브로드캐스트를 받습니다. 플레이어가 인접한 chunk로 이동하면 그 chunk의 Durable Object에 연결합니다. Durable Object는 상태를 자동으로 디스크에 영속화하고 수천 개의 동시 인스턴스로 확장됩니다. <a href="https://developers.cloudflare.com/durable-objects/" target="_blank" rel="noreferrer">Cloudflare Durable Objects 문서</a>와 우리의 <a href="/ko/guides/browser-3d-open-world-tech.html#multiplayer-networking">멀티플레이어 네트워킹에 관한 브라우저 3D 기술 가이드</a>를 보세요.</p>
<p><strong>공간 샤딩.</strong> 지리적 영역에 따라 세계를 서버 인스턴스들에 나누는 것입니다. 각 shard는 월드 그리드의 직사각형 영역을 소유합니다. 플레이어 밀도가 바뀌면 shard는 분할되거나 병합될 수 있습니다. shard 경계 근처에 있는 플레이어는 cross-shard 가시성 쿼리를 통해 두 shard의 콘텐츠를 모두 봅니다. <a href="/ko/guides/browser-3d-open-world-tech.html#server-architecture">EVE Online이 하나의 우주에서 수천 명의 플레이어를 다루는</a> 방식이 바로 이것입니다.</p>
<p><strong>WebSocket 브로드캐스트 fan-out.</strong> 실시간 위치 업데이트를 한 서버에서 연결된 많은 클라이언트로 분배하는 것입니다. 클라이언트당 하향 대역폭은 보이는 군중 규모에 선형으로 비례합니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.666ex;" xmlns="http://www.w3.org/2000/svg" width="23.398ex" height="2.236ex" role="img" focusable="false" viewBox="0 -694 10341.8 988.2" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D435" d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(792,-150) scale(0.707)"><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(444,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(722,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1444,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(2000,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2809.1,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3864.8,0)"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(836,-150) scale(0.707)"><path data-c="76" d="M338 431Q344 429 422 429Q479 429 503 431H508V385H497Q439 381 423 345Q421 341 356 172T288 -2Q283 -11 263 -11Q244 -11 239 -2Q99 359 98 364Q93 378 82 381T43 385H19V431H25L33 430Q41 430 53 430T79 430T104 429T122 428Q217 428 232 431H240V385H226Q187 384 184 370Q184 366 235 234L286 102L377 341V349Q377 363 367 372T349 383T335 385H331V431H338Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(528,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(806,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(1200,0)" style="stroke-width: 3;"/><path data-c="62" d="M307 -11Q234 -11 168 55L158 37Q156 34 153 28T147 17T143 10L138 1L118 0H98V298Q98 599 97 603Q94 622 83 628T38 637H20V660Q20 683 22 683L32 684Q42 685 61 686T98 688Q115 689 135 690T165 693T176 694H179V543Q179 391 180 391L183 394Q186 397 192 401T207 411T228 421T254 431T286 439T323 442Q401 442 461 379T522 216Q522 115 458 52T307 -11ZM182 98Q182 97 187 90T196 79T206 67T218 55T233 44T250 35T271 29T295 26Q330 26 363 46T412 113Q424 148 424 212Q424 287 412 323Q385 405 300 405Q270 405 239 390T188 347L182 339V98Z" transform="translate(1478,0)" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(2034,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2312,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(6921.8,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(7922.1,0)"><g data-mml-node="mi"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(462,-150) scale(0.707)"><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(834,0)" style="stroke-width: 3;"/><path data-c="79" d="M69 -66Q91 -66 104 -80T118 -116Q118 -134 109 -145T91 -160Q84 -163 97 -166Q104 -168 111 -168Q131 -168 148 -159T175 -138T197 -106T213 -75T225 -43L242 0L170 183Q150 233 125 297Q101 358 96 368T80 381Q79 382 78 382Q66 385 34 385H19V431H26L46 430Q65 430 88 429T122 428Q129 428 142 428T171 429T200 430T224 430L233 431H241V385H232Q183 385 185 366L286 112Q286 113 332 227L376 341V350Q376 365 366 373T348 383T334 385H331V431H337H344Q351 431 361 431T382 430T405 429T422 429Q477 429 503 431H508V385H497Q441 380 422 345Q420 343 378 235T289 9T227 -131Q180 -204 113 -204Q69 -204 44 -177T19 -116Q19 -89 35 -78T69 -66Z" transform="translate(1334,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1862,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(2306,0)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><msub><mi>B</mi><mtext>client</mtext></msub><mo>=</mo><msub><mi>N</mi><mtext>visible</mtext></msub><mo>×</mo><msub><mi>b</mi><mtext>player</mtext></msub></math></mjx-assistive-mml></mjx-container><p>게임 수준의 tick 비율(20-30 Hz)에서 각 플레이어는 초당 약 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.666ex;" xmlns="http://www.w3.org/2000/svg" width="11.885ex" height="2.236ex" role="img" focusable="false" viewBox="0 -694 5253.3 988.2" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(462,-150) scale(0.707)"><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(834,0)" style="stroke-width: 3;"/><path data-c="79" d="M69 -66Q91 -66 104 -80T118 -116Q118 -134 109 -145T91 -160Q84 -163 97 -166Q104 -168 111 -168Q131 -168 148 -159T175 -138T197 -106T213 -75T225 -43L242 0L170 183Q150 233 125 297Q101 358 96 368T80 381Q79 382 78 382Q66 385 34 385H19V431H26L46 430Q65 430 88 429T122 428Q129 428 142 428T171 429T200 430T224 430L233 431H241V385H232Q183 385 185 366L286 112Q286 113 332 227L376 341V350Q376 365 366 373T348 383T334 385H331V431H337H344Q351 431 361 431T382 430T405 429T422 429Q477 429 503 431H508V385H497Q441 380 422 345Q420 343 378 235T289 9T227 -131Q180 -204 113 -204Q69 -204 44 -177T19 -116Q19 -89 35 -78T69 -66Z" transform="translate(1334,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1862,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(2306,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2697.6,0)"><path data-c="2248" d="M55 319Q55 360 72 393T114 444T163 472T205 482Q207 482 213 482T223 483Q262 483 296 468T393 413L443 381Q502 346 553 346Q609 346 649 375T694 454Q694 465 698 474T708 483Q722 483 722 452Q722 386 675 338T555 289Q514 289 468 310T388 357T308 404T224 426Q164 426 125 393T83 318Q81 289 69 289Q55 289 55 319ZM55 85Q55 126 72 159T114 210T163 238T205 248Q207 248 213 248T223 249Q262 249 296 234T393 179L443 147Q502 112 553 112Q609 112 649 141T694 220Q694 249 708 249T722 217Q722 153 675 104T555 55Q514 55 468 76T388 123T308 170T224 192Q164 192 125 159T83 84Q80 55 69 55Q55 55 55 85Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3753.3,0)"><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>b</mi><mtext>player</mtext></msub><mo>≈</mo><mn>800</mn></math></mjx-assistive-mml></mjx-container> 바이트의 위치 데이터를 만들어 내므로, 시야에 200명의 플레이어가 있으면 클라이언트당 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="15.964ex" height="1.692ex" role="img" focusable="false" viewBox="0 -666 7056 748" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1722.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2722.4,0)"><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4500.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(5556,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>200</mn><mo>×</mo><mn>800</mn><mo>=</mo><mn>160</mn></math></mjx-assistive-mml></mjx-container> KB/s가 듭니다. 단순한 all-to-all 서버 비용은 그보다 나쁘고 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="3.119ex" height="1.887ex" role="img" focusable="false" viewBox="0 -833.9 1378.8 833.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(975.3,363) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>N</mi><mn>2</mn></msup></math></mjx-assistive-mml></mjx-container>처럼 커지는데, 바로 그래서 관련성 필터링(공간 관심 관리)이 tick 예산 안에서 각 연결로 밀어내기 전에 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="6.414ex" height="1.902ex" role="img" focusable="false" viewBox="0 -683 2834.8 840.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(836,-150) scale(0.707)"><path data-c="76" d="M338 431Q344 429 422 429Q479 429 503 431H508V385H497Q439 381 423 345Q421 341 356 172T288 -2Q283 -11 263 -11Q244 -11 239 -2Q99 359 98 364Q93 378 82 381T43 385H19V431H25L33 430Q41 430 53 430T79 430T104 429T122 428Q217 428 232 431H240V385H226Q187 384 184 370Q184 366 235 234L286 102L377 341V349Q377 363 367 372T349 383T335 385H331V431H338Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(528,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(806,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(1200,0)" style="stroke-width: 3;"/><path data-c="62" d="M307 -11Q234 -11 168 55L158 37Q156 34 153 28T147 17T143 10L138 1L118 0H98V298Q98 599 97 603Q94 622 83 628T38 637H20V660Q20 683 22 683L32 684Q42 685 61 686T98 688Q115 689 135 690T165 693T176 694H179V543Q179 391 180 391L183 394Q186 397 192 401T207 411T228 421T254 431T286 439T323 442Q401 442 461 379T522 216Q522 115 458 52T307 -11ZM182 98Q182 97 187 90T196 79T206 67T218 55T233 44T250 35T271 29T295 26Q330 26 363 46T412 113Q424 148 424 212Q424 287 412 323Q385 405 300 405Q270 405 239 390T188 347L182 339V98Z" transform="translate(1478,0)" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(2034,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2312,0)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>N</mi><mtext>visible</mtext></msub></math></mjx-assistive-mml></mjx-container>을 제한합니다. 델타 압축과 업데이트 빈도의 트레이드오프는 우리의 <a href="/ko/guides/browser-3d-open-world-tech.html#client-server-communication">네트워킹 가이드</a>를 보세요.</p>
<p><strong>모바일 렌더링 제약.</strong> 모바일 GPU는 데스크톱 GPU의 1/5에서 1/10 처리량, 약 1 GB 메모리 한계(데스크톱은 2-4 GB), 그리고 지속 부하에서의 발열 스로틀링을 갖습니다. 모바일 품질 프로필은 세그먼트 밀도, 오브젝트 수, 렌더 해상도, 그리기 거리, 그림자 품질을 줄입니다. 목표는 데스크톱과의 동등함이 아니라 읽힘과 반응성을 유지하는 것입니다. 실제 GPU 벤치마크는 <a href="/ko/guides/browser-3d-open-world-tech.html#browser-3d-performance-real-numbers">브라우저 3D 성능 수치</a>를 보세요.</p>
<hr>
<p>12편 중 3편.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-02-worker-physics.html">2부 - Worker 물리와 입력 지연에 대한 두려움</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy.html">4부 - 화려한 지형보다 먼저 스트리밍</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 4부: 화려한 지형보다 먼저 스트리밍]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[우리는 먼저 단순한 콘텐츠로 chunk 로드와 교체를 테스트한 다음, 점진적 heightmap 정밀화로 넘어갔습니다. 그 순서가 효과를 봤습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-4부-화려한-지형보다-먼저-스트리밍" tabindex="-1">브라우저에서 오픈 월드 만들기, 4부: 화려한 지형보다 먼저 스트리밍 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-4부-화려한-지형보다-먼저-스트리밍" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 4부: 화려한 지형보다 먼저 스트리밍&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p>스트리밍은 &quot;보기 좋은&quot; 프로젝트가 보통 무너지는 지점입니다.</p>
<p>정지 화면에서는 많은 것을 숨길 수 있습니다. 하지만 chunk 경계를 넘을 때 발생하는 40 ms 끊김은 숨길 수 없습니다.</p>
<p>우리는 고급 지형 표현을 만들기 전에 일부러 스트리밍부터 테스트했습니다. 그 덕분에 로드와 언로드 동작에 대한 깨끗한 신호를 얻었습니다.</p>
<p>Spike 6은 단순한 chunk 콘텐츠로 주변 영역 교체를 검증했습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/06-chunk-streaming/" title="Spike 6 Chunk Load Swap" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/06-chunk-streaming/" target="_blank">새 탭에서 Spike 6 열기 ↗</a> · <a href="/blog/spike-source?spike=06-chunk-streaming">소스 보기</a></p>
<p>그다음 Spike 11에서 실제 지형 경로로 넘어갔습니다. worker 쪽 디코드를 사용하는 높이 chunk 스트리밍, 그리고 17에서 33, 65 샘플 그리드로 이어지는 점진적 정밀화입니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/11-chunk-streaming/" title="Spike 11 Heightmap Chunk Streaming" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/11-chunk-streaming/" target="_blank">새 탭에서 Spike 11 열기 ↗</a> · <a href="/blog/spike-source?spike=11-chunk-streaming">소스 보기</a></p>
<p>순서를 정하는 일이 우리가 예상한 것보다 더 중요했습니다. 처음부터 압축된 높이 chunk로 바로 시작했다면, 모든 끊김이 모호했을 겁니다. 디코드 문제인지, 텍스처 업로드 문제인지, 지오메트리 업데이트 문제인지 알 수 없죠. Spike 6은 Spike 11이 복잡도를 더하기 전에 불확실성 한 겹을 먼저 걷어냈습니다.</p>
<p>이 장에서 얻은 실용적인 교훈 하나가 이후 spike들로 이어졌습니다. 업로드 정체는 평균 FPS에서 추론하지 말고 직접 측정해야 합니다. 평균 FPS는 프레임 스파이크를 가리고, 사용자가 실제로 느끼는 건 바로 그 프레임 스파이크입니다.</p>
<p>5부에서는 식생, 지형 셰이더, 캐스케이드 섀도가 같은 프레임 예산을 두고 경쟁하는 시각 비용 장으로 들어갑니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>Chunk 기반 스트리밍.</strong> 월드는 독립적인 chunk들의 그리드로 나뉩니다(보통 64x64 미터). 플레이어가 움직이면 뒤쪽 가장자리의 chunk는 언로드되고, 앞쪽 가장자리의 chunk가 스트리밍되어 들어옵니다. <a href="/ko/guides/browser-3d-open-world-tech.html#skyrim-s-cell-system">Skyrim의 cell 시스템</a>이 이렇게 동작합니다. 플레이어 주변에 5x5 cell 그리드를 로드하고, 움직일 때마다 교체합니다. 브라우저 버전은 여기에 네트워크 지연이 더해지므로, 플레이어 속도에 기반한 예측 선읽기가 매우 중요해집니다. 우리의 <a href="/ko/guides/landscape-generation-browser.html#streaming-architecture-for-terrain">스트리밍 아키텍처 가이드</a>를 보세요.</p>
<p><strong>점진적 heightmap 정밀화.</strong> 지형을 먼저 낮은 해상도로 보낸 다음 정밀화합니다. 그리드 크기는 임의로 정한 게 아닙니다. 각 레벨은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="18.385ex" height="2.497ex" role="img" focusable="false" viewBox="0 -853.7 8126.1 1103.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(389,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(533,363) scale(0.707)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1562.6,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2562.8,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3062.8,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3674.1,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4674.3,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(5063.3,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(533,363) scale(0.707)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(6236.9,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(7237.1,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(7737.1,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><msup><mn>2</mn><mi>k</mi></msup><mo>+</mo><mn>1</mn><mo stretchy="false">)</mo><mo>×</mo><mo stretchy="false">(</mo><msup><mn>2</mn><mi>k</mi></msup><mo>+</mo><mn>1</mn><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container> 그리드라서 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="11.295ex" height="2.09ex" role="img" focusable="false" viewBox="0 -841.7 4992.6 923.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="37" d="M55 458Q56 460 72 567L88 674Q88 676 108 676H128V672Q128 662 143 655T195 646T364 644H485V605L417 512Q408 500 387 472T360 435T339 403T319 367T305 330T292 284T284 230T278 162T275 80Q275 66 275 52T274 28V19Q270 2 255 -10T221 -22Q210 -22 200 -19T179 0T168 40Q168 198 265 368Q285 400 349 489L395 552H302Q128 552 119 546Q113 543 108 522T98 479L95 458V455H55V458Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1277.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(2333.6,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(533,363) scale(0.707)"><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3492.3,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(4492.6,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>17</mn><mo>=</mo><msup><mn>2</mn><mn>4</mn></msup><mo>+</mo><mn>1</mn></math></mjx-assistive-mml></mjx-container>, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="11.295ex" height="2.072ex" role="img" focusable="false" viewBox="0 -833.9 4992.6 915.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1277.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(2333.6,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(533,363) scale(0.707)"><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3492.3,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(4492.6,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>33</mn><mo>=</mo><msup><mn>2</mn><mn>5</mn></msup><mo>+</mo><mn>1</mn></math></mjx-assistive-mml></mjx-container>, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="11.295ex" height="2.072ex" role="img" focusable="false" viewBox="0 -833.9 4992.6 915.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1277.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(2333.6,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(533,363) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3492.3,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(4492.6,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>65</mn><mo>=</mo><msup><mn>2</mn><mn>6</mn></msup><mo>+</mo><mn>1</mn></math></mjx-assistive-mml></mjx-container>이 됩니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="2.891ex" height="1.692ex" role="img" focusable="false" viewBox="0 -666 1278 748" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(778,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo>+</mo><mn>1</mn></math></mjx-assistive-mml></mjx-container> 덕분에 모든 경계에 공유 샘플이 하나씩 유지되어 이웃끼리 딱 맞아떨어지고, 단계마다 샘플 수가 대략 네 배가 됩니다(변의 길이가 두 배가 되면 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="2.345ex" height="1.912ex" role="img" focusable="false" viewBox="0 -833.9 1036.6 844.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D45B" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(633,363) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>n</mi><mn>2</mn></msup></math></mjx-assistive-mml></mjx-container>이 그렇게 늘어납니다). 17x17 그리드(4m 간격일 때 64m chunk의 최소값)는 압축 후 약 200 바이트이고, 눈에 보이는 표면을 즉시 렌더링합니다. 그다음 33x33 정밀화를 스트리밍하고, 이어서 완전한 65x65 해상도를 보냅니다. 각 레벨은 이전 데이터를 대체하지 않고 샘플을 더합니다. 이는 먼 지형에는 저해상도 데이터를, 가까운 지형에는 완전 해상도를 쓰는 지오메트리 clipmap LOD 링에 그대로 대응됩니다. <a href="/ko/guides/landscape-generation-browser.html#progressive-chunk-loading">점진적 chunk 로딩</a>을 보세요.</p>
<p><strong>델타 인코딩과 압축.</strong> 인접한 셀들의 값이 비슷하기 때문에 heightmap 데이터는 압축이 잘 됩니다. 델타 인코딩은 각 셀과 그 예측값(이웃들의 평균)의 차이를 저장해서 값들을 0 근처로 모읍니다. zlib나 brotli와 결합하면 65x65 chunk는 원본 8.4 KB에서 압축 후 1-2 KB로 줄어듭니다. 먼 chunk에 대해 정밀도를 낮추면(16-bit 대신 8-bit) 0.5-1 KB가 됩니다. <a href="/ko/guides/landscape-generation-browser.html#terrain-data-compression-for-streaming">지형 데이터 압축</a>을 보세요.</p>
<p><strong>예측 선읽기.</strong> 플레이어가 도착하기 전에 chunk를 로드합니다. 선행 거리는 chunk가 로드되는 동안 플레이어가 이동하는 거리를 감당해야 하므로 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.65ex;" xmlns="http://www.w3.org/2000/svg" width="16.701ex" height="2.22ex" role="img" focusable="false" viewBox="0 -694 7381.6 981.2" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(553,-150) scale(0.707)"><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(948,0)" style="stroke-width: 3;"/><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" transform="translate(1392,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1698,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(2142,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(2531,0)" style="stroke-width: 3;"/><path data-c="68" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 124T102 167T103 217T103 272T103 329Q103 366 103 407T103 482T102 542T102 586T102 603Q99 622 88 628T43 637H25V660Q25 683 27 683L37 684Q47 685 66 686T103 688Q120 689 140 690T170 693T181 694H184V367Q244 442 328 442Q451 442 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2975,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3377.6,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(4433.3,0)"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(5140.6,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(5640.8,0)"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(394,-150) scale(0.707)"><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(278,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(778,0)" style="stroke-width: 3;"/><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(1278,0)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>d</mi><mtext>prefetch</mtext></msub><mo>=</mo><mi>v</mi><mo>⋅</mo><msub><mi>t</mi><mtext>load</mtext></msub></math></mjx-assistive-mml></mjx-container>가 되고, 속도에 따라 늘어납니다. 걷는 속도(5 km/h)에서는 앞쪽 2개 chunk(128m)를 미리 가져오고, 달리는 속도(15 km/h)에서는 4개를 가져옵니다. 로드 링은 속도 방향에 따라 이동합니다. 우선순위 큐가 대기 중인 요청을 긴급도순으로 정렬하고, 플레이어가 이미 멀어진 chunk에 대한 요청은 취소합니다. <a href="/ko/guides/landscape-generation-browser.html#predictive-pre-fetching">예측 선읽기</a>를 보세요.</p>
<hr>
<p>12부 중 4부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes.html">3부 - 우리를 구한 화려하지 않은 spike들</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty.html">5부 - 예쁜 것들에 예산 배정하기</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 5부: 예쁜 것들에 예산 배정하기]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[식생, 지형 머티리얼, 캐스케이드 섀도우는 보기 좋았다. 진짜 일은 이것들이 프레임 예산에 들어맞는다는 걸 증명하는 거였다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-5부-예쁜-것들에-예산-배정하기" tabindex="-1">브라우저에서 오픈 월드 만들기, 5부: 예쁜 것들에 예산 배정하기 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-5부-예쁜-것들에-예산-배정하기" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 5부: 예쁜 것들에 예산 배정하기&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 파트를 링크해 둡니다.</p>
<p>이번 장은 시각적 야심이 산수와 부딪힌 장이다.</p>
<p>우리는 렌더링 비용을 별도의 spike로 쪼개서 측정했다. 묶어서 나온 결과는 진단하기 어렵기 때문이다. 한 번에 전부 켜면, 알게 되는 건 딱 하나다. 프레임이 느리다는 것. 어떤 기능이 예산을 먹었는지는 알 수 없다.</p>
<p>Spike 7은 식생 밀도와 애니메이션 비용을 겨냥했다. 방식은 지형 chunk마다 32x32 밀도 맵에서 런타임으로 흩뿌리고, 큰 <code>InstancedMesh</code> 세트에 넣어주는 것이었다. 풀잎 하나하나와 관목 덩어리마다 스크롤하는 노이즈 텍스처로 구동되는 버텍스 셰이더 바람을 입혔다. 우리가 지켜본 핵심 수치는 삼각형 개수가 아니라 중급 GPU에서의 draw call 오버헤드와 버텍스 처리량이었다. 인스턴스를 더 적은 mesh로 batch하는 게 잎 하나당 폴리곤 수를 줄이는 것보다 더 중요하다는 걸 알게 됐다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/07-gpu-vegetation/" title="Spike 7 GPU Vegetation" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/07-gpu-vegetation/" target="_blank">새 탭에서 Spike 7 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=07-gpu-vegetation">소스 보기</a></p>
<p>Spike 8은 지형 머티리얼의 복잡도를 밀어붙였다. 경사 각도와 고도로 가중치를 준 다층 블렌딩, 절벽 면에 선택적으로 적용하는 triplanar 투영, 그리고 레이어별 노멀 맵. 셰이더는 네 개의 텍스처 레이어로 경사 기반 splatting을 하고 있었고, 각 레이어마다 diffuse와 normal 샘플이 필요했다. 그러니까 조명을 더하기 전에 이미 프래그먼트당 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="9.176ex" height="1.717ex" role="img" focusable="false" viewBox="0 -677 4056 759" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1722.4,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2500.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3556,0)"><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>4</mn><mo>×</mo><mn>2</mn><mo>=</mo><mn>8</mn></math></mjx-assistive-mml></mjx-container>번의 텍스처 페치가 들어가고, 이 개수는 레이어에 따라 선형으로 늘어난다. 다섯 번째 레이어를 넣으면 픽셀마다 10번 페치라는 뜻이다. 바닥값을 찾으려고 일부러 내장 Intel GPU에서 프로파일링했다. 결론은, 수직 면에서의 triplanar 투영은 그 비용을 들일 만했지만, 다섯 번째 splat 레이어를 추가하는 건 그렇지 않았다는 것이다.</p>
<p><a href="/spikes/08-terrain-material/" target="_blank">새 탭에서 Spike 8 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=08-terrain-material">소스 보기</a></p>
<p>Spike 9는 현실적인 지형과 오브젝트 부하 아래에서의 캐스케이드 섀도우 맵 비용에 집중했다. 세 개의 캐스케이드를 쓰는 CSM이 기준선이었다. 일부러 낮은 각도의 태양 위치로 테스트했는데, 거기가 캐스케이드 압박이 가장 심해지는 지점이기 때문이다. 가장 먼 캐스케이드는 거대한 절두체 조각을 덮고, 섀도우 디테일은 텍셀 밀도 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.783ex;" xmlns="http://www.w3.org/2000/svg" width="7.095ex" height="3.009ex" role="img" focusable="false" viewBox="0 -983.7 3135.9 1330" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D70C" d="M58 -216Q25 -216 23 -186Q23 -176 73 26T127 234Q143 289 182 341Q252 427 341 441Q343 441 349 441T359 442Q432 442 471 394T510 276Q510 219 486 165T425 74T345 13T266 -10H255H248Q197 -10 165 35L160 41L133 -71Q108 -168 104 -181T92 -202Q76 -216 58 -216ZM424 322Q424 359 407 382T357 405Q322 405 287 376T231 300Q217 269 193 170L176 102Q193 26 260 26Q298 26 334 62Q367 92 389 158T418 266T424 322Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(794.8,0)"><path data-c="2248" d="M55 319Q55 360 72 393T114 444T163 472T205 482Q207 482 213 482T223 483Q262 483 296 468T393 413L443 381Q502 346 553 346Q609 346 649 375T694 454Q694 465 698 474T708 483Q722 483 722 452Q722 386 675 338T555 289Q514 289 468 310T388 357T308 404T224 426Q164 426 125 393T83 318Q81 289 69 289Q55 289 55 319ZM55 85Q55 126 72 159T114 210T163 238T205 248Q207 248 213 248T223 249Q262 249 296 234T393 179L443 147Q502 112 553 112Q609 112 649 141T694 220Q694 249 708 249T722 217Q722 153 675 104T555 55Q514 55 468 76T388 123T308 170T224 192Q164 192 125 159T83 84Q80 55 69 55Q55 55 55 85Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(1850.6,0)"><g data-mml-node="msup" transform="translate(220,394) scale(0.707)"><g data-mml-node="mi"><path data-c="1D445" d="M230 637Q203 637 198 638T193 649Q193 676 204 682Q206 683 378 683Q550 682 564 680Q620 672 658 652T712 606T733 563T739 529Q739 484 710 445T643 385T576 351T538 338L545 333Q612 295 612 223Q612 212 607 162T602 80V71Q602 53 603 43T614 25T640 16Q668 16 686 38T712 85Q717 99 720 102T735 105Q755 105 755 93Q755 75 731 36Q693 -21 641 -21H632Q571 -21 531 4T487 82Q487 109 502 166T517 239Q517 290 474 313Q459 320 449 321T378 323H309L277 193Q244 61 244 59Q244 55 245 54T252 50T269 48T302 46H333Q339 38 339 37T336 19Q332 6 326 0H311Q275 2 180 2Q146 2 117 2T71 2T50 1Q33 1 33 10Q33 12 36 24Q41 43 46 45Q50 46 61 46H67Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628Q287 635 230 637ZM630 554Q630 586 609 608T523 636Q521 636 500 636T462 637H440Q393 637 386 627Q385 624 352 494T319 361Q319 360 388 360Q466 361 492 367Q556 377 592 426Q608 449 619 486T630 554Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(792,363) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(377.5,-346.3) scale(0.707)"><path data-c="1D434" d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" style="stroke-width: 3;"/></g><rect width="1045.4" height="60" x="120" y="220"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>ρ</mi><mo>≈</mo><mfrac><msup><mi>R</mi><mn>2</mn></msup><mi>A</mi></mfrac></math></mjx-assistive-mml></mjx-container>로 정해진다 (해상도 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.048ex;" xmlns="http://www.w3.org/2000/svg" width="1.717ex" height="1.593ex" role="img" focusable="false" viewBox="0 -683 759 704" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D445" d="M230 637Q203 637 198 638T193 649Q193 676 204 682Q206 683 378 683Q550 682 564 680Q620 672 658 652T712 606T733 563T739 529Q739 484 710 445T643 385T576 351T538 338L545 333Q612 295 612 223Q612 212 607 162T602 80V71Q602 53 603 43T614 25T640 16Q668 16 686 38T712 85Q717 99 720 102T735 105Q755 105 755 93Q755 75 731 36Q693 -21 641 -21H632Q571 -21 531 4T487 82Q487 109 502 166T517 239Q517 290 474 313Q459 320 449 321T378 323H309L277 193Q244 61 244 59Q244 55 245 54T252 50T269 48T302 46H333Q339 38 339 37T336 19Q332 6 326 0H311Q275 2 180 2Q146 2 117 2T71 2T50 1Q33 1 33 10Q33 12 36 24Q41 43 46 45Q50 46 61 46H67Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628Q287 635 230 637ZM630 554Q630 586 609 608T523 636Q521 636 500 636T462 637H440Q393 637 386 627Q385 624 352 494T319 361Q319 360 388 360Q466 361 492 367Q556 377 592 426Q608 449 619 486T630 554Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>R</mi></math></mjx-assistive-mml></mjx-container>의 섀도우 맵을 지면 면적 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.697ex" height="1.62ex" role="img" focusable="false" viewBox="0 -716 750 716" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D434" d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>A</mi></math></mjx-assistive-mml></mjx-container>에 걸쳐 늘린 것). 맵 하나로 시야 거리 전체를 덮으면 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.697ex" height="1.62ex" role="img" focusable="false" viewBox="0 -716 750 716" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D434" d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>A</mi></math></mjx-assistive-mml></mjx-container>가 엄청나게 커지고 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.489ex;" xmlns="http://www.w3.org/2000/svg" width="1.17ex" height="1.489ex" role="img" focusable="false" viewBox="0 -442 517 658" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D70C" d="M58 -216Q25 -216 23 -186Q23 -176 73 26T127 234Q143 289 182 341Q252 427 341 441Q343 441 349 441T359 442Q432 442 471 394T510 276Q510 219 486 165T425 74T345 13T266 -10H255H248Q197 -10 165 35L160 41L133 -71Q108 -168 104 -181T92 -202Q76 -216 58 -216ZM424 322Q424 359 407 382T357 405Q322 405 287 376T231 300Q217 269 193 170L176 102Q193 26 260 26Q298 26 334 62Q367 92 389 158T418 266T424 322Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>ρ</mi></math></mjx-assistive-mml></mjx-container>가 붕괴한다. 캐스케이드는 절두체를 쪼개서 각 조각이 작은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.697ex" height="1.62ex" role="img" focusable="false" viewBox="0 -716 750 716" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D434" d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>A</mi></math></mjx-assistive-mml></mjx-container> 위에 자기만의 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.048ex;" xmlns="http://www.w3.org/2000/svg" width="6.2ex" height="1.593ex" role="img" focusable="false" viewBox="0 -683 2740.4 704" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D445" d="M230 637Q203 637 198 638T193 649Q193 676 204 682Q206 683 378 683Q550 682 564 680Q620 672 658 652T712 606T733 563T739 529Q739 484 710 445T643 385T576 351T538 338L545 333Q612 295 612 223Q612 212 607 162T602 80V71Q602 53 603 43T614 25T640 16Q668 16 686 38T712 85Q717 99 720 102T735 105Q755 105 755 93Q755 75 731 36Q693 -21 641 -21H632Q571 -21 531 4T487 82Q487 109 502 166T517 239Q517 290 474 313Q459 320 449 321T378 323H309L277 193Q244 61 244 59Q244 55 245 54T252 50T269 48T302 46H333Q339 38 339 37T336 19Q332 6 326 0H311Q275 2 180 2Q146 2 117 2T71 2T50 1Q33 1 33 10Q33 12 36 24Q41 43 46 45Q50 46 61 46H67Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628Q287 635 230 637ZM630 554Q630 586 609 608T523 636Q521 636 500 636T462 637H440Q393 637 386 627Q385 624 352 494T319 361Q319 360 388 360Q466 361 492 367Q556 377 592 426Q608 449 619 486T630 554Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(981.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1981.4,0)"><path data-c="1D445" d="M230 637Q203 637 198 638T193 649Q193 676 204 682Q206 683 378 683Q550 682 564 680Q620 672 658 652T712 606T733 563T739 529Q739 484 710 445T643 385T576 351T538 338L545 333Q612 295 612 223Q612 212 607 162T602 80V71Q602 53 603 43T614 25T640 16Q668 16 686 38T712 85Q717 99 720 102T735 105Q755 105 755 93Q755 75 731 36Q693 -21 641 -21H632Q571 -21 531 4T487 82Q487 109 502 166T517 239Q517 290 474 313Q459 320 449 321T378 323H309L277 193Q244 61 244 59Q244 55 245 54T252 50T269 48T302 46H333Q339 38 339 37T336 19Q332 6 326 0H311Q275 2 180 2Q146 2 117 2T71 2T50 1Q33 1 33 10Q33 12 36 24Q41 43 46 45Q50 46 61 46H67Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628Q287 635 230 637ZM630 554Q630 586 609 608T523 636Q521 636 500 636T462 637H440Q393 637 386 627Q385 624 352 494T319 361Q319 360 388 360Q466 361 492 367Q556 377 592 426Q608 449 619 486T630 554Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>R</mi><mo>×</mo><mi>R</mi></math></mjx-assistive-mml></mjx-container> 맵을 갖게 함으로써 이걸 해결하고, 가까운 곳부터 먼 곳까지 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.489ex;" xmlns="http://www.w3.org/2000/svg" width="1.17ex" height="1.489ex" role="img" focusable="false" viewBox="0 -442 517 658" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D70C" d="M58 -216Q25 -216 23 -186Q23 -176 73 26T127 234Q143 289 182 341Q252 427 341 441Q343 441 349 441T359 442Q432 442 471 394T510 276Q510 219 486 165T425 74T345 13T266 -10H255H248Q197 -10 165 35L160 41L133 -71Q108 -168 104 -181T92 -202Q76 -216 58 -216ZM424 322Q424 359 407 382T357 405Q322 405 287 376T231 300Q217 269 193 170L176 102Q193 26 260 26Q298 26 334 62Q367 92 389 158T418 266T424 322Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>ρ</mi></math></mjx-assistive-mml></mjx-container>를 대체로 일정하게 유지한다. 우리는 두 개와 네 개 캐스케이드 사이의 GPU 시간 차이를 재고, 다음으로 1024와 2048 섀도우 맵 해상도 사이의 차이를 쟀다. 결과는, 1024에서 캐스케이드 세 개가 목표 하드웨어에서 GPU 시간 2ms를 넘지 않으면서 카메라 근처의 접촉 섀도우를 받아들일 만한 수준으로 제공했다는 것이다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/09-csm-shadows/" title="Spike 9 CSM Shadows" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/09-csm-shadows/" target="_blank">새 탭에서 Spike 9 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=09-csm-shadows">소스 보기</a></p>
<p>이 단계에서 어려웠던 건 제품 규율이었다. 어떤 효과들은 아주 훌륭해 보였지만, 시각적 영향에 비해 프레임 예산을 너무 많이 먹어서 결국 제약을 걸어야 했다.</p>
<p>우리의 규칙은 단순해졌다. 어떤 기능은 측정된 프레임 시간 데이터로 자기 비용을 설명할 수 있을 때만 앞으로 나아간다.</p>
<p>당연한 얘기처럼 들린다. 하지만 다음 시각적 성과에 다들 들떠 있는 빠른 프로토타입 사이클에서는 흔한 일이 아니다. 이 규칙을 일찍부터 지킨 덕분에 나중에 clipmap과 볼류메트릭 존을 둘러싼 아키텍처 결정이 훨씬 깔끔해졌다. 같은 16ms를 두고 경쟁하는 모든 것의 기능별 비용을 우리가 이미 알고 있었으니까.</p>
<p>6부에서는 geometry clipmap으로 첫 번째 주요 지형 아키텍처 전환을 맞는다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>InstancedMesh와 GPU 식생.</strong> Three.js의 <code>InstancedMesh</code>는 같은 지오메트리의 N개 복사본을 draw call 한 번으로 렌더링한다. 식생의 경우, 밀도 맵 (chunk당 32x32)이 풀잎과 관목 덩어리를 인스턴스 버퍼로 런타임에 흩뿌리는 작업을 구동한다. 바람 애니메이션은 스크롤하는 노이즈 텍스처를 써서 버텍스 셰이더에서 돌아간다. 규모가 커지면, WebGPU의 <code>ComputeInstanceCulling</code>이 래스터화 전에 화면 밖과 먼 거리의 인스턴스를 제거하고, <code>IndirectBatchedMesh</code>가 여러 식생 타입을 하나의 버퍼에 담아 multi-draw indirect로 그린다. <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-vegetation-culling">GPU 식생 컬링에 관한 지형 가이드</a>를 보라.</p>
<p><strong>Triplanar mapping.</strong> 표준 UV 매핑 텍스처는 가파른 경사에서 UV 좌표가 압축되기 때문에 늘어난다. Triplanar mapping은 세 축(X, Y, Z) 모두를 따라 텍스처를 투영하고 표면 노멀을 기준으로 블렌딩한다. 절벽 면은 X 또는 Z 투영(늘어남 없음)을 받고, 평평한 지면은 Y 투영을 받는다. 블렌딩은 부드럽고 자동이며 UV 언랩이 필요 없다. PBR 지형의 경우, 같은 블렌딩 가중치가 albedo, normal, roughness, ambient occlusion 채널에 그대로 적용된다. <a href="/ko/guides/landscape-generation-browser.html#triplanar-mapping">triplanar mapping 세부 사항</a>을 보라.</p>
<p><strong>경사와 고도 기반 머티리얼 splatting.</strong> 손으로 그린 splat 맵 대신, 머티리얼은 지형 속성을 기준으로 프래그먼트 셰이더에서 절차적으로 할당된다. 낮은 고도의 평지는 풀을 받고, 가파른 경사는 바위를, 높은 고도는 눈을(쌓일 만큼 충분히 평평한 표면에서만), 해수면 근처는 모래를 받는다. 전환은 부드러운 블렌딩을 위해 <code>smoothstep</code>을 쓴다. 우리 구현에서는 각 지형 chunk가 네 개의 텍스처 레이어를 레이어당 diffuse와 normal 샘플로 평가하므로, 조명 전에 프래그먼트당 여덟 번의 텍스처 페치가 일어난다. <a href="/ko/guides/landscape-generation-browser.html#slope-and-altitude-based-material-assignment">경사와 고도 기반 머티리얼 할당</a>을 보라.</p>
<p><strong>캐스케이드 섀도우 맵 (CSM).</strong> CSM은 카메라의 뷰 절두체를 3~4개의 거리 구간(캐스케이드)으로 쪼갠다. 각 캐스케이드는 그 거리에 맞춘 해상도로 태양 시점에서 섀도우 맵을 렌더링한다. 가까운 캐스케이드는 고해상도 섀도우(나무와 건물 아래의 정밀한 접촉 섀도우)를 받고, 먼 캐스케이드는 낮은 해상도(넓은 산 그림자)를 받는다. 지형 셰이더는 모든 캐스케이드를 샘플링하고 프래그먼트마다 적절한 것을 고른다. 성능 비용: 1024x1024로 3~4개 캐스케이드는 섀도우 맵 렌더링에 약 0.5~1 ms, 샘플링에 약 0.2~0.3 ms를 더한다. <a href="/ko/guides/landscape-generation-browser.html#shadows-for-terrain">지형 섀도우</a>를 보라.</p>
<hr>
<p>12부 중 5부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy.html">4부 - 화려한 지형보다 먼저 스트리밍</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-06-clipmaps.html">6부 - Clipmap이 줄거리를 바꿨다</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 6부: 클립맵이 줄거리를 바꿨다]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-06-clipmaps</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-06-clipmaps</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[지오메트리 클립맵 덕분에 훨씬 큰 세계를 이동하면서도 지형 비용을 예측 가능하게 유지할 수 있었다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-6부-클립맵이-줄거리를-바꿨다" tabindex="-1">브라우저에서 오픈 월드 만들기, 6부: 클립맵이 줄거리를 바꿨다 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-6부-클립맵이-줄거리를-바꿨다" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 6부: 클립맵이 줄거리를 바꿨다&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 편을 링크해 둡니다.</p>
<p>Spike 10 이전까지 우리의 머릿속 모델은 여전히 &quot;세계가 커지면 지오메트리도 많아진다&quot;였습니다. Spike 10 이후 그 모델은 &quot;지오메트리 예산은 고정, 카메라 중심의 링 업데이트&quot;로 바뀌었습니다. 이 전환이 프로젝트의 방향을 바꿨습니다.</p>
<p>지오메트리 클립맵의 아이디어는 단순합니다. 지형을 카메라를 중심으로 한 동심원 링 묶음으로 렌더링합니다. 가장 안쪽 링이 정점 밀도가 가장 높습니다. 바깥으로 한 링 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.179ex" height="1.595ex" role="img" focusable="false" viewBox="0 -694 521 705" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math></mjx-assistive-mml></mjx-container>씩 갈 때마다 정점 간격이 두 배가 되어 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.375ex;" xmlns="http://www.w3.org/2000/svg" width="10.935ex" height="2.306ex" role="img" focusable="false" viewBox="0 -853.7 4833.4 1019.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(502,-150) scale(0.707)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1198.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2254,0)"><g data-mml-node="mi"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(502,-150) scale(0.707)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3381.7,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(3882,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(533,363) scale(0.707)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>s</mi><mi>k</mi></msub><mo>=</mo><msub><mi>s</mi><mn>0</mn></msub><mo>⋅</mo><msup><mn>2</mn><mi>k</mi></msup></math></mjx-assistive-mml></mjx-container>가 되고, 그래서 안쪽 링보다 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="2.891ex" height="1.532ex" role="img" focusable="false" viewBox="0 -677 1278 677" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(500,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>4</mn><mo>×</mo></math></mjx-assistive-mml></mjx-container> 넓은 지면을 덮습니다.</p>
<p>이 두 배가 핵심 전부입니다. 시야 거리는 링 개수에 따라 기하급수적으로 늘어나는데 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.375ex;" xmlns="http://www.w3.org/2000/svg" width="13.628ex" height="2.288ex" role="img" focusable="false" viewBox="0 -846 6023.5 1011.5" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(553,-150) scale(0.707)"><path data-c="76" d="M338 431Q344 429 422 429Q479 429 503 431H508V385H497Q439 381 423 345Q421 341 356 172T288 -2Q283 -11 263 -11Q244 -11 239 -2Q99 359 98 364Q93 378 82 381T43 385H19V431H25L33 430Q41 430 53 430T79 430T104 429T122 428Q217 428 232 431H240V385H226Q187 384 184 370Q184 366 235 234L286 102L377 341V349Q377 363 367 372T349 383T335 385H331V431H338Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(528,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(806,0)" style="stroke-width: 3;"/><path data-c="77" d="M90 368Q84 378 76 380T40 385H18V431H24L43 430Q62 430 84 429T116 428Q206 428 221 431H229V385H215Q177 383 177 368Q177 367 221 239L265 113L339 328L333 345Q323 374 316 379Q308 384 278 385H258V431H264Q270 428 348 428Q439 428 454 431H461V385H452Q404 385 404 369Q404 366 418 324T449 234T481 143L496 100L537 219Q579 341 579 347Q579 363 564 373T530 385H522V431H529Q541 428 624 428Q692 428 698 431H703V385H697Q696 385 691 385T682 384Q635 377 619 334L559 161Q546 124 528 71Q508 12 503 1T487 -11H479Q460 -11 456 -4Q455 -3 407 133L361 267Q359 263 266 -4Q261 -11 243 -11H238Q225 -11 220 -3L90 368Z" transform="translate(1250,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2275.2,0)"><path data-c="2248" d="M55 319Q55 360 72 393T114 444T163 472T205 482Q207 482 213 482T223 483Q262 483 296 468T393 413L443 381Q502 346 553 346Q609 346 649 375T694 454Q694 465 698 474T708 483Q722 483 722 452Q722 386 675 338T555 289Q514 289 468 310T388 357T308 404T224 426Q164 426 125 393T83 318Q81 289 69 289Q55 289 55 319ZM55 85Q55 126 72 159T114 210T163 238T205 248Q207 248 213 248T223 249Q262 249 296 234T393 179L443 147Q502 112 553 112Q609 112 649 141T694 220Q694 249 708 249T722 217Q722 153 675 104T555 55Q514 55 468 76T388 123T308 170T224 192Q164 192 125 159T83 84Q80 55 69 55Q55 55 55 85Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3331,0)"><g data-mml-node="mi"><path data-c="1D460" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(502,-150) scale(0.707)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(4458.7,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(4959,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(533,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>d</mi><mtext>view</mtext></msub><mo>≈</mo><msub><mi>s</mi><mn>0</mn></msub><mo>⋅</mo><msup><mn>2</mn><mrow data-mjx-texclass="ORD"><mi>L</mi></mrow></msup></math></mjx-assistive-mml></mjx-container>, 정점 비용은 선형으로만 늘어납니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="14.108ex" height="2.357ex" role="img" focusable="false" viewBox="0 -883.9 6235.6 1041.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(616,-150) scale(0.707)"><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(389,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(889,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(1278,0)" style="stroke-width: 3;"/><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" transform="translate(1778,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2397.6,0)"><path data-c="2248" d="M55 319Q55 360 72 393T114 444T163 472T205 482Q207 482 213 482T223 483Q262 483 296 468T393 413L443 381Q502 346 553 346Q609 346 649 375T694 454Q694 465 698 474T708 483Q722 483 722 452Q722 386 675 338T555 289Q514 289 468 310T388 357T308 404T224 426Q164 426 125 393T83 318Q81 289 69 289Q55 289 55 319ZM55 85Q55 126 72 159T114 210T163 238T205 248Q207 248 213 248T223 249Q262 249 296 234T393 179L443 147Q502 112 553 112Q609 112 649 141T694 220Q694 249 708 249T722 217Q722 153 675 104T555 55Q514 55 468 76T388 123T308 170T224 192Q164 192 125 159T83 84Q80 55 69 55Q55 55 55 85Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(3453.4,0)"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(975.3,413) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5054.4,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(5554.6,0)"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><msub><mi>V</mi><mtext>total</mtext></msub><mo>≈</mo><msup><mi>N</mi><mn>2</mn></msup><mo>⋅</mo><mi>L</mi></math></mjx-assistive-mml></mjx-container><p><mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="6.784ex" height="1.545ex" role="img" focusable="false" viewBox="0 -683 2998.4 683" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1110.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2110.4,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>N</mi><mo>×</mo><mi>N</mi></math></mjx-assistive-mml></mjx-container> 정점짜리 링 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.541ex" height="1.545ex" role="img" focusable="false" viewBox="0 -683 681 683" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>L</mi></math></mjx-assistive-mml></mjx-container>개에 대해 그렇습니다. 얼마나 멀리 볼 수 있는지를 두 배로 늘리는 비용은 링 하나가 더 드는 것이지, 지오메트리가 네 배로 드는 게 아닙니다. 세계 크기와 상관없이 삼각형 수는 대체로 일정하게 유지됩니다. 항상 같은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="1.541ex" height="1.545ex" role="img" focusable="false" viewBox="0 -683 681 683" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>L</mi></math></mjx-assistive-mml></mjx-container>개의 링을 같은 해상도로 렌더링하기 때문입니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/10-clipmap-geomorph/" title="Spike 10 Geometry Clipmaps Geomorphing" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/10-clipmap-geomorph/" target="_blank">새 탭에서 Spike 10 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=10-clipmap-geomorph">소스 보기</a></p>
<p>실전에서의 요령은 링 경계에서의 geomorphing이었습니다. 한 정점이 어떤 LOD 링에서 다음 링으로 넘어갈 때, 그 높이는 고해상도 샘플과 저해상도 샘플 사이에서 부드럽게 섞여야 합니다. 그게 없으면 카메라가 움직여 링이 이동할 때마다 눈에 띄는 pop이 생깁니다. 우리는 정점이 링 가장자리에서 떨어진 거리에 기반한 블렌드 계수로 이를 처리했고, 정점 셰이더에서 높이를 보간했습니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="58.451ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 25835.3 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(853.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1909.6,0)"><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(278,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(722,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(1114,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3579.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3968.6,0)"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(609,-150) scale(0.707)"><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(306,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(584,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(1140,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5747.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(6025.6,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(6359.3,0)"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(609,-150) scale(0.707)"><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(444,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(944,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1444,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(1836,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(2230,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(8909.1,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(9187.1,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(9520.7,0)"><path data-c="1D6FC" d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(10160.7,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(10549.7,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(10827.7,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(12994.4,0)"><path data-c="1D6FC" d="M34 156Q34 270 120 356T309 442Q379 442 421 402T478 304Q484 275 485 237V208Q534 282 560 374Q564 388 566 390T582 393Q603 393 603 385Q603 376 594 346T558 261T497 161L486 147L487 123Q489 67 495 47T514 26Q528 28 540 37T557 60Q559 67 562 68T577 70Q597 70 597 62Q597 56 591 43Q579 19 556 5T512 -10H505Q438 -10 414 62L411 69L400 61Q390 53 370 41T325 18T267 -2T203 -11Q124 -11 79 39T34 156ZM208 26Q257 26 306 47T379 90L403 112Q401 255 396 290Q382 405 304 405Q235 405 183 332Q156 292 139 224T121 120Q121 71 146 49T208 26Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(13912.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(14968,0)"><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" style="stroke-width: 3;"/><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(394,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(1227,0)" style="stroke-width: 3;"/><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(1727,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(2227,0)" style="stroke-width: 3;"/><path data-c="68" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 124T102 167T103 217T103 272T103 329Q103 366 103 407T103 482T102 542T102 586T102 603Q99 622 88 628T43 637H25V660Q25 683 27 683L37 684Q47 685 66 686T103 688Q120 689 140 690T170 693T181 694H184V367Q244 442 328 442Q451 442 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2616,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(3172,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(3566,0)" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(3955,0)" style="stroke-width: 3;"/><path data-c="70" d="M36 -148H50Q89 -148 97 -134V-126Q97 -119 97 -107T97 -77T98 -38T98 6T98 55T98 106Q98 140 98 177T98 243T98 296T97 335T97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 61 434T98 436Q115 437 135 438T165 441T176 442H179V416L180 390L188 397Q247 441 326 441Q407 441 464 377T522 216Q522 115 457 52T310 -11Q242 -11 190 33L182 40V-45V-101Q182 -128 184 -134T195 -145Q216 -148 244 -148H260V-194H252L228 -193Q205 -192 178 -192T140 -191Q37 -191 28 -194H20V-148H36ZM424 218Q424 292 390 347T305 402Q234 402 182 337V98Q222 26 294 26Q345 26 384 80T424 218Z" transform="translate(4399,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(19923,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(20312,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(553,-150) scale(0.707)"><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1500,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(22252.8,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(22530.8,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(22864.5,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(553,-150) scale(0.707)"><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(306,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(806,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(24314.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(24592.6,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(24926.3,0)"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(25446.3,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi>h</mi><mo>=</mo><mi>lerp</mi><mo stretchy="false">(</mo><msub><mi>h</mi><mtext>fine</mtext></msub><mo>,</mo><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><msub><mi>h</mi><mtext>coarse</mtext></msub><mo>,</mo><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mi>α</mi><mo stretchy="false">)</mo><mo>,</mo><mstyle scriptlevel="0"><mspace width="2em"/></mstyle><mi>α</mi><mo>=</mo><mi>smoothstep</mi><mo stretchy="false">(</mo><msub><mi>d</mi><mtext>near</mtext></msub><mo>,</mo><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><msub><mi>d</mi><mtext>far</mtext></msub><mo>,</mo><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mi>d</mi><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container><p>여기서 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.023ex;" xmlns="http://www.w3.org/2000/svg" width="1.176ex" height="1.593ex" role="img" focusable="false" viewBox="0 -694 520 704" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>d</mi></math></mjx-assistive-mml></mjx-container>는 정점이 카메라에서 떨어진 거리입니다. 링 안쪽(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="8.585ex" height="1.927ex" role="img" focusable="false" viewBox="0 -694 3794.4 851.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(797.8,0)"><path data-c="2264" d="M674 636Q682 636 688 630T694 615T687 601Q686 600 417 472L151 346L399 228Q687 92 691 87Q694 81 694 76Q694 58 676 56H670L382 192Q92 329 90 331Q83 336 83 348Q84 359 96 365Q104 369 382 500T665 634Q669 636 674 636ZM84 -118Q84 -108 99 -98H678Q694 -104 694 -118Q694 -130 679 -138H98Q84 -131 84 -118Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(1853.6,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(553,-150) scale(0.707)"><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(556,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(1500,0)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>d</mi><mo>≤</mo><msub><mi>d</mi><mtext>near</mtext></msub></math></mjx-assistive-mml></mjx-container>)에서는 정점이 풀해상도 높이를 쓰고, 다음 링에 도달할 무렵(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="7.474ex" height="1.927ex" role="img" focusable="false" viewBox="0 -694 3303.7 851.8" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(797.8,0)"><path data-c="2265" d="M83 616Q83 624 89 630T99 636Q107 636 253 568T543 431T687 361Q694 356 694 346T687 331Q685 329 395 192L107 56H101Q83 58 83 76Q83 77 83 79Q82 86 98 95Q117 105 248 167Q326 204 378 228L626 346L360 472Q291 505 200 548Q112 589 98 597T83 616ZM84 -118Q84 -108 99 -98H678Q694 -104 694 -118Q694 -130 679 -138H98Q84 -131 84 -118Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(1853.6,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(553,-150) scale(0.707)"><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(306,0)" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(806,0)" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>d</mi><mo>≥</mo><msub><mi>d</mi><mtext>far</mtext></msub></math></mjx-assistive-mml></mjx-container>)에는 이미 그 링이 쓸 거친 높이로 옮겨가 있어서 pop이 일어날 게 남아 있지 않습니다.</p>
<p>미묘한 교훈 하나는 카메라 이동 테스트에서 나왔습니다. 정적 스크린샷으로 클립맵을 판단하면서 전환 아티팩트를 놓치기는 쉽습니다. 우리는 링 경계를 일정한 속도로 가로질러 다니며 시간 축의 노이즈를 살피는 데 시간을 들였습니다. 스크린샷은 거짓말을 했습니다. 움직임이 진실을 말했습니다.</p>
<p>이 spike는 또 깔끔한 아키텍처 경계도 줬습니다. 근거리 지형은 시간이 지나며 동적이고 비싸질 수 있습니다. 볼류메트릭 편집, 더 높은 머티리얼 복잡도, 물리 상호작용이 더해지면서요. 원거리 지형은 안정적이고 예측 가능하고 저렴하게 유지될 수 있습니다. 그 분리가 이 시점부터 모든 아키텍처 결정의 척추가 됐습니다.</p>
<p>자기 프로젝트에 클립맵을 검토하고 있다면, 예쁜 컷이 아니라 스트레스 루프를 테스트하세요. 긴 이동 경로, 변하는 카메라 고도, 반복되는 경계 횡단이야말로 진짜 문제를 드러내는 것들입니다.</p>
<p>7부에서는 볼류메트릭 메싱을 더해 &quot;표면으로서의 지형&quot;에서 &quot;편집 가능한 볼륨으로서의 지형&quot;으로 넘어갑니다. 이 프로젝트가 렌더러이기를 그만두고 월드 에디터가 되기 시작한 지점이 바로 거기였습니다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>지오메트리 클립맵.</strong> Losasso와 Hoppe가 SIGGRAPH 2004에서 소개했으며(<a href="https://hhoppe.com/geomclipmap.pdf" target="_blank" rel="noreferrer">논문</a>), 지오메트리 클립맵은 지형을 카메라를 중심으로 한 동심 정사각형 링으로 렌더링합니다. 각 링은 이전 링의 두 배 면적에 정점 해상도는 절반입니다. 전체 정점 수는 일정합니다. 대략 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="6.295ex" height="1.887ex" role="img" focusable="false" viewBox="0 -833.9 2782.2 833.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(975.3,363) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1601,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2101.2,0)"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>N</mi><mn>2</mn></msup><mo>⋅</mo><mi>L</mi></math></mjx-assistive-mml></mjx-container>입니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="8.42ex" height="1.731ex" role="img" focusable="false" viewBox="0 -683 3721.6 765" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1165.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2221.6,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>N</mi><mo>=</mo><mn>256</mn></math></mjx-assistive-mml></mjx-container>에 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="5.689ex" height="1.731ex" role="img" focusable="false" viewBox="0 -683 2514.6 765" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(958.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2014.6,0)"><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>L</mi><mo>=</mo><mn>8</mn></math></mjx-assistive-mml></mjx-container> 레벨이면 세계 크기와 상관없이 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.439ex;" xmlns="http://www.w3.org/2000/svg" width="18.712ex" height="2.394ex" role="img" focusable="false" viewBox="0 -864 8270.6 1058" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1533,393.1) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2158.8,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3159,0)"><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3936.8,0)"><path data-c="2248" d="M55 319Q55 360 72 393T114 444T163 472T205 482Q207 482 213 482T223 483Q262 483 296 468T393 413L443 381Q502 346 553 346Q609 346 649 375T694 454Q694 465 698 474T708 483Q722 483 722 452Q722 386 675 338T555 289Q514 289 468 310T388 357T308 404T224 426Q164 426 125 393T83 318Q81 289 69 289Q55 289 55 319ZM55 85Q55 126 72 159T114 210T163 238T205 248Q207 248 213 248T223 249Q262 249 296 234T393 179L443 147Q502 112 553 112Q609 112 649 141T694 220Q694 249 708 249T722 217Q722 153 675 104T555 55Q514 55 468 76T388 123T308 170T224 192Q164 192 125 159T83 84Q80 55 69 55Q55 55 55 85Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(4992.6,0)"><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" style="stroke-width: 3;"/><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" transform="translate(1000,0)" style="stroke-width: 3;"/><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" transform="translate(1500,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(1778,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(2278,0)" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(2778,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>256</mn><mn>2</mn></msup><mo>×</mo><mn>8</mn><mo>≈</mo><mn>524,000</mn></math></mjx-assistive-mml></mjx-container>개 정점입니다. CPU는 카메라가 움직일 때 각 링의 heightmap 데이터를 업데이트합니다. 정점 셰이더는 텍스처에서 높이를 읽어 평평한 그리드를 변위시킵니다. <a href="/ko/guides/landscape-generation-browser.html#geometry-clipmaps">지오메트리 클립맵에 관한 우리 지형 가이드</a>와 <a href="https://developer.nvidia.com/gpugems/gpugems2/part-i-geometric-complexity/chapter-2-terrain-rendering-using-gpu-based-geometry" target="_blank" rel="noreferrer">GPU Gems 2, 2장</a>을 보세요.</p>
<p><strong>Geomorphing.</strong> 지형 LOD에서 가장 큰 시각적 아티팩트는 popping입니다. 패치가 LOD 레벨을 바꿀 때 정점이 갑자기 튀는 것이죠. Geomorphing은 전환 구간에 걸쳐 LOD 레벨 사이에서 정점 위치를 블렌딩해 이를 없앱니다. 각 정점은 현재 LOD 높이와 한 단계 거친 LOD 높이를 둘 다 저장합니다. 카메라 거리에 기반한 모프 계수가 둘 사이를 부드럽게 보간합니다. <code>morphedHeight = mix(fineLodHeight, coarseLodHeight, smoothstep(lodNear, lodFar, distance))</code>. 전환 구간은 보통 각 링의 바깥쪽 20%입니다. 정상적인 카메라 속도에서 전환은 보이지 않습니다. <a href="/ko/guides/landscape-generation-browser.html#geomorphing-pop-free-lod-transitions">geomorphing 세부 내용</a>을 보세요.</p>
<p><strong>CDLOD(쿼드트리 적응형 클립맵).</strong> Strugar가 고정 링 클립맵을 개선한 것입니다(2014, <a href="https://www.vertexasylum.com/CDLOD/cdlod_latest.pdf" target="_blank" rel="noreferrer">논문</a>). 균일한 해상도의 동심 링 대신, CDLOD는 지형 복잡도에 적응하는 쿼드트리를 씁니다. 평평한 지역은 거친 노드를 쓰고, 디테일이 높은 지역(절벽, 능선)은 더 세밀하게 분할합니다. 이는 청크마다 복잡도가 크게 다른 창작자 세계에서 중요합니다. <a href="/ko/guides/landscape-generation-browser.html#cdlod-quadtree-adaptive-clipmaps">우리 지형 가이드의 CDLOD</a>를 보세요.</p>
<hr>
<p>12부 중 6부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty.html">5부 - 예쁜 것들에 예산 배정하기</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes.html">7부 - 마칭 큐브와 첫 진짜 동굴들</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 7부: 마칭 큐브와 첫 진짜 동굴]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 12는 실시간 WebGPU 마칭 큐브를 프로젝트에 들여왔고, 지형이 될 수 있는 것을 바꿔놓았습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-7부-마칭-큐브와-첫-진짜-동굴" tabindex="-1">브라우저에서 오픈 월드 만들기, 7부: 마칭 큐브와 첫 진짜 동굴 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-7부-마칭-큐브와-첫-진짜-동굴" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 7부: 마칭 큐브와 첫 진짜 동굴&quot;"></a></h1>
<p><em><a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva의 CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p>하이트맵은 오버행이 필요해지기 전까지는 훌륭합니다.</p>
<p>깎아낸 터널, 떠 있는 바위 턱, 동굴 천장을 원하는 순간, 순수 하이트필드 파이프라인은 당신을 막기 시작합니다. 하이트맵은 XZ 좌표마다 Y 값을 하나만 저장합니다. 자기 위로 접혀 돌아오는 표면은 물리적으로 표현할 수가 없습니다. 우리에게는 볼류메트릭 표현이 필요했습니다.</p>
<p>Spike 12는 WebGPU 컴퓨트 셰이더를 사용해 GPU에서 마칭 큐브를 구현했습니다. 이 알고리즘은 3D 그리드에서 부호 거리장(SDF)을 평가하고, 값이 0이 되는 지점의 표면에서 삼각형 메시를 추출합니다. 각 셀은 8개의 코너를 가지며, 각 코너는 표면 안쪽이거나 바깥쪽이라서 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="8.53ex" height="2.072ex" role="img" focusable="false" viewBox="0 -833.9 3770.1 915.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(533,363) scale(0.707)"><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1214.3,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2270.1,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>2</mn><mn>8</mn></msup><mo>=</mo><mn>256</mn></math></mjx-assistive-mml></mjx-container>가지 부호 패턴이 나옵니다. 룩업 테이블이 각 패턴을 삼각형 집합으로 매핑합니다. 정점은 셀의 모서리에서 값이 0을 가로지르는 지점에 놓입니다. 코너 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.023ex;" xmlns="http://www.w3.org/2000/svg" width="1.197ex" height="1.02ex" role="img" focusable="false" viewBox="0 -441 529 451" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>a</mi></math></mjx-assistive-mml></mjx-container>와 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="0.971ex" height="1.595ex" role="img" focusable="false" viewBox="0 -694 429 705" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>b</mi></math></mjx-assistive-mml></mjx-container> 사이의 모서리에서 값이 각각 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="2.143ex" height="2.059ex" role="img" focusable="false" viewBox="0 -705 947.1 910" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(523,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>f</mi><mi>a</mi></msub></math></mjx-assistive-mml></mjx-container>, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.983ex" height="2.059ex" role="img" focusable="false" viewBox="0 -705 876.3 910" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(523,-150) scale(0.707)"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>f</mi><mi>b</mi></msub></math></mjx-assistive-mml></mjx-container>라면, 선형 보간으로 정점을 다음 위치에 놓습니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -2.016ex;" xmlns="http://www.w3.org/2000/svg" width="37.407ex" height="5.14ex" role="img" focusable="false" viewBox="0 -1381 16534 2272" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D42F" d="M401 444Q413 441 495 441Q568 441 574 444H580V382H510L409 156Q348 18 339 6Q331 -4 320 -4Q318 -4 313 -4T303 -3H288Q273 -3 264 12T221 102Q206 135 197 156L96 382H26V444H34Q49 441 145 441Q252 441 270 444H279V382H231L284 264Q335 149 338 149Q338 150 389 264T442 381Q442 382 418 382H394V444H401Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(884.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(1940.6,0)"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D429" d="M32 442L123 446Q214 450 215 450H221V409Q222 409 229 413T251 423T284 436T328 446T382 450Q480 450 540 388T600 223Q600 128 539 61T361 -6H354Q292 -6 236 28L227 34V-132H296V-194H287Q269 -191 163 -191Q56 -191 38 -194H29V-132H98V113V284Q98 330 97 348T93 370T83 376Q69 380 42 380H29V442H32ZM457 224Q457 303 427 349T350 395Q282 395 235 352L227 345V104L233 97Q274 45 337 45Q383 45 420 86T457 224Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(672,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3258.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(4259.1,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(4620.1,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mo" transform="translate(4787.1,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(5176.1,0)"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D429" d="M32 442L123 446Q214 450 215 450H221V409Q222 409 229 413T251 423T284 436T328 446T382 450Q480 450 540 388T600 223Q600 128 539 61T361 -6H354Q292 -6 236 28L227 34V-132H296V-194H287Q269 -191 163 -191Q56 -191 38 -194H29V-132H98V113V284Q98 330 97 348T93 370T83 376Q69 380 42 380H29V442H32ZM457 224Q457 303 427 349T350 395Q282 395 235 352L227 345V104L233 97Q274 45 337 45Q383 45 420 86T457 224Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(672,-150) scale(0.707)"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(6423.6,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(7423.9,0)"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D429" d="M32 442L123 446Q214 450 215 450H221V409Q222 409 229 413T251 423T284 436T328 446T382 450Q480 450 540 388T600 223Q600 128 539 61T361 -6H354Q292 -6 236 28L227 34V-132H296V-194H287Q269 -191 163 -191Q56 -191 38 -194H29V-132H98V113V284Q98 330 97 348T93 370T83 376Q69 380 42 380H29V442H32ZM457 224Q457 303 427 349T350 395Q282 395 235 352L227 345V104L233 97Q274 45 337 45Q383 45 420 86T457 224Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(672,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(8519.9,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(8908.9,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(9186.9,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(11353.6,0)"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(11992.4,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(13048.1,0)"><g data-mml-node="mrow" transform="translate(880.4,676)"><g data-mml-node="mo"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(778,0)"><g data-mml-node="mi"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(523,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mrow" transform="translate(220,-686)"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(523,-150) scale(0.707)"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1098.6,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2098.8,0)"><g data-mml-node="mi"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(523,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g><rect width="3245.9" height="60" x="120" y="220"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">v</mi></mrow><mo>=</mo><msub><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">p</mi></mrow><mi>a</mi></msub><mo>+</mo><mi>t</mi><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mo stretchy="false">(</mo><msub><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">p</mi></mrow><mi>b</mi></msub><mo>−</mo><msub><mrow data-mjx-texclass="ORD"><mi mathvariant="bold">p</mi></mrow><mi>a</mi></msub><mo stretchy="false">)</mo><mo>,</mo><mstyle scriptlevel="0"><mspace width="2em"/></mstyle><mi>t</mi><mo>=</mo><mfrac><mrow><mo>−</mo><msub><mi>f</mi><mi>a</mi></msub></mrow><mrow><msub><mi>f</mi><mi>b</mi></msub><mo>−</mo><msub><mi>f</mi><mi>a</mi></msub></mrow></mfrac></math></mjx-assistive-mml></mjx-container><p>이는 모서리를 따라 값이 0에 닿는 지점의 비율입니다. 가로지르는 모서리에서 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="2.143ex" height="2.059ex" role="img" focusable="false" viewBox="0 -705 947.1 910" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(523,-150) scale(0.707)"><path data-c="1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>f</mi><mi>a</mi></msub></math></mjx-assistive-mml></mjx-container>와 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.983ex" height="2.059ex" role="img" focusable="false" viewBox="0 -705 876.3 910" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(523,-150) scale(0.707)"><path data-c="1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>f</mi><mi>b</mi></msub></math></mjx-assistive-mml></mjx-container>는 부호가 반대이므로, <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="0.817ex" height="1.441ex" role="img" focusable="false" viewBox="0 -626 361 637" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D461" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>t</mi></math></mjx-assistive-mml></mjx-container>는 항상 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="4.526ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 2000.7 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="5B" d="M118 -250V750H255V710H158V-210H255V-250H118Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(278,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(778,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1222.7,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1722.7,0)"><path data-c="5D" d="M22 710V750H159V-250H22V-210H119V710H22Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mn>0</mn><mo>,</mo><mn>1</mn><mo stretchy="false">]</mo></math></mjx-assistive-mml></mjx-container> 안에 들어옵니다. 우리는 이것을 동시에 활성화된 64-큐브 청크 4개에서 돌렸고, 프레임마다 리메시하는 애니메이션 SDF 편집을 테스트했습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/12-webgpu-marching-cubes/" title="Spike 12 WebGPU Marching Cubes" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/12-webgpu-marching-cubes/" target="_blank">새 탭에서 Spike 12 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=12-webgpu-marching-cubes">소스 보기</a></p>
<p>첫 번째 수확은 컴퓨트 파이프라인 자체에 대한 자신감이었습니다. 단 한 번의 디스패치로 CPU 리드백 없이 SDF를 평가하고, 셀을 분류하고, 정점을 GPU 버퍼에 내보낼 수 있었습니다. 두 번째 수확은 &quot;된다&quot;가 얼마나 빨리 아티팩트 사냥으로 바뀌는지 알게 된 것입니다. 사라진 삼각형은 마칭 큐브 이론의 문제인 경우가 드물었습니다. 테이블 인덱스 불일치이거나, 활성 정점 개수를 넘어서 읽는 잘못된 드로우 범위이거나, 이웃 SDF 샘플을 쓸 수 없는 청크 경계 근처의 엣지 케이스 상호작용이었습니다.</p>
<p>이 spike는 우리가 구역 단위로 생각하게 만들었습니다. 카메라 가까이에서는 플레이어가 깎고, 파고, 동굴을 볼 수 있도록 볼류메트릭 자유도가 필요합니다. 카메라에서 멀리에서는 평평한 하이트맵이 더 싸고 완벽하게 충분한 클립맵 효율이 필요합니다. 이 이원성은 Spike 13 이후로 우리가 계속 다듬어온 아키텍처의 척추가 되었습니다.</p>
<p>내가 가장 좋아한 디버깅 순간 중 하나는 편집이 돌아가는 와중에 와이어프레임을 토글한 것이었습니다. 위상 구조가 실시간으로 만들어지고 녹아 사라지는 것을 지켜보니 품질의 트레이드오프가 곧바로 눈에 보였습니다. 정점 밀도가 충분히 높은 곳, 너무 거칠어진 곳, 그리고 결국 균열을 피하려면 LOD 전환에 Transvoxel 지원이 어디서 필요할지 정확히 볼 수 있었습니다.</p>
<p>8부에서는 통합 과제를 다룹니다. 원시 컴퓨트 기반 메시와 Three.js 씬 그래프 로직을 안정적인 렌더링 파이프라인 하나에 담아두는 것은 따로 떼어낸 데모가 암시한 것보다 더 어려웠습니다.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>마칭 큐브.</strong> 3D 스칼라 장에서 삼각형 메시를 추출하는 알고리즘입니다(Lorensen and Cline, 1987). 규칙적인 3D 그리드의 각 셀은 8개의 코너에서 장을 샘플링해 분류됩니다. 부호 패턴이 케이스 인덱스(0-255)를 만들고, 룩업 테이블이 각 케이스를 삼각형 집합으로 매핑합니다. 정점은 두 코너 사이를 보간해서 그리드 모서리에 놓입니다. 각 셀이 독립적으로 처리되기 때문에 이 알고리즘은 엄청나게 병렬적이고, GPU 컴퓨트에 이상적입니다. 우리의 <a href="/ko/guides/landscape-generation-browser.html#signed-distance-fields-sdfs">SDF와 마칭 큐브에 관한 지형 가이드</a>를 보세요.</p>
<p><strong>부호 거리장(SDF).</strong> 3D 공간의 모든 점에 가장 가까운 표면까지의 부호 있는 거리를 저장하는 볼류메트릭 표현입니다. 양수 값은 바깥쪽, 음수 값은 안쪽이고, 0을 가로지르는 지점이 표면입니다. SDF는 임의의 3D 형태를 표현할 수 있습니다. 동굴, 아치, 오버행, 그리고 하이트맵이 표현하지 못하는 떠 있는 지오메트리까지요. 편집은 장에 대한 자연스러운 집합 대수입니다. 재료 추가(두 형태의 합집합)는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="15.06ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 6656.3 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(797.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1853.6,0)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1111,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3520.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3909.6,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(4866.1,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(5310.8,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(6267.3,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>d</mi><mo>=</mo><mo data-mjx-texclass="OP" movablelimits="true">min</mo><mo stretchy="false">(</mo><msub><mi>d</mi><mn>1</mn></msub><mo>,</mo><msub><mi>d</mi><mn>2</mn></msub><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>이고, 제거(파내기)는 깎아내는 형태를 음수로 만든 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="17.259ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 7628.3 1000" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(797.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1853.6,0)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="78" d="M201 0Q189 3 102 3Q26 3 17 0H11V46H25Q48 47 67 52T96 61T121 78T139 96T160 122T180 150L226 210L168 288Q159 301 149 315T133 336T122 351T113 363T107 370T100 376T94 379T88 381T80 383Q74 383 44 385H16V431H23Q59 429 126 429Q219 429 229 431H237V385Q201 381 201 369Q201 367 211 353T239 315T268 274L272 270L297 304Q329 345 329 358Q329 364 327 369T322 376T317 380T310 384L307 385H302V431H309Q324 428 408 428Q487 428 493 431H499V385H492Q443 385 411 368Q394 360 377 341T312 257L296 236L358 151Q424 61 429 57T446 50Q464 46 499 46H516V0H510H502Q494 1 482 1T457 2T432 2T414 3Q403 3 377 3T327 1L304 0H295V46H298Q309 46 320 51T331 63Q331 65 291 120L250 175Q249 174 219 133T185 88Q181 83 181 74Q181 63 188 55T206 46Q208 46 208 23V0H201Z" transform="translate(1333,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3714.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(4103.6,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5060.1,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(5504.8,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(6282.8,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(7239.3,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>d</mi><mo>=</mo><mo data-mjx-texclass="OP" movablelimits="true">max</mo><mo stretchy="false">(</mo><msub><mi>d</mi><mn>1</mn></msub><mo>,</mo><mo>−</mo><msub><mi>d</mi><mn>2</mn></msub><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>이며, 부드러운 블렌드는 다음과 같은 소프트 최솟값을 사용합니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -1.577ex;" xmlns="http://www.w3.org/2000/svg" width="64.842ex" height="4.993ex" role="img" focusable="false" viewBox="0 -1509.9 28660.1 2206.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" style="stroke-width: 3;"/><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(394,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(1227,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1505,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2061,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2450,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3406.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3851.2,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(4807.8,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(5252.4,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(5773.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(6440.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(7496,0)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1111,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(9163,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(9552,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(10508.5,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(10953.2,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(11909.8,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(12521,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(13521.2,0)"><g data-mml-node="msup" transform="translate(224.2,676)"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(609,363) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mrow" transform="translate(220,-686)"><g data-mml-node="mn"><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(500,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g><rect width="1221" height="60" x="120" y="220"/></g><g data-mml-node="mo" transform="translate(14982.2,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(15260.2,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(17426.9,0)"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(18280.7,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(19336.4,0)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="78" d="M201 0Q189 3 102 3Q26 3 17 0H11V46H25Q48 47 67 52T96 61T121 78T139 96T160 122T180 150L226 210L168 288Q159 301 149 315T133 336T122 351T113 363T107 370T100 376T94 379T88 381T80 383Q74 383 44 385H16V431H23Q59 429 126 429Q219 429 229 431H237V385Q201 381 201 369Q201 367 211 353T239 315T268 274L272 270L297 304Q329 345 329 358Q329 364 327 369T322 376T317 380T310 384L307 385H302V431H309Q324 428 408 428Q487 428 493 431H499V385H492Q443 385 411 368Q394 360 377 341T312 257L296 236L358 151Q424 61 429 57T446 50Q464 46 499 46H516V0H510H502Q494 1 482 1T457 2T432 2T414 3Q403 3 377 3T327 1L304 0H295V46H298Q309 46 320 51T331 63Q331 65 291 120L250 175Q249 174 219 133T185 88Q181 83 181 74Q181 63 188 55T206 46Q208 46 208 23V0H201Z" transform="translate(1333,0)" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="OPEN" transform="translate(21197.4,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="28" d="M152 251Q152 646 388 850H416Q422 844 422 841Q422 837 403 816T357 753T302 649T255 482T236 250Q236 124 255 19T301 -147T356 -251T403 -315T422 -340Q422 -343 416 -349H388Q359 -325 332 -296T271 -213T212 -97T170 56T152 251Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(21655.4,0)"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(22398.7,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(23398.9,0) translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(23676.9,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(24855.7,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(25855.9,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(553,-150) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(26812.4,0) translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(27090.4,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(27368.4,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mn" transform="translate(27702.1,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" data-mjx-texclass="CLOSE" transform="translate(28202.1,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="29" d="M305 251Q305 -145 69 -349H56Q43 -349 39 -347T35 -338Q37 -333 60 -307T108 -239T160 -136T204 27T221 250T204 473T160 636T108 740T60 807T35 839Q35 850 50 850H56H69Q197 743 256 566Q305 425 305 251Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi>smin</mi><mo stretchy="false">(</mo><msub><mi>d</mi><mn>1</mn></msub><mo>,</mo><msub><mi>d</mi><mn>2</mn></msub><mo>,</mo><mi>k</mi><mo stretchy="false">)</mo><mo>=</mo><mo data-mjx-texclass="OP" movablelimits="true">min</mo><mo stretchy="false">(</mo><msub><mi>d</mi><mn>1</mn></msub><mo>,</mo><msub><mi>d</mi><mn>2</mn></msub><mo stretchy="false">)</mo><mo>−</mo><mfrac><msup><mi>h</mi><mn>2</mn></msup><mrow><mn>4</mn><mi>k</mi></mrow></mfrac><mo>,</mo><mstyle scriptlevel="0"><mspace width="2em"/></mstyle><mi>h</mi><mo>=</mo><mo data-mjx-texclass="OP" movablelimits="true">max</mo><mrow data-mjx-texclass="OPEN"><mo minsize="1.2em" maxsize="1.2em">(</mo></mrow><mi>k</mi><mo>−</mo><mo data-mjx-texclass="ORD" stretchy="false">|</mo><msub><mi>d</mi><mn>1</mn></msub><mo>−</mo><msub><mi>d</mi><mn>2</mn></msub><mo data-mjx-texclass="ORD" stretchy="false">|</mo><mo>,</mo><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><mn>0</mn><mrow data-mjx-texclass="CLOSE"><mo minsize="1.2em" maxsize="1.2em">)</mo></mrow></math></mjx-assistive-mml></mjx-container><p>여기서 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.179ex" height="1.595ex" role="img" focusable="false" viewBox="0 -694 521 705" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math></mjx-assistive-mml></mjx-container>는 블렌드 반경을 제어합니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="5.829ex" height="1.62ex" role="img" focusable="false" viewBox="0 -694 2576.6 716" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D458" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(798.8,0)"><path data-c="2192" d="M56 237T56 250T70 270H835Q719 357 692 493Q692 494 692 496T691 499Q691 511 708 511H711Q720 511 723 510T729 506T732 497T735 481T743 456Q765 389 816 336T935 261Q944 258 944 250Q944 244 939 241T915 231T877 212Q836 186 806 152T761 85T740 35T732 4Q730 -6 727 -8T711 -11Q691 -11 691 0Q691 7 696 25Q728 151 835 230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2076.6,0)"><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mo accent="false" stretchy="false">→</mo><mn>0</mn></math></mjx-assistive-mml></mjx-container>이 되면 다시 단단한 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="3.771ex" height="1.514ex" role="img" focusable="false" viewBox="0 -669 1667 669" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(833,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1111,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo data-mjx-texclass="OP" movablelimits="true">min</mo></math></mjx-assistive-mml></mjx-container>으로 무너집니다. <a href="/ko/guides/landscape-generation-browser.html#signed-distance-fields-sdfs">SDF 지형 표현</a>을 보세요.</p>
<p><strong>WebGPU 컴퓨트 셰이더.</strong> 래스터화 파이프라인에 묶이지 않고 범용 계산을 수행하는 GPU 프로그램입니다. 컴퓨트 셰이더는 병렬로 실행되는 스레드 워크그룹을 디스패치합니다. 마칭 큐브에서는 각 스레드가 그리드 셀 하나를 처리합니다. SDF를 샘플링하고, 셀을 분류하고, 삼각화를 룩업하고, 모서리 정점을 보간하고, 아토믹 카운터를 사용해 메시 버퍼에 추가합니다. 출력 버퍼가 렌더링용 정점 데이터로 직접 쓰이기 때문에 CPU 리드백이 필요 없습니다. Will Usher의 <a href="https://www.willusher.io/webgpu-marching-cubes/" target="_blank" rel="noreferrer">webgpu-marching-cubes</a>는 브라우저에서 실시간 256^3 그리드 처리를 보여줍니다. 우리의 <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">WebGPU 기반 LOD에 관한 지형 가이드</a>를 보세요.</p>
<p><strong>하이트맵 + SDF 하이브리드 아키텍처.</strong> 브라우저 지형의 실용적인 접근법입니다. 하이트맵은 세계 전체를 덮고(싸고 컴팩트함), SDF 볼륨은 동굴, 오버행, 또는 창작자가 깎아낸 특징이 필요한 청크에만 존재합니다(청크의 5-10%). 카메라 가까이에서는 볼류메트릭 자유도가 깎기와 동굴을 가능하게 합니다. 멀리에서는 하이트맵이 효율적인 평평한 지형을 제공합니다. <a href="/ko/guides/landscape-generation-browser.html#hybrid-heightmap-base--volumetric-overlays">하이브리드 지형 표현</a>을 보세요.</p>
<hr>
<p>12편 중 7편.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-06-clipmaps.html">6부 - 클립맵이 줄거리를 바꿨다</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-08-webgpu-integration.html">8부 - 기준선을 잃지 않고 통합하기</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 8부: 기준선을 잃지 않고 통합하기]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-08-webgpu-integration</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-08-webgpu-integration</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 13과 14는 기능보다 프로세스 규율에 관한 작업이었습니다. 깨끗한 기준선을 동결한 뒤 한 번에 한 계층씩 단단하게 다졌습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-8부-기준선을-잃지-않고-통합하기" tabindex="-1">브라우저에서 오픈 월드 만들기, 8부: 기준선을 잃지 않고 통합하기 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-8부-기준선을-잃지-않고-통합하기" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 8부: 기준선을 잃지 않고 통합하기&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 보시나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분으로 연결해 줍니다.</p>
<p>통합은 프로젝트가 엉망이 되는 지점입니다. 따로 떼어 놓으면 잘 도는 부분들이 있습니다. 그것들을 연결하면 갑자기 모든 버그가 어디에나 있을 수 있는 것처럼 보입니다.</p>
<p>Spike 13과 14는 그 함정에 대한 우리의 답이었습니다. Spike 13은 깨끗한 Three.js WebGPU 기준선을 세웠습니다. renderer 하나, scene 하나, camera 하나, 그리고 단순한 mesh 하나뿐이었습니다. 지형도, compute도, 이펙트도 없었습니다. 우리는 Three.js의 WebGPU 백엔드가 제대로 초기화되는지, 렌더 루프가 안정적인지, TSL(Three.js Shading Language) 노드 머티리얼이 기대대로 동작하는지 확인했습니다. 그 체크포인트를 통과한 뒤에야 계층을 추가하기 시작했습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/13-threejs-webgpu/" title="Spike 13 Three.js WebGPU Baseline" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/13-threejs-webgpu/" target="_blank">새 탭에서 Spike 13 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=13-threejs-webgpu">소스 보기</a></p>
<p>Spike 14는 점진적 강화였습니다. 한 번에 하나의 기능씩 추가했습니다. 먼저 카메라 컨트롤, 그다음 조명, 그다음 marching cubes 파이프라인에서 compute로 생성한 mesh, 그다음 GPU 출력을 Three.js 지오메트리 속성에 직접 연결하는 buffer 배선. 추가할 때마다 이전 계층이 여전히 제대로 동작하는지 확인했습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/14-threejs-webgpu-incremental/" title="Spike 14 Incremental Hardening" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/14-threejs-webgpu-incremental/" target="_blank">새 탭에서 Spike 14 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=14-threejs-webgpu-incremental">소스 보기</a></p>
<p>느려 보입니다. 딱 하루 느렸고, 곧이어 seam 로직과 정책 전환이 복잡해졌을 때 며칠을 아껴 줬습니다.</p>
<p>이 규율이 정당했음을 증명한 특정 버그 부류는 머리카락처럼 가는 아티팩트였습니다. 지오메트리 손상처럼 보이는 얇은 조각이었지만 사실은 과거 데이터였습니다. compute shader는 buffer에 N개의 정점을 쓰는데, draw call은 여전히 이전 프레임의 N+M개 정점을 렌더링하도록 설정되어 있었습니다. 그 여분의 정점에는 이전 dispatch에서 남은 쓰레기 값이 들어 있었습니다. 시각적 결과는 예측할 수 없이 나타났다 사라지는, 깜빡이는 면도날처럼 얇은 삼각형이었습니다.</p>
<p>이런 부류의 버그는 직관으로 이기는 게 아닙니다. 마지막으로 잘 돌던 상태와 지금 망가진 상태 사이에 정확히 무엇이 바뀌었는지 아는, 통제된 델타로 이깁니다.</p>
<p>WebGPU 통합은 buffer 생명주기에 대해서도 가르쳐 줬습니다. WebGPU의 GPU buffer는 특정 usage로 매핑되고 나면 불변입니다. marching cubes 출력이 커져서 vertex buffer를 키워야 한다면, 새 buffer를 만들고 바인딩을 갱신해야 합니다. <code>realloc</code>은 없습니다. 그 생명주기를 제대로 하는 것, 즉 진행 중인 GPU 작업과 경쟁하지 않으면서 옛 buffer를 파괴하는 것은 WebGL에 없는 명시적 fence 관리를 필요로 했습니다.</p>
<p>9부에서는 Transvoxel seam 작업으로 들어갑니다. 그 장은 의도적으로 스캐폴드에서 시작합니다. 이 시점에 우리는 통합을 서두르면 미스터리가 생기고, 통제된 셋업은 디버깅 가능한 문제를 만든다는 교훈을 완전히 체화한 상태였습니다.</p>
<h2 id="이-장에서-다룬-기술" tabindex="-1">이 장에서 다룬 기술 <a class="header-anchor" href="#이-장에서-다룬-기술" aria-label="Permalink to &quot;이 장에서 다룬 기술&quot;"></a></h2>
<p><strong>WebGPU.</strong> WebGL의 후속으로, 브라우저에서 compute shader와 indirect rendering을 갖춘 저수준 GPU 접근을 제공합니다. 오픈 월드에 중요한 WebGPU의 두 가지 핵심 기능은 이렇습니다. compute shader는 GPU 측 지형 생성, 식생 배치, 컬링을 가능하게 하고, indirect rendering은 GPU가 compute 출력을 바탕으로 무엇을 그릴지 결정하게 해서 밀집된 장면에서 CPU 병목을 없앱니다. 데스크톱의 Chrome, Edge, Firefox에서 쓸 수 있습니다. <a href="/ko/guides/browser-3d-open-world-tech.html#webgpu-the-performance-unlock">성능 면에서의 WebGPU</a>를 보세요.</p>
<p><strong>Three.js Shading Language (TSL).</strong> Three.js의 노드 기반 셰이더 시스템으로, 날것의 GLSL/WGSL을 조합 가능한 JavaScript 표현식으로 대체합니다. <code>texture()</code>, <code>positionWorld</code>, <code>smoothstep()</code>, <code>fog()</code> 같은 TSL 노드는 런타임에 셰이더 그래프를 만들고 적절한 백엔드(WebGL의 GLSL이나 WebGPU의 WGSL)로 컴파일됩니다. TSL 덕분에 머티리얼 로직을 한 번 작성하고 두 렌더러 모두를 대상으로 삼을 수 있습니다. 노드 그래프는 프레임마다 평가되므로 동적 uniform과 조건 분기가 자연스럽게 동작합니다.</p>
<p><strong>WebGPU의 GPU buffer 생명주기.</strong> WebGPU buffer는 특정 usage 플래그(<code>VERTEX</code>, <code>STORAGE</code>, <code>COPY_DST</code> 등)와 함께 생성되며 생성 후에는 크기를 바꿀 수 없습니다. 한 번의 marching cubes dispatch가 buffer가 담을 수 있는 것보다 많은 정점을 만들어 내면, 새 buffer를 만들고 바인딩을 갱신하고 옛것을 파괴해야 합니다. 진행 중인 GPU 명령이 아직 참조하는 buffer를 파괴하면 오류가 납니다. 명시적 fence 관리(<code>device.queue.onSubmittedWorkDone()</code>를 통해)는 GPU가 다 쓸 때까지 옛 buffer가 파괴되지 않도록 보장합니다. 이런 생명주기 규율은 드라이버가 메모리를 암묵적으로 관리하는 WebGL에는 없습니다.</p>
<p><strong>점진적 강화.</strong> 통합을 위한 프로세스 규율입니다. 검증된 기준선을 세우고, 한 번에 한 기능씩 추가하고, 추가할 때마다 이전 계층이 여전히 동작하는지 확인합니다. 이 접근은 하루는 더 느리지만 나중에 디버깅할 때 며칠을 아껴 줍니다. 각 회귀를 구체적이고 통제된 변경 하나로 추적할 수 있기 때문입니다. 기준선을 먼저 세우고 점진적으로 늘려 가는 패턴은 <a href="/ko/guides/browser-3d-open-world-tech.html#what-we-d-build-first">AAA 오픈 월드 개발</a>에서 흔하며, 거기서는 위험을 관리하기 위해 시스템을 특정 순서로 통합합니다.</p>
<hr>
<p>12부 중 8부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes.html">7부 - Marching cubes와 첫 진짜 동굴</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut.html">9부 - Transvoxel은 스캐폴드에서 시작했다</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 9부: Transvoxel은 발판부터 시작했다]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[우리는 전체 이음새 처리에 곧장 뛰어들지 않았다. 먼저 이음새 테스트 장치를 만들고, 그다음 참조 데이터로 한 면을 검증했다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-9부-transvoxel은-발판부터-시작했다" tabindex="-1">브라우저에서 오픈 월드 만들기, 9부: Transvoxel은 발판부터 시작했다 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-9부-transvoxel은-발판부터-시작했다" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 9부: Transvoxel은 발판부터 시작했다&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 파트를 링크해 둡니다.</p>
<p>이음새는 확신이 죽으러 가는 곳이다.</p>
<p>두 해상도가 만나기 전까지는 모든 게 안정적으로 보일 수 있다. LOD 0 chunk가 LOD 1 chunk 옆에 놓인다. 두 mesh는 독립적으로 생성된다. 둘이 경계를 공유하는 지점에서는 저해상도 chunk의 그리드 밀도가 절반이기 때문에 정점 위치가 맞지 않는다. 그 결과로 눈에 보이는 균열, T 자 교차점, 깜빡이는 가장자리가 생긴다.</p>
<p>Transvoxel 알고리즘은 서로 다른 해상도의 두 chunk 사이 경계면을 따라 특수한 전이 cell을 생성해서 이 문제를 해결한다. 이 cell들은 고해상도 그리드와 저해상도 그리드에서 동시에 샘플링해서 두 표면을 꿰매 붙이는 삼각형을 만들어 낸다. 알고리즘은 일반 marching cubes 테이블과는 별개로 자체 룩업 테이블을 쓰며, 512가지 전이 cell case를 가진다.</p>
<p>이 시점쯤 우리는 구현을 서두르면 안 된다는 걸 알 만큼 통합으로 생긴 흉터가 충분히 있었다.</p>
<p>Spike 15에는 임무가 하나뿐이었다. 전체 알고리즘을 건드리기 전에 믿을 수 있는 이음새 테스트 장치를 만드는 것. 우리는 알려진 SDF 데이터를 가진 두 chunk를 서로 다른 해상도로 나란히 놓은 통제된 환경을 세팅했고, 메인 mesh, 이음새 mesh, wireframe, 법선을 각각 독립적으로 토글하는 시각화 컨트롤을 붙였다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/15-transvoxel-seam/" title="Spike 15 Transvoxel Seam Scaffold" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/15-transvoxel-seam/" target="_blank">새 탭에서 Spike 15 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=15-transvoxel-seam">소스 보기</a></p>
<p>테스트 장치가 안정되자 Spike 16은 테이블 기반 전이 cell 생성을 단일 면에서 검증했다. 우리는 축에 정렬된 면 하나(+X 경계)를 골라서 그 면만 전이 cell 평가를 구현했고, 출력을 Transvoxel 논문의 참조 데이터와 비교했다.</p>
<p><a href="/spikes/16-transvoxel-face/" target="_blank">새 탭에서 Spike 16 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=16-transvoxel-face">소스 보기</a></p>
<p>우리는 일부러 한 번에 한 면씩 테스트했는데, 전이 테이블 배선에는 독립적인 실패 모드가 많기 때문이다. case 인덱스 계산은 두 그리드 양쪽에서 올바른 정점을 샘플링하는 데 달려 있다. 전이 cell 안의 정점 인덱싱은 일반 marching cubes cell과 다른 번호 매김 방식을 쓴다. 와인딩 순서는 메인 mesh와 일관돼야 하며, 그렇지 않으면 백페이스 컬링이 당신의 이음새 삼각형을 잡아먹는다. 여섯 면을 한꺼번에 테스트하면 모든 증상이 무작위로 보인다. 한 면을 철저히 테스트하면 의미 있고 디버그 가능한 실패를 얻는다.</p>
<p>이 단계에서 얻은 또 다른 미묘한 성과는 도구에 대한 투자였다. 우리는 가시성 토글, 이음새 전용 렌더링, 색상으로 구분한 LOD 표시기를 일찍 만들었다. 당시에는 이 컨트롤들이 부담처럼 느껴졌다. 나중에 코너 케이스가 험해졌을 때, 정확히 어떤 이음새 cell이 말썽인지 격리할 수 있었기 때문에 이 컨트롤들은 거듭거듭 본전을 뽑았다.</p>
<p>이 장이 끝날 때 우리는 &quot;이음새를 끝낸&quot; 상태가 아니었다. 우리는 이음새 버그를 두려워하는 대신 추론할 수 있는 위치에 있었다.</p>
<p>10부에서 진짜 롤러코스터가 시작된다. 혼합 LOD 코너, 와인딩 뒤집힘, 부분 overdraw 잔상, 그리고 알고리즘이 틀렸다고 확신했다가 사실 버그는 draw 범위가 활성 정점 수 너머를 읽고 있었던 것임을 발견하는 순간들.</p>
<h2 id="이-장에서-언급한-기술" tabindex="-1">이 장에서 언급한 기술 <a class="header-anchor" href="#이-장에서-언급한-기술" aria-label="Permalink to &quot;이 장에서 언급한 기술&quot;"></a></h2>
<p><strong>Transvoxel 알고리즘.</strong> Eric Lengyel이 설계했고(<a href="https://transvoxel.org/" target="_blank" rel="noreferrer">transvoxel.org</a>), Transvoxel은 볼류메트릭 지형 LOD에서 가장 어려운 문제를 해결한다. 바로 서로 다른 해상도의 chunk 사이 이음새다. 고해상도 chunk가 저해상도 chunk 옆에 놓이면 marching cubes mesh가 경계에서 정렬되지 않아 눈에 보이는 균열이 생긴다. Transvoxel은 경계면을 따라 특수한 전이 cell을 끼워 넣어 양쪽에 맞는 추가 삼각형으로 해상도 차이를 메운다. 알고리즘은 (일반 marching cubes와 별개인) 자체 룩업 테이블을 쓰며 512가지 전이 cell case를 가지는데, 이는 73개의 등가 클래스로 줄어든다. 특허가 없으며 출시된 게임들(Space Engineers, Astroneer)에서 쓰였다. <a href="/ko/guides/landscape-generation-browser.html#the-transvoxel-algorithm">Transvoxel에 관한 지형 가이드</a>를 참고하라.</p>
<p><strong>전이 cell.</strong> 두 LOD 레벨 사이의 면에서 생성되는 특수한 cell. 한 그리드에서 8개의 모서리를 샘플링하는 일반 marching cubes cell과 달리, 전이 cell은 고해상도와 저해상도 그리드에서 동시에 샘플링한다. 고해상도 면은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="9.176ex" height="1.692ex" role="img" focusable="false" viewBox="0 -666 4056 748" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1722.4,0)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2500.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3556,0)"><path data-c="39" d="M352 287Q304 211 232 211Q154 211 104 270T44 396Q42 412 42 436V444Q42 537 111 606Q171 666 243 666Q245 666 249 666T257 665H261Q273 665 286 663T323 651T370 619T413 560Q456 472 456 334Q456 194 396 97Q361 41 312 10T208 -22Q147 -22 108 7T68 93T121 149Q143 149 158 135T173 96Q173 78 164 65T148 49T135 44L131 43Q131 41 138 37T164 27T206 22H212Q272 22 313 86Q352 142 352 280V287ZM244 248Q292 248 321 297T351 430Q351 508 343 542Q341 552 337 562T323 588T293 615T246 625Q208 625 181 598Q160 576 154 546T147 441Q147 358 152 329T172 282Q197 248 244 248Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>3</mn><mo>×</mo><mn>3</mn><mo>=</mo><mn>9</mn></math></mjx-assistive-mml></mjx-container>개의 샘플 지점을 가지고, 저해상도 면은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="9.176ex" height="1.717ex" role="img" focusable="false" viewBox="0 -677 4056 759" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1722.4,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2500.2,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(3556,0)"><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>2</mn><mo>×</mo><mn>2</mn><mo>=</mo><mn>4</mn></math></mjx-assistive-mml></mjx-container>개를 가진다. 이 9개의 샘플이 알고리즘에 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="8.53ex" height="2.072ex" role="img" focusable="false" viewBox="0 -833.9 3770.1 915.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(533,363) scale(0.707)"><path data-c="39" d="M352 287Q304 211 232 211Q154 211 104 270T44 396Q42 412 42 436V444Q42 537 111 606Q171 666 243 666Q245 666 249 666T257 665H261Q273 665 286 663T323 651T370 619T413 560Q456 472 456 334Q456 194 396 97Q361 41 312 10T208 -22Q147 -22 108 7T68 93T121 149Q143 149 158 135T173 96Q173 78 164 65T148 49T135 44L131 43Q131 41 138 37T164 27T206 22H212Q272 22 313 86Q352 142 352 280V287ZM244 248Q292 248 321 297T351 430Q351 508 343 542Q341 552 337 562T323 588T293 615T246 625Q208 625 181 598Q160 576 154 546T147 441Q147 358 152 329T172 282Q197 248 244 248Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1214.3,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2270.1,0)"><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" style="stroke-width: 3;"/><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" transform="translate(1000,0)" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>2</mn><mn>9</mn></msup><mo>=</mo><mn>512</mn></math></mjx-assistive-mml></mjx-container>가지 원시 case를 주는데, 회전과 반사를 접어 내면 73개의 고유한 삼각화로 무너진다. cell 분류와 삼각화는 양쪽 해상도의 정점을 잇는 삼각형을 만들어 내는 전용 테이블을 쓴다. 정점 번호 매김 방식이 일반 MC cell과 달라서 흔한 구현 버그의 원인이 된다.</p>
<p><strong>LOD 전이 이음새.</strong> 위상 불일치가 시각적 아티팩트를 일으키는 두 mesh 해상도 사이의 경계. 꿰매지 않으면 LOD 0 chunk(1m 그리드)가 LOD 1 chunk(2m 그리드) 옆에 놓일 때 T 자 교차점이 생긴다. 미세한 mesh는 경계를 따라 정점을 가지지만 거친 mesh는 그걸 공유하지 않아서, 빛이 새어 들어오는 균열이 생긴다. Transvoxel, 지오모핑, 스커트 지오메트리가 이 이음새를 고치는 세 가지 접근법이다. 볼류메트릭 지형에서는 지오모핑이 heightmap에만 통하기 때문에 Transvoxel이 표준 해법이다. <a href="/ko/guides/landscape-generation-browser.html#lod-for-volumetric-terrain">볼류메트릭 지형의 LOD</a>를 참고하라.</p>
<hr>
<p>12부 중 9부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-08-webgpu-integration.html">8부 - 기준선을 잃지 않고 통합하기</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-10-seam-chaos.html">10부 - 이음새 혼돈과 코너 보스전</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 10부: 이음새 혼란과 코너 보스전]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-10-seam-chaos</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-10-seam-chaos</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 17부터 22까지는 이론이 엣지 케이스와 부딪힌 구간이었습니다. 우리는 와인딩 버그, 사라진 삼각형, 오버드로 잔상, 하이브리드 폴백 로직을 쫓았습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-10부-이음새-혼란과-코너-보스전" tabindex="-1">브라우저에서 오픈 월드 만들기, 10부: 이음새 혼란과 코너 보스전 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-10부-이음새-혼란과-코너-보스전" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 10부: 이음새 혼란과 코너 보스전&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 파트를 링크해 둡니다.</p>
<p>앞부분이 차근차근 진행되는 느낌이었다면, 이 챕터는 전투 같았습니다.</p>
<p>Spike 17부터 22까지는 우리의 코너 케이스 시대였습니다. 듀얼 LOD marching cubes, heightmap에서 MC로 넘어가는 경계 이음새, 세 개나 네 개의 LOD 레벨이 만나는 혼합 해상도 코너 chunk, GPU 이음새 생성, 그리고 폴백 모드 동작. 각 spike는 우리가 마주쳤거나 예상했던 특정 실패 시나리오를 다뤘습니다.</p>
<p>Spike 17은 두 개의 LOD 레벨이 동시에 활성화된 상태의 듀얼 marching cubes를 테스트했습니다. 어려운 점은 하나의 chunk의 이웃들이 면마다 서로 다른 해상도일 수 있다는 것이었습니다. Spike 16에서 만든 전이 셀 로직은 한 번에 한 면에 대해서는 잘 작동했지만, chunk가 여러 면에 전이 셀이 필요할 때는 정점 버퍼 관리가 복잡해졌습니다. 각 면의 전이 셀은 다른 면을 덮어쓰지 않으면서 생성되고 추가되어야 했습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/19-transvoxel-corner-grid/" title="Spike 19 Corner Grid Transvoxel" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/19-transvoxel-corner-grid/" target="_blank">새 탭에서 Spike 19 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=19-transvoxel-corner-grid">소스 보기</a></p>
<p>반복해서 등장한 첫 번째 악당은 와인딩 순서였습니다. 여러 번 우리는 토폴로지 문제라고 생각했지만 알고 보니 방향 문제였습니다. 백페이스 컬링이 유효한 이음새 삼각형을 먹어 치우고 있었는데, 와인딩이 메인 메시 기준으로 뒤집혀 있었기 때문입니다. 같은 근본 원인인데 카메라 각도에 따라 시각적 증상이 달랐습니다. 해결책은 전이 셀 방출 코드에서 일관된 와인딩 규칙을 강제하고, 양면 머티리얼 토글로 그것을 검증하는 것이었습니다.</p>
<p>두 번째 악당은 부분적인 정확성에서 오는 잘못된 확신이었습니다. 이음새가 한 카메라 각도에서는 완벽해 보이다가, 고해상도와 저해상도 chunk 사이에서 LOD 역할이 바뀌면 깨질 수 있었습니다. 전이 셀은 비대칭입니다. 고해상도 쪽과 저해상도 쪽을 서로 다르게 샘플링합니다. 어떤 구성에서 &quot;어느 쪽이 고해상도인가&quot; 로직을 거꾸로 하면, 카메라가 특정 위치로 움직일 때만 그 버그가 보입니다.</p>
<p>그다음에는 우리가 가장 좋아하는 복구 중 하나가 있었습니다. 우리는 heightmap 타일에서 이음새가 잘리는 아티팩트를 쫓으면서 전이 로직을 탓하고 있었습니다. 거기에 이틀을 태웠습니다. 진짜 범인은 오래된 오버드로였습니다. 이전 프레임의 고해상도 지오메트리가, chunk가 더 낮은 LOD로 다운스케일된 뒤에도 버퍼 꼬리에 그대로 남아 있었습니다. 드로 범위는 여전히 예전의 더 큰 정점 수로 설정되어 있었죠. compute shader의 atomic counter가 보고하는 활성 정점 수로 드로 범위를 잘라내자, 그 &quot;정체불명의 이음새 문제&quot;가 사라졌습니다.</p>
<p>이건 렌더링 버그가 종종 메싱 버그로 위장한다는 좋은 일깨움이었습니다. 지오메트리는 처음부터 끝까지 옳았습니다. 드로 콜이 유효한 데이터의 끝을 지나서까지 읽고 있었을 뿐입니다.</p>
<p>Spike 22에 이르러서는 하이브리드 폴백을 테스트하고 있었습니다. chunk가 특정 조건에서 marching cubes에서 heightmap 모드로 전환할 수 있는 방식인데, 예를 들어 chunk에 볼류메트릭 편집이 없고 카메라에서 충분히 멀리 떨어져 있을 때입니다. 이것은 전부 아니면 전무 정책보다 더 실용적인 길을 줬습니다. 근거리의 편집된 chunk는 볼류메트릭 자유를 위해 MC를 씁니다. 원거리의 편집되지 않은 chunk는 효율을 위해 heightmap을 씁니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/22-gpu-mc-heightmap-fallback/" title="Spike 22 MC Heightmap Fallback" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/22-gpu-mc-heightmap-fallback/" target="_blank">새 탭에서 Spike 22 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=22-gpu-mc-heightmap-fallback">소스 보기</a></p>
<p>이 챕터는 롤러코스터의 가파른 낙하였습니다. 짜증나면서도 동시에 생산적이었습니다. 개별 수정 다수는 작았고, 어떤 때는 비교 연산자 하나나 오프셋 하나를 바꾸는 한 줄이었습니다. 하지만 그것들이 만들어낸, LOD 전이와 버퍼 관리와 드로 범위가 어떻게 상호작용하는지에 대한 이해는 결코 작지 않았습니다.</p>
<p>11부에서는 혼란 뒤에 온 안정화 레이어를 다룹니다. 정책 기반 chunk 모드, 그리고 반응적인 버그 수정에서 명시적인 시스템 규칙으로의 전환입니다.</p>
<h2 id="이-챕터에서-언급된-기술" tabindex="-1">이 챕터에서 언급된 기술 <a class="header-anchor" href="#이-챕터에서-언급된-기술" aria-label="Permalink to &quot;이 챕터에서 언급된 기술&quot;"></a></h2>
<p><strong>듀얼 LOD marching cubes.</strong> marching cubes를 두 개의 해상도 레벨에서 동시에 돌리면서, 전이 셀로 경계를 꿰매는 것입니다. 어려운 점은 하나의 chunk의 이웃들이 면마다 서로 다른 해상도일 수 있어서, 면마다 독립적인 전이 셀 생성이 필요하다는 것입니다. 각 면의 전이 셀은 다른 면을 덮어쓰지 않으면서 정점 버퍼에 추가됩니다. atomic counter가 모든 면에 걸친 총 활성 정점 수를 추적합니다.</p>
<p><strong>와인딩 순서(winding order).</strong> 각 삼각형 안의 정점 순서가 어느 쪽이 &quot;앞&quot; 면인지 결정합니다. 일관된 와인딩(보통 바깥에서 봤을 때 반시계 방향)은 백페이스 컬링에 필요합니다. 전이 셀이 삼각형을 방출할 때 와인딩은 메인 메시의 규칙과 일치해야 합니다. 거꾸로 하면 백페이스 컬링이 유효한 이음새 삼각형을 먹어 치우는데, 이는 특정 카메라 각도에서 표면이 사라진 것처럼 보입니다. 흔한 디버깅 기법은 머티리얼에서 <code>side: THREE.DoubleSide</code>를 토글해서, 아티팩트가 와인딩 문제인지 진짜 토폴로지 구멍인지 확인하는 것입니다.</p>
<p><strong>Heightmap-to-MC fallback.</strong> 하이브리드 chunk 모드로, 멀거나 편집되지 않은 chunk는 heightmap 지형(저렴하고 평평한 표면)을 쓰고, 가깝거나 편집된 chunk는 marching cubes(볼류메트릭, 동굴 지원)를 씁니다. 폴백 결정은 카메라로부터의 거리와 chunk에 SDF 편집이 있는지에 달려 있습니다. heightmap chunk와 MC chunk 사이의 이음새는 자체 전이 지오메트리가 필요한데, Transvoxel과 비슷하지만 두 개의 LOD 레벨이 아니라 두 개의 서로 다른 표현을 잇는다는 점이 다릅니다. <a href="/ko/guides/landscape-generation-browser.html#hybrid-heightmap-base--volumetric-overlays">하이브리드 heightmap + 볼류메트릭 오버레이</a>를 보세요.</p>
<p><strong>드로 범위와 atomic counter.</strong> GPU 주도 메시 생성에서는 compute shader가 정점을 버퍼에 쓰고, 몇 개의 정점이 방출되었는지 추적하기 위해 atomic counter를 증가시킵니다. 드로 콜은 버퍼 용량이 아니라 이 counter를 정점 수로 써야 합니다. 드로 범위가 활성 카운트로 잘리지 않으면, 이전 프레임의 오래된 정점들(여전히 버퍼 꼬리에 남아 있는)이 잔상 지오메트리를 만듭니다. 얇은 조각과 깜박이는 삼각형인데, 토폴로지 오류처럼 보이지만 사실은 유효한 데이터를 지나서 읽어서 생긴 렌더링 아티팩트입니다.</p>
<hr>
<p>12부 중 10부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut.html">9부 - Transvoxel은 스캐폴드로 시작했다</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-11-policy-modes.html">11부 - 하드코딩 모드가 아니라 정책 모드</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 11부: 하드코딩 모드가 아닌 정책 모드]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-11-policy-modes</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-11-policy-modes</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 23은 우리를 반응적 수정에서 명시적 정책으로 옮겨놓았습니다. 거리 기반 LOD, 편집 기반 HM/MC 전환, 그리고 더 나은 이음매 디버깅 제어.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-11부-하드코딩-모드가-아닌-정책-모드" tabindex="-1">브라우저에서 오픈 월드 만들기, 11부: 하드코딩 모드가 아닌 정책 모드 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-11부-하드코딩-모드가-아닌-정책-모드" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 11부: 하드코딩 모드가 아닌 정책 모드&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO이자 공동 창업자</em></p>
<p>처음 오셨나요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 부분을 링크해 둡니다.</p>
<p>이음매 혼돈 챕터가 끝난 뒤, 우리는 반응하기를 멈추고 다스리기를 시작해야 했습니다.</p>
<p>Spike 23은 즉흥적인 동작을 명시적인 정책 규칙으로 바꿨습니다. chunk가 각자의 로컬 상태가 시키는 대로 아무렇게나 움직이는 대신, 이제 중앙 정책 시스템이 결정을 내립니다. 이 chunk는 어떤 LOD 레벨을 받을까? heightmap으로 렌더링될까, marching cubes로 렌더링될까? 전환 cell이 필요할까, 그렇다면 어느 면에서? 그 답은 카메라까지의 거리, 편집 이력, 이웃의 해상도 상태를 평가하는 정책 함수에서 나왔습니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/23-policy-chunk-modes/" title="Spike 23 Policy Chunk Modes" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/23-policy-chunk-modes/" target="_blank">새 탭에서 Spike 23 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=23-policy-chunk-modes">소스 보기</a></p>
<p>거리 기반 LOD 할당은 카메라를 중심으로 한 동심원 링을 사용했습니다. clipmap 개념과 비슷하지만 chunk 그리드에 적용한 것이죠. 링 0의 chunk는 전체 해상도 MC를 받습니다. 링 1은 절반 해상도 MC를 받습니다. 링 2 이상은 heightmap 모드로 갑니다. 인접 제약이 핵심이었습니다. 이웃한 두 chunk에 대해 우리는 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.666ex;" xmlns="http://www.w3.org/2000/svg" width="12.84ex" height="2.361ex" role="img" focusable="false" viewBox="0 -749.5 5675.3 1043.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(278,0)"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(714,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1508.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2508.4,0)"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(714,-150) scale(0.707)"><path data-c="1D457" d="M297 596Q297 627 318 644T361 661Q378 661 389 651T403 623Q403 595 384 576T340 557Q322 557 310 567T297 596ZM288 376Q288 405 262 405Q240 405 220 393T185 362T161 325T144 293L137 279Q135 278 121 278H107Q101 284 101 286T105 299Q126 348 164 391T252 441Q253 441 260 441T272 442Q296 441 316 432Q341 418 354 401T367 348V332L318 133Q267 -67 264 -75Q246 -125 194 -164T75 -204Q25 -204 7 -183T-12 -137Q-12 -110 7 -91T53 -71Q70 -71 82 -81T95 -112Q95 -148 63 -167Q69 -168 77 -168Q111 -168 139 -140T182 -74L193 -32Q204 11 219 72T251 197T278 308T289 365Q289 372 288 376Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3563.7,0) translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4119.5,0)"><path data-c="2264" d="M674 636Q682 636 688 630T694 615T687 601Q686 600 417 472L151 346L399 228Q687 92 691 87Q694 81 694 76Q694 58 676 56H670L382 192Q92 329 90 331Q83 336 83 348Q84 359 96 365Q104 369 382 500T665 634Q669 636 674 636ZM84 -118Q84 -108 99 -98H678Q694 -104 694 -118Q694 -130 679 -138H98Q84 -131 84 -118Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(5175.3,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo data-mjx-texclass="ORD" stretchy="false">|</mo><msub><mi>L</mi><mi>i</mi></msub><mo>−</mo><msub><mi>L</mi><mi>j</mi></msub><mo data-mjx-texclass="ORD" stretchy="false">|</mo><mo>≤</mo><mn>1</mn></math></mjx-assistive-mml></mjx-container>을 요구합니다. 한 면을 가로지르는 해상도 비율은 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="6.754ex" height="2.02ex" role="img" focusable="false" viewBox="0 -893 2985.2 893" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="TeXAtom" transform="translate(533,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(278,0)"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(714,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1286,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2064,0)"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(714,-150) scale(0.707)"><path data-c="1D457" d="M297 596Q297 627 318 644T361 661Q378 661 389 651T403 623Q403 595 384 576T340 557Q322 557 310 567T297 596ZM288 376Q288 405 262 405Q240 405 220 393T185 362T161 325T144 293L137 279Q135 278 121 278H107Q101 284 101 286T105 299Q126 348 164 391T252 441Q253 441 260 441T272 442Q296 441 316 432Q341 418 354 401T367 348V332L318 133Q267 -67 264 -75Q246 -125 194 -164T75 -204Q25 -204 7 -183T-12 -137Q-12 -110 7 -91T53 -71Q70 -71 82 -81T95 -112Q95 -148 63 -167Q69 -168 77 -168Q111 -168 139 -140T182 -74L193 -32Q204 11 219 72T251 197T278 308T289 365Q289 372 288 376Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3119.3,0) translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>2</mn><mrow data-mjx-texclass="ORD"><mo data-mjx-texclass="ORD" stretchy="false">|</mo><msub><mi>L</mi><mi>i</mi></msub><mo>−</mo><msub><mi>L</mi><mi>j</mi></msub><mo data-mjx-texclass="ORD" stretchy="false">|</mo></mrow></msup></math></mjx-assistive-mml></mjx-container>이고, Transvoxel 전환 테이블은 2:1 경우(<mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.666ex;" xmlns="http://www.w3.org/2000/svg" width="12.84ex" height="2.361ex" role="img" focusable="false" viewBox="0 -749.5 5675.3 1043.7" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo" transform="translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(278,0)"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(714,-150) scale(0.707)"><path data-c="1D456" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1508.2,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2508.4,0)"><g data-mml-node="mi"><path data-c="1D43F" d="M228 637Q194 637 192 641Q191 643 191 649Q191 673 202 682Q204 683 217 683Q271 680 344 680Q485 680 506 683H518Q524 677 524 674T522 656Q517 641 513 637H475Q406 636 394 628Q387 624 380 600T313 336Q297 271 279 198T252 88L243 52Q243 48 252 48T311 46H328Q360 46 379 47T428 54T478 72T522 106T564 161Q580 191 594 228T611 270Q616 273 628 273H641Q647 264 647 262T627 203T583 83T557 9Q555 4 553 3T537 0T494 -1Q483 -1 418 -1T294 0H116Q32 0 32 10Q32 17 34 24Q39 43 44 45Q48 46 59 46H65Q92 46 125 49Q139 52 144 61Q147 65 216 339T285 628Q285 635 228 637Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(714,-150) scale(0.707)"><path data-c="1D457" d="M297 596Q297 627 318 644T361 661Q378 661 389 651T403 623Q403 595 384 576T340 557Q322 557 310 567T297 596ZM288 376Q288 405 262 405Q240 405 220 393T185 362T161 325T144 293L137 279Q135 278 121 278H107Q101 284 101 286T105 299Q126 348 164 391T252 441Q253 441 260 441T272 442Q296 441 316 432Q341 418 354 401T367 348V332L318 133Q267 -67 264 -75Q246 -125 194 -164T75 -204Q25 -204 7 -183T-12 -137Q-12 -110 7 -91T53 -71Q70 -71 82 -81T95 -112Q95 -148 63 -167Q69 -168 77 -168Q111 -168 139 -140T182 -74L193 -32Q204 11 219 72T251 197T278 308T289 365Q289 372 288 376Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3563.7,0) translate(0 -0.5)"><path data-c="7C" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4119.5,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(5175.3,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo data-mjx-texclass="ORD" stretchy="false">|</mo><msub><mi>L</mi><mi>i</mi></msub><mo>−</mo><msub><mi>L</mi><mi>j</mi></msub><mo data-mjx-texclass="ORD" stretchy="false">|</mo><mo>=</mo><mn>1</mn></math></mjx-assistive-mml></mjx-container>)에 대해서만 정의되어 있습니다. 2레벨 점프는 테이블이 표현할 수 없는 4:1 전환이 필요하므로, 정책은 제약이 충족될 때까지 더 낮은 디테일의 chunk를 업그레이드하도록 강제합니다.</p>
<p>HM/MC 전환 로직은 각 chunk의 편집 비트맵을 확인했습니다. chunk에 볼류메트릭 편집(동굴, 터널, 지형 조각)이 하나라도 있으면, 거리와 관계없이 MC 모드에 남았습니다. 편집되지 않은 chunk는 충분히 멀어지면 heightmap 모드로 내려갈 수 있었습니다. 이 하이브리드 방식 덕분에 중요한 곳에서는 볼류메트릭 자유를, 그렇지 않은 곳에서는 효율을 얻었습니다.</p>
<p>이 spike는 밖에서 보기엔 이전의 몇몇보다 작아 보였습니다. 실제로는 개발 편의성에서 큰 개선이었습니다.</p>
<p>시스템이 chunk가 왜 모드를 바꿨는지 설명할 수 있으면, 추측에 쓰는 시간이 줄어듭니다. 우리는 색상으로 구분한 오버레이를 추가했습니다. heightmap chunk는 녹색, MC chunk는 파란색, 전환이 활성화된 면은 주황색입니다. 이음매 가시성에 전용 렌더 제어가 있으면, 시각적 디버깅의 모호함이 줄어듭니다. draw 범위가 정책 시스템의 활성 정점 수에 명시적으로 묶여 있으면, 오래된 지오메트리 잔상이 오후 시간을 갉아먹는 일이 사라집니다.</p>
<p>이 spike에서 우리는 카메라 동작도 대폭 손봤습니다. 이전 spike들의 단순한 orbit 컨트롤은 스크린샷에는 괜찮았지만 버그 재현에는 쓸모가 없었습니다. Spike 23은 속도 조절이 가능한 WASD 비행 카메라, 고도 잠금 토글, 위치 표시를 추가했습니다. 사소하게 들립니다. 하지만 이것은 &quot;저 능선 근처 어딘가에서 버그를 봤다&quot;와 &quot;버그는 북서쪽을 바라보는 위치 (142, 12, -67)에서 나타난다&quot;의 차이를 의미했습니다.</p>
<p>이 챕터의 핵심 통찰은 정책이 복잡도를 줄이지 않았다는 것입니다. 정책은 복잡도를 조직했습니다. 같은 수의 엣지 케이스가 그대로 존재했습니다. 하지만 이제 각 엣지 케이스에는 이름이 있고, 트리거 조건이 있고, 브레이크포인트를 걸 수 있는 코드상의 자리가 있습니다. 이것은 다른 종류의 승리이고, 시스템이 계속 진화할 수 있는지 아니면 제 무게에 짓눌려 무너지는지를 결정하는 요소입니다.</p>
<p>Spike 23이 끝날 무렵, 우리에게는 상호작용 버그에 대한 끊임없는 두려움 없이 원거리 clipmap 링 전략에 연결할 수 있을 만큼 예측 가능한 근거리 동작 레이어가 생겼습니다.</p>
<p>12부에서는 Spike 24를 다룹니다. 링 전환, 스카이박스 안개, Three.js 버전 수준의 셰이더 통합이 이 프로젝트의 이 챕터를 마무리합니다.</p>
<h2 id="이-챕터에서-언급한-기술" tabindex="-1">이 챕터에서 언급한 기술 <a class="header-anchor" href="#이-챕터에서-언급한-기술" aria-label="Permalink to &quot;이 챕터에서 언급한 기술&quot;"></a></h2>
<p><strong>거리 기반 LOD 정책.</strong> 카메라까지의 거리, 편집 이력, 이웃 상태를 바탕으로 각 chunk에 LOD 레벨과 렌더링 모드를 할당하는 중앙 함수입니다. 동심 거리 링이 기본 LOD를 결정합니다. 링 0 = 전체 해상도 MC, 링 1 = 절반 해상도 MC, 링 2+ = heightmap 모드. 정책 함수는 카메라가 움직임에 따라 프레임마다 실행되며 chunk 전환을 트리거합니다. 이것은 즉흥적인 chunk별 결정을 예측 가능하고 디버깅 가능한 규칙 시스템으로 바꿉니다. compute shader 등가물은 <a href="/ko/guides/landscape-generation-browser.html#gpu-driven-lod-with-webgpu">GPU 기반 LOD 선택</a>을 보세요.</p>
<p><strong>인접 제약.</strong> Transvoxel 알고리즘은 2:1 해상도 비율만 처리합니다. 이웃한 두 chunk가 한 LOD 레벨을 초과해 차이 나면(예: LOD 0 옆에 LOD 2), 전환 테이블이 유효한 이음매 지오메트리를 만들 수 없습니다. 정책 시스템은 LOD 차이가 1을 넘을 때 더 낮은 디테일의 chunk를 업그레이드해 이를 강제합니다. 이 제약 전파는 연쇄될 수 있습니다. 한 chunk를 업그레이드하면 그 이웃들도 업그레이드를 강제할 수 있습니다. 구현은 단순한 반복 패스이며, 일반적인 그리드 구성에서 2-3회 반복이면 수렴합니다.</p>
<p><strong>모드 선택을 위한 편집 비트맵.</strong> 각 chunk는 볼류메트릭 SDF 편집(동굴, 터널, 조각)을 포함하는지 기록하는 비트맵을 유지합니다. 편집이 하나라도 있는 chunk는 거리와 관계없이 marching cubes 모드에 남아 창작자의 수정을 보존합니다. 편집되지 않은 chunk는 카메라에서 충분히 멀어지면 heightmap 모드로 내려가 연산과 메모리를 아낍니다. 비트맵은 chunk당 단일 플래그이지만, 더 세분화된 모드 결정을 위해 편집 밀도를 추적하도록 확장할 수 있습니다.</p>
<p><strong>디버그 시각화 오버레이.</strong> 색상으로 구분한 chunk 렌더링으로, 녹색 = heightmap 모드, 파란색 = MC 모드, 주황색 = 전환이 활성화된 면입니다. LOD 레벨 숫자, 모드 라벨, wireframe 토글이 달린 chunk별 오버레이도 있습니다. 이것들은 출시 기능이 아니라 개발 도구이지만, LOD 전환과 이음매 아티팩트를 디버깅할 때 거듭 본전을 뽑습니다. 정확한 월드 위치를 알려주는 WASD 비행 카메라와 결합하면, &quot;어딘가에서 버그를 봤다&quot;가 &quot;버그는 이 LOD 구성에서 (142, 12, -67)에 나타난다&quot;로 바뀝니다.</p>
<hr>
<p>12부 중 11부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-10-seam-chaos.html">10부 - 이음매 혼돈과 코너 보스전</a><br>
다음: <a href="/ko/blog/2026-02-25-open-world-browser-part-12-lessons.html">12부 - 링, 하늘 안개, 그리고 다시 한다면 할 일</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저에서 오픈 월드 만들기, 12부: 링, 하늘 안개, 그리고 다시 해도 똑같이 할 것들]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-12-lessons</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-part-12-lessons</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 24는 clipmap 링 전환, 스카이박스 안개 통합, 그리고 힘들게 배운 교훈 한 줄 목록으로 이 챕터를 마무리했습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저에서-오픈-월드-만들기-12부-링-하늘-안개-그리고-다시-해도-똑같이-할-것들" tabindex="-1">브라우저에서 오픈 월드 만들기, 12부: 링, 하늘 안개, 그리고 다시 해도 똑같이 할 것들 <a class="header-anchor" href="#브라우저에서-오픈-월드-만들기-12부-링-하늘-안개-그리고-다시-해도-똑같이-할-것들" aria-label="Permalink to &quot;브라우저에서 오픈 월드 만들기, 12부: 링, 하늘 안개, 그리고 다시 해도 똑같이 할 것들&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO 겸 공동창업자</em></p>
<p>처음이신가요? <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">시리즈 가이드</a>를 보세요. spike가 무엇인지 설명하고 모든 파트를 링크해 둡니다.</p>
<p>Spike 24는 원래 &quot;지형에 clipmap 링을 추가&quot;하는 작업이어야 했습니다. 그런데 렌더링, 셰이더, 모듈 인프라, 비주얼 통합을 한꺼번에 건드린 본격적인 피날레가 되어 버렸습니다.</p>
<p>핵심 지형 작업은 버텍스 셰이더에서 카메라를 중심으로 한 동심원 clipmap 링을 생성하는 것이었습니다. 각 링은 카메라를 중심으로 한 평면 그리드 메시이고, 버텍스는 heightmap 샘플로 변위됩니다. 가장 안쪽 링은 최대 해상도를 씁니다. 바깥쪽으로 갈수록 링마다 버텍스 간격이 두 배가 되고 더 넓은 영역을 덮습니다. 까다로운 부분은 링 사이의 경계입니다. 고해상도 링이 저해상도 링과 만나는 곳에서, 더 촘촘한 메시의 가장자리 버텍스는 더 성긴 메시 가장자리의 중점으로 스냅되어야 합니다. 우리는 경계 버텍스(링 가장자리를 따라 그리드 좌표가 홀수인 버텍스)를 감지해 그 높이를 양쪽 짝수 이웃의 중점으로 스냅하는 방식으로 2:1 가장자리 모핑을 했습니다. <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.781ex;" xmlns="http://www.w3.org/2000/svg" width="19.274ex" height="2.737ex" role="img" focusable="false" viewBox="0 -864.9 8519.1 1209.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(853.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(1909.6,0)"><g data-mml-node="mfrac"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><rect width="553.6" height="60" x="120" y="220"/></g></g><g data-mml-node="mo" transform="translate(2703.1,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3092.1,0)"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(609,-150) scale(0.707)"><path data-c="6C" d="M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z" style="stroke-width: 3;"/><path data-c="65" d="M28 218Q28 273 48 318T98 391T163 433T229 448Q282 448 320 430T378 380T406 316T415 245Q415 238 408 231H126V216Q126 68 226 36Q246 30 270 30Q312 30 342 62Q359 79 369 104L379 128Q382 131 395 131H398Q415 131 415 121Q415 117 412 108Q393 53 349 21T250 -11Q155 -11 92 58T28 218ZM333 275Q322 403 238 411H236Q228 411 220 410T195 402T166 381T143 340T127 274V267H333V275Z" transform="translate(278,0)" style="stroke-width: 3;"/><path data-c="66" d="M273 0Q255 3 146 3Q43 3 34 0H26V46H42Q70 46 91 49Q99 52 103 60Q104 62 104 224V385H33V431H104V497L105 564L107 574Q126 639 171 668T266 704Q267 704 275 704T289 705Q330 702 351 679T372 627Q372 604 358 590T321 576T284 590T270 627Q270 647 288 667H284Q280 668 273 668Q245 668 223 647T189 592Q183 572 182 497V431H293V385H185V225Q185 63 186 61T189 57T194 54T199 51T206 49T213 48T222 47T231 47T241 46T251 46H282V0H273Z" transform="translate(722,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1028,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(4975.3,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(5975.5,0)"><g data-mml-node="mi"><path data-c="210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z" style="stroke-width: 3;"/></g><g data-mml-node="mtext" transform="translate(609,-150) scale(0.707)"><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(392,0)" style="stroke-width: 3;"/><path data-c="67" d="M329 409Q373 453 429 453Q459 453 472 434T485 396Q485 382 476 371T449 360Q416 360 412 390Q410 404 415 411Q415 412 416 414V415Q388 412 363 393Q355 388 355 386Q355 385 359 381T368 369T379 351T388 325T392 292Q392 230 343 187T222 143Q172 143 123 171Q112 153 112 133Q112 98 138 81Q147 75 155 75T227 73Q311 72 335 67Q396 58 431 26Q470 -13 470 -72Q470 -139 392 -175Q332 -206 250 -206Q167 -206 107 -175Q29 -140 29 -75Q29 -39 50 -15T92 18L103 24Q67 55 67 108Q67 155 96 193Q52 237 52 292Q52 355 102 398T223 442Q274 442 318 416L329 409ZM299 343Q294 371 273 387T221 404Q192 404 171 388T145 343Q142 326 142 292Q142 248 149 227T179 192Q196 182 222 182Q244 182 260 189T283 207T294 227T299 242Q302 258 302 292T299 343ZM403 -75Q403 -50 389 -34T348 -11T299 -2T245 0H218Q151 0 138 -6Q118 -15 107 -34T95 -74Q95 -84 101 -97T122 -127T170 -155T250 -167Q319 -167 361 -139T403 -75Z" transform="translate(670,0)" style="stroke-width: 3;"/><path data-c="68" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 124T102 167T103 217T103 272T103 329Q103 366 103 407T103 482T102 542T102 586T102 603Q99 622 88 628T43 637H25V660Q25 683 27 683L37 684Q47 685 66 686T103 688Q120 689 140 690T170 693T181 694H184V367Q244 442 328 442Q451 442 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1170,0)" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(1726,0)" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(8130.1,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>h</mi><mo>=</mo><mstyle displaystyle="false" scriptlevel="0"><mfrac><mn>1</mn><mn>2</mn></mfrac></mstyle><mo stretchy="false">(</mo><msub><mi>h</mi><mtext>left</mtext></msub><mo>+</mo><msub><mi>h</mi><mtext>right</mtext></msub><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>. 이게 정확히 성긴 링의 한 가장자리가 놓이는 지점이라서, 촘촘한 가장자리와 성긴 가장자리가 같은 선을 그립니다. 이렇게 하면 전환용 지오메트리 없이도 빈틈없는 이음새가 만들어집니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/spikes/24-gpu-clipmap-rings/" title="Spike 24 Clipmap Rings and Sky Fog" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/spikes/24-gpu-clipmap-rings/" target="_blank">새 탭에서 Spike 24 열기 ↗</a> · <a href="/ko/blog/spike-source?spike=24-gpu-clipmap-rings">소스 보기</a></p>
<p>그다음은 안개와 하늘 통합이었습니다. 우리는 멀리 있는 지형이 평평한 상수 색이 아니라 실제 하늘 색으로 페이드되길 원했습니다. 그러려면 안개 셰이더가 각 프래그먼트의 방향에서 하늘이 어떤 색일지 알아야 했습니다. 우리는 equirectangular HDR 스카이박스 텍스처를 로드하고, 카메라에서 프래그먼트로 향하는 뷰 방향으로 프래그먼트 셰이더에서 샘플링했습니다. 이때 TSL의 <code>equirectUV</code> 노드로 equirectangular UV 좌표로 변환했습니다. 안개 계수는 카메라 공간 깊이를 위한 <code>positionView.z.negate()</code>를 써서 거리 기반으로 구하고, 가까운 거리와 먼 거리 사이를 <code>smoothstep</code>으로 블렌딩했습니다.</p>
<p>모듈 배선은 어떤 지오메트리보다도 더 성가신 일이었습니다. 우리는 Three.js 0.183.1로 올렸는데, 이게 빌드 출력물 구조를 바꿔 놨습니다. <code>three/tsl</code> import는 <code>three.tsl.js</code>로 해석되어야 했고, TSL은 내부적으로 <code>three/webgpu</code>를 bare specifier로 import했습니다. 두 매핑 모두 HTML import map에 명시되어야 했습니다. 어느 하나라도 빠지면 어떤 매핑이 잘못됐는지 전혀 알려주지 않는 &quot;does not provide an export&quot; 또는 &quot;failed to resolve module specifier&quot; 같은 알쏭달쏭한 오류가 났습니다. 둘 다 import map에 들어가고 나니 셰이더 그래프가 제대로 로드됐습니다.</p>
<p>스카이박스 방향 문제도 있었는데, 텍스처가 위아래가 뒤집혀 렌더링됐습니다. 해결책은 equirectangular 텍스처에 <code>flipY = true</code>를 주는 것이었습니다. 이건 로드된 텍스처에 대한 Three.js 기본값이지만, 우리 초기 코드에서는 <code>false</code>로 설정되어 있었습니다.</p>
<p>원래 안개 구현은 거의 상수에 가까운 방향에서 하늘을 샘플링해서, 자연스러운 그라디언트 대신 지평선 색의 얇은 띠를 만들어 냈습니다. 해결책은 픽셀마다 실제 카메라-프래그먼트 월드 방향을 <code>positionWorld.sub(cameraPosition).normalize()</code>로 계산해, 그걸 <code>equirectUV</code>에 넘겨 안개 색을 조회하는 것이었습니다. 이렇게 하니 지형 프래그먼트가 실제로 그 뒤에 있는 하늘 색으로 페이드돼서, 어느 카메라 각도에서 봐도 맞아 보였습니다.</p>
<p>개별 수정들 아래에서, 핵심 결과는 유지됐습니다. 이제 우리는 근거리 볼류메트릭 편집(marching cubes에 Transvoxel 이음새), 중거리 heightmap 청크, 원거리 clipmap 링을 결합한 지형 시스템을 갖췄고, 이 모두가 모드, LOD, 전환 동작을 결정하는 정책 레이어의 관리를 받습니다.</p>
<p>다음 프로젝트에서 다시 쓸 패턴을 꼽으라면, 이런 것들입니다.</p>
<p>기능 작업에 들어가기 전에 리스크 spike부터 시작하세요. Spike 1은 콘텐츠 파이프라인에 투자하기 전에 &quot;우리가 충분히 빠르게 렌더링이라도 할 수 있나&quot;라는 질문을 먼저 정리해 줬습니다.</p>
<p>통합 점프 전에 검증된 안정 베이스라인을 동결하세요. Spike 13과 14는 회귀를 이분 탐색하느라 날릴 며칠을 아껴 줬습니다.</p>
<p>최적화 마라톤 전에 정책과 관측 가능성을 강제하세요. Spike 23은 정체불명의 버그를 트리거 규칙이 붙은 이름 있는 조건으로 바꿔 줬습니다.</p>
<p>스크린샷이 아니라 움직임 속에서 테스트하세요. clipmap 팝, 이음새 깜빡임, 스트리밍 끊김은 전부 정지 프레임에 숨어 있습니다.</p>
<p>평균 FPS가 아니라 기능별 프레임 시간 비용을 측정하세요. 평균은 사용자가 실제로 느끼는 스파이크를 가립니다.</p>
<p>그리고 지저분한 부분을 공개하세요. 잘못 든 길, 오래된 버퍼 유령 사냥, 실제로는 draw range가 잘못됐는데 전환 로직을 탓하며 보낸 이틀. 사람들이 정말로 배울 수 있는 건 바로 그런 부분입니다.</p>
<h2 id="외부-현실-점검-vuntra-city-개발-일지" tabindex="-1">외부 현실 점검: Vuntra City 개발 일지 <a class="header-anchor" href="#외부-현실-점검-vuntra-city-개발-일지" aria-label="Permalink to &quot;외부 현실 점검: Vuntra City 개발 일지&quot;"></a></h2>
<p>이 시리즈를 끝낸 뒤, 우리는 우리 오픈 월드 가정에 대한 외부 구현 점검으로 <code>@VuntraCity</code> 개발 일지를 살펴봤습니다. 그건 브라우저 스택이 아니라 네이티브 UE5 프로젝트지만, 시스템 패턴이 꽤 잘 대응돼서 비교가 쓸모 있었습니다.</p>
<p>첫 번째 신호는 이동 속도가 게임플레이만이 아니라 스트리밍 제어로 다뤄져야 한다는 것입니다. Vuntra City에서는 고속 이동이 의도적으로 대부분의 실내 위로 우회되고, 스폰 churn과 정체를 피하려고 디테일 범위가 이동 속도에 맞춰 조정됩니다(<a href="https://www.youtube.com/watch?v=KKeBElJS6-M" target="_blank" rel="noreferrer">교통 시스템</a>, <a href="https://www.youtube.com/watch?v=aPuYXyJet38" target="_blank" rel="noreferrer">성능 기법</a>). 이건 우리 정책 레이어 방향과 일치합니다. 이동 모드는 청크 반경, 실내 활성화, 프레임당 허용 작업량에 직접 영향을 줘야 합니다.</p>
<p>두 번째 신호는 아키텍처입니다. 그들의 맵과 주소 시스템은, 로드되지 않은 영역에 대해서도 전역 쿼리가 돌 수 있도록 월드 토폴로지를 렌더링되는 오브젝트와 분리해야 했습니다(<a href="https://www.youtube.com/watch?v=6dLn1GQpu2c" target="_blank" rel="noreferrer">맵과 주소</a>). 이건 브라우저에서 월드 검색, 퀘스트 라우팅, 모더레이션 스캔, POI 인덱싱을 렌더링에 묶인 데이터 경로를 강제하지 않고 하기 위해 우리에게도 필요한 바로 그 분리입니다.</p>
<p>세 번째 신호는 시뮬레이션 티어링입니다. 그들의 백만 NPC 설계는 거친 스케줄 상태는 저렴하고 전역적으로 유지하면서, 비싼 행동 예산은 플레이어 근처에서만 씁니다(<a href="https://www.youtube.com/watch?v=nBV0yAAJUf0" target="_blank" rel="noreferrer">백만 NPC 개요</a>, <a href="https://www.youtube.com/watch?v=eUi7DB1ar3s" target="_blank" rel="noreferrer">시스템 심층 분석</a>). 이건 우리 AOI 우선 시뮬레이션 모델을 뒷받침합니다. 근거리 충실도와 원거리 결정론은 별도의 예산을 가진 별개의 관심사입니다.</p>
<p>그리고 네 번째 신호는 순수한 규모가 아니라 디자인 품질입니다. 그들의 가장 강렬한 탐험 순간은 끊임없는 UI 오버레이가 아니라 가중 분포, 희귀한 이상치, 디제틱한 길찾기 단서에서 나옵니다(<a href="https://www.youtube.com/watch?v=4MZ5-KQW3pc" target="_blank" rel="noreferrer">절차적 환경 노트</a>, <a href="https://www.youtube.com/watch?v=ixR1hqZJlv4" target="_blank" rel="noreferrer">미니맵 없는 루프</a>). 우리에게 이건, 기술 시스템이 단순히 최대 처리량이 아니라 발견 가능한 다양성을 만들어 내도록 튜닝되어야 한다는 점을 일깨워 줍니다.</p>
<h2 id="이-챕터에서-언급한-기술" tabindex="-1">이 챕터에서 언급한 기술 <a class="header-anchor" href="#이-챕터에서-언급한-기술" aria-label="Permalink to &quot;이 챕터에서 언급한 기술&quot;"></a></h2>
<p><strong>Clipmap 링 지오메트리.</strong> 각 링은 카메라를 중심으로 한 평면 그리드 메시이고, 버텍스는 heightmap 샘플로 변위됩니다. 가장 안쪽 링은 최대 해상도를 씁니다. 바깥쪽으로 갈수록 링마다 버텍스 간격이 두 배가 되고 더 넓은 영역을 덮습니다. 까다로운 부분은 경계입니다. 고해상도 링이 저해상도 링과 만나는 곳에서, 더 촘촘한 메시의 가장자리 버텍스는 더 성긴 메시 가장자리의 중점으로 스냅됩니다. 이 기법은 Losasso와 Hoppe의 SIGGRAPH 2004 논문(<a href="https://hhoppe.com/geomclipmap.pdf" target="_blank" rel="noreferrer">PDF</a>)에서 비롯됐고 <a href="https://developer.nvidia.com/gpugems/gpugems2/part-i-geometric-complexity/chapter-2-terrain-rendering-using-gpu-based-geometry" target="_blank" rel="noreferrer">GPU Gems 2, 2장</a>에서 자세히 다룹니다. 우리의 <a href="/ko/guides/landscape-generation-browser.html#geometry-clipmaps">지오메트리 clipmap에 관한 지형 가이드</a>를 보세요.</p>
<p><strong>2:1 가장자리 모핑.</strong> 두 clipmap 링 사이의 경계에서, 더 촘촘한 링은 더 성긴 링이 공유하지 않는 위치에 버텍스를 가집니다. 링 가장자리를 따라 그리드 좌표가 홀수인 경계 버텍스를 감지하고, 그 높이를 이웃한 두 짝수 버텍스 사이에서 보간합니다. 이렇게 하면 전용 전환 지오메트리 없이도 빈틈없는 이음새가 만들어집니다. 보간은 버텍스 셰이더에서 실행됩니다. 경계 버텍스에 대해 <code>morphedHeight = mix(heightLeft, heightRight, 0.5)</code>이며, <a href="/ko/guides/landscape-generation-browser.html#geomorphing-pop-free-lod-transitions">우리 가이드</a>에서 설명한 것과 같은 지오모핑 프레임워크를 씁니다.</p>
<p><strong>Equirectangular 스카이박스 매핑.</strong> 경도-위도 투영으로 하늘 방향의 완전한 구면을 매핑하는 하나의 2D 이미지입니다. 가로축은 0~360도를 덮고, 세로축은 0~180도를 덮습니다. 정규화된 뷰 방향 <mjx-container class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.667ex;" xmlns="http://www.w3.org/2000/svg" width="14.501ex" height="3.07ex" role="img" focusable="false" viewBox="0 -1062 6409.6 1357" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mover"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(427,268) translate(-250 0)"><path data-c="5E" d="M112 560L249 694L257 686Q387 562 387 560L361 531Q359 532 303 581L250 627L195 580Q182 569 169 557T148 538L140 532Q138 530 125 546L112 560Z" style="stroke-width: 3;"/></g></g></g><g data-mml-node="mo" transform="translate(797.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1853.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2242.6,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(553,-150) scale(0.707)"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3250,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3694.7,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(553,-150) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(4644.2,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(5088.8,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(553,-150) scale(0.707)"><path data-c="1D467" d="M347 338Q337 338 294 349T231 360Q211 360 197 356T174 346T162 335T155 324L153 320Q150 317 138 317Q117 317 117 325Q117 330 120 339Q133 378 163 406T229 440Q241 442 246 442Q271 442 291 425T329 392T367 375Q389 375 411 408T434 441Q435 442 449 442H462Q468 436 468 434Q468 430 463 420T449 399T432 377T418 358L411 349Q368 298 275 214T160 106L148 94L163 93Q185 93 227 82T290 71Q328 71 360 90T402 140Q406 149 409 151T424 153Q443 153 443 143Q443 138 442 134Q425 72 376 31T278 -11Q252 -11 232 6T193 40T155 57Q111 57 76 -3Q70 -11 59 -11H54H41Q35 -5 35 -2Q35 13 93 84Q132 129 225 214T340 322Q352 338 347 338Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(6020.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mrow data-mjx-texclass="ORD"><mover><mi>d</mi><mo stretchy="false">^</mo></mover></mrow><mo>=</mo><mo stretchy="false">(</mo><msub><mi>d</mi><mi>x</mi></msub><mo>,</mo><msub><mi>d</mi><mi>y</mi></msub><mo>,</mo><msub><mi>d</mi><mi>z</mi></msub><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container>는 그 경도와 위도를 읽어 UV 좌표로 변환됩니다.</p>
<mjx-container tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -1.577ex;" xmlns="http://www.w3.org/2000/svg" width="48.882ex" height="4.982ex" role="img" focusable="false" viewBox="0 -1505 21605.8 2202" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D462" d="M21 287Q21 295 30 318T55 370T99 420T158 442Q204 442 227 417T250 358Q250 340 216 246T182 105Q182 62 196 45T238 27T291 44T328 78L339 95Q341 99 377 247Q407 367 413 387T427 416Q444 431 463 431Q480 431 488 421T496 402L420 84Q419 79 419 68Q419 43 426 35T447 26Q469 29 482 57T512 145Q514 153 532 153Q551 153 551 144Q550 139 549 130T540 98T523 55T498 17T462 -8Q454 -10 438 -10Q372 -10 347 46Q345 45 336 36T318 21T296 6T267 -6T233 -11Q189 -11 155 7Q103 38 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(849.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(1905.6,0)"><g data-mml-node="mn" transform="translate(220,676)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(220,-686)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><rect width="700" height="60" x="120" y="220"/></g><g data-mml-node="mo" transform="translate(3067.8,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(4068,0)"><g data-mml-node="mrow" transform="translate(220,710)"><g data-mml-node="TeXAtom" data-mjx-texclass="OP"><g data-mml-node="mi"><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" style="stroke-width: 3;"/><path data-c="74" d="M27 422Q80 426 109 478T141 600V615H181V431H316V385H181V241Q182 116 182 100T189 68Q203 29 238 29Q282 29 292 100Q293 108 293 146V181H333V146V134Q333 57 291 17Q264 -10 221 -10Q187 -10 162 2T124 33T105 68T98 100Q97 107 97 248V385H18V422H27Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" transform="translate(889,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(1389,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(2111.7,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2611.7,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(3000.7,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(553,-150) scale(0.707)"><path data-c="1D467" d="M347 338Q337 338 294 349T231 360Q211 360 197 356T174 346T162 335T155 324L153 320Q150 317 138 317Q117 317 117 325Q117 330 120 339Q133 378 163 406T229 440Q241 442 246 442Q271 442 291 425T329 392T367 375Q389 375 411 408T434 441Q435 442 449 442H462Q468 436 468 434Q468 430 463 420T449 399T432 377T418 358L411 349Q368 298 275 214T160 106L148 94L163 93Q185 93 227 82T290 71Q328 71 360 90T402 140Q406 149 409 151T424 153Q443 153 443 143Q443 138 442 134Q425 72 376 31T278 -11Q252 -11 232 6T193 40T155 57Q111 57 76 -3Q70 -11 59 -11H54H41Q35 -5 35 -2Q35 13 93 84Q132 129 225 214T340 322Q352 338 347 338Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3932.5,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(4210.5,0)"><g data-mml-node="mspace"/></g><g data-mml-node="msub" transform="translate(4544.1,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(553,-150) scale(0.707)"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5551.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mrow" transform="translate(2655.3,-686)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(500,0)"><path data-c="1D70B" d="M132 -11Q98 -11 98 22V33L111 61Q186 219 220 334L228 358H196Q158 358 142 355T103 336Q92 329 81 318T62 297T53 285Q51 284 38 284Q19 284 19 294Q19 300 38 329T93 391T164 429Q171 431 389 431Q549 431 553 430Q573 423 573 402Q573 371 541 360Q535 358 472 358H408L405 341Q393 269 393 222Q393 170 402 129T421 65T431 37Q431 20 417 5T381 -10Q370 -10 363 -7T347 17T331 77Q330 86 330 121Q330 170 339 226T357 318T367 358H269L268 354Q268 351 249 275T206 114T175 17Q164 -11 132 -11Z" style="stroke-width: 3;"/></g></g><rect width="6140.6" height="60" x="120" y="220"/></g><g data-mml-node="mo" transform="translate(10448.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mstyle" transform="translate(10726.6,0)"><g data-mml-node="mspace"/></g><g data-mml-node="mi" transform="translate(12893.3,0)"><path data-c="1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(13656,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(14711.8,0)"><g data-mml-node="mn" transform="translate(220,676)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(220,-686)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z" style="stroke-width: 3;"/></g><rect width="700" height="60" x="120" y="220"/></g><g data-mml-node="mo" transform="translate(15874,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mfrac" transform="translate(16874.3,0)"><g data-mml-node="mrow" transform="translate(220,755)"><g data-mml-node="mi"><path data-c="61" d="M137 305T115 305T78 320T63 359Q63 394 97 421T218 448Q291 448 336 416T396 340Q401 326 401 309T402 194V124Q402 76 407 58T428 40Q443 40 448 56T453 109V145H493V106Q492 66 490 59Q481 29 455 12T400 -6T353 12T329 54V58L327 55Q325 52 322 49T314 40T302 29T287 17T269 6T247 -2T221 -8T190 -11Q130 -11 82 20T34 107Q34 128 41 147T68 188T116 225T194 253T304 268H318V290Q318 324 312 340Q290 411 215 411Q197 411 181 410T156 406T148 403Q170 388 170 359Q170 334 154 320ZM126 106Q126 75 150 51T209 26Q247 26 276 49T315 109Q317 116 318 175Q318 233 317 233Q309 233 296 232T251 223T193 203T147 166T126 106Z" style="stroke-width: 3;"/><path data-c="72" d="M36 46H50Q89 46 97 60V68Q97 77 97 91T98 122T98 161T98 203Q98 234 98 269T98 328L97 351Q94 370 83 376T38 385H20V408Q20 431 22 431L32 432Q42 433 60 434T96 436Q112 437 131 438T160 441T171 442H174V373Q213 441 271 441H277Q322 441 343 419T364 373Q364 352 351 337T313 322Q288 322 276 338T263 372Q263 381 265 388T270 400T273 405Q271 407 250 401Q234 393 226 386Q179 341 179 207V154Q179 141 179 127T179 101T180 81T180 66V61Q181 59 183 57T188 54T193 51T200 49T207 48T216 47T225 47T235 46T245 46H276V0H267Q249 3 140 3Q37 3 28 0H20V46H36Z" transform="translate(500,0)" style="stroke-width: 3;"/><path data-c="63" d="M370 305T349 305T313 320T297 358Q297 381 312 396Q317 401 317 402T307 404Q281 408 258 408Q209 408 178 376Q131 329 131 219Q131 137 162 90Q203 29 272 29Q313 29 338 55T374 117Q376 125 379 127T395 129H409Q415 123 415 120Q415 116 411 104T395 71T366 33T318 2T249 -11Q163 -11 99 53T34 214Q34 318 99 383T250 448T370 421T404 357Q404 334 387 320Z" transform="translate(892,0)" style="stroke-width: 3;"/><path data-c="73" d="M295 316Q295 356 268 385T190 414Q154 414 128 401Q98 382 98 349Q97 344 98 336T114 312T157 287Q175 282 201 278T245 269T277 256Q294 248 310 236T342 195T359 133Q359 71 321 31T198 -10H190Q138 -10 94 26L86 19L77 10Q71 4 65 -1L54 -11H46H42Q39 -11 33 -5V74V132Q33 153 35 157T45 162H54Q66 162 70 158T75 146T82 119T101 77Q136 26 198 26Q295 26 295 104Q295 133 277 151Q257 175 194 187T111 210Q75 227 54 256T33 318Q33 357 50 384T93 424T143 442T187 447H198Q238 447 268 432L283 424L292 431Q302 440 314 448H322H326Q329 448 335 442V310L329 304H301Q295 310 295 316Z" transform="translate(1336,0)" style="stroke-width: 3;"/><path data-c="69" d="M69 609Q69 637 87 653T131 669Q154 667 171 652T188 609Q188 579 171 564T129 549Q104 549 87 564T69 609ZM247 0Q232 3 143 3Q132 3 106 3T56 1L34 0H26V46H42Q70 46 91 49Q100 53 102 60T104 102V205V293Q104 345 102 359T88 378Q74 385 41 385H30V408Q30 431 32 431L42 432Q52 433 70 434T106 436Q123 437 142 438T171 441T182 442H185V62Q190 52 197 50T232 46H255V0H247Z" transform="translate(1730,0)" style="stroke-width: 3;"/><path data-c="6E" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z" transform="translate(2008,0)" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2564,0)"><path data-c="2061" d="" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2564,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msub" transform="translate(2953,0)"><g data-mml-node="mi"><path data-c="1D451" d="M366 683Q367 683 438 688T511 694Q523 694 523 686Q523 679 450 384T375 83T374 68Q374 26 402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487H491Q506 153 506 145Q506 140 503 129Q490 79 473 48T445 8T417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157Q33 205 53 255T101 341Q148 398 195 420T280 442Q336 442 364 400Q369 394 369 396Q370 400 396 505T424 616Q424 629 417 632T378 637H357Q351 643 351 645T353 664Q358 683 366 683ZM352 326Q329 405 277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q233 26 290 98L298 109L352 326Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(553,-150) scale(0.707)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(3902.5,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mi" transform="translate(2080.7,-686)"><path data-c="1D70B" d="M132 -11Q98 -11 98 22V33L111 61Q186 219 220 334L228 358H196Q158 358 142 355T103 336Q92 329 81 318T62 297T53 285Q51 284 38 284Q19 284 19 294Q19 300 38 329T93 391T164 429Q171 431 389 431Q549 431 553 430Q573 423 573 402Q573 371 541 360Q535 358 472 358H408L405 341Q393 269 393 222Q393 170 402 129T421 65T431 37Q431 20 417 5T381 -10Q370 -10 363 -7T347 17T331 77Q330 86 330 121Q330 170 339 226T357 318T367 358H269L268 354Q268 351 249 275T206 114T175 17Q164 -11 132 -11Z" style="stroke-width: 3;"/></g><rect width="4491.5" height="60" x="120" y="220"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi>u</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mo>+</mo><mfrac><mrow><mrow data-mjx-texclass="OP"><mi>atan</mi><mn>2</mn></mrow><mo stretchy="false">(</mo><msub><mi>d</mi><mi>z</mi></msub><mo>,</mo><mstyle scriptlevel="0"><mspace width="0.167em"/></mstyle><msub><mi>d</mi><mi>x</mi></msub><mo stretchy="false">)</mo></mrow><mrow><mn>2</mn><mi>π</mi></mrow></mfrac><mo>,</mo><mstyle scriptlevel="0"><mspace width="2em"/></mstyle><mi>v</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mo>−</mo><mfrac><mrow><mi>arcsin</mi><mo data-mjx-texclass="NONE">⁡</mo><mo stretchy="false">(</mo><msub><mi>d</mi><mi>y</mi></msub><mo stretchy="false">)</mo></mrow><mi>π</mi></mfrac></math></mjx-assistive-mml></mjx-container><p>Three.js에서는 <code>texture.mapping = EquirectangularReflectionMapping</code>을 <code>SRGBColorSpace</code>와 함께 설정하면 이걸 씬 배경으로 활성화합니다. TSL에서는 <code>equirectUV(direction)</code>이 같은 변환을 적용해, 3D 뷰 방향을 텍스처 샘플링용 2D UV 좌표로 바꿉니다.</p>
<p><strong>하늘에서 가져오는 프래그먼트별 안개 색.</strong> 표준 안개는 프래그먼트를 하나의 상수 색으로 블렌딩합니다. 디테일한 스카이박스가 있는 씬에서는 하늘 색이 방향마다 다르기 때문에 이게 잘못돼 보입니다. 해결책은 픽셀마다 카메라-프래그먼트 월드 방향(<code>positionWorld.sub(cameraPosition).normalize()</code>)을 계산하고, 그 방향에서 스카이박스를 샘플링해 안개 색으로 쓰는 것입니다. 각 프래그먼트는 실제로 그 뒤에 있는 하늘 색으로 페이드돼서, 어느 카메라 각도에서도 올바르게 블렌딩됩니다. 안개 계수는 카메라 공간 깊이를 위한 <code>positionView.z.negate()</code>와 함께 <code>smoothstep(nearDist, farDist, viewDepth)</code>을 씁니다.</p>
<p><strong>ES 모듈용 import map.</strong> bare 모듈 specifier(<code>three/tsl</code> 같은)를 실제 URL로 매핑하는 브라우저 네이티브 메커니즘(<code>&lt;script type=&quot;importmap&quot;&gt;</code>)입니다. Three.js 0.183.1이 빌드 출력물을 재구성하면서, <code>three/tsl</code>은 <code>three.tsl.js</code>로 해석되어야 했고 TSL은 내부적으로 <code>three/webgpu</code>를 bare specifier로 import했습니다. 두 매핑 모두 import map에 명시되어야 했고, 그렇지 않으면 브라우저가 &quot;does not provide an export&quot; 또는 &quot;failed to resolve module specifier&quot; 오류를 냈습니다.</p>
<h2 id="더-읽을거리" tabindex="-1">더 읽을거리 <a class="header-anchor" href="#더-읽을거리" aria-label="Permalink to &quot;더 읽을거리&quot;"></a></h2>
<p>이 시리즈 전반에서 사용한 기술을 더 깊이 다룬, 우리 동반 가이드를 보세요.</p>
<ul>
<li><a href="/ko/guides/landscape-generation-browser.html">브라우저 오픈 월드를 위한 동적 LOD와 스트리밍 기반 지형 생성</a>은 heightmap, SDF, marching cubes, Transvoxel, 지오메트리 clipmap, 지오모핑, 스트리밍 아키텍처, 지형 머티리얼, 식생 렌더링을 다룹니다.</li>
<li><a href="/ko/guides/browser-3d-open-world-tech.html">멀티플레이어 크리에이터 월드를 위한 브라우저 3D 오픈 월드 기술</a>은 렌더링 스택, WebGPU, 물리, 네트워킹, 멀티플레이어 아키텍처, 그리고 Skyrim, The Witcher 3, Breath of the Wild, GTA V에서 얻은 교훈을 다룹니다.</li>
</ul>
<p>12부에 걸친 이 여정을 따라와 주셔서 감사합니다.</p>
<p>1부: <a href="/ko/blog/2026-02-25-open-world-browser-part-01-risk-first.html">우리는 그걸 부수려는 것부터 시작했다</a><br>
2부: <a href="/ko/blog/2026-02-25-open-world-browser-part-02-worker-physics.html">워커 물리와 입력 지연 공포</a><br>
3부: <a href="/ko/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes.html">우리를 구한 화려하지 않은 spike들</a><br>
4부: <a href="/ko/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy.html">화려한 지형보다 스트리밍 먼저</a><br>
5부: <a href="/ko/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty.html">예쁜 것들에 예산 책정하기</a><br>
6부: <a href="/ko/blog/2026-02-25-open-world-browser-part-06-clipmaps.html">Clipmap이 줄거리를 바꿨다</a><br>
7부: <a href="/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes.html">Marching cubes와 첫 진짜 동굴</a><br>
8부: <a href="/ko/blog/2026-02-25-open-world-browser-part-08-webgpu-integration.html">베이스라인을 잃지 않고 통합하기</a><br>
9부: <a href="/ko/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut.html">Transvoxel은 뼈대부터 시작했다</a><br>
10부: <a href="/ko/blog/2026-02-25-open-world-browser-part-10-seam-chaos.html">이음새 혼돈과 코너 보스전</a><br>
11부: <a href="/ko/blog/2026-02-25-open-world-browser-part-11-policy-modes.html">하드코딩 모드가 아니라 정책 모드</a></p>
<hr>
<p>14부 중 12부.<br>
이전: <a href="/ko/blog/2026-02-25-open-world-browser-part-11-policy-modes.html">11부 - 하드코딩 모드가 아니라 정책 모드</a><br>
다음: <a href="/ko/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting.html">13부 - 지형 조각과 수학 함수의 죽음</a><br>
시리즈 가이드: <a href="/ko/blog/2026-02-25-open-world-browser-series-guide.html">/ko/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[브라우저 오픈 월드 시리즈 가이드]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-series-guide</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-25-open-world-browser-series-guide</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[29부작 브라우저 오픈 월드 시리즈의 읽는 순서, 쉬운 말로 풀어 쓴 spike 용어집, 그리고 라이브 데모 지도.]]></description>
            <content:encoded><![CDATA[<h1 id="브라우저-오픈-월드-시리즈-가이드" tabindex="-1">브라우저 오픈 월드 시리즈 가이드 <a class="header-anchor" href="#브라우저-오픈-월드-시리즈-가이드" aria-label="Permalink to &quot;브라우저 오픈 월드 시리즈 가이드&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva의 CTO이자 공동 창업자</em></p>
<p>이 페이지는 시리즈 전체를 위한 길잡이 허브입니다.</p>
<p>어쩌다 한 편만 보고 들어왔다면 여기서 시작하세요.</p>
<p>2026년 3월 업데이트: <a href="/ko/blog/2026-02-25-open-world-browser-part-12-lessons.html">Part 12</a>에 Vuntra City 개발 일지에서 가져온 외부 구현 교차 점검을 추가했고, 같은 발견을 담아 자매편 <a href="/ko/guides/browser-3d-open-world-tech.html">브라우저 오픈 월드 기술 가이드</a>를 확장했습니다.</p>
<p>2026년 4월 업데이트: Part 13-14는 지형 조각(Spike 25-27)과 비주얼/게임플레이 레이어, 즉 멀티 머티리얼 텍스처링, 인스턴스드 식생, HM+SDF 충돌이 들어간 character controller(Spike 28-30)를 다룹니다.</p>
<p>2026년 5월 업데이트: 시리즈는 29부까지 갔습니다. Part 15-29는 빌드의 긴 중반을 다룹니다. 멀티플레이어 지형과 물, 코드 구조 리팩터, 애니메이션과 AI 산포, 임포스터와 패럴랙스, 결국 본전을 못 뽑은 가시성 버퍼, 구름과 메시렛 컬링, 배치 처리한 아바타와 근접 음성, 월드 영속성과 GPU 바람, 유니버설 캐릭터, 물을 만드는 세 가지 방법, 절차적 섬, 풀과 오클루전, 그리고 어떤 몸체든 구동하는 플러그형 character controller(Spike 31-60)까지 이어집니다.</p>
<p>2026년 6월 업데이트: Part 30은 충돌을 인식하는 카메라를 추가합니다. 플러그형 콜라이더 계약을 가진 스프링암 붐과, 언덕뿐 아니라 돌출부나 동굴 천장에도 시점이 막히게 하는 부호 거리 프로브를 다룹니다.</p>
<h2 id="이-시리즈에서-spike-가-뜻하는-것" tabindex="-1">이 시리즈에서 &quot;spike&quot;가 뜻하는 것 <a class="header-anchor" href="#이-시리즈에서-spike-가-뜻하는-것" aria-label="Permalink to &quot;이 시리즈에서 &quot;spike&quot;가 뜻하는 것&quot;"></a></h2>
<p>spike는 짧고 집중된 실험입니다.</p>
<p>각 spike는 위험한 질문 하나를 테스트합니다. 범위를 좁게 유지하고, 정말 중요한 것을 측정한 다음, 다음에 무엇을 할지 결정합니다. 잘 다듬어진 기능이 아니라 학습 도구라고 생각하면 됩니다.</p>
<p>이 프로젝트에서 spike는 대부분 <code>/spikes/*</code> 아래에 있는 독립 페이지로, 직접 실행해 볼 수 있습니다.</p>
<h2 id="시리즈를-순서대로-읽기" tabindex="-1">시리즈를 순서대로 읽기 <a class="header-anchor" href="#시리즈를-순서대로-읽기" aria-label="Permalink to &quot;시리즈를 순서대로 읽기&quot;"></a></h2>
<ol>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-01-risk-first.html">Part 1: 우리는 그것을 부수려는 시도부터 시작했다</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-02-worker-physics.html">Part 2: Worker 물리와 입력 지연에 대한 두려움</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes.html">Part 3: 우리를 구한 화려하지 않은 spike들</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy.html">Part 4: 화려한 지형보다 먼저 스트리밍</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty.html">Part 5: 예쁜 것들에 예산 매기기</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-06-clipmaps.html">Part 6: Clipmap이 줄거리를 바꿨다</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-07-marching-cubes.html">Part 7: Marching cubes와 첫 진짜 동굴들</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-08-webgpu-integration.html">Part 8: 베이스라인을 잃지 않고 통합하기</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut.html">Part 9: Transvoxel은 골격부터 시작했다</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-10-seam-chaos.html">Part 10: 이음새 혼돈과 모서리 보스전</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-11-policy-modes.html">Part 11: 하드코딩 모드가 아니라 정책 모드</a></li>
<li><a href="/ko/blog/2026-02-25-open-world-browser-part-12-lessons.html">Part 12: 링, 하늘 안개, 그리고 다시 할 것들</a></li>
<li><a href="/ko/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting.html">Part 13: 지형 조각과 수학 함수의 죽음</a></li>
<li><a href="/ko/blog/2026-04-13-open-world-browser-part-14-world-comes-alive.html">Part 14: 세계가 살아난다</a></li>
<li><a href="/ko/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water.html">Part 15: 베이스라인을 교체하고, 그다음 동기화하기</a></li>
<li><a href="/ko/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring.html">Part 16: 계속 자라는 세계를 위한 구조</a></li>
<li><a href="/ko/blog/2026-05-01-open-world-browser-part-17-animations-and-search.html">Part 17: 리타게팅이 필요 없던 애니메이션, 그리고 실시간 에셋 검색</a></li>
<li><a href="/ko/blog/2026-05-02-open-world-browser-part-18-ai-scattering.html">Part 18: AI가 배치한 듯한 산포 브러시</a></li>
<li><a href="/ko/blog/2026-05-04-open-world-browser-part-19-imposters.html">Part 19: 숲에서 살아남아야 하는 임포스터</a></li>
<li><a href="/ko/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion.html">Part 20: 평평한 면에서 깊이 속이기</a></li>
<li><a href="/ko/blog/2026-05-06-open-world-browser-part-21-visibility-buffer.html">Part 21: 더 빠르지 않았던 더 빠른 렌더러</a></li>
<li><a href="/ko/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets.html">Part 22: 조명을 줄 수 있는 구름, 그리고 먹여 줘야 하는 컬링</a></li>
<li><a href="/ko/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice.html">Part 23: 아바타 쉰 명, 그리고 방 안의 목소리</a></li>
<li><a href="/ko/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind.html">Part 24: 세계를 저장하기, 그리고 눈에 보이는 바람</a></li>
<li><a href="/ko/blog/2026-05-10-open-world-browser-part-25-universal-characters.html">Part 25: 골격 하나, 모든 의상</a></li>
<li><a href="/ko/blog/2026-05-12-open-world-browser-part-26-water.html">Part 26: 물을 만드는 세 가지 방법</a></li>
<li><a href="/ko/blog/2026-05-13-open-world-browser-part-27-island-and-terrain.html">Part 27: 노이즈에서 나온 섬, 땅처럼 보이는 땅</a></li>
<li><a href="/ko/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion.html">Part 28: 지평선까지 뻗는 풀, 그리고 스스로 숨는 땅</a></li>
<li><a href="/ko/blog/2026-05-15-open-world-browser-part-29-pluggable-character.html">Part 29: 컨트롤러 하나, 어떤 몸체든</a></li>
<li><a href="/ko/blog/2026-06-04-open-world-browser-part-30-collision-aware-camera.html">Part 30: 벽을 존중하는 카메라</a></li>
</ol>
<h2 id="라이브-spike-지도" tabindex="-1">라이브 spike 지도 <a class="header-anchor" href="#라이브-spike-지도" aria-label="Permalink to &quot;라이브 spike 지도&quot;"></a></h2>
<p>기술 타임라인을 직접 클릭해 보고 싶다면 이것들로 시작하세요.</p>
<p><a href="/spikes/01-terrain/" target="_blank">Spike 1</a> 지형과 인스턴싱 · <a href="/ko/blog/spike-source?spike=01-terrain">소스</a><br>
<a href="/spikes/02-rapier-worker/" target="_blank">Spike 2</a> worker 물리 · <a href="/ko/blog/spike-source?spike=02-rapier-worker">소스</a><br>
Spike 3 Durable Object 브로드캐스트 부하 테스트는 독립 페이지가 아니라 서비스 스크립트로 실행됨<br>
Spike 4 모바일 품질 제약, Spike 1의 query 파라미터로 테스트함<br>
Spike 5 LLM 동작 신뢰성, 독립 페이지가 아니라 스크립트로 실행됨<br>
<a href="/spikes/06-chunk-streaming/" target="_blank">Spike 6</a> chunk 로드와 교체 · <a href="/ko/blog/spike-source?spike=06-chunk-streaming">소스</a><br>
<a href="/spikes/07-gpu-vegetation/" target="_blank">Spike 7</a> 밀도 맵에서 만든 식생 · <a href="/ko/blog/spike-source?spike=07-gpu-vegetation">소스</a><br>
<a href="/spikes/08-terrain-material/" target="_blank">Spike 8</a> 지형 머티리얼 비용 · <a href="/ko/blog/spike-source?spike=08-terrain-material">소스</a><br>
<a href="/spikes/09-csm-shadows/" target="_blank">Spike 9</a> 캐스케이드 섀도 예산 · <a href="/ko/blog/spike-source?spike=09-csm-shadows">소스</a><br>
<a href="/spikes/10-clipmap-geomorph/" target="_blank">Spike 10</a> clipmap과 geomorphing · <a href="/ko/blog/spike-source?spike=10-clipmap-geomorph">소스</a><br>
<a href="/spikes/11-chunk-streaming/" target="_blank">Spike 11</a> heightmap chunk 스트리밍 · <a href="/ko/blog/spike-source?spike=11-chunk-streaming">소스</a><br>
<a href="/spikes/12-webgpu-marching-cubes/" target="_blank">Spike 12</a> WebGPU marching cubes · <a href="/ko/blog/spike-source?spike=12-webgpu-marching-cubes">소스</a><br>
<a href="/spikes/13-threejs-webgpu/" target="_blank">Spike 13</a> WebGPU 통합 베이스라인 · <a href="/ko/blog/spike-source?spike=13-threejs-webgpu">소스</a><br>
<a href="/spikes/14-threejs-webgpu-incremental/" target="_blank">Spike 14</a> 점진적 강화 · <a href="/ko/blog/spike-source?spike=14-threejs-webgpu-incremental">소스</a><br>
<a href="/spikes/15-transvoxel-seam/" target="_blank">Spike 15</a> 이음새 골격 · <a href="/ko/blog/spike-source?spike=15-transvoxel-seam">소스</a><br>
<a href="/spikes/16-transvoxel-face/" target="_blank">Spike 16</a> 첫 Transvoxel 면 · <a href="/ko/blog/spike-source?spike=16-transvoxel-face">소스</a><br>
<a href="/spikes/17-dual-mc-lod/" target="_blank">Spike 17</a> 듀얼 MC LOD · <a href="/ko/blog/spike-source?spike=17-dual-mc-lod">소스</a><br>
<a href="/spikes/18-transvoxel-heightmap-seam/" target="_blank">Spike 18</a> heightmap 이음새 · <a href="/ko/blog/spike-source?spike=18-transvoxel-heightmap-seam">소스</a><br>
<a href="/spikes/19-transvoxel-corner-grid/" target="_blank">Spike 19</a> 혼합 해상도 모서리 · <a href="/ko/blog/spike-source?spike=19-transvoxel-corner-grid">소스</a><br>
<a href="/spikes/20-gpu-transvoxel-corner/" target="_blank">Spike 20</a> GPU 모서리 이음새 · <a href="/ko/blog/spike-source?spike=20-gpu-transvoxel-corner">소스</a><br>
<a href="/spikes/21-gpu-mc-transvoxel-corner/" target="_blank">Spike 21</a> GPU MC 모서리 이음새 · <a href="/ko/blog/spike-source?spike=21-gpu-mc-transvoxel-corner">소스</a><br>
<a href="/spikes/22-gpu-mc-heightmap-fallback/" target="_blank">Spike 22</a> MC에서 HM으로의 fallback · <a href="/ko/blog/spike-source?spike=22-gpu-mc-heightmap-fallback">소스</a><br>
<a href="/spikes/23-policy-chunk-modes/" target="_blank">Spike 23</a> 정책 기반 chunk 모드 · <a href="/ko/blog/spike-source?spike=23-policy-chunk-modes">소스</a><br>
<a href="/spikes/24-gpu-clipmap-rings/" target="_blank">Spike 24</a> clipmap 링과 하늘 안개 · <a href="/ko/blog/spike-source?spike=24-gpu-clipmap-rings">소스</a><br>
<a href="/spikes/25-heightmap-brush/" target="_blank">Spike 25</a> 샘플링한 데이터 위의 heightmap 브러시 · <a href="/ko/blog/spike-source?spike=25-heightmap-brush">소스</a><br>
<a href="/spikes/26-sdf-brush/" target="_blank">Spike 26</a> GPU compute를 통한 SDF 브러시 · <a href="/ko/blog/spike-source?spike=26-sdf-brush">소스</a><br>
<a href="/spikes/27-hm-mc-brush/" target="_blank">Spike 27</a> HM + MC + 브러시 통합 · <a href="/ko/blog/spike-source?spike=27-hm-mc-brush">소스</a><br>
<a href="/spikes/28-multi-material/" target="_blank">Spike 28</a> 멀티 머티리얼 텍스처링 · <a href="/ko/blog/spike-source?spike=28-multi-material">소스</a><br>
<a href="/spikes/29-vegetation/" target="_blank">Spike 29</a> 식생과 셰이더 풀 · <a href="/ko/blog/spike-source?spike=29-vegetation">소스</a><br>
<a href="/spikes/30-physics/" target="_blank">Spike 30</a> 지형 물리와 character controller · <a href="/ko/blog/spike-source?spike=30-physics">소스</a><br>
<a href="/spikes/31-multiplayer-sync/" target="_blank">Spike 31</a> 멀티플레이어 지형 동기화 · <a href="/ko/blog/spike-source?spike=31-multiplayer-sync">소스</a><br>
<a href="/spikes/32-water-swimming/" target="_blank">Spike 32</a> 물과 수영 · <a href="/ko/blog/spike-source?spike=32-water-swimming">소스</a><br>
<a href="/spikes/33-code-structure/" target="_blank">Spike 33</a> 코드 구조 리팩터 · <a href="/ko/blog/spike-source?spike=33-code-structure">소스</a><br>
<a href="/spikes/34-world-authoring/" target="_blank">Spike 34</a> 월드 내 오서링 · <a href="/ko/blog/spike-source?spike=34-world-authoring">소스</a><br>
<a href="/spikes/35-combat-animations/" target="_blank">Spike 35</a> 전투 애니메이션과 리타게팅 · <a href="/ko/blog/spike-source?spike=35-combat-animations">소스</a><br>
<a href="/spikes/36-polyhaven-models/" target="_blank">Spike 36</a> 실시간 Poly Haven 에셋 검색 · <a href="/ko/blog/spike-source?spike=36-polyhaven-models">소스</a><br>
<a href="/spikes/37-ai-scattering/" target="_blank">Spike 37</a> AI 보조 소품 산포 · <a href="/ko/blog/spike-source?spike=37-ai-scattering">소스</a><br>
<a href="/spikes/38-imposters/" target="_blank">Spike 38</a> 팔면체 임포스터 · <a href="/ko/blog/spike-source?spike=38-imposters">소스</a><br>
<a href="/spikes/39-parallax-pom/" target="_blank">Spike 39</a> 패럴랙스 오클루전 매핑 · <a href="/ko/blog/spike-source?spike=39-parallax-pom">소스</a><br>
<a href="/spikes/40-visibility-buffer/" target="_blank">Spike 40</a> 가시성 버퍼 렌더러 · <a href="/ko/blog/spike-source?spike=40-visibility-buffer">소스</a><br>
<a href="/spikes/41-imposter-forest/" target="_blank">Spike 41</a> 숲 속의 임포스터 · <a href="/ko/blog/spike-source?spike=41-imposter-forest">소스</a><br>
<a href="/spikes/42-imposter-flicker/" target="_blank">Spike 42</a> 임포스터 깜빡임 수정 · <a href="/ko/blog/spike-source?spike=42-imposter-flicker">소스</a><br>
<a href="/spikes/43-clouds-atmosphere/" target="_blank">Spike 43</a> 대기와 볼류메트릭 구름 · <a href="/ko/blog/spike-source?spike=43-clouds-atmosphere">소스</a><br>
<a href="/spikes/44-meshlet-clusters/" target="_blank">Spike 44</a> 메시렛 Hi-Z 컬링 · <a href="/ko/blog/spike-source?spike=44-meshlet-clusters">소스</a><br>
<a href="/spikes/45-avatar-network-sync/" target="_blank">Spike 45</a> 배치 아바타 스키닝과 네트워크 동기화 · <a href="/ko/blog/spike-source?spike=45-avatar-network-sync">소스</a><br>
<a href="/spikes/46-proximity-voice/" target="_blank">Spike 46</a> 근접 음성 채팅 · <a href="/ko/blog/spike-source?spike=46-proximity-voice">소스</a><br>
<a href="/spikes/47-world-persistence/" target="_blank">Spike 47</a> 서버 권위 월드 영속성 · <a href="/ko/blog/spike-source?spike=47-world-persistence">소스</a><br>
Spike 48 아바타 리그 통합, 이후 spike들이 공유 코드로 재사용함(독립 페이지 없음)<br>
<a href="/spikes/49-gpu-wind-props/" target="_blank">Spike 49</a> 소품과 잎사귀 위의 GPU 바람 · <a href="/ko/blog/spike-source?spike=49-gpu-wind-props">소스</a><br>
<a href="/spikes/50-universal-characters/" target="_blank">Spike 50</a> 유니버설 캐릭터와 착용물 · <a href="/ko/blog/spike-source?spike=50-universal-characters">소스</a><br>
<a href="/spikes/51-water-ssr-caustics/" target="_blank">Spike 51</a> 스크린 스페이스 리플렉션 물 · <a href="/ko/blog/spike-source?spike=51-water-ssr-caustics">소스</a><br>
<a href="/spikes/52-water-planar/" target="_blank">Spike 52</a> 평면 거울 물 · <a href="/ko/blog/spike-source?spike=52-water-planar">소스</a><br>
<a href="/spikes/53-water-pro/" target="_blank">Spike 53</a> 프로덕션 물 라이브러리 · <a href="/ko/blog/spike-source?spike=53-water-pro">소스</a><br>
<a href="/spikes/54-procgen-island/" target="_blank">Spike 54</a> 절차적 섬 생성 · <a href="/ko/blog/spike-source?spike=54-procgen-island">소스</a><br>
<a href="/spikes/55-terrain-shading/" target="_blank">Spike 55</a> 지형 셰이딩과 타일링 깨뜨리기 · <a href="/ko/blog/spike-source?spike=55-terrain-shading">소스</a><br>
<a href="/spikes/56-grass/" target="_blank">Spike 56</a> GPU 교차 쿼드 풀 · <a href="/ko/blog/spike-source?spike=56-grass">소스</a><br>
<a href="/spikes/57-terrain-occlusion/" target="_blank">Spike 57</a> 지형 오클루전 컬링 · <a href="/ko/blog/spike-source?spike=57-terrain-occlusion">소스</a><br>
<a href="/spikes/58-pluggable-character/" target="_blank">Spike 58</a> 플러그형 character controller · <a href="/ko/blog/spike-source?spike=58-pluggable-character">소스</a><br>
<a href="/spikes/59-pluggable-with-avatar/" target="_blank">Spike 59</a> 실제 아바타가 붙은 컨트롤러 · <a href="/ko/blog/spike-source?spike=59-pluggable-with-avatar">소스</a><br>
<a href="/spikes/60-polygon-animations/" target="_blank">Spike 60</a> Synty 폴리곤 애니메이션 · <a href="/ko/blog/spike-source?spike=60-polygon-animations">소스</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Breaker Belt: 스네이크와 아르카노이드의 만남, 사흘 만에 바이브 코딩으로]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-18-a-breaker-belt</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-18-a-breaker-belt</guid>
            <pubDate>Wed, 18 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[우주 뱀 한 마리가 50개 웨이브를 가로지르며 벽돌을 깬다. 반응형 음악, AI 내레이션, 23종의 벽돌과 함께. 두 사람. 사흘. 웹, 모바일, PC.]]></description>
            <content:encoded><![CDATA[<h1 id="a-breaker-belt-스네이크와-아르카노이드의-만남-사흘-만에-바이브-코딩으로" tabindex="-1">A Breaker Belt: 스네이크와 아르카노이드의 만남, 사흘 만에 바이브 코딩으로 <a class="header-anchor" href="#a-breaker-belt-스네이크와-아르카노이드의-만남-사흘-만에-바이브-코딩으로" aria-label="Permalink to &quot;A Breaker Belt: 스네이크와 아르카노이드의 만남, 사흘 만에 바이브 코딩으로&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Mariana Muntean</a>, Cinevva CEO</em></p>
<img src="https://cdn.cinevva.com/blog/breaker-belt-cover.webp" alt="A Breaker Belt gameplay: a neon cosmic serpent breaking bricks in space" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>우리는 뱀이 패들이 되고 벽돌이 반격하는 게임을 만들었습니다. 웹, 모바일, PC에 모두 출시했습니다. 두 사람이 약 사흘 동안 만들었습니다. 짬짬이, 무리하지 않고요. 그리고 정말로 재미있습니다.</p>
<p>바로 그 마지막 부분이 주목할 만한 지점입니다.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0">
<iframe src="https://www.youtube.com/embed/VaFkfCT3OuU" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0" allow="accelerometer;autoplay;clipboard-write;encrypted-media;gyroscope;picture-in-picture" allowfullscreen></iframe>
</div>
<h2 id="아무도-부탁하지-않은-그-조합" tabindex="-1">아무도 부탁하지 않은 그 조합 <a class="header-anchor" href="#아무도-부탁하지-않은-그-조합" aria-label="Permalink to &quot;아무도 부탁하지 않은 그 조합&quot;"></a></h2>
<p>스네이크는 성장과 공간 감각에 관한 게임입니다. 아르카노이드는 반사 신경과 각도 예측에 관한 게임입니다. 둘은 완전히 다른 설계 철학에서 나왔고, 이 둘을 한데 섞는다는 건 정중하게 거절당할 만한 제안처럼 들립니다.</p>
<p>하지만 <a href="https://app.cinevva.com/engine" target="_blank" rel="noreferrer">A Breaker Belt</a>는 그걸 해냅니다. 당신은 우주 뱀, 표류하는 금속 척추와 혜성 실로 엮인 살아있는 네온 전류의 호가 되어, 깨지는 블록으로 가득한 소행성 지대를 누빕니다. 당신의 머리는 패들입니다. 점점 길어지는 꼬리는 가장 강력한 무기이자 가장 끊임없는 위협입니다. 구체는 당신의 몸에 튕겨 벽돌을 부수지만, 한 번이라도 방향을 잘못 틀어 자기 꼬리를 들이받으면 끝입니다.</p>
<p>이건 보통 아무도 플레이해보기 전에 죽어버리는 그런 이상한 장르 교차 실험입니다. 이상한 아이디어가 통하는지 알아내는 개발 비용이 전통적으로 &quot;개월&quot; 단위로 측정되기 때문이죠. 여기서는 &quot;오후&quot; 단위로 측정됐습니다.</p>
<h2 id="실제로-출시된-것" tabindex="-1">실제로 출시된 것 <a class="header-anchor" href="#실제로-출시된-것" aria-label="Permalink to &quot;실제로 출시된 것&quot;"></a></h2>
<p>규모가 이걸 흥미롭게 만듭니다. 자리만 채운 사각형과 소리도 없는 게임 잼 프로토타입이 아닙니다.</p>
<p>게임은 50개 웨이브까지 깊게 이어집니다. 똑같은 벽돌 벽의 50가지 변형이 아닙니다. 진형은 부드러운 입문용 호에서 시작해, 측면 틈으로 비스듬한 샷을 요구하는 요새 고리로 진화하고, 다시 한 칸 너비의 입구를 통과하려면 정밀한 조향이 필요한 다층 대각선 미로로 발전합니다. 폭발 벽돌은 이웃을 함께 날려버립니다. 유령 벽돌은 존재와 비존재 사이를 깜빡입니다. 재생 벽돌은 깨고 나면 다시 회복돼서, 왼쪽에서 오른쪽으로 쓸어내는 대신 목표의 우선순위를 정하게 만듭니다. 포털 벽돌은 당신의 구체를 경기장 반대편으로 순간이동시킵니다. 중력 우물은 당신의 샷을 느리게 휘어지는 찬송가로 구부립니다. 레이저 방출기는 허공에 붉은 선을 그립니다. 미믹 벽돌은 해롭지 않아 보이다가, 해롭지 않기를 그만두기로 마음먹습니다. 15번째 웨이브쯤 되면 당신이 헤쳐 나가는 건 퍼즐이라기보다 당신의 습관을 학습하는 살아있는 시스템처럼 느껴집니다.</p>
<p>음악은 루프가 아닙니다. 당신의 플레이와 함께 쌓여가는 반응형 사운드트랙입니다. 바탕 시스템은 E 단조 140 BPM으로 베이스 라인, 리드 신스, 패드, 킥, 스네어, 하이햇을 돌리고, 액션이 격해질수록 추가 타악기와 신스 레이어가 페이드인합니다. 웨이브 사이에 분위기가 가라앉으면 앰비언트 패드가 넘겨받습니다. 음악이 당신과 함께 호흡합니다. 전담 작곡가라면 그런 반응성을 다듬는 데 몇 주를 쓸 겁니다. 여기서는 그게 창작 흐름의 일부였습니다.</p>
<p>음향 효과는 무료 팩에서 끌어온 샘플이 아닙니다. 모든 벽돌 부서짐, 파워업 획득, 구체 튕김, 충돌이 실시간으로 합성됩니다. 머리 접촉과 꼬리 접촉은 음높이가 다릅니다. 우주적인 느낌을 위한 따뜻한 리버브. 거슬리지 않으면서도 만족스럽게 유지하는 로우패스 필터링. 콤보를 연결하면 화면보다 소리가 먼저 알려줍니다.</p>
<p>그리고 스토리텔링이 있습니다. 각 웨이브는 AI로 생성된 음성이 전하는 서사의 한 박자로 시작합니다. 글에는 진짜 개성이 있습니다. 첫 번째 웨이브: &quot;그들은 그것을 Breaker Belt라 부른다. 오래된 별을 경고처럼 도는, 설계된 잔해의 띠다.&quot; 38번째 웨이브쯤이면: &quot;이 Belt는 벽처럼 느껴지기를 멈추고 정신처럼 느껴지기 시작한다. 그것은 너의 반사 신경이 아니라 너의 습관을 시험한다. 너는 습관을 깬다. Belt는 알아차린다.&quot; 당신이 왜 우주에서 벽돌을 깨는 뱀인지 마음 쓰게 만드는 50장의 우주 신화입니다.</p>
<p>배경도 진화합니다. 초반 웨이브는 부드러운 유성우가 내리는 차분한 남색 별밭입니다. 중반에 이르면 오로라 띠와 성운 구름이 나타납니다. 후반은 완전히 Ion Storm 스타일로, 거의 검은 우주를 가로지르는 날카로운 청록색 줄무늬가 펼쳐집니다. 15번째 웨이브와 그 이후로는 Event Horizon의 영역입니다. 느리게 움직이는 성운 필라멘트와 희미한 블랙홀 렌즈 효과가 점점이 박힌 깊은 허공이죠. 게임은 난이도만큼이나 분위기로 진행 상황을 전달합니다.</p>
<p>이 모든 게 키보드, 게임패드, 터치스크린에서 돌아갑니다. 하나의 코드베이스에서 웹, 모바일, PC로 출시됐습니다. 별도 빌드도, 포팅도 없습니다.</p>
<h2 id="필요-없었던-팀" tabindex="-1">필요 없었던 팀 <a class="header-anchor" href="#필요-없었던-팀" aria-label="Permalink to &quot;필요 없었던 팀&quot;"></a></h2>
<p>여기가 게임 개발자라면 누구든 잠시 멈춰야 할 부분입니다.</p>
<p>이 정도 콘텐츠 깊이의 게임이라면 보통 게임 디자이너, 프로그래머 두어 명, 2D 아티스트, 사운드 디자이너, 작곡가, 레벨 디자이너, 서사 작가, 그리고 QA가 필요합니다. 여덟아홉 명이죠. 적당한 인디 속도로 본다면 서너 달에서 여섯 달의 협업이 걸립니다. 스탠드업, Jira 티켓, 에셋 파이프라인, 플랫폼별 디버깅까지요.</p>
<p>우리 둘이 <a href="https://app.cinevva.com/engine" target="_blank" rel="noreferrer">Cinevva Engine</a>에서 긴 주말 한 번에 이걸 만들었습니다.</p>
<p>필요한 재능이 바뀐 게 아닙니다. 창작 의도와 구현 부담 사이의 비율이 바뀐 겁니다. 시간은 게임이 어떤 느낌이어야 하는지 정하는 데 쓰였지, 그걸 만들려고 도구와 싸우는 데 쓰이지 않았습니다.</p>
<h2 id="당신이-무언가를-만든다면-이게-왜-중요한가" tabindex="-1">당신이 무언가를 만든다면 이게 왜 중요한가 <a class="header-anchor" href="#당신이-무언가를-만든다면-이게-왜-중요한가" aria-label="Permalink to &quot;당신이 무언가를 만든다면 이게 왜 중요한가&quot;"></a></h2>
<p>흥미로운 질문은 AI 도구가 게임을 더 빨리 만드는 데 도움이 되느냐가 아닙니다. 그건 이미 답이 나왔습니다. 흥미로운 질문은, 예전에는 시도하기엔 너무 위험했던 아이디어들에 무슨 일이 생기느냐입니다.</p>
<p>&quot;스네이크인데 당신이 아르카노이드 경기장의 패들&quot;이라는 건 프로듀서가 승인할 만한 게 아닙니다. 몇몇 인디 개발자가 itch.io에서 이 조합의 변형을 시도해봤지만(<a href="https://newdron.itch.io/breaksnake" target="_blank" rel="noreferrer">BreakSnake</a>, <a href="https://neop87.itch.io/snakeout" target="_blank" rel="noreferrer">SnakeOut</a>, <a href="https://merrak.itch.io/snake-break" target="_blank" rel="noreferrer">Snake Break</a>), 모두 작은 게임 잼 실험입니다. 이 장르 융합은 반응형 음악, AI 내레이션, 수십 종의 벽돌, 50개 웨이브의 점증하는 레벨 디자인을 갖춘 진짜 제작 단계를 거쳐본 적이 없습니다. 전통적인 개발에서 위험한 콘셉트에 그만한 완성도를 들이는 일은 아무도 코드 한 줄 쓰기 전에 회의에서 죽습니다.</p>
<p>이상한 걸 시도하는 비용이 한 분기 예산이 아니라 오후 한나절이 되면, 이상한 아이디어들이 실제로 만들어집니다. 그중 일부는 정말로 괜찮은 것으로 드러납니다. A Breaker Belt가 그중 하나입니다.</p>
<h2 id="플레이하세요-아니면-직접-만드세요" tabindex="-1">플레이하세요. 아니면 직접 만드세요. <a class="header-anchor" href="#플레이하세요-아니면-직접-만드세요" aria-label="Permalink to &quot;플레이하세요. 아니면 직접 만드세요.&quot;"></a></h2>
<p><a href="https://app.cinevva.com/engine" target="_blank" rel="noreferrer">A Breaker Belt</a>는 지금 바로 웹, 모바일, PC에서 플레이할 수 있습니다. 뭔가 만들고 싶어진다면 <a href="https://app.cinevva.com/engine" target="_blank" rel="noreferrer">Cinevva Engine</a>은 무료로 쓸 수 있습니다. 원하는 걸 설명하고, 돌아온 결과물을 다듬고, 준비되면 출시하세요. <a href="https://app.cinevva.com/tools/music" target="_blank" rel="noreferrer">음악</a>, <a href="https://app.cinevva.com/tools/sfx" target="_blank" rel="noreferrer">음향 효과</a>, <a href="https://app.cinevva.com/tools/flux" target="_blank" rel="noreferrer">아트</a>, <a href="https://app.cinevva.com/tools/hunyuan3d" target="_blank" rel="noreferrer">3D 모델</a>이 모두 내장돼 있습니다.</p>
<p>당신의 이상한 게임 아이디어가 존재하기까지 사흘밖에 안 남았을지도 모릅니다.</p>
<hr>
<p><em><a href="https://app.cinevva.com/engine" target="_blank" rel="noreferrer">A Breaker Belt 플레이하기</a> | <a href="https://app.cinevva.com/engine" target="_blank" rel="noreferrer">직접 게임 만들기</a> | <a href="https://cinevva.com/charts" target="_blank" rel="noreferrer">커뮤니티 게임 둘러보기</a></em></p>
<p><strong>관련 글:</strong></p>
<ul>
<li><a href="/ko/signals/2026-03-13-vibe-coding-new-game-jam.html">바이브 코딩은 새로운 게임 잼이다</a> — AI 도구가 아이디어와 프로토타입 사이의 간극을 어떻게 좁히는가</li>
<li><a href="/ko/guides/game-jams-hackathons.html">게임 잼 &amp; 해커톤</a> — 이상한 조합을 가능하게 하는 잼 형식</li>
<li><a href="/ko/guides/web-game-engines-comparison.html">웹 게임 엔진 비교</a> — 웹, 모바일, PC로 출시하기 위한 엔진</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[라디오 방송국을 만들 줄은 몰랐습니다]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-17-we-didnt-expect-a-radio-station</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-17-we-didnt-expect-a-radio-station</guid>
            <pubDate>Tue, 17 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[게임 창작자들이 사운드트랙을 만들 수 있도록 Cinevva에 음악 생성기를 두었습니다. 사람들은 그냥 만들 수 있다는 이유로 음악을 만들기 시작했습니다. 362곡이 쌓인 끝에 Cinevva Radio가 문을 열었습니다.]]></description>
            <content:encoded><![CDATA[<h1 id="라디오-방송국을-만들-줄은-몰랐습니다" tabindex="-1">라디오 방송국을 만들 줄은 몰랐습니다 <a class="header-anchor" href="#라디오-방송국을-만들-줄은-몰랐습니다" aria-label="Permalink to &quot;라디오 방송국을 만들 줄은 몰랐습니다&quot;"></a></h1>
<p><em><a href="/ko/about.html">Mariana Muntean</a>, Cinevva CEO</em></p>
<img src="https://cdn.cinevva.com/blog/cinevva-radio-lofi-cafe.png" alt="Cinevva Community Radio with 8 stations including Soundstage, Voltage, Lo-Fi Cafe, Main Stage, Ivory Tower, and Electric Dreams, currently playing Quiet Flute Drone" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Cinevva 플랫폼에는 <a href="https://app.cinevva.com/tools/music" target="_blank" rel="noreferrer">음악 생성기</a>가 있습니다. 게임 창작자들이 라이선스 문제로 골치 아플 일 없이 게임 사운드트랙과 효과음을 만들 수 있게 하려고 만든 것이죠. 그런데 그다음에 벌어진 일은 우리 계획에 없던 거였습니다. 사람들이 그냥 음악을 만들고 싶어서 음악을 만들기 시작했습니다. 게임이나 프로젝트를 위해서가 아니라요. 순수하게 음악 제작이었습니다.</p>
<h2 id="bella-bay는-2주-만에-100곡-넘게-만들었습니다" tabindex="-1">Bella Bay는 2주 만에 100곡 넘게 만들었습니다 <a class="header-anchor" href="#bella-bay는-2주-만에-100곡-넘게-만들었습니다" aria-label="Permalink to &quot;Bella Bay는 2주 만에 100곡 넘게 만들었습니다&quot;"></a></h2>
<p>과장이 아닙니다. 우리 창작자 중 한 명인 Bella Bay는 약 2주 만에 100곡이 넘는 트랙을 생성했습니다. <a href="https://cinevva.com/radio" target="_blank" rel="noreferrer">Cinevva Radio</a>에서 그 곡들을 쭉 들어 보면 발전 과정이 들립니다. 초반 트랙들은 실험입니다. 후반 트랙들은 자기 스타일을 찾은 사람의 작품처럼 들립니다. 이런 식의 창작 가속은 도구와 씨름하고 있을 때는 일어나지 않습니다. 도구가 비켜 줄 때 일어납니다.</p>
<p>Bella Bay는 마음가짐에서 예외적인 게 아니라 양에서만 예외적입니다. 플랫폼 전반에서 사람들이 음악 생성기를 게임 에셋용 도구가 아니라 창작 악기로 다루기 시작했습니다. 한 번도 시도하지 않았던 장르를 실험하는 프로듀서들. 딱 맞아떨어질 때까지 한 사운드를 계속 다듬는 사람들. 제대로 된 제작 도구를 한 번도 써 본 적 없던 침실 아티스트들이 갑자기 그 도구를 손에 넣고 전력을 다했습니다.</p>
<h2 id="그래서-라디오를-만들었습니다" tabindex="-1">그래서 라디오를 만들었습니다 <a class="header-anchor" href="#그래서-라디오를-만들었습니다" aria-label="Permalink to &quot;그래서 라디오를 만들었습니다&quot;"></a></h2>
<p>안 만들 수가 없었습니다.</p>
<p>이 모든 트랙이 각자의 계정 안에 모여 있을 공간 없이 흩어져 있었습니다. 다른 사람들이 뭘 만들고 있는지 발견할 방법도 없었고요. 당신의 오후를 바꿔 놓을 트랙을 우연히 마주칠 방법도 없었습니다.</p>
<p><a href="https://cinevva.com/radio" target="_blank" rel="noreferrer">Cinevva Radio</a>가 이제 문을 열었습니다. 여덟 개 방송국. 362곡의 커뮤니티 창작 트랙이 있고 매일 늘어나고 있습니다. 모든 곡이 플랫폼에 있는 누군가가 만든 것입니다. 열면 뭔가가 흘러나옵니다. 검색할 필요도 없고 고를 필요도 없습니다. 그냥 들으면 됩니다.</p>
<p>**<a href="https://cinevva.com/radio#cinematic" target="_blank" rel="noreferrer">Soundstage</a>**는 우리의 가장 큰 방송국입니다. 영화 같고 웅장한 스코어 111곡. 솔직히 이건 예상 못 했습니다. 사람들은 드라마틱한 영화풍 음악 만드는 걸 정말 좋아하더군요.</p>
<p>**<a href="https://cinevva.com/radio#mixed" target="_blank" rel="noreferrer">Discovery</a>**는 어떤 장르에도 깔끔하게 들어맞지 않는 것들을 다 담았습니다. 78곡. 라틴 비트 옆에 Afrobeats, 그 옆에 컨트리, 또 그 옆에 뭐라 설명할 수 없는 무언가. 이 방송국은 정말 거칩니다.</p>
<p>**<a href="https://cinevva.com/radio#pop" target="_blank" rel="noreferrer">Main Stage</a>**는 팝과 보컬 트랙입니다. 완전한 가사와 보컬이 들어간 56곡. 사람들이 러브송, 이별 노래, 워십 음악, 발라드를 쓰고 있습니다. 일부는 진짜로 귀에 꽂힙니다.</p>
<p>**<a href="https://cinevva.com/radio#rock" target="_blank" rel="noreferrer">Voltage</a>**는 록과 메탈입니다. 53곡. 기타 리프, 펑크의 에너지, 그런지, 하드 록. 저는 일할 때 이걸 틀어 둡니다.</p>
<p>**<a href="https://cinevva.com/radio#lofi" target="_blank" rel="noreferrer">Lo-Fi Cafe</a>**는 이름 그대로입니다. 공부하거나 일하거나 그냥 분위기 즐기기 좋은 차분한 앰비언트 트랙 25곡.</p>
<p>**<a href="https://cinevva.com/radio#electronic" target="_blank" rel="noreferrer">Electric Dreams</a>**에는 전자 음악과 신스 트랙 22곡이 있습니다. Synthwave, techno, EDM, drum and bass.</p>
<p>**<a href="https://cinevva.com/radio#classical" target="_blank" rel="noreferrer">Ivory Tower</a>**는 클래식과 오케스트라입니다. 10곡. 피아노곡, 현악 편곡, 교향곡풍 작품들. 작지만 커 가고 있습니다.</p>
<p>**<a href="https://cinevva.com/radio#hiphop" target="_blank" rel="noreferrer">The Cipher</a>**는 힙합과 랩입니다. 아직 7곡. 가장 새로운 방송국이고 여전히 자기 색깔을 찾는 중입니다.</p>
<h2 id="들을-때-보이는-것" tabindex="-1">들을 때 보이는 것 <a class="header-anchor" href="#들을-때-보이는-것" aria-label="Permalink to &quot;들을 때 보이는 것&quot;"></a></h2>
<p><a href="https://cinevva.com/radio" target="_blank" rel="noreferrer">Cinevva Radio</a>를 열면 라이브 스트림입니다. 플레이리스트 앱이라기보다 실제 라디오 방송국에 더 가깝다고 생각하시면 됩니다. 트랙이 끊김 없이 계속 재생됩니다. 실시간으로 반응하고, 다른 청취자들과 채팅하고, 각 트랙을 누가 만들었는지 볼 수 있습니다.</p>
<p>창작자는 자기 트랙이 재생되는 동안 화면에 크레딧으로 표시됩니다. 이름, 프롬프트, 장르까지요. 마음에 드는 곡을 들으면 누가 만들었는지 알 수 있습니다. 커뮤니티가 만든 콘텐츠 위에 발견 레이어를 한 겹 얹은 것입니다. 무엇이 들을 만한지 알고리즘이 정하지 않습니다. 문지기도 없습니다. 당신이 트랙을 하나 만들면 그 장르에 맞는 방송국에 올라가고, 사람들이 듣습니다.</p>
<h2 id="이건-하나의-기능보다-큽니다" tabindex="-1">이건 하나의 기능보다 큽니다 <a class="header-anchor" href="#이건-하나의-기능보다-큽니다" aria-label="Permalink to &quot;이건 하나의 기능보다 큽니다&quot;"></a></h2>
<p>수십 년 동안 음악 제작에는 값비싼 소프트웨어, 여러 해의 훈련, 그리고 대부분의 사람이 살 수 없는 장비가 필요했습니다. 우리가 지금 보고 있는 건 다른 종류의 창작자입니다. 음표와 박자표가 아니라 묘사와 감정으로 사고하는 사람들이죠.</p>
<p>&quot;고장 난 피아노로 연주하는 비 오는 밤의 재즈&quot;는 하나의 창작 방향입니다. 그 프롬프트를 쓴 사람은 예술적 선택을 한 것입니다. 분위기, 악기 편성, 감정의 결을 연출했습니다. 단지 피아노를 칠 줄 모를 뿐이죠.</p>
<p>저는 그게 그 사람의 결과물을 덜 정당하게 만든다고 생각하지 않습니다. &quot;음악가&quot;라는 정의가 넓어지고 있다는 뜻이라고 봅니다. 그리고 Bella Bay 같은 사람이 2주 만에 0에서 100곡까지 가는 걸 보면, 창작 욕구는 늘 거기 있었다는 걸 알 수 있습니다. 도구가 없었을 뿐입니다.</p>
<h2 id="다음-단계" tabindex="-1">다음 단계 <a class="header-anchor" href="#다음-단계" aria-label="Permalink to &quot;다음 단계&quot;"></a></h2>
<p>우리는 프로듀서들이 자기 카탈로그를 보여 주고 팬을 모을 수 있는 커뮤니티 프로필을 만들고 있습니다. <a href="https://cinevva.com/charts" target="_blank" rel="noreferrer">차트 페이지</a>는 이미 모든 도구에 걸친 커뮤니티 창작물을 보여 주고 있는데, 우리는 바로 그 에너지를 음악에도 똑같이 가져오고 싶습니다.</p>
<p>하지만 지금 당장, 라디오는 열려 있습니다. <a href="https://cinevva.com/radio" target="_blank" rel="noreferrer">들으러 가세요</a>. 그리고 직접 트랙을 만들고 싶다면 <a href="https://app.cinevva.com/tools/music" target="_blank" rel="noreferrer">음악 생성기</a>는 무료로 쓸 수 있습니다. 당신의 트랙이 전파를 탈지도 모릅니다.</p>
<hr>
<p><em><a href="https://cinevva.com/radio" target="_blank" rel="noreferrer">Cinevva Radio 듣기</a> | <a href="https://app.cinevva.com/tools/music" target="_blank" rel="noreferrer">음악 만들기</a> | <a href="https://cinevva.com/charts" target="_blank" rel="noreferrer">커뮤니티 창작물 둘러보기</a></em></p>
<p><strong>관련 글:</strong></p>
<ul>
<li><a href="/ko/guides/frontier-gen-ai-models.html">최전선 오픈소스 생성형 AI 모델</a> — 뒤에서 돌아가는 AI 음악 및 오디오 모델</li>
<li><a href="/ko/tutorials/web-audio-api-games.html">게임을 위한 Web Audio API</a> — 브라우저에서 인터랙티브 오디오 만들기</li>
<li><a href="/ko/signals/2026-03-13-vibe-coding-new-game-jam.html">Vibe coding은 새로운 game jam이다</a> — 의도를 묘사하는 것이 어떻게 주된 창작 입력이 되는가</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AI 시대의 직관적인 사고]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-02-10-the-intuitive-mind</link>
            <guid>https://app.cinevva.com/ko/blog/2026-02-10-the-intuitive-mind</guid>
            <pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[젠슨 황은 순수한 수학 능력이 이제 흔한 상품이 됐다고 말한다. SAT에 떨어지고, 규칙을 무시하고, 사람들이 진짜로 원하는 것을 만들어낸 사람에게 이 말이 왜 이렇게 와닿는지 이야기해본다.]]></description>
            <content:encoded><![CDATA[<h1 id="ai-시대의-직관적인-사고" tabindex="-1">AI 시대의 직관적인 사고 <a class="header-anchor" href="#ai-시대의-직관적인-사고" aria-label="Permalink to &quot;AI 시대의 직관적인 사고&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Mariana Muntean</a>, Cinevva CEO</em></p>
<img src="https://cdn.cinevva.com/blog/game-jam-houston-2018.png" alt="Mariana Muntean with classmates during a 48 hours game jam in Houston 2018" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<small>2018년 휴스턴에서 열린 48시간 game jam에서 동기들과 함께</small>
<p>AI는 사실상 순수한 논리와 계산 능력을 흔한 상품으로 만들어버렸다. 우리가 떠받들던 능력들, 암산, 패턴 인식, 복잡한 알고리즘을 끈질기게 풀어내는 능력, 이 모든 걸 이제 AI가 한다. 더 빠르게, 더 잘, 지치지도 않고. 그래도 우리가 그걸 알아야 할까? 당연히 그렇다. 하지만 인식은 바뀐다. 이제 모두가 새로운 시대에 맞춰가야 한다. 직관적인 상호작용과 결과의 시대 말이다.</p>
<p>NVIDIA CEO <a href="https://business.columbia.edu/insights/digital-future/nvidia-ceo-jensen-huang-reveals-keys-ai-and-leadership" target="_blank" rel="noreferrer">젠슨 황</a>에 따르면, 이제 중요한 건 &quot;분위기&quot;를 감지하고 데이터가 나타나기 전에 모퉁이 너머를 내다보는 능력이다. 기술적 소양과 깊은 공감이 만나는 지점. 실리콘이 닿을 수 없는 직관적인 이해.</p>
<p>그만큼 신뢰받는 사람이 내 인생 전체의 궤적을 이렇게까지 직접적으로 인정해주는 말을 한 적은 한 번도 들어본 적이 없다.</p>
<h2 id="sat-그리고-나를-위해-만들어지지-않은-시스템" tabindex="-1">SAT, 그리고 나를 위해 만들어지지 않은 시스템 <a class="header-anchor" href="#sat-그리고-나를-위해-만들어지지-않은-시스템" aria-label="Permalink to &quot;SAT, 그리고 나를 위해 만들어지지 않은 시스템&quot;"></a></h2>
<p>몇 년 전 나는 SAT를 봤고 떨어졌다. 자랑스럽지는 않지만, 다시 보지도 않았다. 그 모든 게 근본적으로 뭔가 잘못됐다는 느낌이었고, 사람들이 아무리 그냥 더 열심히 공부해서 다시 보라고 해도 그 느낌을 떨칠 수가 없었다.</p>
<p>돌이켜보면, 내가 맞았다고 생각한다.</p>
<p>SAT는 미국 교육 시스템을 위해 설계됐다. 당연한 말처럼 들리지만 그 함의는 깊다. 미국 고등학교는 특정한 패턴, 문제 유형, 문제를 구성하는 방식에 맞춰 가르친다. 학생들은 초등학교 때부터 그런 식의 표준화 시험에 푹 절어서 자란다. SAT를 칠 무렵이면 그 리듬이 이미 몸에 배어 있다.</p>
<p>국제 학생에게는 그런 이점이 없다. 우리는 교육 철학이 다른 시스템에서 왔다. 유럽 학교는 폭보다 깊이를, 객관식보다 논술형 시험을, 답안지보다 구술 시험을 강조하는 경우가 많다. 아시아 시스템에는 자체 표준화 시험이 있지만, 다른 것을 다른 방식으로 측정한다. 남미, 아프리카, 중동의 교육 전통도 각자의 논리를 지니고 있다.</p>
<p>국제 학생을 SAT 앞에 떨어뜨려 놓으면, 단지 그 사람의 지식을 시험하는 게 아니다. 낯선 시험 문화에 얼마나 빨리 적응하면서 동시에 내용을 얼마나 잘 익혔는지를 보여줄 수 있는지를 시험하는 것이다. 학업 능력만큼이나 문화적 적응 능력을 시험하는 셈이다.</p>
<p>나는 여름 한 철 동안 이걸 준비해서 만점에 가깝게 받아낼 거라 기대받았다. 시험 문화 한 세트를 통째로 배우고, 내 교육적 본능을 버리고, 미국 입학 사정관을 감동시킬 수준으로 해내라는 거였다. 그것도 몇 달 만에.</p>
<p>나는 그렇게 하지 않기로 했다.</p>
<p>어릴 때는 다른 방식으로 똑똑하다. 직관적인 방식으로. 그때 나는 나 자신을 위한 길을 내고 있었다. 정확히 왜 그러는지 말로 설명하지는 못했지만 말이다. 내 안의 무언가가 알고 있었다. 이 시스템은 내 것이 아니라는 걸.</p>
<h2 id="대신-창작의-실을-따라가다" tabindex="-1">대신 창작의 실을 따라가다 <a class="header-anchor" href="#대신-창작의-실을-따라가다" aria-label="Permalink to &quot;대신 창작의 실을 따라가다&quot;"></a></h2>
<p>나는 게임 개발과 디자인을 공부했다. 창의력과 시각 효과로 사람들이 직접 플레이하고 상호작용할 수 있는 가상 세계를 만든다는 발상이 좋았기 때문이다. 예술과 기술이 만나는 지점, 이야기와 상호작용이 만나는 지점이 좋았다.</p>
<p>내가 발견한 것은 충격적이었다.</p>
<p>게임에는 진지한 기술적 깊이가 필요하다. 물리 시뮬레이션, 충돌 감지, 벡터 수학, 조명 계산, 최적화. 이건 들어가기 전부터 알고 있었다. 수학과 공학은 게임 개발의 장애물이 아니다. 게임이 작동하게 만드는 일부다.</p>
<p>문제는 창작의 비전과 구현 사이의 간극이었다. 업계를 지배하는 엔진과 도구들은 엔지니어가 엔지니어를 위해 설계한 것이었다. 모든 게 &quot;if&quot;와 &quot;then&quot;, 그리고 노드 기반 블루프린트로 돌아갔다. 소용돌이 효과를 원한다고? 셰이더 프로그래밍을 배워라. 특정한 조명 분위기를 원한다고? 머티리얼 그래프를 파고들어라. 캐릭터 움직임이 자연스럽게 느껴지길 원한다고? 캐릭터 컨트롤러나 물리 파라미터를 몇 시간씩 디버깅해라.</p>
<p>당신이 시각적인 사람이라면, 생생한 색과 움직이는 이미지로 생각한다면, 아이디어가 소리와 질감과 감정의 무게까지 갖춘 완성된 장면으로 떠오른다면, 그 모든 걸 일단 기술 언어로 번역해야만 무언가를 만들기 시작할 수 있었다. 머릿속에 조명과 분위기, 캐릭터가 공간을 가로질러 움직이는 방식까지 완성된 세계가 보인다. 그러고는 컴퓨터 앞에 앉아 다음 여섯 시간 동안 왜 캐릭터가 바닥을 뚫고 떨어지는지를 디버깅하며 보낸다.</p>
<p>기술적 토대는 중요하다. 하지만 도구들은 창작자가 그 복잡성을 추상화해 치워버리는 대신 구현 세부사항 속에서 살게 만들었다. 게임 제작은 이야기를 들려주거나, 사람들이 참여할 수 있는 영화를 연출하는 것처럼 느껴져야 한다. 그게 이 매체의 마법이다. 그런데 그건 시작하기도 전에 공학 시험을 치르는 것처럼 느껴졌다.</p>
<p>영화감독은 자기 비전을 표현하기 위해 물리 엔진을 몇 년씩 배우지 않는다. 예산과, 기술적 실행을 맡아줄 팀을 받는다. 하지만 인디 게임 개발에서는 예산이 있는 경우가 드물다. 당신이 가진 건 시간과 도구에 대한 접근권뿐이다. 그리고 당신이 기술적인 사람이라면, 끝내주는 게임을 만들 수 있다. 단, 그럴 때만.</p>
<p>이렇게 해서 Limbo 같은 작품이 나왔다. 작은 팀이 하나의 독특한 예술적 비전과 그것을 실행할 기술적 역량을 갖추고 만든 게임이다. 또는 Undertale, 창의적 직관과 프로그래밍 능력의 적절한 조합을 마침 갖춘 한 사람이 거의 혼자 만든 게임이다. 또는 Stardew Valley, Eric Barone이 픽셀 아트부터 작곡, C# 프로그래밍까지 모든 걸 몇 년에 걸쳐 독학한 게임이다.</p>
<p>이 게임들은 엄청난 역경을 뚫고 성공했다. 하지만 Limbo 하나당, 도구가 창작자가 갖출 수 없는 기술적 능숙함을 요구하는 바람에 사라진 창작의 비전이 수백만 개는 있다. 인디 게임 개발자 중 의미 있는 성공을 거두는 사람은 3%도 안 된다. &quot;if&quot;와 &quot;then&quot;의 벽에 부딪혀 포기한 창작자들 때문에 끝내 만들어지지 못한 멋진 게임은 또 얼마나 많을까?</p>
<p>진입 장벽은 창의력이 아니었다. 도구 자체에 내장된 기술적 문지기였다.</p>
<h2 id="원래-있었어야-할-것을-만들다" tabindex="-1">원래 있었어야 할 것을 만들다 <a class="header-anchor" href="#원래-있었어야-할-것을-만들다" aria-label="Permalink to &quot;원래 있었어야 할 것을 만들다&quot;"></a></h2>
<p>그래서 5년 전 나는 다른 무언가를 만들기 시작했다.</p>
<p>제안은 단순했다. 게임 개발은 창의적 비전을 가진 누구에게나 열려 있어야 한다. 상호작용 매체로 자신을 표현하기 위해 컴퓨터 공학 학위가 필요해서는 안 된다. 도구가 창의적인 사람들이 실제로 생각하는 방식에 맞춰야지, 그 반대가 되어서는 안 된다.</p>
<p>Sequoia, Pear, Draper를 비롯한 수십 곳의 VC들이 안 될 거라고 했다. B2C라서. 시장이 없어서. 인디 개발자들은 아무것도 결제하지 않아서. 능력을 희생하지 않고는 게임 개발을 단순화할 수 없어서. 게이머는 복잡한 게임을 원하고, 복잡한 게임에는 복잡한 도구가 필요해서. 시장 분석으로 포장된 수백만 가지 변명이었다.</p>
<p>사람들은 내가 미쳤다고 했다. 어쩌면 그랬는지도 모른다. 하지만 나는 계속 같은 질문으로 돌아왔다. 왜 수백만 달러짜리 예산이 창의적 표현의 전제 조건이어야 하는가? 영화감독과 유명 게임 프로듀서에게는 팀과 자원이 있다. 나머지 모두에게는 코드 에디터 하나와 기도 한 마디뿐이다. 나는 그 간극을 메우는 것을 만들고 싶었다. 원하는 걸 설명하면, 그게 눈앞에서 일어난다. 내 안의 모든 부분이 이게 옳다는 걸 알았다. 온몸의 모든 세포로 그걸 느낄 수 있었다.</p>
<p>오늘날 수천 명이 매일 Cinevva로 3D 게임 에셋, 게임, 음악, 레벨, 경험을 만든다. 지금까지 만들어진 프로젝트의 조회수는 수백만에 이른다. 매일같이 늘어난다. Sand Hill Road를 향한 2분짜리 피치는 &quot;나는 SAT에 떨어졌지만 내 직관을 믿어달라&quot;에 딱 맞는 형식은 아니다.</p>
<h2 id="직관이-진짜-의미하는-것" tabindex="-1">직관이 진짜 의미하는 것 <a class="header-anchor" href="#직관이-진짜-의미하는-것" aria-label="Permalink to &quot;직관이 진짜 의미하는 것&quot;"></a></h2>
<p><a href="https://singjupost.com/transcript-jensen-huangs-interview-cisco-ai-summit-2026/" target="_blank" rel="noreferrer">황</a>이 한 말은 단지 철학적인 이야기가 아니었다. 그는 무엇이 가치 있는 지능을 이루는가에 대한 진짜 변화를 묘사하고 있었다.</p>
<p>수십 년 동안 우리는 잘못된 것을 위해 최적화했다. 암기와 계산에 보상을 주는 교육 시스템을 만들었다. 이전에 본 문제와의 패턴 일치를 측정하는 표준화 시험을 설계했다. 4년간의 학문적 문지기를 견뎌냈음을 증명하는 자격증을 보고 사람을 채용했다. AI는 그 모든 걸 그저 덜 특별하게 만들어버렸다.</p>
<p>AI가 할 수 없는 것은, 적어도 아직은, 무엇이 빠졌는지를 감지하는 것이다. 뭔가 어긋났을 때 그걸 느끼는 것. 사람들이 스스로 말로 표현하기도 전에 그들이 무엇을 필요로 하는지 직관하는 것. 분위기를 읽는 것. 어떤 데이터셋에도 담기지 않은 맥락을 이해하는 것.</p>
<p>나는 내 시간, 국제적인 삶의 경험, 돈, 그리고 직관적인 지식을 Cinevva를 만드는 데 쏟아부었다. 이건 대학에서 얻기 어려운 조합이다. SAT로 시험하기 어렵다. AI가 순수한 인지적 처리 능력을 흔하게 만들기 전에 설계된 어떤 자격증 체계로도 담아내기 어렵다.</p>
<p>16년 혹은 20년 전, 컴퓨터 과학자들이 도구가 어떤 모습이어야 하고 어떻게 작동해야 하는지를 결정했다. 그들은 자신들을 위해, 자신들처럼 생각하는 사람들을 위해 만들었다. 나머지 우리는 거기에 적응할 것으로 기대됐다. 그 시대는 끝나가고 있다. 다음에 올 것을 만들어갈 사람들은 인간이 진짜로 무엇을 원하는지 이해하는 사람들이다. 무언가 잘못됐을 때와 옳을 때를 느낄 수 있는 사람들. 기술적 우아함이 아니라 사람을 위해 만드는 사람들.</p>
<p>나는 시스템이 가치 없다고 말한 내 안의 무언가를 믿었다. 그리고 내가 옳았다.</p>
<hr>
<p><strong>관련 글:</strong></p>
<ul>
<li><a href="/ko/blog/2026-01-18-skills-over-degrees.html">채용 시장이 바뀌고 있다 — 자격증에서 역량으로</a></li>
<li><a href="/ko/guides/game-dev-courses.html">온라인 게임 개발 강좌</a> — 전통적인 문지기를 우회하는 역량 우선 경로</li>
<li><a href="/ko/signals/2026-03-04-everyone-wants-ai-game-engine.html">이제 모두가 AI 게임 엔진이 되고 싶어 한다</a> — 사람들이 생각하는 방식에 맞추는 도구로 향하는 업계의 변화</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AI 논란, 신뢰, 그리고 게임의 포스트 AI 경제]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-01-18-ai-controversy-and-post-ai-economy</link>
            <guid>https://app.cinevva.com/ko/blog/2026-01-18-ai-controversy-and-post-ai-economy</guid>
            <pubDate>Sun, 18 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[현실적인 관점: AI는 핵심이 아니다. 신뢰가 핵심이다. 왜 라벨링, 필터, 공정한 분배가 'AI 찬성' 대 'AI 반대' 논쟁보다 더 중요한가.]]></description>
            <content:encoded><![CDATA[<h1 id="ai-논란-신뢰-그리고-게임의-포스트-ai-경제" tabindex="-1">AI 논란, 신뢰, 그리고 게임의 포스트 AI 경제 <a class="header-anchor" href="#ai-논란-신뢰-그리고-게임의-포스트-ai-경제" aria-label="Permalink to &quot;AI 논란, 신뢰, 그리고 게임의 포스트 AI 경제&quot;"></a></h1>
<p><em>글 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO</em></p>
<p>게임 속 AI는 2024년 중반 어디쯤에서 진짜 지뢰밭이 됐다. 일자리가 사라진다. 다음은 내 차례라고 확신하는 사람들. 변호사들조차 풀어내지 못하는 저작권 문제. 끝없이 제자리를 맴도는 미학 논쟁. 아무도 원하지 않은 것들로 넘쳐나는 Steam. 그리고 그 모든 것 아래, 이제 모든 창작자가 품게 된 이 거슬리는 걱정. &quot;내가 지금 뭔가를 만들고 있는 건가, 아니면 그냥... 프롬프트를 치고 있는 건가?&quot;</p>
<p>우리는 플랫폼을 운영한다. 그 일을 하다 보면 한 가지를 빠르게 배운다.</p>
<p><strong>누구도 속았다는 기분을 좋아하지 않는다.</strong></p>
<h2 id="이-수치들은-우리도-놀랐다" tabindex="-1">이 수치들은 우리도 놀랐다 <a class="header-anchor" href="#이-수치들은-우리도-놀랐다" aria-label="Permalink to &quot;이 수치들은 우리도 놀랐다&quot;"></a></h2>
<p>AI 도입이 늘어날 거라고는 예상했다. 하지만 이 정도는 아니었다. 2025년 말 기준으로 상황이 이렇게 정리됐다.</p>
<table tabindex="0">
<thead>
<tr>
<th>우리가 추적한 것</th>
<th>2024</th>
<th>2025</th>
<th>변화</th>
</tr>
</thead>
<tbody>
<tr>
<td>AI 사용을 공개한 Steam 게임</td>
<td>~1,000</td>
<td>7,818</td>
<td>7배 증가</td>
</tr>
<tr>
<td>AI를 쓴 Steam 신작 출시</td>
<td>~3%</td>
<td>~20%</td>
<td>다섯 중 하나</td>
</tr>
<tr>
<td>AI가 품질을 해친다고 보는 개발자</td>
<td>34%</td>
<td>47%</td>
<td>13포인트 상승</td>
</tr>
<tr>
<td>AI가 품질에 도움이 된다고 보는 개발자</td>
<td>—</td>
<td>11%</td>
<td>많지 않다</td>
</tr>
<tr>
<td>AI 공개 게임의 매출</td>
<td>—</td>
<td>$660M</td>
<td>12개 게임이 8자리 매출 돌파</td>
</tr>
</tbody>
</table>
<p>출처: Tom's Hardware / Totally Human Media 분석, GDC 2025 개발자 설문, Unity 2025 게이밍 리포트</p>
<h2 id="플레이어들이-이렇게까지-회의적이-된-이유" tabindex="-1">플레이어들이 이렇게까지 회의적이 된 이유 <a class="header-anchor" href="#플레이어들이-이렇게까지-회의적이-된-이유" aria-label="Permalink to &quot;플레이어들이 이렇게까지 회의적이 된 이유&quot;"></a></h2>
<p>이건 갑자기 생긴 게 아니다. 실제로 일이 잘못됐다. 그리고 사람들은 기억한다.</p>
<h3 id="성우들은-자신이-복제됐다는-걸-알았다-—-출시-당일에" tabindex="-1">성우들은 자신이 복제됐다는 걸 알았다 — 출시 당일에 <a class="header-anchor" href="#성우들은-자신이-복제됐다는-걸-알았다-—-출시-당일에" aria-label="Permalink to &quot;성우들은 자신이 복제됐다는 걸 알았다 — 출시 당일에&quot;"></a></h3>
<p><em>Tomb Raider 4-6 Remastered</em>는 원본 음성 연기의 AI 생성 버전을 담아 출시됐다. 성우들은 다른 모두와 똑같은 순간에 그 사실을 알았다. 출시 당일이었다. 법적 압박이 쌓이자 퍼블리셔는 결국 패치로 그 음성을 제거했다. 11개월간 이어진 SAG-AFTRA 파업? 바로 이 시나리오가 그걸 끌고 갔다.</p>
<h3 id="ai-slop-은-이제-사람들이-쓰는-말이-됐다" tabindex="-1">&quot;AI slop&quot;은 이제 사람들이 쓰는 말이 됐다 <a class="header-anchor" href="#ai-slop-은-이제-사람들이-쓰는-말이-됐다" aria-label="Permalink to &quot;&quot;AI slop&quot;은 이제 사람들이 쓰는 말이 됐다&quot;"></a></h3>
<p><em>Call of Duty: Black Ops 6</em>는 Steam 페이지에 슬그머니 AI 공개 문구를 추가했다. 이미 출시된 다음에. 플레이어들은 그 이상함을 알아챘다. 여기저기 흩어진 시각적 결함들. 한 로딩 화면 캐릭터는 손가락이 여섯 개였다. &quot;AI slop&quot;은 뭔가... 어딘가 어긋난 것을 가리키는 줄임말이 됐다. 텅 빈 느낌. 아무도 제대로 확인할 만큼 신경 쓰지 않은 것 같은.</p>
<h3 id="어워드-후보-지명이-사라졌다" tabindex="-1">어워드 후보 지명이 사라졌다 <a class="header-anchor" href="#어워드-후보-지명이-사라졌다" aria-label="Permalink to &quot;어워드 후보 지명이 사라졌다&quot;"></a></h3>
<p><em>Clair Obscur: Expedition 33</em>는 Indie Game Awards에서 올해의 게임 후보 지명이 철회됐다. 그런데 출시된 게임은 AI를 쓰지 않았다. 문제는 개발 중에 쓴 AI 플레이스홀더였다. 플레이어에게는 한 번도 전달되지 않은 내부 자료였다. 최종 에셋은 전부 사람이 만든 것이었다. 그래도 소용없었다. 선이 정확히 어디여야 하는지를 두고 몇 주간 논쟁이 이어졌다.</p>
<h3 id="ai를-전혀-손대지-않은-팀들이-그걸-증명해야-했다" tabindex="-1">AI를 전혀 손대지 않은 팀들이 그걸 증명해야 했다 <a class="header-anchor" href="#ai를-전혀-손대지-않은-팀들이-그걸-증명해야-했다" aria-label="Permalink to &quot;AI를 전혀 손대지 않은 팀들이 그걸 증명해야 했다&quot;"></a></h3>
<p><em>Chessplus</em>와 <em>Peak</em> 둘 다 AI 의혹에 휩싸였다. 둘 다 쓰지 않았다. 둘 다 어워드 후보였다. 두 개발팀은 결국 자기들 작업이 수작업이라는 걸 보여주려고 옛날 스크린샷과 레이어 파일을 뒤져야 했다. <em>Peak</em> 팀이 가장 잘 표현했다. &quot;우리는 slop일지 몰라도, 사람이 만든 지역 생산 수제 slop이다.&quot;</p>
<h3 id="스튜디오들은-완전히-반대-방향으로-갔다" tabindex="-1">스튜디오들은 완전히 반대 방향으로 갔다 <a class="header-anchor" href="#스튜디오들은-완전히-반대-방향으로-갔다" aria-label="Permalink to &quot;스튜디오들은 완전히 반대 방향으로 갔다&quot;"></a></h3>
<p><strong>SNK</strong> — <em>Fatal Fury: City of the Wolves</em> 트레일러에 AI 같은 비주얼이 등장하자 Discord 모더레이터들이 떠났다. <strong>Games Workshop</strong> — 모든 Warhammer 자산에서 AI를 전면 금지했다. <strong>Larian Studios</strong> — Baldur's Gate 3에서 AI는 아주 초기 콘셉트 스케치에만 썼고 최종 게임에는 전혀 없다고 밝혔다. <strong>Tim Sweeney</strong> — Steam의 AI 라벨이 쓸모없다며 없애버리라고 선언했다. <strong>Valve</strong> — AI 라벨에 불평하는 개발자들은 대개 자기 작업이 &quot;성의 없어&quot; 보일까 걱정하는 거라고 받아쳤다.</p>
<h2 id="게임을-찾는-일이-신뢰-문제가-됐다" tabindex="-1">게임을 찾는 일이 신뢰 문제가 됐다 <a class="header-anchor" href="#게임을-찾는-일이-신뢰-문제가-됐다" aria-label="Permalink to &quot;게임을 찾는 일이 신뢰 문제가 됐다&quot;"></a></h2>
<p>이제는 누구든 제대로 평가할 수 있는 속도보다 더 빠르게 물건이 만들어진다. 질문이 바뀌었다.</p>
<p>내가 지금 보고 있는 게 도대체 뭐지?
누가 만들었지?
여기에 시간을 쓰면 후회하게 될까?
이게 트레일러가 약속한 거랑 맞기는 한 건가?</p>
<p>거창한 해결책 같은 건 아마 오지 않을 거다. AI 대 수작업에 대한 결정적 판결도 없을 거다.</p>
<p>더 가능성 높은 것은 이것이다. <strong>필터, 진짜 투명성, 그리고 정직함 쪽으로 밀어붙이는 인센티브 구조.</strong></p>
<h2 id="이-한가운데-끼인-작은-스튜디오들" tabindex="-1">이 한가운데 끼인 작은 스튜디오들 <a class="header-anchor" href="#이-한가운데-끼인-작은-스튜디오들" aria-label="Permalink to &quot;이 한가운데 끼인 작은 스튜디오들&quot;"></a></h2>
<p>인디 개발자들은 묘한 자리에 놓였다.</p>
<p><strong>좋은 점은 솔직히 무시하기 어렵다.</strong>
반복 작업이 더 빨라진다. 네 명이 모든 걸 만들 때 비용이 떨어진다. 1인 개발자가 이제 실제로 작업을 끝낼 수 있다. 현지화가 예산 전체를 잡아먹는 일이 사라진다.</p>
<p><strong>나쁜 점도 그만큼 진짜다.</strong>
밋밋하게 느껴지는 결과물. 변호사들이 아직 손대지 않으려는 학습 데이터와 IP 문제. 완전히 이해하지 못하는 시스템을 출시하는 것. 어떤 사람들은 이걸 이해 부채라고 부른다. 성의 없는 출시물의 홍수에 한데 묶이는 것. 설문에 응한 개발자의 거의 절반이 AI가 전반적으로 게임을 더 나쁘게 만든다고 본다.</p>
<p>Unity의 2025년 리포트는 개발자의 79%가 AI 도구에 긍정적이라고 말한다. 꽤 확정적으로 들린다. 현실은 더 지저분하다. 이걸 잘 해내는 팀들은 AI를 지루한 부분에 쓰는 경향이 있다. 막노동, 거친 초안, QA의 따분함. 창작 방향은? 그건 사람의 몫으로 남는다.</p>
<h2 id="cinevva의-입장-ai에-중립-정직함에는-엄격" tabindex="-1">Cinevva의 입장: AI에 중립, 정직함에는 엄격 <a class="header-anchor" href="#cinevva의-입장-ai에-중립-정직함에는-엄격" aria-label="Permalink to &quot;Cinevva의 입장: AI에 중립, 정직함에는 엄격&quot;"></a></h2>
<p>우리는 AI를 썼다는 이유로 게임을 돌려보내지 않는다. 그렇다고 특별 대우를 해주지도 않는다.</p>
<p>규칙은 단순하다. <strong>AI가 관여했다면, 그렇다고 밝혀라.</strong> 무엇에 신경 쓸지는 플레이어가 정한다. 그러면 필터가 실제로 작동한다.</p>
<ul>
<li><a href="/ko/ai-content.html">AI 생성 콘텐츠 정책</a></li>
</ul>
<h2 id="필터는-논쟁보다-더-잘-작동한다" tabindex="-1">필터는 논쟁보다 더 잘 작동한다 <a class="header-anchor" href="#필터는-논쟁보다-더-잘-작동한다" aria-label="Permalink to &quot;필터는 논쟁보다 더 잘 작동한다&quot;"></a></h2>
<p>게임 속 AI 논쟁은 당분간 합의에 도달하지 못한다. 아마 영영 못 할 거다. 하지만 개인의 취향은? 그건 충분히 분명하다.</p>
<p>어떤 플레이어는 사람이 방향을 잡은 아트를 콕 집어 원한다. 사람에게서 나온 글. 눈에 보이는 장인정신.</p>
<p>다른 사람들은 정말로 신경 쓰지 않는다. 재밌으면 재밌는 거다.</p>
<p>필터는 두 집단 모두가 찾는 걸 찾게 해준다. 누구도 이길 필요가 없다.</p>
<h2 id="결제-모델은-누구의-의견보다-더-중요하다" tabindex="-1">결제 모델은 누구의 의견보다 더 중요하다 <a class="header-anchor" href="#결제-모델은-누구의-의견보다-더-중요하다" aria-label="Permalink to &quot;결제 모델은 누구의 의견보다 더 중요하다&quot;"></a></h2>
<p>매출이 판매 수량이 아니라 <strong>플레이 시간</strong>에 묶이면, 이런 식으로 돈을 번다.</p>
<p>플레이어를 빠르게 빠져들게 한다. 그들의 관심을 붙잡는다. 마케팅에서 말한 그대로를 전달한다.</p>
<p>품질이 당연한 길이 된다. 어떻게 만들었는지는 덜 중요해진다.</p>
<p>트레일러에서 과하게 약속했다고? 플레이어는 즉시 떠난다. 리텐션이 곤두박질친다. 그들이 받게 될 걸 정확히 보여줬다고? 그들은 머문다. 플레이 시간이 쌓인다. 매출이 따라온다. 경제는 알아서 정리된다.</p>
<h2 id="_2026년이-가져올-가능성이-큰-것들" tabindex="-1">2026년이 가져올 가능성이 큰 것들 <a class="header-anchor" href="#_2026년이-가져올-가능성이-큰-것들" aria-label="Permalink to &quot;2026년이 가져올 가능성이 큰 것들&quot;"></a></h2>
<p><strong>더 많은 규칙</strong> — EU AI Act는 계속 확장된다. 미국의 음성과 초상권 보호는 SAG-AFTRA 이후 특히 커지고 있다.</p>
<p><strong>전문화된 도구</strong> — 작은 팀을 위해 특별히 만들어진 AI. 사람이 키를 잡도록 설계된 것.</p>
<p><strong>더 똑똑한 라벨</strong> — &quot;Made with AI&quot;는 너무 거칠다. AI 보조 워크플로와 AI 생성 최종 에셋을 구분하는 흐름을 예상하라.</p>
<p><strong>갈라지는 관객</strong> — 어떤 플레이어는 일부러 전통적으로 만든 게임을 찾아 나선다. 다른 사람들은 신경조차 쓰지 않는다. 두 집단 모두 게임을 만들 만큼 충분히 크다.</p>
<p><strong>플랫폼 경쟁</strong> — 스토어가 투명성과 발견을 어떻게 다루는지가 진짜 차별점이 된다.</p>
<h2 id="실제로-상황을-앞으로-나아가게-하는-것" tabindex="-1">실제로 상황을 앞으로 나아가게 하는 것 <a class="header-anchor" href="#실제로-상황을-앞으로-나아가게-하는-것" aria-label="Permalink to &quot;실제로 상황을 앞으로 나아가게 하는 것&quot;"></a></h2>
<p>논쟁으로는 AI 문제가 정리되지 않는다. 정리하는 건 이것이다.</p>
<ol>
<li><strong>플레이어</strong>가 자신에게 진짜 중요한 것을 기준으로 고르는 것</li>
<li><strong>창작자</strong>가 자신이 어떻게 작업하는지 정직하게 밝히는 것</li>
<li><strong>플랫폼</strong>이 두 집단이 서로를 찾도록 돕는 도구를 만드는 것</li>
</ol>
<p>그게 포스트 AI 경제다. 서로 싸우는 진영이 아니라. 신뢰가 그 전체를 붙들어 준다.</p>
<hr>
<p><strong>관련 글:</strong></p>
<ul>
<li><a href="/ko/ai-content.html">AI 생성 콘텐츠 정책</a></li>
<li><a href="/ko/creators.html">게임 창작자를 위해</a></li>
<li><a href="/ko/faq.html">FAQ</a></li>
<li><a href="/ko/guides/frontier-gen-ai-models.html">프런티어 오픈소스 생성 AI 모델</a> — 구체적인 모델들과 그 작동 방식</li>
<li><a href="/ko/signals/2026-03-06-open-source-ai-pollution.html">오픈소스에는 AI 오염 문제가 있다</a> — AI 결과물이 오픈소스 프로젝트에 넘쳐날 때 벌어지는 일</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[취업 시장이 바뀌고 있다 — 학력에서 역량으로]]></title>
            <link>https://app.cinevva.com/ko/blog/2026-01-18-skills-over-degrees</link>
            <guid>https://app.cinevva.com/ko/blog/2026-01-18-skills-over-degrees</guid>
            <pubDate>Sun, 18 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[이제 기업의 90%가 학위보다 역량을 우선합니다. 기술과 게임 개발 분야에 진입하는 신입 졸업생에게 이것이 무엇을 의미하는지 살펴봅니다.]]></description>
            <content:encoded><![CDATA[<h1 id="취업-시장이-바뀌고-있다-—-학력에서-역량으로" tabindex="-1">취업 시장이 바뀌고 있다 — 학력에서 역량으로 <a class="header-anchor" href="#취업-시장이-바뀌고-있다-—-학력에서-역량으로" aria-label="Permalink to &quot;취업 시장이 바뀌고 있다 — 학력에서 역량으로&quot;"></a></h1>
<p><em>글쓴이 <a href="/ko/about.html">Oleg Sidorkin</a>, Cinevva CTO</em></p>
<p>저는 2023년에 사촌이 우등으로 졸업하는 걸 지켜봤습니다. 괜찮은 주립대학교의 컴퓨터공학 학위, 탄탄한 학점. 그는 일자리를 구하기까지 열네 달 동안 지원서를 넣었습니다. 반면 2학년 때 자퇴하고 인디 게임을 만들던 친구는 일자리를 찾기로 마음먹은 지 한 달 만에 세 군데에서 제안을 받았습니다.</p>
<p>이건 더 이상 예외가 아닙니다. 이게 패턴입니다.</p>
<h2 id="우리가-느껴온-것을-마침내-숫자가-따라잡았다" tabindex="-1">우리가 느껴온 것을 마침내 숫자가 따라잡았다 <a class="header-anchor" href="#우리가-느껴온-것을-마침내-숫자가-따라잡았다" aria-label="Permalink to &quot;우리가 느껴온 것을 마침내 숫자가 따라잡았다&quot;"></a></h2>
<p>2025년까지 **HR 책임자의 90%**가 전통적인 4년제 학위 밖에서 채용했다고 답했습니다 (<a href="https://fortune.com/2025/07/01/90-percent-hr-leaders-looking-to-hire-outside-of-traditional-college-degrees-as-they-prioritize-skills/" target="_blank" rel="noreferrer">Fortune</a>). 미국 기업의 4분의 1은 학사 학위 요건을 완전히 없앴습니다 (<a href="https://www.hrdive.com/news/employer-eliminate-degree-requirements-2025/748998/" target="_blank" rel="noreferrer">HR Dive</a>). 그리고 막 학자금 대출을 다 갚은 사람이라면 따끔하게 느껴질 대목이 있습니다. <strong>고용주의 94%는 역량 기반으로 채용한 사람이 학력으로 채용한 사람보다 더 좋은 성과를 낸다고 말합니다</strong> (<a href="https://www.forbes.com/sites/cynthiapong/2024/12/26/90-of-companies-make-better-hires-based-on-skills-over-degrees/" target="_blank" rel="noreferrer">Forbes</a>).</p>
<p>Verizon은 이제 자사 직무의 99%가 학위를 요구하지 않는다고 말합니다. Sergey Brin은 Google이 학사 학위 없는 사람들을 &quot;엄청나게&quot; 많이 채용한다고 인정했습니다. IBM은 &quot;New Collar&quot; 프로그램을 통해 미국 채용 공고의 절반을 학위 선택 사항으로 만들었습니다.</p>
<p>이건 기업이 자선을 베푸는 게 아닙니다. 학위가 누가 실제로 일을 잘할지를 예측하지 못한다는 사실을 깨달은 겁니다.</p>
<h2 id="옛-시스템이-무너진-이유" tabindex="-1">옛 시스템이 무너진 이유 <a class="header-anchor" href="#옛-시스템이-무너진-이유" aria-label="Permalink to &quot;옛 시스템이 무너진 이유&quot;"></a></h2>
<p>솔직한 답은 이렇습니다. 학위는 게으른 필터가 되어버렸습니다.</p>
<p>지원서가 400장 들어왔을 때 학사 학위를 요구하면 그 더미가 절반으로 줄어듭니다. 하지만 누가 실제로 일을 해낼 수 있는지는 알려주지 않습니다. 4년 동안 교실에 앉아 있을 돈과 시간, 그리고 가정의 안정을 가졌던 사람이 누구인지를 알려줄 뿐입니다. 학위와 능력의 상관관계는 우리가 인정한 척했던 것보다 항상 약했습니다.</p>
<p>그리고 이제 세 가지 일이 동시에 일어났습니다.</p>
<p><strong>역량이 너무 빠르게 움직였다.</strong> 게임 엔진, AI 도구, 웹 프레임워크. 커리큘럼 위원회가 어떤 주제에 관한 강의를 승인할 즈음이면 그건 이미 구식이 됩니다. 4년제 학위는 4년 전의 이론을 가르칩니다. 기술 분야에서 그건 까마득한 옛날이야기입니다.</p>
<p><strong>포트폴리오는 부정할 수 없게 됐다.</strong> GitHub를 볼 수 있는데 굳이 누군가 코딩을 할 수 있는지 추측할 이유가 있을까요? itch.io 페이지에 플레이어 리뷰가 달린 완성된 프로젝트가 다섯 개나 있는데, 그 사람이 게임을 출시할 수 있을지 궁금해할 이유가 있을까요?</p>
<p><strong>기업이 절박해졌다.</strong> 인재 부족은 실제 상황입니다. 학위 없는 사람을 모두 배제하면 정확히 당신이 필요로 하는 사람을 배제하게 됩니다. 일부 채용 담당자는 독학한 개발자가 학위를 가진 채용자들을 완전히 압도하는 걸 본 뒤에 이 사실을 어렵게 깨달았습니다.</p>
<h2 id="게임-업계는-이걸-미리-봤다" tabindex="-1">게임 업계는 이걸 미리 봤다 <a class="header-anchor" href="#게임-업계는-이걸-미리-봤다" aria-label="Permalink to &quot;게임 업계는 이걸 미리 봤다&quot;"></a></h2>
<p>게임 업계가 이 부분에서는 앞서 있었다고 생각합니다. 그 이유를 이해할 가치가 있습니다.</p>
<p>스튜디오는 당신이 어느 학교를 나왔는지 별로 신경 쓴 적이 없습니다. 무엇을 출시했는지를 신경 썼죠. 잘 다듬은 48시간 잼 게임 하나가 4년제 게임 디자인 학위보다 채용 담당자에게 더 많은 것을 말해줍니다. 압박 속에서 일을 끝낼 수 있다는 걸 증명합니다. 범위에 관한 어려운 결정을 내렸다는 걸 증명합니다. 그 게임이 이론에 그치지 않고 실제로 플레이할 수 있다는 걸 증명합니다.</p>
<p>2026년에 게임 업계에 진입하려 한다면 실제로 중요한 건 이것입니다 (<a href="https://www.dice.com/career-advice/aspiring-video-game-designers-in-2025-what-you-need-to-know" target="_blank" rel="noreferrer">Dice</a>, <a href="https://combinegr.com/2025-global-gaming-employment-outlook-trends-talent-strategy/" target="_blank" rel="noreferrer">CombineGR</a>). 잘 다듬은 플레이 가능한 데모 두세 개. 무엇을 왜 했는지 설명하는 사례 연구. 당신이 일을 끝낸다는 증거. 실제 프로젝트로 보여주는, 적어도 하나의 주요 엔진에 대한 능숙함.</p>
<p>채용 담당자는 잠재력을 찾는 게 아닙니다. 증거를 찾습니다.</p>
<h2 id="아무도-말하지-않는-불편한-부분" tabindex="-1">아무도 말하지 않는 불편한 부분 <a class="header-anchor" href="#아무도-말하지-않는-불편한-부분" aria-label="Permalink to &quot;아무도 말하지 않는 불편한 부분&quot;"></a></h2>
<p>연구를 파고들면서 저를 답답하게 만든 게 있습니다.</p>
<p>Harvard/Burning Glass 연구에 따르면 학위 요건을 없앤 기업들이 실제로는 학위 없는 지원자를 더 많이 채용하지는 않은 경우가 많았습니다. 증가폭은 약 3.5%포인트에 그쳤습니다 (<a href="https://www.forbes.com/sites/jenamcgregor/2024/02/14/companies-are-dropping-diploma-requirements-for-more-jobs-but-hiring-few-non-degreed-workers-to-fill-them/" target="_blank" rel="noreferrer">Forbes</a>). 정책은 바뀌었지만 채용 관행은 뒤처졌습니다.</p>
<p>비전통적인 경로로 간다면 여전히 더 열심히 해야 한다는 뜻입니다. 문은 예전보다 더 열려 있지만 아직 동등한 조건으로 들어가는 건 아닙니다. 당신의 포트폴리오는 부정할 수 없어야 합니다. 당신의 프로젝트가 다른 사람의 학력보다 더 크게 말해야 합니다.</p>
<p>공정하지 않습니다. 하지만 이걸 아는 것이 준비하는 데 도움이 됩니다.</p>
<h2 id="지금-막-시작하는-사람에게-해주고-싶은-말" tabindex="-1">지금 막 시작하는 사람에게 해주고 싶은 말 <a class="header-anchor" href="#지금-막-시작하는-사람에게-해주고-싶은-말" aria-label="Permalink to &quot;지금 막 시작하는 사람에게 해주고 싶은 말&quot;"></a></h2>
<p>학교에 다니고 있다면 그만두지 마세요. 다만 학위만으로는 더 이상 충분하지 않다는 걸 이해하세요. 틈틈이 무언가를 만드세요. 게임 잼에 참가하세요. <a href="https://grow.google/certificates/" target="_blank" rel="noreferrer">Google Career Certificate</a>나 Unity 인증을 받으세요. 학위를 여러 자격 중 하나로 여기되, 유일한 자격으로 여기지 마세요.</p>
<p>학위를 추구하지 않는다면 다른 길이지만 반드시 더 어려운 길은 아닙니다. 적극적으로 만드세요. 출시하세요. 모든 걸 기록하세요. 당신의 <a href="https://github.com" target="_blank" rel="noreferrer">GitHub</a>, 당신의 <a href="https://itch.io" target="_blank" rel="noreferrer">itch.io</a> 페이지, 당신의 개인 사이트. 그게 이제 당신의 자격입니다.</p>
<p>어느 쪽이든 자신의 작업을 설명하는 연습을 하세요. 무엇을 만들었는지뿐 아니라 왜 그런 선택을 했는지도요. 다시 한다면 무엇을 다르게 할지. 무엇을 배웠는지. 면접관은 자기 생각을 또렷하게 풀어내는 사람을 기억합니다.</p>
<h2 id="이건-채용보다-더-큰-이야기다" tabindex="-1">이건 채용보다 더 큰 이야기다 <a class="header-anchor" href="#이건-채용보다-더-큰-이야기다" aria-label="Permalink to &quot;이건 채용보다 더 큰 이야기다&quot;"></a></h2>
<p>지금 벌어지는 일은 단지 기업이 자리를 채우는 방식의 변화가 아닙니다. 우리가 다 함께 무엇을 가치 있게 여기는지에 대한 변화입니다.</p>
<p>수십 년 동안 학력은 필터 역할을 했습니다. 비싸고 시간이 많이 들지만 읽어내기 쉬웠죠. 누군가 학위를 가졌다면 어떤 것들을 가정할 수 있었습니다. 그건 직접적인 측정이 아니라 신호였지만 그래도 충분히 쓸만했습니다.</p>
<p>이제 그 신호가 무너지고 있습니다. 기술 덕분에 누군가 실제로 무엇을 할 수 있는지 볼 수 있게 됐습니다. 원격 근무는 어디에 앉아 있었느냐보다 결과물이 더 중요하다는 걸 증명했습니다. AI는 이론적 지식을 실무 적용보다 덜 가치 있게 만들고 있습니다.</p>
<p>전환이 어수선하더라도 저는 이것이 진심으로 희망적이라고 느낍니다. 예전 질문은 &quot;어디서 공부했나요?&quot;였습니다. 이제는 &quot;무엇을 만들 수 있나요?&quot;입니다.</p>
<p>그게 더 나은 질문입니다.</p>
<hr>
<h2 id="출처" tabindex="-1">출처 <a class="header-anchor" href="#출처" aria-label="Permalink to &quot;출처&quot;"></a></h2>
<ul>
<li><a href="https://fortune.com/2025/07/01/90-percent-hr-leaders-looking-to-hire-outside-of-traditional-college-degrees-as-they-prioritize-skills/" target="_blank" rel="noreferrer">Fortune: HR 책임자의 90%가 전통적 학위 밖에서 채용</a></li>
<li><a href="https://www.forbes.com/sites/cynthiapong/2024/12/26/90-of-companies-make-better-hires-based-on-skills-over-degrees/" target="_blank" rel="noreferrer">Forbes: 기업의 90%가 역량 기반으로 더 나은 채용 결정</a></li>
<li><a href="https://www.forbes.com/sites/jenamcgregor/2024/02/14/companies-are-dropping-diploma-requirements-for-more-jobs-but-hiring-few-non-degreed-workers-to-fill-them/" target="_blank" rel="noreferrer">Forbes: 학위 요건을 없애지만 학위 없는 인력은 거의 채용하지 않는 기업들</a></li>
<li><a href="https://www.hrdive.com/news/employer-eliminate-degree-requirements-2025/748998/" target="_blank" rel="noreferrer">HR Dive: 학위 요건을 없애는 고용주들</a></li>
<li><a href="https://www.computerworld.com/article/1623286/no-degree-no-problem-tech-firms-move-away-from-college-requirement-for-new-hires.html" target="_blank" rel="noreferrer">Computerworld: 신규 채용에서 대학 요건을 멀리하는 기술 기업들</a></li>
<li><a href="https://www.dice.com/career-advice/aspiring-video-game-designers-in-2025-what-you-need-to-know" target="_blank" rel="noreferrer">Dice: 2025년 게임 디자이너를 꿈꾸는 이들에게</a></li>
<li><a href="https://combinegr.com/2025-global-gaming-employment-outlook-trends-talent-strategy/" target="_blank" rel="noreferrer">CombineGR: 2025년 글로벌 게임 채용 전망</a></li>
</ul>
<hr>
<p><strong>관련 글:</strong></p>
<ul>
<li><a href="/ko/guides/game-jams-hackathons.html">게임 잼에서 성공하는 법</a></li>
<li><a href="/ko/guides/game-dev-courses.html">온라인 게임 개발 강좌</a> — 모든 예산에 맞는 역량 우선 학습 경로</li>
<li><a href="/ko/tutorials/agentic-code-tools.html">에이전트형 AI 코드 도구</a> — 어떤 역량이 중요한지를 다시 짜고 있는 도구들</li>
<li><a href="/ko/blog/2026-02-10-the-intuitive-mind.html">직관적인 마음</a> — 학력보다 직관이 더 중요한 이유</li>
</ul>
]]></content:encoded>
        </item>
    </channel>
</rss>