<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>유니티 Archives - 어제와 내일의 나 그 사이의 이야기</title>
	<atom:link href="https://lycos7560.com/tag/%EC%9C%A0%EB%8B%88%ED%8B%B0/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>생각의 흐름을 타고 다니며 만드는 블로그</description>
	<lastBuildDate>Wed, 14 Jan 2026 20:24:25 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://lycos7560.com/wp-content/uploads/2022/11/cropped-cropped-cropped-log-1-150x150-1-80x80.png</url>
	<title>유니티 Archives - 어제와 내일의 나 그 사이의 이야기</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Unity Netcode for Entities – Connecting server and clients</title>
		<link>https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/</link>
					<comments>https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Thu, 01 May 2025 06:21:00 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Unity]]></category>
		<category><![CDATA[client]]></category>
		<category><![CDATA[Client / Server worlds]]></category>
		<category><![CDATA[dtls]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[multiplayer]]></category>
		<category><![CDATA[Netcode]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[UDP]]></category>
		<category><![CDATA[WSS]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39997</guid>

					<description><![CDATA[<p>🔥 Connecting server and clients Netcode for Entities 1.5.0v https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/creating-multiplayer-gameplay.html 주제 설명 서버와 클라이언트 연결Connecting server and clients Netcode for Entities는 Unity Transport 패키지를 사용하여 연결을 관리합니다. 각 연결은 하나의 엔티티로 저장되며, 해당 엔티티는 NetworkStreamConnection 컴포넌트를 포함하고 있어, 연결에 사용되는 Transport 핸들을 참조합니다. 이 엔티티의 이름은 일반적으로 'NetworkConnection [nid]' 형식입니다. 상태 및 입력 동기화Synchronizing states [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/">Unity Netcode for Entities – Connecting server and clients</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-cbe7176c      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#connecting-server-and-clients" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Connecting server and clients</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#서버와-클라이언트-연결" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서버와 클라이언트 연결</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#명령-수신-대상-설정" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 명령 수신 대상 설정</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#게임-상태-진입" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 게임 상태 진입</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#연결-해제-요청" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 해제 요청</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#수신-버퍼-incoming-buffers" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 수신 버퍼 (Incoming Buffers)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#송신-버퍼-outgoing-buffers" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 송신 버퍼 (Outgoing Buffers)</a></li></ul><li class="uagb-toc__list"><a href="#연결-흐름-connection-flow" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 흐름 (Connection flow)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-수동-연결-리스닝-manually-listen-or-connect" class="uagb-toc-link__trigger">1&#x20e3; 수동 연결 / 리스닝 (Manually listen or connect )</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-autoconnectport-사용-using-theautoconnectport" class="uagb-toc-link__trigger">2&#x20e3; AutoConnectPort 사용 (Using the AutoConnectPort)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-networkstreamrequest로-연결-흐름-제어" class="uagb-toc-link__trigger">3&#x20e3; NetworkStreamRequest로 연결 흐름 제어</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-network-simulator" class="uagb-toc-link__trigger">4&#x20e3; Network simulator</a></li></ul><li class="uagb-toc__list"><a href="#클라이언트-연결-이벤트-수신" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클라이언트 연결 이벤트 수신</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-netcodeconnectionevents-on-the-client" class="uagb-toc-link__trigger">1&#x20e3; NetCodeConnectionEvents on the client</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-netcodeconnectionevents-on-the-server" class="uagb-toc-link__trigger">2&#x20e3; NetCodeConnectionEvents on the server</a></li></ul><li class="uagb-toc__list"><a href="#connection-approval" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Connection approval</a></li></ul></li><li class="uagb-toc__list"><a href="#연결-확인-sample-코드" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 확인 Sample 코드</a></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Connecting server and clients</h2>



<p><strong>Netcode for Entities 1.5.0v</strong></p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/creating-multiplayer-gameplay.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/creating-multiplayer-gameplay.html</a></p>



<figure class="wp-block-table"><table><thead><tr><th>주제</th><th>설명</th></tr></thead><tbody><tr><td><strong>서버와 클라이언트 연결</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-connection.html" target="_blank" rel="noreferrer noopener">Connecting server and clients</a></strong></td><td>Netcode for Entities는 Unity Transport 패키지를 사용하여 연결을 관리합니다. <br>각 연결은 하나의 엔티티로 저장되며, 해당 엔티티는 <code><strong>NetworkStreamConnection</strong></code> 컴포넌트를 포함하고 있어, 연결에 사용되는 Transport 핸들을 참조합니다. <br>이 엔티티의 이름은 일반적으로 <code><strong>'NetworkConnection [nid]'</strong></code> 형식입니다.</td></tr><tr><td><strong>상태 및 입력 동기화</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/synchronization.html" target="_blank" rel="noreferrer noopener">Synchronizing states and inputs</a></strong></td><td>Netcode는 고스트(ghost) 상태와 입력/명령을 동기화합니다. <br>이 항목에서는 지원되는 타입 목록과, 어떤 필드와 컴포넌트를 <strong>eventual consistency 모델</strong>을 통해 복제할지 표시하는 방법(마크업)을 설명합니다.</td></tr><tr><td><strong>시간 동기화</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/time-synchronization.html" target="_blank" rel="noreferrer noopener">Time synchronization</a></strong></td><td>Netcode는 <strong>서버 권한 모델(server authoritative model)</strong> 을 사용합니다. <br>서버는 고정된 시간 간격으로 시뮬레이션을 실행하며, 이 간격은 마지막 업데이트 이후 경과한 시간에 따라 결정됩니다. <br>따라서 <strong>클라이언트는 항상 서버 시간과 동기화되어야 이 모델이 제대로 작동</strong>합니다.</td></tr><tr><td><strong>보간 및 예측보간</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/interpolation.html" target="_blank" rel="noreferrer noopener">Interpolation and extrapolation</a></strong></td><td>게임에서 <strong>보간(interpolation)</strong> 및 <strong>예측보간(extrapolation)</strong> 을 사용하여, 불안정한 네트워크 환경에서도 부드러운 게임플레이 경험을 제공할 수 있습니다.</td></tr><tr><td><strong>예측</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/prediction.html" target="_blank" rel="noreferrer noopener">Prediction</a></strong></td><td>게임의 지연(latency)을 보완하기 위해 <strong>예측 로직</strong>을 사용할 수 있습니다. <br>예측은 클라이언트가 로컬에서 먼저 행동을 시뮬레이션하고, 이후 서버로부터 확정된 결과를 받는 방식입니다.</td></tr><tr><td><strong>물리</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/physics.html" target="_blank" rel="noreferrer noopener">Physics</a></strong></td><td><strong>Netcode 패키지는 Unity Physics와의 일부 통합 기능을 제공</strong>합니다. <br>이를 통해 네트워크 환경에서도 물리 기반 오브젝트를 보다 쉽게 사용할 수 있습니다. <br>이 통합 기능은 <strong>predicted ghosts</strong>와 <strong>interpolated ghosts</strong> 양쪽 모두에 대한 물리 처리를 지원합니다.</td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서버와 클라이언트 연결</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-connection.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-connection.html</a></p>



<p><strong>Netcode for Entities</strong>는 연결을 관리하기 위해 <strong>Unity Transport 패키지</strong>를 사용하며, 각 연결을 하나의 <strong>엔티티</strong>로 저장합니다.</p>



<p>이 엔티티는 <code>NetworkStreamConnection</code> 컴포넌트를 가지며, 연결에 사용된 <strong>Transport 핸들</strong>을 포함합니다. </p>



<p>연결이 종료되면(서버가 유저 연결을 끊거나 클라이언트가 요청한 경우) 이 엔티티는 삭제됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 명령 수신 대상 설정</h4>



<p><code>[AutoCommandTarget feature]</code>를 사용하지 않거나 더 세밀한 제어가 필요한 경우, <strong>CommandTarget</strong>을 설정해야 합니다. </p>



<p>이 설정은 클라이언트에서 받은 명령을 저장할 엔티티를 지정합니다. </p>



<p>이 엔티티 참조를 최신 상태로 유지하는 것은 게임 개발자의 책임입니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 게임 상태 진입</h4>



<p>게임은 <code>NetworkStreamInGame</code> 컴포넌트를 연결 엔티티에 수동으로 추가해야 합니다. 이 작업은 자동으로 이루어지지 않습니다. </p>



<p>이 컴포넌트가 추가되기 전에는 클라이언트가 명령을 전송하지 않으며, 서버도 스냅샷을 전송하지 않습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 해제 요청</h4>



<p>연결을 해제하려면 해당 엔티티에 <code>NetworkStreamRequestDisconnect</code> 컴포넌트를 추가하세요. </p>



<p>Transport 드라이버를 통한 <strong>직접적인 연결 해제는 지원되지 않습니다.</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 수신 버퍼 (Incoming Buffers)</h4>



<p>각 연결은 최대 3개의 수신 버퍼를 가질 수 있습니다:</p>



<ul class="wp-block-list">
<li>명령: <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingRpcDataStreamBuffer.html" target="_blank" rel="noreferrer noopener">IncomingRpcDataStreamBuffer</a></strong></code></li>



<li>RPC: <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingCommandDataStreamBuffer.html" target="_blank" rel="noreferrer noopener">IncomingCommandDataStreamBuffer</a></strong></code></li>



<li>스냅샷 (클라이언트 전용): <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingSnapshotDataStreamBuffer.html" target="_blank" rel="noreferrer noopener">IncomingSnapshotDataStreamBuffer</a></strong></code></li>
</ul>



<p>서버에서 클라이언트로 스냅샷이 전송되면 버퍼에 저장되고 나중에 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingSnapshotDataStreamBuffer.html" target="_blank" rel="noreferrer noopener"><strong>GhostReceiveSystem</strong></a></code>에 의해 처리됩니다.</p>



<p>RPC 및 명령도 동일한 방식으로 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamReceiveSystem.html"><strong>NetworkStreamReceiveSystem</strong></a></code>이 수집하고, 이후 각각의 시스템이 처리합니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서버는 <code>IncomingSnapshotDataStreamBuffer</code>를 가지지 않습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 송신 버퍼 (Outgoing Buffers)</h4>



<p>각 연결은 최대 2개의 송신 버퍼를 가질 수 있습니다:</p>



<ul class="wp-block-list">
<li>명령 (클라이언트 전용): <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.OutgoingRpcDataStreamBuffer.html" target="_blank" rel="noreferrer noopener">OutgoingRpcDataStreamBuffer</a></strong></code></li>



<li>RPC:<strong> <code>OutgoingRpcDataStreamBuffer</code></strong></li>
</ul>



<p>생성된 명령은 먼저 송신 버퍼에 저장되고, 클라이언트가 매 틱마다 이 버퍼를 전송합니다. </p>



<p>RPC도 마찬가지로 해당 송신 시스템이 버퍼에 인코딩하고, <code>RpcSystem</code>이 이를 묶어 MTU 단위로 전송합니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 흐름 (Connection flow)</h3>



<p>Netcode는 게임 시작 시 <strong>자동으로 서버 또는 클라이언트 연결을 설정하지 않습니다</strong>. </p>



<p>기본적으로 <code>ClientServerBootstrap</code>는 클라이언트와 서버 월드만 생성합니다. </p>



<p>연결 채널을 여는 방식은 개발자가 결정합니다.</p>



<p><strong>선택 가능한 방법:</strong></p>



<ul class="wp-block-list">
<li>1&#x20e3; <code><strong>NetworkStreamDriver</strong></code>를 사용하여 직접 <strong><code>Connect</code> </strong>또는 <strong><code>Listen</code> </strong>호출</li>



<li>2&#x20e3; <strong><code>AutoConnectPort</code> </strong>및 <strong><code>DefaultConnectAddress</code> </strong>설정</li>



<li><strong><code>NetworkStreamRequestConnect</code> </strong>및 <strong><code>NetworkStreamRequestListen</code> </strong>요청 엔티티 생성</li>
</ul>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 주의 </p>



<p>연결 중에는 반드시 <code>Application.runInBackground = true</code>로 설정해야 하며, 그렇지 않으면 <strong>포커스를 잃었을 때 연결이 끊길 수 있습니다.</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">1&#x20e3; 수동 연결 / 리스닝 (Manually listen or connect )</h4>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamDriver.html" target="_blank" rel="noreferrer noopener">NetworkStreamDriver</a></code> 싱글톤을 사용해 <code>Connect</code> 또는 <code>Listen</code> 메서드를 호출합니다. </p>



<p>코드 예시는 <a href="https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/NetcodeSamples/Assets/Samples/HelloNetcode/1_Basics/01_BootstrapAndFrontend/Frontend/Frontend.cs#L80" target="_blank" rel="noreferrer noopener">DOTS samples repository</a> 참고</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        public void StartClientServer(string sceneName)
        {
            Debug.Log($"[StartClientServer] Called with '{sceneName}'.");
            if (ClientServerBootstrap.RequestedPlayType != ClientServerBootstrap.PlayType.ClientAndServer)
            {
                Debug.LogError($"Creating client/server worlds is not allowed if playmode is set to {ClientServerBootstrap.RequestedPlayType}");
                return;
            }

            var server = ClientServerBootstrap.CreateServerWorld("ServerWorld");
            var client = ClientServerBootstrap.CreateClientWorld("ClientWorld");

            SceneManager.LoadScene("FrontendHUD");

            //Destroy the local simulation world to avoid the game scene to be loaded into it
            //This prevent rendering (rendering from multiple world with presentation is not greatly supported)
            //and other issues.
            DestroyLocalSimulationWorld();
            if (World.DefaultGameObjectInjectionWorld == null)
                World.DefaultGameObjectInjectionWorld = server;
            SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);

            var port = ParsePortOrDefault(Port.text);

            NetworkEndpoint ep = NetworkEndpoint.AnyIpv4.WithPort(port);
            {
                using var drvQuery = server.EntityManager.CreateEntityQuery(ComponentType.ReadWrite&lt;NetworkStreamDriver>());
                drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.RequireConnectionApproval = sceneName.Contains("ConnectionApproval", StringComparison.OrdinalIgnoreCase);
                drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.Listen(ep);
            }

            ep = NetworkEndpoint.LoopbackIpv4.WithPort(port);
            {
                using var drvQuery = client.EntityManager.CreateEntityQuery(ComponentType.ReadWrite&lt;NetworkStreamDriver>());
                drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.Connect(client.EntityManager, ep);
            }
        }</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">2&#x20e3; <strong>AutoConnectPort 사용 (Using the&nbsp;AutoConnectPort)</strong></h4>



<p><code>ClientServerBootstrap</code>  <a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html#Unity_NetCode_ClientServerBootstrap_AutoConnectPort" target="_blank" rel="noreferrer noopener"><code>AutoConnectPort</code></a>필드에는 서버와 클라이언트가 처음 설정될 때 각각 자동으로 수신하고 연결하도록 지시하는 데 사용할 수 있는 두 가지 특수 속성이 포함되어 있습니다.</p>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html#Unity_NetCode_ClientServerBootstrap_DefaultConnectAddress" target="_blank" rel="noreferrer noopener">DefaultConnectAddress</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html#Unity_NetCode_ClientServerBootstrap_DefaultListenAddress" target="_blank" rel="noreferrer noopener">DefaultListenAddress</a></li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class AutoConnectBootstrap : ClientServerBootstrap
{
    public override bool Initialize(string defaultWorldName)
    {
        AutoConnectPort = 7979;
        CreateDefaultClientServerWorlds();
        return true;
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>서버는 와일드카드 주소(<code>DefaultListenAddress:AutoConnectPort</code>)에서 리슨을 시작합니다. </p>



<p><code>DefaultConnectAddress</code>는 기본적으로 <code>NetworkEndpoint.AnyIpv4</code>로 설정되어 있습니다. </p>



<p>클라이언트는 서버 주소(<code>DefaultConnectAddress:AutoConnectPort</code>)로 연결을 시작하며, 이 <code>DefaultConnectAddress</code>는 기본적으로 <code>NetworkEndpoint.Loopback</code>으로 설정되어 있습니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>참고:</strong></p>



<p>에디터에서는 <strong>PlayMode 도구</strong>를 사용해 <code>AutoConnectAddress</code>와 <code>AutoConnectPort</code> 값을 오버라이드할 수 있습니다. </p>



<p>그러나 <strong><code>AutoConnectPort</code>를 0으로 설정한 경우</strong>에는 PlayMode 도구의 오버라이드 기능이 작동하지 않으며, 이 경우 <strong>수동으로 연결을 트리거해야 합니다.</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">3&#x20e3; <strong>NetworkStreamRequest로 연결 흐름 제어</strong></h4>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamDriver.html" target="_blank" rel="noreferrer noopener">NetworkStreamDriver</a></code>에서 직접 메서드를 호출하는 대신, 다음과 같은 싱글톤을 생성하여 연결 흐름을 제어할 수 있습니다:</p>



<ul class="wp-block-list">
<li><strong><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamRequestConnect.html" target="_blank" rel="noreferrer noopener">NetworkStreamRequestConnect</a></code> singleton&nbsp;</strong>: 원하는 서버 주소/포트로 연결을 요청할 때 사용합니다.</li>



<li><strong><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamRequestListen.html" target="_blank" rel="noreferrer noopener">NetworkStreamRequestListen</a></code> singleton&nbsp;</strong>: 서버가 원하는 주소/포트에서 리슨을 시작하도록 요청할 때 사용합니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 클라이언트 월드에서, NetworkStreamRequestConnect가 있는 새 엔티티 생성
// 이 엔티티는 이후 NetworkStreamReceiveSystem에 의해 처리됩니다.
var connectRequest = clientWorld.EntityManager.CreateEntity(typeof(NetworkStreamRequestConnect));
EntityManager.SetComponentData(connectRequest, new NetworkStreamRequestConnect { Endpoint = serverEndPoint });

// 서버 월드에서, NetworkStreamRequestListen이 있는 새 엔티티 생성
// 이 엔티티도 마찬가지로 NetworkStreamReceiveSystem에 의해 처리됩니다.
var listenRequest = serverWorld.EntityManager.CreateEntity(typeof(NetworkStreamRequestListen));
EntityManager.SetComponentData(listenRequest, new NetworkStreamRequestListen { Endpoint = serverEndPoint });
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>이러한 요청은 런타임에 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamReceiveSystem.html" target="_blank" rel="noreferrer noopener">NetworkStreamReceiveSystem</a></code>에 의해 소비되어 실제 연결 동작을 수행합니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>참고 :</strong></p>



<p>실행 중 오류가 발생하면 <strong>PlayMode Tools</strong> 창을 열고 다시 <strong>Play Mode</strong>로 진입해 보세요.</p>



<p>만약 월드가 이미 존재한다면, 부트스트랩 코드(위 설명 참조)에 의해 자동으로 월드가 생성되고 있을 가능성이 큽니다.</p>



<p>서버가 이미 리슨 중이거나 클라이언트가 이미 연결 중이라면, 자동 연결 기능이 이미 활성화되어 있는 것입니다.</p>



<p>이 경우 수동 연결 방식을 사용하려면 <strong>부트스트랩 코드에서 자동 연결을 비활성화</strong>해야 합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">4&#x20e3; <strong>Network simulator</strong></h4>



<p>Unity Transport는 <code><strong>SimulatorUtility</strong></code>를 제공합니다. </p>



<p>이 도구는 <strong>Netcode for Entities 패키지</strong>에 포함되어 있으며, 에디터 내에서 다음 경로를 통해 접근하고 설정할 수 있습니다:</p>



<p>Multiplayer &gt; PlayMode Tools</p>



<p>실제 네트워크 상황을 보다 현실적으로 반영하기 위해, 시뮬레이터를 활성화한 상태로 자주 게임플레이를 테스트해보는 것이 좋습니다.</p>



<figure class="wp-block-image size-full is-resized"><img fetchpriority="high" decoding="async" width="1261" height="990" src="https://lycos7560.com/wp-content/uploads/2025/05/image-6.png" alt="" class="wp-image-39999" style="width:838px;height:auto" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-6.png 1261w, https://lycos7560.com/wp-content/uploads/2025/05/image-6-300x236.png 300w, https://lycos7560.com/wp-content/uploads/2025/05/image-6-768x603.png 768w" sizes="(max-width: 1261px) 100vw, 1261px" /><figcaption class="wp-element-caption">PlayMode Tools</figcaption></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클라이언트 연결 이벤트 수신</h3>



<p><code>NetworkStreamDriver</code> 싱글톤을 통해 제공되는 <code>ConnectionEventsForTick</code> (형식: <code>NativeArray&lt;NetCodeConnectionEvent&gt;.ReadOnly</code>) 컬렉션을 사용하여, </p>



<p>클라이언트 및 서버에서 클라이언트 연결 이벤트를 반복(iterate)하면서 반응할 수 있습니다.</p>



<p>이 이벤트는 오직 <strong>단일 SimulationSystemGroup 틱 동안만 존재</strong>하며, 각각 <code>NetworkStreamConnectSystem</code>과 <code>NetworkStreamListenSystem</code>에서 초기화됩니다.</p>



<p>시스템이 위 시스템들의 job 이후에 실행되면, 같은 틱에서 발생한 이벤트를 수신하게 됩니다.</p>



<p>반면, 그 이전에 컬렉션을 조회하면 <strong>이전 틱의 값들을 반복</strong>하게 됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 예제 시스템
[UpdateAfter(typeof(NetworkReceiveSystemGroup))]
[BurstCompile]
public partial struct NetCodeConnectionEventListener : ISystem
{
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var connectionEventsForClient = SystemAPI.GetSingleton&lt;NetworkStreamDriver>().ConnectionEventsForTick;
        foreach (var evt in connectionEventsForClient)
        {
            UnityEngine.Debug.Log($"[{state.WorldUnmanaged.Name}] {evt.ToFixedString()}!");
        }
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의 :</strong></p>



<p>서버는 고정된 델타 타임으로 실행되기 때문에, <code>SimulationSystemGroup</code>은 각 렌더 프레임마다 <strong>0번 이상 실행</strong>될 수 있습니다.</p>



<p>따라서 <code>ConnectionEventsForTick</code>은 반드시 <code>SimulationSystemGroup</code> 내에서 실행되는 시스템 안에서만 읽어야 합니다.</p>



<p>예를 들어 <code>InitializationSystemGroup</code>, <code>PresentationSystemGroup</code>, 또는 어떤 MonoBehaviour 메서드 내에서 접근하면 다음과 같은 문제가 발생할 수 있습니다:</p>



<p>b) 시뮬레이션이 <strong>이 프레임에서 실행되지 않을 경우, 이벤트를 중복 수신</strong></p>



<p>a) 이전 틱 이벤트를 <strong>놓치고 현재 틱만 받음</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">1&#x20e3; NetCodeConnectionEvents on the client</h4>



<figure class="wp-block-table"><table><thead><tr><th>상태</th><th>호출 규칙</th></tr></thead><tbody><tr><td>Unknown</td><td>절대 발생하지 않음</td></tr><tr><td>Connecting</td><td>자신의 클라이언트에서 한 번 발생. <code>NetworkStreamReceiveSystem</code>이 <code>Connect</code> 호출을 인식한 시점 (호출 프레임 다음일 수 있음)</td></tr><tr><td>Handshake</td><td>내부 transport 드라이버가 <code>Connected</code> 상태에 진입하면 한 번 발생</td></tr><tr><td>Approval</td><td>연결 승인 기능이 활성화된 경우에만 발생. Handshake 이후</td></tr><tr><td>Connected</td><td>서버가 <code>NetworkId</code>를 보내면 발생</td></tr><tr><td>Disconnected</td><td>연결 종료 또는 타임아웃 또는 서버에 의해 연결 해제 시 발생. <code>DisconnectReason</code>이 설정됨</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의 :</strong></p>



<p>클라이언트는 다른 클라이언트의 이벤트를 수신하지 않습니다. 클라이언트 월드에서 발생한 이벤트는 <strong>자신의 클라이언트</strong>에 대한 이벤트뿐입니다.</p>



<p>Handshake 및 Approval 단계는 실패할 수 있으며, <code>ClientServerTickRate.HandshakeApprovalTimeoutMS</code> (기본값: 5000ms)의 타임아웃을 가집니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">2&#x20e3; NetCodeConnectionEvents on the server</h4>



<figure class="wp-block-table"><table><thead><tr><th>상태</th><th>호출 규칙</th></tr></thead><tbody><tr><td>Unknown</td><td>절대 발생하지 않음</td></tr><tr><td>Connecting</td><td>클라이언트가 연결을 시작하는 순간을 서버는 알 수 없으므로 발생하지 않음</td></tr><tr><td>Handshake</td><td>모든 클라이언트에 대해 발생. transport 연결이 수락되면 진입</td></tr><tr><td>Approval</td><td>승인 기능이 활성화된 경우에만 발생. Handshake 성공 후</td></tr><tr><td>Connected</td><td>클라이언트가 <code>NetworkId</code>를 부여받는 순간 발생</td></tr><tr><td>Disconnected</td><td>클라이언트가 연결 해제되거나 타임아웃되면 발생. <code>DisconnectReason</code> 설정됨</td></tr></tbody></table></figure>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의 :</strong></p>



<p>서버는 바인딩 성공이나 리스닝 시작에 대한 이벤트는 발생시키지 않습니다. <strong>기존 API를 통해 상태를 확인해야 합니다.</strong></p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Connection approval</h3>



<p>서버에서 각 클라이언트 연결에 대해 <strong>승인을 요구하도록 설정할 수 있습니다</strong>.</p>



<p>연결 승인은 다음과 같은 목적으로 사용됩니다:</p>



<ul class="wp-block-list">
<li>플레이어 편의성: 화이트리스트 / 블랙리스트, 비밀번호 보호된 서버 등</li>



<li>보안 검증: 매치메이킹 응답으로 받은 <strong>시크릿 토큰</strong>을 사용하여, 매치메이킹된 플레이어만 서버에 입장하도록 제한</li>
</ul>



<p>연결 승인이 활성화되면 다음과 같은 변경이 발생 :</p>



<ol class="wp-block-list">
<li>클라이언트는 <strong>Handshake</strong> 및 <strong>Approval</strong> 단계에서만 <code>IApprovalRpcCommand</code> 형식의 RPC를 서버에 전송할 수 있습니다.</li>



<li>모든 클라이언트는 <strong>Handshake</strong> 상태에서 곧바로 <strong>Connected</strong>로 넘어가는 것이 아니라 <strong>Approval</strong> 상태로 이동합니다.</li>



<li>서버는 연결된 각 클라이언트의 엔티티에 <strong><code>ConnectionApproved</code> 컴포넌트</strong>를 <strong>직접 추가</strong>해야만 승인됩니다.</li>



<li><code>NetworkId</code>는 <strong>승인 성공 이후</strong>에만 할당됩니다. 승인에 실패하면 클라이언트는 연결이 끊어집니다.</li>



<li>승인 과정에는 <strong>타임아웃</strong>이 존재합니다 (<code>ClientServerTickRate.HandshakeApprovalTimeoutMS</code> 참조, 기본값: 5000ms)</li>
</ol>



<p>다시 강조하면:</p>



<ul class="wp-block-list">
<li>Handshake 및 Approval 단계 동안, 클라이언트는 <strong>여러 개의 RPC 메시지를 보낼 수 있습니다.</strong></li>



<li>단, 이들 모두 <code>IApprovalRpcCommand</code> 타입이어야 합니다.</li>



<li>이 RPC의 payload에는 인증 토큰, 플레이어 정보 등 클라이언트의 유효성을 검증하기 위한 모든 정보를 담을 수 있습니다.</li>



<li>서버는 <code>ConnectionApproved</code> 컴포넌트를 클라이언트의 연결 엔티티에 추가함으로써 연결을 승인합니다. 이후 연결 흐름이 계속 진행됩니다.</li>
</ul>



<p><code>NetworkStreamDriver</code>에는 <code>RequireConnectionApproval</code> 필드가 있으며, <strong>클라이언트와 서버 모두에서 true로 설정</strong>해야 연결 승인 흐름이 올바르게 작동합니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:2px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">if (isServer)
{
    using var drvQuery = server.EntityManager.CreateEntityQuery(ComponentType.ReadWrite&lt;NetworkStreamDriver>());
    drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.RequireConnectionApproval = true;
    drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.Listen(ep);
}
else
{
    using var drvQuery = client.EntityManager.CreateEntityQuery(ComponentType.ReadWrite&lt;NetworkStreamDriver>());
    drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.RequireConnectionApproval = true;
    drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.Connect(client.EntityManager, ep);
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>연결 승인 처리도 다음과 같이 설정할 수 있습니다 : </p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// The approval RPC, here it contains a hypothetical payload the server will validate
public struct ApprovalFlow : IApprovalRpcCommand
{
    public FixedString512Bytes Payload;
}

// This is used to indicate we've already sent an approval RPC and don't need to do so again
public struct ApprovalStarted : IComponentData
{
}

[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
public partial struct ClientConnectionApprovalSystem : ISystem
{
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate&lt;RpcCollection>();
    }

    public void OnUpdate(ref SystemState state)
    {
        var ecb = new EntityCommandBuffer(Allocator.Temp);
        // Check connections which have not yet fully connected and send connection approval message
        foreach (var (connection, entity) in SystemAPI.Query&lt;RefRW&lt;NetworkStreamConnection>>().WithNone&lt;NetworkId>().WithNone&lt;ApprovalStarted>().WithEntityAccess())
        {
            var sendApprovalMsg = ecb.CreateEntity();
            ecb.AddComponent(sendApprovalMsg, new ApprovalFlow { Payload = "ABC" });
            ecb.AddComponent&lt;SendRpcCommandRequest>(sendApprovalMsg);

            ecb.AddComponent&lt;ApprovalStarted>(entity);
        }
        ecb.Playback(state.EntityManager);
    }
}

[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
public partial struct ServerConnectionApprovalSystem : ISystem
{
    public void OnUpdate(ref SystemState state)
    {
        var ecb = new EntityCommandBuffer(Allocator.Temp);
        // Check connections which have not yet fully connected and send connection approval message
        foreach (var (receiveRpc, approvalMsg, entity) in SystemAPI.Query&lt;RefRO&lt;ReceiveRpcCommandRequest>,RefRW&lt;ApprovalFlow>>().WithEntityAccess())
        {
            var connectionEntity = receiveRpc.ValueRO.SourceConnection;
            if (approvalMsg.ValueRO.Payload.Equals("ABC"))
            {
                ecb.AddComponent&lt;ConnectionApproved>(connectionEntity);

                // Destroy RPC message
                ecb.DestroyEntity(entity);
            }
            else
            {
                // Failed approval messages should be disconnected
                ecb.AddComponent&lt;NetworkStreamRequestDisconnect>(connectionEntity);
            }
        }
        ecb.Playback(state.EntityManager);
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 확인 Sample 코드</h2>



<p><a href="https://discussions.unity.com/t/lobby-relay-and-netcode-for-entities/1538817/8" target="_blank" rel="noreferrer noopener">https://discussions.unity.com/t/lobby-relay-and-netcode-for-entities/1538817/8</a></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>WorldManager.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System.Diagnostics.CodeAnalysis;
using Unity.Entities;

namespace Managers 
{
    public static class WorldManager 
    {
        private static World _clientWorld, _serverWorld;
		
        [SuppressMessage("ReSharper", "ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator")]
        public static void DestroyLocalSimulationWorld() {
            foreach (var world in World.All) {
                if (world.Flags != WorldFlags.Game) continue;
                world.Dispose();
                break;
            }
        }
		
        public static void RegisterServerWorld(World world) => _serverWorld = world;
        public static void RegisterClientWorld(World world) => _clientWorld = world;

        public static World GetServerWorld() => _serverWorld;
        public static World GetClientWorld() => _clientWorld;
    }
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>RelayServerDataHelper.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using Unity.Services.Relay.Models;

namespace Extension 
{
    public static class RelayServerDataHelper 
    {
        private static RelayServerData GetRelayData(List&lt;RelayServerEndpoint> endpoints, byte[] allocationIdBytes, byte[] connectionDataBytes, byte[] hostConnectionDataBytes, byte[] keyBytes) 
        {
            
            var endpoint = endpoints.FirstOrDefault(e => e.ConnectionType == "dtls") ?? throw new InvalidOperationException($"Endpoint for connectionType dtls not found");
            
            var server = NetworkEndpoint.Parse(endpoint.Host, (ushort)endpoint.Port);
    
            var allocationId = RelayAllocationId.FromByteArray(allocationIdBytes);
            var connData = RelayConnectionData.FromByteArray(connectionDataBytes);
            var hostData = RelayConnectionData.FromByteArray(hostConnectionDataBytes);
            var key = RelayHMACKey.FromByteArray(keyBytes);

            return new RelayServerData(ref server, 0, ref allocationId, ref connData, ref hostData, ref key, true); 
        }

        public static RelayServerData RelayData(JoinAllocation a) => GetRelayData(a.ServerEndpoints, a.AllocationIdBytes, a.ConnectionData, a.HostConnectionData, a.Key);

        public static RelayServerData RelayData(Allocation a) => GetRelayData(a.ServerEndpoints, a.AllocationIdBytes, a.ConnectionData, a.ConnectionData, a.Key);
    }
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>RelayInitializer.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System;
using System.Collections;
using System.Threading.Tasks;
using Unity.Entities;
using Unity.NetCode;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Relay;
using UnityEngine;
using Extension;

namespace Managers 
{
    public class RelayInitializer : MonoBehaviour 
    {
        private static RelayServerData? _relayServerData, _relayClientData;
        private static Action OnConnectionComplete;
        public static string _joinCode;
    
        // Singleton (without duplicate destroy logic) for access to the class instance from within the static methods
        private static RelayInitializer Instance { get; set; }
        protected void Awake() => Instance = this;
        
        // HOSTING

        public static void StartHost() => Instance.StartCoroutine(InitializeHost());

        private static IEnumerator InitializeHost() 
        {
            var initializeTask = UnityServices.InitializeAsync();
            while (!initializeTask.IsCompleted)
                yield return null;
            if (ProcessTaskFail(initializeTask, nameof(initializeTask)))
                yield break;

            var signInTask = Task.CompletedTask;
            if (!AuthenticationService.Instance.IsSignedIn) {
                signInTask = AuthenticationService.Instance.SignInAnonymouslyAsync();
                while (!signInTask.IsCompleted)
                    yield return null; 
            }
            
            if (ProcessTaskFail(signInTask, nameof(signInTask)))
                yield break;

            var allocationTask = RelayService.Instance.CreateAllocationAsync(5);
            
            while (!allocationTask.IsCompleted)
                yield return null;
            
            if (ProcessTaskFail(allocationTask, nameof(allocationTask)))
                yield break;

            var joinCodeTask = RelayService.Instance.GetJoinCodeAsync(allocationTask.Result.AllocationId);
            
            while (!joinCodeTask.IsCompleted)
                yield return null;
            
            if (ProcessTaskFail(joinCodeTask, nameof(joinCodeTask)))
                yield break;

            _joinCode = joinCodeTask.Result;

            try 
            {
                Debug.Log("Hosting relay data");
                _relayServerData = RelayServerDataHelper.RelayData(allocationTask.Result);
            } catch (Exception e) {
                Debug.LogException(e);
                _relayServerData = null;
                yield break;
            }

            Debug.Log("Success, players may now connect");
            while (_relayServerData == null || (!_relayServerData?.Endpoint.IsValid ?? false))
                yield return null;
                
            yield return JoinUsingCode(_joinCode);
            yield return WaitRelayConnection();
            SetupRelayHostedServerAndConnect();
        }

        private static void SetupRelayHostedServerAndConnect() 
        {
            if (ClientServerBootstrap.RequestedPlayType != ClientServerBootstrap.PlayType.ClientAndServer) 
            {
                UnityEngine.Debug.LogError($"Creating client/server worlds is not allowed if playmode is set to {ClientServerBootstrap.RequestedPlayType}");
                return;
            }

            var relayServerData = _relayServerData.GetValueOrDefault();
            var relayClientData = _relayClientData.GetValueOrDefault();

            var oldConstructor = NetworkStreamReceiveSystem.DriverConstructor;
            NetworkStreamReceiveSystem.DriverConstructor = new RelayDriverConstructor(relayServerData, relayClientData);
            var server = ClientServerBootstrap.CreateServerWorld("ServerWorld");
            WorldManager.RegisterServerWorld(server);
            var client = ClientServerBootstrap.CreateClientWorld("ClientWorld");
            WorldManager.RegisterClientWorld(client);
            NetworkStreamReceiveSystem.DriverConstructor = oldConstructor;

            

            WorldManager.DestroyLocalSimulationWorld();
            World.DefaultGameObjectInjectionWorld ??= server;

            // Load scene here if you want to.
            
            Debug.Log(_joinCode);

            var networkStreamEntity = server.EntityManager.CreateEntity(ComponentType.ReadWrite&lt;NetworkStreamRequestListen>());
            server.EntityManager.SetName(networkStreamEntity, "NetworkStreamRequestListen");
            server.EntityManager.SetComponentData(networkStreamEntity,
                new NetworkStreamRequestListen { Endpoint = NetworkEndpoint.AnyIpv4 });

            networkStreamEntity =
                client.EntityManager.CreateEntity(ComponentType.ReadWrite&lt;NetworkStreamRequestConnect>());
            client.EntityManager.SetName(networkStreamEntity, "NetworkStreamRequestConnect");
            client.EntityManager.SetComponentData(networkStreamEntity,
                new NetworkStreamRequestConnect { Endpoint = relayClientData.Endpoint });
            
            ProcessConnectionComplete();
        }

        // CONNECTING
    
        public static void ConnectByCode(string joinCode) => Instance.StartCoroutine(ProcessCodeConnection(joinCode));
    
        private static IEnumerator ProcessCodeConnection(string joinCode) 
        {
            Instance.StartCoroutine(JoinExternalServer(joinCode));
            yield return WaitRelayConnection();
            ConnectToRelayServer();
        }

        private static IEnumerator WaitRelayConnection() {
            while (_relayClientData == null || (!_relayClientData?.Endpoint.IsValid ?? false))
                yield return null;
        }
        
        private static IEnumerator JoinExternalServer(string joinCode) {
            Debug.Log("Waiting for relay response");
            var setupTask = UnityServices.InitializeAsync();

            while (!setupTask.IsCompleted)
                yield return null;
            
            var signInTask = Task.CompletedTask;
            if (!AuthenticationService.Instance.IsSignedIn) {
                signInTask = AuthenticationService.Instance.SignInAnonymouslyAsync();
                while (!signInTask.IsCompleted)
                    yield return null;
            }
            if (ProcessTaskFail(signInTask, nameof(signInTask)))
                yield break;

            yield return JoinUsingCode(joinCode);
        }

        private static IEnumerator JoinUsingCode(string joinCode) 
        {
            // Send the join request to the Relay service
            var joinTask = RelayService.Instance.JoinAllocationAsync(joinCode);
            while (!joinTask.IsCompleted)
                yield return null;
            
            if (ProcessTaskFail(joinTask, nameof(joinTask)))
                yield break;
            
            // Format the server data, based on desired connectionType
            try {
                _relayClientData = RelayServerDataHelper.RelayData(joinTask.Result);
            } catch (Exception e) 
            {
                Debug.LogException(e);
                _relayClientData = null;
            }

            _joinCode = joinCode;
        }
    
        private static void ConnectToRelayServer() 
        {
            var relayClientData = _relayClientData.GetValueOrDefault();
            
            var oldConstructor = NetworkStreamReceiveSystem.DriverConstructor;
            NetworkStreamReceiveSystem.DriverConstructor = new RelayDriverConstructor(new RelayServerData(), relayClientData);
            var client = ClientServerBootstrap.CreateClientWorld("ClientWorld");
            WorldManager.RegisterClientWorld(client);
            NetworkStreamReceiveSystem.DriverConstructor = oldConstructor;

            WorldManager.DestroyLocalSimulationWorld();
            World.DefaultGameObjectInjectionWorld ??= client;
        
            var networkStreamEntity =
                client.EntityManager.CreateEntity(ComponentType.ReadWrite&lt;NetworkStreamRequestConnect>());
            client.EntityManager.SetName(networkStreamEntity, "NetworkStreamRequestConnect");
            client.EntityManager.SetComponentData(networkStreamEntity,
                new NetworkStreamRequestConnect { Endpoint = relayClientData.Endpoint });
            ProcessConnectionComplete();
        }

        // COMMON
    
        private static bool ProcessTaskFail(Task task, string taskName) {
            if (!task.IsFaulted) return false;
            Debug.LogError($"Task {taskName} failed.");
            Debug.LogException(task.Exception);
            return true;
        }

        public static void SubscribeToConnectionComplete(Action handler) => OnConnectionComplete += handler;

        public static void ProcessConnectionComplete() {
            if (OnConnectionComplete == null)
                return;
            OnConnectionComplete?.Invoke();
            foreach (var handler in OnConnectionComplete?.GetInvocationList()!)
                OnConnectionComplete -= (Action)handler;
        }
    }

    public class RelayDriverConstructor : INetworkStreamDriverConstructor 
    {
        private RelayServerData _relayServerData, _relayClientData;
    
        public RelayDriverConstructor(RelayServerData serverData, RelayServerData clientData) {
            _relayServerData = serverData;
            _relayClientData = clientData;
        }

        public void CreateClientDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug) {
            var settings = DefaultDriverBuilder.GetNetworkSettings();
            settings.WithRelayParameters(ref _relayClientData);
            DefaultDriverBuilder.RegisterClientDriver(world, ref driverStore, netDebug, settings);
        }

        public void CreateServerDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug) =>
            DefaultDriverBuilder.RegisterServerDriver(world, ref driverStore, netDebug, ref _relayServerData);
    }
}</pre>
<p>The post <a href="https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/">Unity Netcode for Entities – Connecting server and clients</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity Netcode for Entities &#8211; Client / Server worlds</title>
		<link>https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/</link>
					<comments>https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Thu, 01 May 2025 00:50:19 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Unity]]></category>
		<category><![CDATA[client]]></category>
		<category><![CDATA[Client / Server worlds]]></category>
		<category><![CDATA[dtls]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[multiplayer]]></category>
		<category><![CDATA[Netcode]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[UDP]]></category>
		<category><![CDATA[WSS]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39993</guid>

					<description><![CDATA[<p>🔥 Client / Server worlds Setting Netcode for Entities 1.5.0v https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/set-up-client-server-worlds.html Netcode for Entities의 네트워킹 모델을 사용하여client 와 server를 설정합니다. ✅ 클라이언트 / 서버 World 네트워크 모델 https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/client-server-worlds.html Netcode for Entities는 Client와 Server의 로직을 각각 Client world와 Server world로 분리하여 처리합니다. 월드(World)는 Unity의 ECS(Entity Component System) 개념으로, 엔티티와 시스템을 시스템 그룹(SystemGroup)으로 구성한 단위입니다. 기본적인 Client [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/">Unity Netcode for Entities &#8211; Client / Server worlds</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-cbe7176c      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#client-server-worlds-setting" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server worlds Setting</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#클라이언트-서버-world-네트워크-모델" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클라이언트 / 서버 World 네트워크 모델</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#시스템-생성-및-업데이트-구성" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 시스템 생성 및 업데이트 구성</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-특정-시스템-그룹에-할당하기" class="uagb-toc-link__trigger">1&#x20e3; 특정 시스템 그룹에 할당하기</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-worldsystemfilter-사용" class="uagb-toc-link__trigger">2&#x20e3; WorldSystemFilter 사용</a></li></ul><li class="uagb-toc__list"><a href="#client-server-worlds-with-bootstrapping" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server worlds with bootstrapping</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#0-bootstrapping-커스터-마이징" class="uagb-toc-link__trigger">0&#x20e3; Bootstrapping 커스터 마이징</a></li></ul><li class="uagb-toc__list"><a href="#client-server-업데이트-주기" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server 업데이트 주기</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#성능-문제-방지" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 성능 문제 방지</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#프레임-속도-유지-방식-설정" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 프레임 속도 유지 방식 설정</a></li></ul><li class="uagb-toc__list"><a href="#월드-마이그레이션-world-migration" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 월드 마이그레이션 (World Migration)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#additional-resources" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2795.png" alt="➕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Additional resources</a></li></ul><li class="uagb-toc__list"><a href="#네트워크-프로토콜-검사" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 네트워크 프로토콜 검사</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#개발-중-발생할-수-있는-문제" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 개발 중 발생할 수 있는 문제</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#프로토콜-검사-해제" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 프로토콜 검사 해제</a></li></ul><li class="uagb-toc__list"><a href="#additional-resources" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2795.png" alt="➕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Additional resources</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server worlds Setting</h2>



<p><strong>Netcode for Entities 1.5.0v</strong></p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/set-up-client-server-worlds.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/set-up-client-server-worlds.html</a></p>



<p>Netcode for Entities의 네트워킹 모델을 사용하여client 와 server를 설정합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클라이언트 / 서버 World 네트워크 모델</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/client-server-worlds.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/client-server-worlds.html</a></p>



<p><strong>Netcode for Entities</strong>는 <strong>Client</strong>와 Server의 로직을 각각 <strong>Client world</strong>와 <strong>Server world</strong>로 분리하여 처리합니다.</p>



<p>월드(World)는 Unity의 <strong>ECS(Entity Component System)</strong> 개념으로, <strong>엔티티와 시스템을 시스템 그룹(SystemGroup)으로 구성한 단위</strong>입니다.</p>



<p>기본적인 Client / Server 월드 외에도, 개발 중에 게임을 테스트할 수 있도록 <strong>씬 클라이언트(Thin Client)</strong> 기능도 지원합니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 시스템 생성 및 업데이트 구성</h4>



<p>기본적으로, 모든 시스템은 클라이언트/서버 월드의 <code><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.SimulationSystemGroup.html" target="_blank" rel="noreferrer noopener"><code>SimulationSystemGroup</code></a></code>에서 생성되고 업데이트됩니다. </p>



<p>하지만 특정 시스템을 <strong>클라이언트에만</strong>, 또는 <strong>서버에만</strong> 작동하게 만들고 싶을 때는 다음 두 가지 방법을 사용할 수 있습니다</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading">1&#x20e3; 특정 시스템 그룹에 할당하기</h5>



<p>시스템이 속할 시스템 그룹을 지정하면, <strong>그 시스템 그룹이 존재하지 않는 월드에서는 자동으로 필터링</strong>됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[UpdateInGroup(typeof(GhostInputSystemGroup))]
public class MyInputSystem : SystemBase
{
  ...
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 참고: </p>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.PresentationSystemGroup.html" target="_blank" rel="noreferrer noopener"><code>PresentationSystemGroup</code></a></code>에 속한 시스템은 클라이언트 월드에서만 작동합니다. </p>



<p>Server / Thin client worlds에는 이 시스템 그룹이 생성되지 않기 때문입니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading">2&#x20e3; WorldSystemFilter 사용</h5>



<p>시스템이 어떤 월드에서 작동할지 더 세부적으로 설정하고 싶다면 <strong><code>WorldSystemFilter</code> </strong>속성을 사용하세요.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// WorldSystemFilterFlags 옵션 
// - LocalSimulation: 오프라인 로컬 시뮬레이션 (Netcode 시스템 없음)
// - ServerSimulation: 서버 시뮬레이션
// - ClientSimulation: 클라이언트 시뮬레이션
// - ThinClientSimulation: 씬 클라이언트
// 속성을 지정하지 않으면, 기본적으로 시스템은 상위 그룹의 필터링 규칙을 따릅니다 (WorldSystemFilterFlags.Default)

[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
public class MySystem : SystemBase
{
  ...
}</pre>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server worlds with bootstrapping</h4>



<p><strong>Netcode for Entities</strong>를 프로젝트에 추가하면, 기본 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html" target="_blank" rel="noreferrer noopener"><code>ClientServerBootstrap</code></a></code> 클래스가 제공됩니다. </p>



<p>이 클래스는 <strong>게임 시작 시 클라이언트 및 서버 월드를 자동 생성</strong>합니다</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public virtual bool Initialize(string defaultWorldName)
{
    CreateDefaultClientServerWorlds();
    return true;
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>자동 부트스트래핑은 <strong>에디터에서 Play 모드 진입 시 매우 유용</strong>합니다. </p>



<p>하지만, <strong>실제 게임에서는 메인 메뉴와 같은 전처리 과정이 필요</strong>하므로 <strong>월드 생성을 지연</strong>시키거나 수동 제어할 필요가 있습니다.</p>



<p>예를 들어</p>



<ul class="wp-block-list">
<li>&#8220;클라이언트-호스트 서버 실행&#8221; → <strong>서버</strong>와 <strong>클라이언트</strong> 모두 생성</li>



<li>&#8220;전용 서버에 접속&#8221; → <strong>클라이언트</strong>만 생성</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading">0&#x20e3; Bootstrapping 커스터 마이징</h5>



<p>기본 <code>ClientServerBootstrap</code>을 상속하여 원하는 방식으로 월드 생성을 제어할 수 있습니다</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class MyGameSpecificBootstrap : ClientServerBootstrap
{
    public override bool Initialize(string defaultWorldName)
    {
        // Netcode 없이 로컬 시뮬레이션 월드만 생성
        CreateLocalWorld(defaultWorldName);
        return true;
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>버튼 클릭 등의 타이밍에 다음을 호출하여 월드 생성:</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var clientWorld = ClientServerBootstrap.CreateClientWorld();
var serverWorld = ClientServerBootstrap.CreateServerWorld();

AutomaticThinClientWorldsUtility.NumThinClientsRequested = 10;
AutomaticThinClientWorldsUtility.BootstrapThinClientWorlds();

ClientServerBootstrap.CreateDefaultClientServerWorlds();
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Netcode Sample  <a href="https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/NetcodeSamples/README.md" target="_blank" rel="noreferrer noopener">https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/NetcodeSamples/README.md</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server 업데이트 주기</h4>



<p>Netcode for Entities를 사용할 때, 서버는 항상 <strong>Fixed Timestep</strong>으로 업데이트됩니다.</p>



<p>이는 클라이언트 예측을 위한 기본적인 결정론 수준을 보장하고(엄격한 결정론은 아니지만), 물리 시스템의 안정성과 프레임 레이트 독립성을 보장하기 위함입니다.</p>



<p>또한 이 패키지는 프레임당 최대 Fixed Step 반복 횟수를 제한하여 서버가 단일 프레임을 시뮬레이션하는 데 몇 초가 걸리는 상태에 빠지지 않도록 합니다.</p>



<p>중요한 점은 서버의 고정 업데이트가 <a href="https://docs.unity3d.com/Manual/class-TimeManager.html"><strong>표준 Unity 업데이트 빈도</strong></a>&nbsp;또 <strong>Unity 물리 시스템의 Fixed Timestep</strong>를 사용하지 않는다는 것입니다. </p>



<p><strong>대신 자체적인 <code>ClientServerTickRate.SimulationTickRate</code> 를 사용합니다. </strong>&#8211; 고정된 틱(tick) 간격</p>



<p>(이것은 <code>Unity.Physics</code>가 사용 중이라면 정수 배수여야 합니다. <code>ClientServerTickRate.PredictedFixedStepSimulationTickRatio</code>를 참조하세요)</p>



<p>그러나 클라이언트는 동적 타임스텝으로 업데이트됩니다. </p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/intro-to-prediction.html" target="_blank" rel="noreferrer noopener">예측 코드만 예외</a>로, 이는 항상 서버와 동일한 고정 타임스텝으로 실행되어 두 시뮬레이션 간의 결정론적 관계를 유지하려고 합니다.</p>



<p>전체 틱과 동기화되지 않은 리프레시 레이트에 대한 예측 처리 방법을 이해하려면 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/intro-to-prediction.html#partial-ticks" target="_blank" rel="noreferrer noopener">부분 틱</a>을 참조하세요.</p>



<p>설정 예시:</p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.ClientServerTickRate.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.ClientServerTickRate.html</a></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class MyCustomClientServerBootstrap : ClientServerBootstrap
{
   override public void Initialize(string defaultWorld)
   {
       base.Initialise(defaultWorld);
       var customTickRate = new ClientServerTickRate();
       //run at 30hz
       customTickRate.simulationTickRate = 30;
       customTickRate.ResolveDefault();
       foreach(var world in World.All)
       {
           if(world.IsServer())
           {
              // 이 경우 서버에서만 생성되지만 클라이언트 세계에서도 동일한 작업을 수행할 수 있습니다
              var tickRateEntity = world.EntityManager.CreateSingleton(new ClientServerTickRate
              {
                  SimulationTickRate = 30;
              });
           }
       }
   }
}


// SimulationTickRate = 초당 몇 번의 시뮬레이션 틱을 실행할지 설정합니다. 기본값은 초당 60 틱입니다.
// NetworkTickRate = 서버가 클라이언트에게 스냅샷(snapshot)을 전송하는 빈도를 설정합니다. 기본값은 SimulationTickRate와 동일합니다.</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 성능 문제 방지</h5>



<p>서버가 설정된 시뮬레이션 틱 레이트보다 <strong>느린 속도로 업데이트될 경우</strong>, 한 프레임에서 여러 개의 시뮬레이션 틱을 처리하려고 시도합니다.</p>



<p>예를 들어, 서버의 마지막 업데이트가 16ms가 아닌 50ms가 걸렸다면, 서버는 다음 프레임에서 이를 따라잡기 위해 약 <strong>3번의 시뮬레이션 스텝</strong>을 실행합니다 (16ms × 3 ≈ 50ms).</p>



<p>이러한 동작은 <strong>성능 저하를 악화시키는 악순환</strong>을 유발할 수 있습니다:</p>



<p>서버는 더 많은 시뮬레이션 스텝을 처리해야 하므로 점점 더 느려지고, 그 결과 틱 간격을 더 많이 놓치게 됩니다.</p>



<p>위와 같은 상황을 방지하기 위해 <code>ClientServerTickRate</code>에서는 다음과 같은 설정을 제공합니다</p>



<ul class="wp-block-list">
<li><code>MaxSimulationStepsPerFrame</code><br>서버가 한 프레임 내에 수행할 수 있는 <strong>최대 시뮬레이션 스텝 수</strong>를 제한합니다.</li>



<li><code>MaxSimulationStepBatchSize</code><br>여러 틱을 <strong>하나의 배치(batch)</strong> 로 묶어 처리하도록 지시합니다. <br>이때는 <strong>델타 타임(delta time)을 곱한 값</strong>으로 단일 스텝을 실행합니다.<br>예: 2개의 스텝을 실행하는 대신, <strong>1개의 스텝</strong>만 실행하되 <strong>델타 타임을 2배</strong>로 설정하여 처리합니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6ab.png" alt="🚫" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의</strong>: <br><code>MaxSimulationStepBatchSize</code> 에 의한 배칭 처리는 특정 조건에서만 작동하며, 자체적인 제한 사항이 있습니다.<br>게임 로직에서 &#8220;<strong>한 시뮬레이션 스텝 = 하나의 틱</strong>&#8220;이라고 가정하지 않도록 하며, <code>TimeData.DeltaTime</code> 값을 <strong>하드코딩하지 마십시오</strong>.<br>배칭이 발생하면 <strong>서버와 클라이언트 간의 시뮬레이션 정밀도가 달라져 예측 오류</strong>가 발생할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 프레임 속도 유지 방식 설정</h5>



<p>서버가 유휴 상태일 때 <strong>프레임 속도를 어떻게 유지할지</strong>도 설정할 수 있습니다. </p>



<p><code>TargetFrameRateMode</code>는 서버가 틱 레이트를 유지하기 위한 <strong>유휴 시간 소비 방식</strong>을 제어합니다.</p>



<ul class="wp-block-list">
<li><strong><code>BusyWait</code></strong><br>가능한 한 빠른 속도로 계속 실행 (CPU 사용량 높음)</li>



<li><strong><code>Sleep</code></strong><br><code>Application.targetFrameRate</code>에 맞춰 대기하여 CPU 부하를 줄임</li>



<li><strong><code>Auto</code></strong><br>헤드리스(콘솔 없는) 서버에서는 <code>Sleep</code>을 사용하고, 그 외에는 <code>BusyWait</code>을 사용</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 월드 마이그레이션 (World Migration)</h4>



<p>현재 사용 중인 월드를 <strong>파괴(destroy)</strong> 하고, <strong>연결 상태를 유지한 채로 새로운 월드로 전환</strong>하고자 할 경우, <code>DriverMigrationSystem</code>을 사용할 수 있습니다.</p>



<p>이 시스템은 네트워크 전송(transport) 관련 정보를 저장 및 불러올 수 있게 해주며, <strong>매끄러운 월드 전환</strong>을 가능하게 합니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public World MigrateWorld(World sourceWorld)
{
    DriverMigrationSystem migrationSystem = default;
    foreach (var world in World.All)
    {
        if ((migrationSystem = world.GetExistingSystem&lt;DriverMigrationSystem>()) != null)
            break;
    }

    var ticket = migrationSystem.StoreWorld(sourceWorld);
    sourceWorld.Dispose();

    var newWorld = migrationSystem.LoadWorld(ticket);

    // NOTE: LoadWorld는 반드시 새 월드에 필요한 시스템을 추가하기 전에 호출해야 합니다!
    // 이유: LoadWorld는 NetworkStreamReceiveSystem이 올바른 드라이버를 불러오기 위해 필요한 
    // `MigrationTicket` 컴포넌트를 생성하기 때문입니다.

    return ClientServerBootstrap.CreateServerWorld(DefaultWorld, newWorld.Name, newWorld);
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p>이 기능은 예를 들어 <strong>로비에서 인게임으로 넘어가거나</strong>, <strong>씬을 바꾸면서도 연결을 유지해야 하는 경우</strong>에 매우 유용합니다.</p>



<h4 class="wp-block-heading" id="additional-resources"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2795.png" alt="➕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Additional resources</h4>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/manual/index.html" target="_blank" rel="noreferrer noopener">Entities overview</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/thin-clients.html" target="_blank" rel="noreferrer noopener">Thin clients</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/intro-to-prediction.html" target="_blank" rel="noreferrer noopener">Introduction to prediction</a></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 네트워크 프로토콜 검사</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-protocol-checks.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-protocol-checks.html</a></p>



<p>클라이언트가 서버에 연결할 때, <strong>Netcode 프로토콜 버전(NetworkProtocolVersion)</strong> 을 주고받습니다. </p>



<p>이 프로토콜에는 다음과 같은 정보가 포함되어 있습니다:</p>



<ul class="wp-block-list">
<li>Netcode 버전 (netcode version)</li>



<li>게임 버전 (game version)</li>



<li>RPC 컬렉션 (RPC collection)</li>



<li>직렬화된 컴포넌트 컬렉션 (erialized component collections)</li>
</ul>



<p>서로 호환되지 않는 게임 버전 간의 연결을 <strong>사전에 차단</strong>하여 예측할 수 없는 동작을 방지합니다.</p>



<p> <strong>RPC 컬렉션</strong>은 모든 로드된 어셈블리에서 컴파일된 RPC들의 <strong>타입과 멤버</strong>를 기반으로 해시를 계산합니다.</p>



<p><strong>Serialized Component 컬렉션</strong> 역시 Netcode for Entities가 수집한 고스트(Ghost) 컴포넌트를 기반으로 해시를 계산합니다.</p>



<p>이러한 타입 정보와 멤버들을 기반으로 계산된 <strong>해시값</strong>이 프로토콜의 일부로 사용됩니다.</p>



<p>Netcode for Entities는 기본적으로 이 해시값이 <strong>완전히 동일해야</strong> 통신이 가능하도록 설정되어 있습니다.</p>



<p>이렇게 하면 중간에 <strong>예외가 발생하는 것을 방지</strong>하고, <strong>대역폭 최적화</strong>가 가능합니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 개발 중 발생할 수 있는 문제</h4>



<p>개발 중에는 <strong>호환 가능한 빌드조차도</strong> 이 검사 때문에 <strong>부적합한 버전으로 잘못 판단되는</strong> 경우가 있습니다.</p>



<p>예를 들어:</p>



<ul class="wp-block-list">
<li>독립 실행형 빌드와 Unity Editor에서 실행 중인 월드를 연결하려는 경우</li>



<li>Editor는 테스트용 어셈블리를 포함하고 있는데, 빌드에는 포함되어 있지 않을 경우</li>



<li>이로 인해 해시가 일치하지 않아 연결이 끊어짐</li>
</ul>



<p>이러한 <strong>엄격한 프로토콜 검사</strong>는 개발 중 테스트에 방해가 될 수 있으므로, <strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-protocol-checks.html#disabling-the-check" target="_blank" rel="noreferrer noopener">비활성화</a>할 수 있습니다.</strong></p>



<p>이 프로토콜 버전 오류가 발생하면 각 피어는 사용자 코드가 읽을 수 있는 를 통해 원격 피어와의 연결을 끊고&nbsp;</p>



<p><code>NetworkStreamDisconnectReason.BadProtocolVersion</code>, 이를 사용하여 플레이어에게 해당 빌드가 대상 원격 피어와 호환되지 않음을 알립니다. </p>



<p>개발 빌드에서는 패키지가 로컬 피어에 로드된 RPC 및 고스트 유형의 전체 목록과 정렬된 목록을 나타내는 오류 로그도 출력합니다. </p>



<p>유형 불일치 문제를 해결하려면 이러한 로그를 원격 피어에서 발생한 로그와 상호 참조하세요.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>프로토콜 검사</strong> 해제</h5>



<p>검사를 비활성화하려면, 다음과 같이 <code>RpcCollection.DynamicAssemblyList</code>를 <code>true</code>로 설정합니다:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[BurstCompile] // 선택 사항
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
[UpdateInGroup(typeof(InitializationSystemGroup))]
[CreateAfter(typeof(RpcSystem))]
public partial struct SetRpcSystemDynamicAssemblyListSystem : ISystem
{
    public void OnCreate(ref SystemState state)
    {
        SystemAPI.GetSingletonRW&lt;RpcCollection>().ValueRW.DynamicAssemblyList = true;
        state.Enabled = false;
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6ab.png" alt="🚫" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의</strong>: </p>



<p>이 설정은 <code>RpcSystem.OnUpdate</code>가 실행되기 전에 적용되어야 하며,</p>



<p><code>RpcSystem.OnCreate</code> 이후에 설정되어야 합니다.</p>



<p><strong>클라이언트와 서버 모두 이 플래그 값을 동일하게 설정해야</strong> 연결이 가능합니다. (값이 다르면 프로토콜 해석 방식이 달라지기 때문)</p>



<p>이 기능을 활성화하면 다음과 같은 단점이 있습니다:</p>



<ul class="wp-block-list">
<li>각 RPC마다 <strong>6바이트의 오버헤드</strong>가 발생합니다 (ushort 인덱스 대신 해시값 전체를 전송)</li>



<li>게임 도중, 클라이언트가 <strong>알 수 없는 RPC나 고스트 타입을 수신</strong>하게 되면<br>→ 런타임 오류 발생 후 <strong>즉시 연결이 끊어짐</strong><br>→ 즉, 연결 시점이 아닌 게임 중간에 강제 종료될 수 있습니다</li>
</ul>



<p>따라서 이 설정은 <strong>개발 중 테스트 목적</strong>으로 사용하는 것이 좋으며, <strong>출시용 빌드에서는 권장되지 않습니다.</strong></p>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2795.png" alt="➕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Additional resources</h4>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.NetworkProtocolVersion.html" target="_blank" rel="noreferrer noopener">NetworkProtocolVersion API</a></li>
</ul>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/">Unity Netcode for Entities &#8211; Client / Server worlds</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>IInputComponentData [Netcode for Entities]</title>
		<link>https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/</link>
					<comments>https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sun, 27 Apr 2025 06:33:37 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[client]]></category>
		<category><![CDATA[Client / Server worlds]]></category>
		<category><![CDATA[compress]]></category>
		<category><![CDATA[connect]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[dtls]]></category>
		<category><![CDATA[ECS]]></category>
		<category><![CDATA[Entities]]></category>
		<category><![CDATA[Entity]]></category>
		<category><![CDATA[IComponentData]]></category>
		<category><![CDATA[IInputComponentData]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[multiplayer]]></category>
		<category><![CDATA[Netcode]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[NFE]]></category>
		<category><![CDATA[online]]></category>
		<category><![CDATA[Quantization]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[UDP]]></category>
		<category><![CDATA[WSS]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[양자]]></category>
		<category><![CDATA[양자화]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39970</guid>

					<description><![CDATA[<p>🔍 IInputComponentData https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.IInputComponentData.html Netcode for Entities (NFE)에서 클라이언트의 입력을 서버로 전송하기 위해 특별히 설계된 인터페이스 IInputComponentData의 핵심 역할 1️⃣ 입력 데이터의 네트워크 동기화 2️⃣ 예측(Prediction) 시스템 지원 3️⃣ 입력 버퍼링 ✍🏻예시 코드 ❓[GhostField(Quantization = 100)] 양자화를 사용하는 이유 Netcode for Entities (NFE)에서&#160;네트워크 대역폭을 최적화하기 위해 사용되는 핵심 기능 1️⃣ 데이터 압축으로 대역폭 절감 2️⃣ 네트워크 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/">IInputComponentData [Netcode for Entities]</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-ab9c0ba8      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#iinputcomponentdata" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> IInputComponentData</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#iinputcomponentdata의-핵심-역할" class="uagb-toc-link__trigger">IInputComponentData의 핵심 역할</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-입력-데이터의-네트워크-동기화" class="uagb-toc-link__trigger">1&#x20e3; 입력 데이터의 네트워크 동기화</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-예측prediction-시스템-지원" class="uagb-toc-link__trigger">2&#x20e3; 예측(Prediction) 시스템 지원</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-입력-버퍼링" class="uagb-toc-link__trigger">3&#x20e3; 입력 버퍼링</a></li></ul><li class="uagb-toc__list"><a href="#예시-코드" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270d-1f3fb.png" alt="✍🏻" class="wp-smiley" style="height: 1em; max-height: 1em;" />예시 코드</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ghostfieldquantization-100-양자화를-사용하는-이유" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" />[GhostField(Quantization = 100)] 양자화를 사용하는 이유</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-데이터-압축으로-대역폭-절감" class="uagb-toc-link__trigger">1&#x20e3; 데이터 압축으로 대역폭 절감</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-네트워크-지연-감소" class="uagb-toc-link__trigger">2&#x20e3; 네트워크 지연 감소</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-작동-원리" class="uagb-toc-link__trigger">3&#x20e3; 작동 원리</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-간단-적용-예시" class="uagb-toc-link__trigger">4&#x20e3; 간단 적용 예시</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#5-최적화-가이드" class="uagb-toc-link__trigger">5&#x20e3; 최적화 가이드</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#6-주의사항" class="uagb-toc-link__trigger">6&#x20e3; 주의사항</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#7-성능비교" class="uagb-toc-link__trigger">7&#x20e3; 성능비교</a></li></ul></li></ul><li class="uagb-toc__list"><a href="#iinputcomponentdata-와-icomponentdata의-차이점" class="uagb-toc-link__trigger">IInputComponentData 와 IComponentData의 차이점</a></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <code>IInputComponentData</code></h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.IInputComponentData.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.IInputComponentData.html</a></p>



<p><strong>Netcode for Entities (NFE)</strong>에서 클라이언트의 입력을 서버로 전송하기 위해 특별히 설계된 인터페이스</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><strong><code>IInputComponentData</code>의 핵심 역할</strong></h3>



<h4 class="wp-block-heading"><strong>1&#x20e3; 입력 데이터의 네트워크 동기화</strong></h4>



<ul class="wp-block-list">
<li><strong>클라이언트 → 서버</strong>로의 입력 전송을 최적화합니다.</li>



<li>NFE는 이 인터페이스가 붙은 컴포넌트를 자동으로 직렬화/역직렬화합니다.</li>
</ul>



<h4 class="wp-block-heading"><strong>2&#x20e3; 예측(Prediction) 시스템 지원</strong></h4>



<ul class="wp-block-list">
<li><strong>클라이언트 측 예측</strong>과&nbsp;<strong>서버 측 보정</strong>을 가능하게 합니다.</li>



<li><code>GhostPredictionSystemGroup</code>에서 특별 처리됩니다.</li>
</ul>



<h4 class="wp-block-heading"><strong>3&#x20e3; 입력 버퍼링</strong></h4>



<ul class="wp-block-list">
<li>틱(tick) 기반으로 입력을 저장해&nbsp;<strong>네트워크 지연 보정</strong>에 사용됩니다.</li>
</ul>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270d-1f3fb.png" alt="✍🏻" class="wp-smiley" style="height: 1em; max-height: 1em;" /><strong>예시 코드</strong></h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Unity.Entities;
using Unity.NetCode;

// 반드시 IInputComponentData를 상속해야 함
public struct NetcodePlayerInput : IInputComponentData
{
    // 필드에 [GhostField] 속성을 추가해 직렬화 옵션 지정
    [GhostField(Quantization = 100)] // 값 범위: -1.0 ~ 1.0 → -100 ~ 100으로 압축
    public float MoveX; // 좌우 이동 입력 (-1: 왼쪽, 1: 오른쪽)

    [GhostField]
    public float MoveY; // 전후 이동 입력

    [GhostField]
    public InputEvent Jump; // 점프 입력 (버튼 상태)

    // 현재 틱 정보 (NFE가 자동으로 주입)
    public uint Tick { get; set; }
}</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" />[GhostField(Quantization = 100)] 양자화를 사용하는 이유</h4>



<p>Netcode for Entities (NFE)에서&nbsp;<strong>네트워크 대역폭을 최적화</strong>하기 위해 사용되는 핵심 기능</p>



<h5 class="wp-block-heading"><strong><strong>1&#x20e3;</strong> 데이터 압축으로 대역폭 절감</strong></h5>



<ul class="wp-block-list">
<li><strong>원본 데이터</strong>:&nbsp;<code>float</code>&nbsp;(32비트)</li>



<li><strong>양자화 후</strong>:&nbsp;<code>short</code>&nbsp;(16비트) 등 작은 타입으로 변환</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[GhostField(Quantization = 100)] 
public float MoveX; // -1.0 ~ 1.0 → -100 ~ 100 정수로 압축
// 1.75f → 175 (전송) : 수신 측에서 1.75f로 복원</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong><strong>2&#x20e3;</strong> 네트워크 지연 감소</strong></h5>



<p>작은 데이터 패킷으로 통신하여&nbsp;<strong>전송 시간 단축</strong>하여 <strong>실시간 반응성 향상</strong> (지연 시간 감소)</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong><strong>3&#x20e3;</strong> <strong><strong>작동 원리</strong></strong></strong></h5>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>원본 값</th><th>양자화 계수</th><th>송신 값</th><th>복원 값</th><th>오차</th></tr></thead><tbody><tr><td>0.73f</td><td>100</td><td>73</td><td>0.73f</td><td>0%</td></tr><tr><td>1.28f</td><td>100</td><td>128</td><td>1.28f</td><td>0%</td></tr><tr><td>0.123f</td><td>100</td><td>12</td><td>0.12f</td><td>2.4%</td></tr></tbody></table></figure>



<ul class="wp-block-list">
<li><strong>적정 범위</strong>:&nbsp;<code>-1.0 ~ 1.0</code>&nbsp;(조이스틱 입력 등)
<ul class="wp-block-list">
<li><code>Quantization = 100</code>&nbsp;→&nbsp;<code>-100 ~ +100</code>&nbsp;(총 201단계)</li>



<li><strong>필요 비트</strong>:&nbsp;<code>⌈log₂(201)⌉ = 8비트</code>&nbsp;(1바이트)</li>
</ul>
</li>



<li><strong>정밀도 vs 효율 트레이드오프</strong>:
<ul class="wp-block-list">
<li><strong>100</strong>: 0.01 단위 정밀도 (대부분의 게임 입력에 충분)</li>



<li><strong>1000</strong>: 0.001 단위 (고정밀 필요 시) → 대역폭 2배 소모</li>
</ul>
</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong>4&#x20e3; <strong><strong>간단 적용 예시</strong></strong></strong></h5>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 캐릭터 이동
[GhostField(Quantization = 100)]
public float Horizontal; // 좌우 이동 (-1.0 ~ 1.0)

[GhostField(Quantization = 100)]
public float Vertical;   // 전후 이동

// 캐릭터 회전
[GhostField(Quantization = 32767)] // short.MaxValue
public float RotationY; // 0 ~ 360도 → -32767 ~ 32767
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong> </strong>5&#x20e3; 최적화 가이드</h5>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>값 범위</strong></th><th><strong>권장 양자화 계수</strong></th><th><strong>비트 사용량</strong></th></tr></thead><tbody><tr><td>-1.0 ~ 1.0</td><td>100</td><td>8비트</td></tr><tr><td>-10.0 ~ 10.0</td><td>10</td><td>8비트</td></tr><tr><td>0 ~ 360 (각도)</td><td>32767</td><td>16비트</td></tr><tr><td>고정밀 물리 파라미터</td><td>10000+</td><td>16~32비트</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong>6&#x20e3; 주의사항</strong></h5>



<ul class="wp-block-list">
<li><strong>오버플로우 방지</strong><br><code>Quantization</code>&nbsp;값을 너무 크게 설정하면 정수 변환 시 오버플로우 발생 가능:</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 위험 예시 (float.MaxValue → 양자화 시 오류)
[GhostField(Quantization = 1000000)] 
public float DangerValue;</pre>



<ul class="wp-block-list">
<li><strong><strong>정밀도 한계</strong></strong><br><code>0.005f</code>&nbsp;같은 미세한 값은&nbsp;<code>Quantization=100</code>에서&nbsp;<strong>반올림 오차</strong>&nbsp;발생:</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">0.005f * 100 = 0.5f → 반올림 → 1 → 복원 시 0.01f (100% 오차)</pre>



<ul class="wp-block-list">
<li><strong><strong>에디터 디버깅</strong></strong><br><code>NetworkProtocol</code>&nbsp;로그에서 실제 전송 크기 확인:</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Unity 콘솔에 패킷 크기 출력
Debug.Log($"패킷 크기: {System.Runtime.InteropServices.Marshal.SizeOf(packet)}바이트");</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong>7&#x20e3; </strong>성능비교</h5>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 양자화 미적용 (32비트 float)
[GhostField] 
public float Uncompressed; // 4바이트

// 양자화 적용 (8비트 압축)
[GhostField(Quantization = 100)] 
public float Compressed; // 1바이트

절감 효과: 75% 대역폭 감소 (4배 효율)
초당 60프레임 기준:
미적용: 60fps * 4B = 240B/s
적용: 60fps * 1B = 60B/s</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><strong><code>IInputComponentData</code></strong> 와 <code>IComponentData</code>의 차이점</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>특징</th><th><code>IInputComponentData</code></th><th><code>IComponentData</code></th></tr></thead><tbody><tr><td><strong>자동 직렬화</strong></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 네트워크 전송 최적화</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 직접 구현 필요</td></tr><tr><td><strong>예측 지원</strong></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;<code>PredictedGhost</code>와 연동</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 별도 시스템 필요</td></tr><tr><td><strong>틱 동기화</strong></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;<code>Tick</code>&nbsp;프로퍼티 자동 관리</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 수동 처리</td></tr><tr><td><strong>버퍼링</strong></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 입력 히스토리 유지</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 직접 구현</td></tr></tbody></table></figure>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/">IInputComponentData [Netcode for Entities]</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity Canvas Scaler</title>
		<link>https://lycos7560.com/unity/unity-canvas-scaler/40382/</link>
					<comments>https://lycos7560.com/unity/unity-canvas-scaler/40382/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sat, 14 Dec 2024 19:42:10 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[9:16]]></category>
		<category><![CDATA[9:21]]></category>
		<category><![CDATA[Anchor]]></category>
		<category><![CDATA[Android Development]]></category>
		<category><![CDATA[Aspect Ratio]]></category>
		<category><![CDATA[Best Practice]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[Canvas Group]]></category>
		<category><![CDATA[Canvas Render]]></category>
		<category><![CDATA[Canvas Scaler]]></category>
		<category><![CDATA[Clipping]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Constant Physical Size]]></category>
		<category><![CDATA[Constant Pixel Size]]></category>
		<category><![CDATA[Cross Platform]]></category>
		<category><![CDATA[Development Tips]]></category>
		<category><![CDATA[Device Simulator]]></category>
		<category><![CDATA[DPI]]></category>
		<category><![CDATA[Dynamic UI]]></category>
		<category><![CDATA[Expand Mode]]></category>
		<category><![CDATA[Frontend]]></category>
		<category><![CDATA[Game Design]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[Game Engine]]></category>
		<category><![CDATA[Game Programming]]></category>
		<category><![CDATA[Graphic Design]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[Hierarchy]]></category>
		<category><![CDATA[How-to]]></category>
		<category><![CDATA[Indie Game]]></category>
		<category><![CDATA[iOS Development]]></category>
		<category><![CDATA[Landscape Mode]]></category>
		<category><![CDATA[Layout]]></category>
		<category><![CDATA[Letterbox]]></category>
		<category><![CDATA[Match Width or Height]]></category>
		<category><![CDATA[Mobile Game]]></category>
		<category><![CDATA[Mobile UX]]></category>
		<category><![CDATA[Multi-resolution]]></category>
		<category><![CDATA[Notch]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Pillarbox]]></category>
		<category><![CDATA[Pivot]]></category>
		<category><![CDATA[Pixel Density]]></category>
		<category><![CDATA[Portrait Mode]]></category>
		<category><![CDATA[PPI]]></category>
		<category><![CDATA[PPU]]></category>
		<category><![CDATA[Professional UI]]></category>
		<category><![CDATA[Punch Hole]]></category>
		<category><![CDATA[Rect Transform]]></category>
		<category><![CDATA[Reference Pixels Per Unit]]></category>
		<category><![CDATA[Reference Resolution]]></category>
		<category><![CDATA[Responsive UI]]></category>
		<category><![CDATA[Safe Area]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Scale With Screen Size]]></category>
		<category><![CDATA[Scaler]]></category>
		<category><![CDATA[Screen Match Mode]]></category>
		<category><![CDATA[Screen Resolution]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[Shrink Mode]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Sprite]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Tablet UI]]></category>
		<category><![CDATA[Tech Blog]]></category>
		<category><![CDATA[Technical Artist]]></category>
		<category><![CDATA[TUTORIAL]]></category>
		<category><![CDATA[UGUI]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[UI Canvas]]></category>
		<category><![CDATA[UI Container]]></category>
		<category><![CDATA[UI Layout Group]]></category>
		<category><![CDATA[UI Optimization]]></category>
		<category><![CDATA[UI Scaling]]></category>
		<category><![CDATA[UI 레이아웃 그룹]]></category>
		<category><![CDATA[UI 스케일링]]></category>
		<category><![CDATA[UI 최적화]]></category>
		<category><![CDATA[UI 캔버스]]></category>
		<category><![CDATA[UI 컨테이너]]></category>
		<category><![CDATA[Unity 2D]]></category>
		<category><![CDATA[Unity 3D]]></category>
		<category><![CDATA[Unity UI System]]></category>
		<category><![CDATA[User Experience]]></category>
		<category><![CDATA[User Interface]]></category>
		<category><![CDATA[UX]]></category>
		<category><![CDATA[Visual studio]]></category>
		<category><![CDATA[가로 모드]]></category>
		<category><![CDATA[가이드]]></category>
		<category><![CDATA[개발 팁]]></category>
		<category><![CDATA[게임 디자인]]></category>
		<category><![CDATA[게임 엔진]]></category>
		<category><![CDATA[게임 프로그래밍]]></category>
		<category><![CDATA[게임개발]]></category>
		<category><![CDATA[계층 구조]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[그래픽 디자인]]></category>
		<category><![CDATA[기술 블로그]]></category>
		<category><![CDATA[기준 해상도]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[노치 디자인]]></category>
		<category><![CDATA[다중 해상도]]></category>
		<category><![CDATA[동적 UI]]></category>
		<category><![CDATA[디바이스 시뮬레이터]]></category>
		<category><![CDATA[레이아웃]]></category>
		<category><![CDATA[레터박스]]></category>
		<category><![CDATA[렉트 트랜스폼]]></category>
		<category><![CDATA[모바일 UX]]></category>
		<category><![CDATA[모바일 게임]]></category>
		<category><![CDATA[반응형 UI]]></category>
		<category><![CDATA[방법론]]></category>
		<category><![CDATA[베스트 프랙티스]]></category>
		<category><![CDATA[비주얼 스튜디오]]></category>
		<category><![CDATA[세로 모드]]></category>
		<category><![CDATA[세이프 에어리어]]></category>
		<category><![CDATA[소프트웨어 공학]]></category>
		<category><![CDATA[슈링크 모드]]></category>
		<category><![CDATA[스크린 매치 모드]]></category>
		<category><![CDATA[스크립팅]]></category>
		<category><![CDATA[스프라이트]]></category>
		<category><![CDATA[씨샵]]></category>
		<category><![CDATA[아이폰 개발]]></category>
		<category><![CDATA[안드로이드 개발]]></category>
		<category><![CDATA[앵커]]></category>
		<category><![CDATA[유니티]]></category>
		<category><![CDATA[유니티 2D]]></category>
		<category><![CDATA[유니티 3D]]></category>
		<category><![CDATA[익스팬드 모드]]></category>
		<category><![CDATA[인디 게임]]></category>
		<category><![CDATA[최적화]]></category>
		<category><![CDATA[캔버스 그룹]]></category>
		<category><![CDATA[캔버스 렌더]]></category>
		<category><![CDATA[캔버스 스케일러]]></category>
		<category><![CDATA[코딩]]></category>
		<category><![CDATA[크로스 플랫폼]]></category>
		<category><![CDATA[클리핑]]></category>
		<category><![CDATA[태블릿 UI]]></category>
		<category><![CDATA[테크니컬 아티스트]]></category>
		<category><![CDATA[튜토리얼]]></category>
		<category><![CDATA[펀치홀]]></category>
		<category><![CDATA[프로페셔널 UI]]></category>
		<category><![CDATA[프론트엔드]]></category>
		<category><![CDATA[피벗]]></category>
		<category><![CDATA[픽셀 밀도]]></category>
		<category><![CDATA[필러박스]]></category>
		<category><![CDATA[화면 비율]]></category>
		<category><![CDATA[화면 해상도]]></category>
		<category><![CDATA[확장성]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=40382</guid>

					<description><![CDATA[<p>Canvas Scaler (캔버스 스케일러) https://docs.unity3d.com/Packages/com.unity.ugui@2.0/manual/script-CanvasScaler.html 캔버스 내 모든 UI 요소의 전체적인 스케일(크기)과 픽셀 밀도를 제어하는 데 사용하는 컴포넌트 이 스케일링은 폰트 크기와 이미지 테두리(Borders)를 포함하여 캔버스 아래에 있는 모든 요소에 영향을 미친다. 1. 주요 속성 (Properties) 속성 기능 UI Scale Mode 캔버스의 UI 요소가 스케일링되는 방식을 결정 &#8211; Constant Pixel Size 화면 크기에 상관없이 UI [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/unity-canvas-scaler/40382/">Unity Canvas Scaler</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-e856a7fc      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#canvas-scaler-캔버스-스케일러" class="uagb-toc-link__trigger">Canvas Scaler (캔버스 스케일러)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-주요-속성-properties" class="uagb-toc-link__trigger">1. 주요 속성 (Properties)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-scale-with-screen-size" class="uagb-toc-link__trigger">(1) Scale With Screen Size</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-constant-pixel-size" class="uagb-toc-link__trigger">(2) Constant Pixel Size</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-constant-physical-size" class="uagb-toc-link__trigger">(3) Constant Physical Size</a></li></ul><li class="uagb-toc__list"><a href="#2-언제-사용하나요" class="uagb-toc-link__trigger">2. 언제 사용하나요?</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-모바일-게임-scale-with-screen-size" class="uagb-toc-link__trigger">(1) 모바일 게임 &#8211; Scale With Screen Size</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-도구-모음-정교한-그래픽-툴-constant-pixel-size" class="uagb-toc-link__trigger">(2) 도구 모음, 정교한 그래픽 툴 &#8211; Constant Pixel Size</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-실제-크기가-중요-constant-physical-size" class="uagb-toc-link__trigger">(3) 실제 크기가 중요 &#8211; Constant Physical Size</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">Canvas Scaler (캔버스 스케일러)</h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.ugui@2.0/manual/script-CanvasScaler.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.ugui@2.0/manual/script-CanvasScaler.html</a></p>



<p>캔버스 내 모든 UI 요소의 <strong>전체적인 스케일(크기)과 픽셀 밀도</strong>를 제어하는 데 사용하는 컴포넌트</p>



<p>이 스케일링은 폰트 크기와 이미지 테두리(Borders)를 포함하여 <strong>캔버스 아래에 있는 모든 요소에 영향</strong>을 미친다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-default" style="margin-top:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--30)"/>



<h3 class="wp-block-heading">1. <strong>주요 속성 (Properties)</strong></h3>



<figure class="wp-block-image size-full"><img decoding="async" width="399" height="119" src="https://lycos7560.com/wp-content/uploads/2026/01/image.png" alt="" class="wp-image-40383" srcset="https://lycos7560.com/wp-content/uploads/2026/01/image.png 399w, https://lycos7560.com/wp-content/uploads/2026/01/image-300x89.png 300w" sizes="(max-width: 399px) 100vw, 399px" /></figure>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>속성</strong></td><td><strong>기능</strong></td></tr></thead><tbody><tr><td><strong>UI Scale Mode</strong></td><td>캔버스의 UI 요소가 스케일링되는 방식을 결정</td></tr><tr><td><strong>&#8211; Constant Pixel Size</strong></td><td>화면 크기에 상관없이 UI 요소가 동일한 <strong>픽셀 크기</strong>를 유지</td></tr><tr><td><strong>&#8211; Scale With Screen Size</strong></td><td>화면이 커질수록 UI 요소도 함께 커짐 (가장 많이 사용)</td></tr><tr><td><strong>&#8211; Constant Physical Size</strong></td><td>화면 크기나 해상도에 상관없이 UI 요소가 동일한 <strong>물리적 크기(mm 등)</strong>를 유지</td></tr></tbody></table></figure>



<h4 class="wp-block-heading">(1) Scale With Screen Size</h4>



<figure class="wp-block-image size-full"><img decoding="async" width="402" height="152" src="https://lycos7560.com/wp-content/uploads/2026/01/image-1.png" alt="" class="wp-image-40384" srcset="https://lycos7560.com/wp-content/uploads/2026/01/image-1.png 402w, https://lycos7560.com/wp-content/uploads/2026/01/image-1-300x113.png 300w" sizes="(max-width: 402px) 100vw, 402px" /></figure>



<p>특정 <strong>기준 해상도(Reference Resolution)</strong>를 설정하고, 현재 화면에 맞춰 UI를 키우거나 줄입니다.</p>



<p><strong>Reference Resolution</strong>: UI 레이아웃을 설계할 때 기준이 되는 해상도입니다.</p>



<p><strong>Screen Match Mode</strong>: 현재 화면 비율이 기준 해상도와 다를 때 캔버스 영역을 맞추는 방식입니다.</p>



<ul class="wp-block-list">
<li><strong>Match Width or Height</strong>: 가로 폭이나 세로 높이 중 하나를 기준으로(또는 그 사이 값으로) 스케일을 조절합니다.</li>



<li><strong>Expand</strong>: 캔버스 크기가 기준 해상도보다 작아지지 않도록 가로나 세로 방향으로 확장합니다.</li>



<li><strong>Shrink</strong>: 캔버스 크기가 기준 해상도보다 커지지 않도록 가로나 세로 방향으로 자릅니다(Crop).</li>
</ul>



<p><strong>Match</strong>: 가로(0)와 세로(1) 중 어느 쪽을 스케일링 기준으로 삼을지 결정합니다.</p>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">(2) Constant Pixel Size</h4>



<figure class="wp-block-image size-full"><img decoding="async" width="402" height="104" src="https://lycos7560.com/wp-content/uploads/2026/01/image-3.png" alt="" class="wp-image-40386" srcset="https://lycos7560.com/wp-content/uploads/2026/01/image-3.png 402w, https://lycos7560.com/wp-content/uploads/2026/01/image-3-300x78.png 300w" sizes="(max-width: 402px) 100vw, 402px" /></figure>



<p>UI 요소의 위치와 크기가 <strong>화면의 픽셀 단위로 지정</strong>됩니다.</p>



<ul class="wp-block-list">
<li><strong>Scale Factor</strong>: 캔버스 내 모든 UI 요소에 일괄적으로 적용되는 스케일 값입니다.</li>



<li><strong>Reference Pixels Per Unit</strong>: 스프라이트의 &#8216;Pixels Per Unit&#8217; 설정이 이 값과 같다면, 스프라이트의 1픽셀은 UI상의 1유닛(픽셀)과 대응합니다.</li>
</ul>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">(3) Constant Physical Size</h4>



<figure class="wp-block-image size-full"><img decoding="async" width="400" height="138" src="https://lycos7560.com/wp-content/uploads/2026/01/image-2.png" alt="" class="wp-image-40385" srcset="https://lycos7560.com/wp-content/uploads/2026/01/image-2.png 400w, https://lycos7560.com/wp-content/uploads/2026/01/image-2-300x104.png 300w" sizes="(max-width: 400px) 100vw, 400px" /></figure>



<p>UI 요소의 크기를 밀리미터(mm), 포인트(points), 파이카(picas) 등 <strong>물리적 단위</strong>로 지정합니다.</p>



<ul class="wp-block-list">
<li><strong>Physical Unit</strong>: 위치와 크기를 지정할 물리적 단위입니다.</li>



<li><strong>Fallback Screen DPI</strong>: 기기의 DPI를 알 수 없을 때 가정할 기본 DPI 값입니다.</li>



<li><strong>Default Sprite DPI</strong>: 스프라이트의 픽셀 밀도 기준입니다.</li>



<li><strong>Reference Pixels Per Unit</strong>: 스프라이트의 &#8216;Pixels Per Unit&#8217; 설정이 이 값과 같다면, 스프라이트의 1픽셀은 UI상의 1유닛(픽셀)과 대응합니다.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"/>



<h3 class="wp-block-heading">2. 언제 사용하나요?</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>모드</strong></td><td><strong>핵심 개념</strong></td><td><strong>주 사용처</strong></td></tr></thead><tbody><tr><td><strong>Scale With Screen Size</strong></td><td><strong>비율</strong> 중심</td><td>일반적인 모든 모바일/PC 게임</td></tr><tr><td><strong>Constant Pixel Size</strong></td><td><strong>픽셀 수</strong> 중심</td><td>전문 도구, 캔버스 좌표가 중요한 앱</td></tr><tr><td><strong>Constant Physical Size</strong></td><td><strong>실제 길이(cm)</strong> 중심</td><td>물리적 크기가 고정되어야 하는 특수 목적 앱</td></tr></tbody></table></figure>



<h4 class="wp-block-heading">(1) <strong>모바일 게임</strong> &#8211; Scale With Screen Size</h4>



<p><strong>가장 많이 사용하며, 모바일 게임 개발의 표준입니다.</strong></p>



<ul class="wp-block-list">
<li><strong>언제 사용하나?</strong>
<ul class="wp-block-list">
<li>대부분의 <strong>모바일 게임, PC 게임</strong>을 만들 때.</li>



<li>화면이 커지면 UI도 그에 비례해서 커지길 원할 때.</li>



<li>다양한 해상도(아이폰, 갤럭시, 태블릿 등)에 대응해야 할 때.</li>
</ul>
</li>



<li><strong>특징:</strong> 기준 해상도(예: 1440&#215;2560)를 정해두면 유니티가 알아서 기기 화면에 맞춰 UI를 키우거나 줄여줍니다. 개발자는 한 가지 사이즈만 고민하면 됩니다.</li>
</ul>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">(2) <strong>도구 모음</strong>, <strong>정교한 그래픽 툴</strong> &#8211; Constant Pixel Size</h4>



<p><strong>픽셀 숫자를 그대로 유지합니다.</strong></p>



<ul class="wp-block-list">
<li><strong>언제 사용하나?</strong>
<ul class="wp-block-list">
<li><strong>웹 브라우저의 도구 모음</strong>이나 <strong>정교한 그래픽 툴</strong> 같은 앱을 만들 때.</li>



<li>해상도가 높아져도 아이콘이 커지지 않고, 대신 <strong>더 넓은 작업 공간</strong>을 보여주고 싶을 때.</li>



<li>저해상도와 고해상도에서 UI의 &#8220;선명도&#8221;를 1:1 픽셀 매칭으로 유지하고 싶을 때.</li>
</ul>
</li>



<li><strong>특징:</strong> 100&#215;100 픽셀 버튼은 4K 모니터에서도 100&#215;100 픽셀입니다. 따라서 고해상도 기기일수록 UI가 매우 작게 보입니다.</li>
</ul>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="1207" height="511" src="https://lycos7560.com/wp-content/uploads/2024/12/image-222.png" alt="" class="wp-image-40394" style="aspect-ratio:2.3621642749455583;width:472px;height:auto" srcset="https://lycos7560.com/wp-content/uploads/2024/12/image-222.png 1207w, https://lycos7560.com/wp-content/uploads/2024/12/image-222-300x127.png 300w, https://lycos7560.com/wp-content/uploads/2024/12/image-222-768x325.png 768w" sizes="(max-width: 1207px) 100vw, 1207px" /><figcaption class="wp-element-caption">그림판</figcaption></figure>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">(3) <strong>실제 크기가 중요</strong> &#8211; Constant Physical Size</h4>



<p><strong>실제 자(Ruler)로 쟀을 때의 물리적 크기를 유지합니다.</strong></p>



<ul class="wp-block-list">
<li><strong>언제 사용하나?</strong>
<ul class="wp-block-list">
<li><strong>실제 크기가 중요한 앱:</strong> 예를 들어 화면에 대고 길이를 재는 &#8216;자(Ruler) 앱&#8217;이나, 사람의 손가락 크기에 맞춰 버튼 크기가 물리적으로 일정해야 하는 특수 장비용 앱.</li>



<li>화면의 밀도(DPI)와 상관없이 버튼이 항상 1cm가 되어야 할 때.</li>
</ul>
</li>



<li><strong>특징:</strong> 기기가 5인치든 10인치든 상관없이 버튼의 실제 길이를 유지하려 노력합니다. 기기가 화면의 DPI 정보를 정확히 전달해줘야 정상 작동합니다.</li>
</ul>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/unity-canvas-scaler/40382/">Unity Canvas Scaler</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-canvas-scaler/40382/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Getting started with Shader Graph &#8211; Create Node Menu</title>
		<link>https://lycos7560.com/unity/getting-started-with-shader-graph-create-node-menu/38017/</link>
					<comments>https://lycos7560.com/unity/getting-started-with-shader-graph-create-node-menu/38017/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Tue, 19 Mar 2024 15:06:33 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[UnityShader]]></category>
		<category><![CDATA[Block Node]]></category>
		<category><![CDATA[Contextual]]></category>
		<category><![CDATA[Contextual Create Node Menu]]></category>
		<category><![CDATA[Create]]></category>
		<category><![CDATA[Create Node]]></category>
		<category><![CDATA[Create Node Menu]]></category>
		<category><![CDATA[Getting started with Shader Graph]]></category>
		<category><![CDATA[Manual]]></category>
		<category><![CDATA[Master Stack]]></category>
		<category><![CDATA[Master Stack Create Node Menu]]></category>
		<category><![CDATA[Node Menu]]></category>
		<category><![CDATA[Shader Graph]]></category>
		<category><![CDATA[Unity Shader]]></category>
		<category><![CDATA[URP]]></category>
		<category><![CDATA[노드]]></category>
		<category><![CDATA[노드 생성]]></category>
		<category><![CDATA[생성]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=38017</guid>

					<description><![CDATA[<p>https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Create-Node-Menu.html Create Node Menu Description Shader Graph에서 nodes를 생성하기 위해 Create Node Menu를 사용합니다.Use the Create Node Menu to create nodes in Shader Graph. 노드 생성 메뉴를 열려면 Shader Graph 창의 작업 공간을 마우스 오른쪽 버튼으로 클릭하고 &#8220;Create Node&#8221;을 선택하거나, 스페이스바를 누릅니다.To open the Create Node Menu, either right-click on the workspace in the Shader Graph Window and select Create Node, or press [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/getting-started-with-shader-graph-create-node-menu/38017/">Getting started with Shader Graph &#8211; Create Node Menu</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Create-Node-Menu.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Create-Node-Menu.html</a></p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-12711d18      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							Getting started with Shader Graph						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#create-node-menu" class="uagb-toc-link__trigger">Create Node Menu</a><li class="uagb-toc__list"><a href="#contextual-create-node-menu" class="uagb-toc-link__trigger">Contextual Create Node Menu</a><li class="uagb-toc__list"><a href="#master-stack-create-node-menu" class="uagb-toc-link__trigger">Master Stack Create Node Menu</a></ol>					</div>
									</div>
				</div>
			


<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-uagb-advanced-heading uagb-block-5260c951"><h2 class="uagb-heading-text">Create Node Menu</h2></div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"/>



<p class="has-medium-font-size"><strong>Description</strong></p>



<p>Shader Graph에서 <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Node.html" target="_blank" rel="noreferrer noopener">nodes</a>를 생성하기 위해 <strong>Create Node Menu</strong>를 사용합니다.<br>Use the <strong>Create Node Menu</strong> to create <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Node.html" target="_blank" rel="noreferrer noopener">nodes</a> in Shader Graph. </p>



<p>노드 생성 메뉴를 열려면 Shader Graph 창의 작업 공간을 <strong>마우스 오른쪽 버튼으로 클릭하고 &#8220;Create Node&#8221;을 선택하거나, 스페이스바를 누릅니다.</strong><br>To open the <strong>Create Node Menu</strong>, either right-click on the workspace in the <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Shader-Graph-Window.html" target="_blank" rel="noreferrer noopener">Shader Graph Window</a> and select <strong>Create Node</strong>, or press the spacebar.</p>



<p><strong>Create Node Menu</strong>의 맨 위에는 검색 창이 있습니다.<br>At the top of the <strong>Create Node Menu</strong> is a search bar. </p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure data-wp-context="{&quot;imageId&quot;:&quot;69c29fb47ba44&quot;}" data-wp-interactive="core/image" data-wp-key="69c29fb47ba44" class="wp-block-image size-full wp-lightbox-container"><img decoding="async" width="267" height="297" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://lycos7560.com/wp-content/uploads/2024/03/image-34.png" alt="" class="wp-image-38019"/><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="확대하기"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">마우스 우클릭 후 <strong>Create Node</strong> 선택</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure data-wp-context="{&quot;imageId&quot;:&quot;69c29fb47be28&quot;}" data-wp-interactive="core/image" data-wp-key="69c29fb47be28" class="wp-block-image size-full wp-lightbox-container"><img decoding="async" width="333" height="318" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://lycos7560.com/wp-content/uploads/2024/03/image-35.png" alt="" class="wp-image-38020" srcset="https://lycos7560.com/wp-content/uploads/2024/03/image-35.png 333w, https://lycos7560.com/wp-content/uploads/2024/03/image-35-300x286.png 300w" sizes="(max-width: 333px) 100vw, 333px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="확대하기"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption"><strong>SpaceBar</strong></figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure data-wp-context="{&quot;imageId&quot;:&quot;69c29fb47c1a8&quot;}" data-wp-interactive="core/image" data-wp-key="69c29fb47c1a8" class="wp-block-image size-full wp-lightbox-container"><img decoding="async" width="346" height="327" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://lycos7560.com/wp-content/uploads/2024/03/image-36.png" alt="" class="wp-image-38021" srcset="https://lycos7560.com/wp-content/uploads/2024/03/image-36.png 346w, https://lycos7560.com/wp-content/uploads/2024/03/image-36-300x284.png 300w" sizes="(max-width: 346px) 100vw, 346px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="확대하기"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption"><strong>Tab</strong>을 이용하여 예측 텍스트 수락</figcaption></figure>
</div>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>node를 검색하려면 검색 필드에 이름의 일부를 입력하십시오.<br>To search for a node, type any part of its name in the search field. </p>



<p>검색 상자는 자동 완성 옵션을 제공하며, 예측 텍스트를 수락하려면 <strong>Tab을 누르십시오.</strong><br>The search box gives you autocomplete options, and you can press Tab to accept the predictive text.</p>



<p>일치하는 텍스트를 노란색으로 강조합니다.<br>It highlights matching text in yellow.</p>



<p><strong>Create Node Menu</strong> lists에는 기능별로 분류된 Shader Graph에서 사용 가능한 모든 노드가 나열됩니다.<br>The <strong>Create Node Menu</strong> lists all nodes that are available in Shader Graph, categorized by their function.</p>



<p>사용자가 작성한 <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Sub-graph.html" target="_blank" rel="noreferrer noopener">Sub Graphs</a>는 서브 그래프 에셋 하위의 <strong>Create Node Menu</strong>에서 사용할 수 있으며, <strong>Sub Graph Assets</strong>에서 정의한 사용자 지정 카테고리에도 사용할 수 있습니다.<br>User-created <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Sub-graph.html" target="_blank" rel="noreferrer noopener">Sub Graphs</a> are also available in the <strong>Create Node Menu</strong> under <strong>Sub Graph Assets</strong>, or in a custom category that you define in the Sub Graph Asset.</p>



<p>작업 공간에 노드를 추가하려면 <strong>Create Node Menu</strong>에서 해당 노드를 두 번 클릭하십시오.<br>To add a node to the workspace, double-click it in the <strong>Create Node Menu</strong>.</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="contextual-create-node-menu">Contextual Create Node Menu</h2>



<p>컨텍스트에 맞는 <strong>Create Node Menu</strong>는 사용 가능한 노드를 필터링하고 선택한 엣지의 <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Data-Types.html" target="_blank" rel="noreferrer noopener">Data Type</a>을 사용하는 노드만 표시합니다.<br>A contextual <strong>Create Node Menu</strong> filters the available nodes, and only shows those that use the <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Data-Types.html" target="_blank" rel="noreferrer noopener">Data Type</a> of a selected edge. </p>



<p>해당 Data Type과 일치하는 노드의 모든 사용 가능한 <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Port.html" target="_blank" rel="noreferrer noopener">Port</a>를 나열합니다.<br>It lists every available <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Port.html" target="_blank" rel="noreferrer noopener">Port</a> on nodes that match that Data Type.</p>



<p>컨텍스트에 맞는  <strong>Create Node Menu</strong>를 열려면 포트에서 <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Edge.html" target="_blank" rel="noreferrer noopener">Edge</a>를 클릭하고 드래그한 다음 작업 공간의 빈 영역에 놓으면 됩니다.<br>To open a contextual <strong>Create Node Menu</strong>, click and drag an <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Edge.html" target="_blank" rel="noreferrer noopener">Edge</a> from a Port, and then release it in an empty area of the workspace.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure data-wp-context="{&quot;imageId&quot;:&quot;69c29fb47c849&quot;}" data-wp-interactive="core/image" data-wp-key="69c29fb47c849" class="wp-block-image size-full wp-lightbox-container"><img decoding="async" width="905" height="389" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://lycos7560.com/wp-content/uploads/2024/03/image-37.png" alt="" class="wp-image-38022" srcset="https://lycos7560.com/wp-content/uploads/2024/03/image-37.png 905w, https://lycos7560.com/wp-content/uploads/2024/03/image-37-300x129.png 300w, https://lycos7560.com/wp-content/uploads/2024/03/image-37-768x330.png 768w" sizes="(max-width: 905px) 100vw, 905px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="확대하기"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">정점(Edge)을 클릭하고 드래그하여 생성<br>선택한 정점(Edge)의 DataType을 기반으로 사용 가능한 node를 필터링하여 특정 컨텍스트에서 사용자에게 적합한 노드를 제안하는 메뉴</figcaption></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="master-stack-create-node-menu">Master Stack Create Node Menu</h2>



<p>새로운 <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Create-Node-Menu.html" target="_blank" rel="noreferrer noopener">Block Node</a>를 <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Create-Node-Menu.html">Master Stack</a>에 추가하려면 마우스 오른쪽 버튼을 클릭하고 &#8220;<strong>Create Node</strong>&#8220;을 선택하거나 스택을 선택한 상태에서 스페이스바를 누르세요.<br>To add a new <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Create-Node-Menu.html" target="_blank" rel="noreferrer noopener">Block Node</a> to the <a href="https://docs.unity3d.com/Packages/com.unity.shadergraph@17.0/manual/Create-Node-Menu.html" target="_blank" rel="noreferrer noopener">Master Stack</a>, either right click and select <strong>Create Node</strong> or press spacebar with the stack selected.</p>



<p>&#8220;<strong>Create Node Menu</strong>&#8220;는 <strong>프로젝트의 렌더 파이프라인을 기반으로 마스터 스택에 사용 가능한 모든 블록을 표시</strong>합니다.<br>The <strong>Create Node Menu</strong> will display all available blocks for the master stack based on the render pipelines in your project.</p>



<p>&#8220;<strong>Create Node Menu</strong>&#8220;를 통해 마스터 스택에 어떤 블록이든 추가할 수 있습니다.<br>Any block can be added to the master stack via the <strong>Create Node Menu</strong>.</p>



<p>추가된 block이 현재 Graph settings과 호환되지 않는 경우, 해당 block은 설정이 지원될 때까지 <strong>비활성화</strong>됩니다.<br>If the block added is not compatible with the current Graph settings, the block will be disabled until the settings are configured to support it.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure data-wp-context="{&quot;imageId&quot;:&quot;69c29fb47ccf1&quot;}" data-wp-interactive="core/image" data-wp-key="69c29fb47ccf1" class="wp-block-image size-full wp-lightbox-container"><img decoding="async" width="1164" height="713" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://lycos7560.com/wp-content/uploads/2024/03/image-38.png" alt="" class="wp-image-38023" srcset="https://lycos7560.com/wp-content/uploads/2024/03/image-38.png 1164w, https://lycos7560.com/wp-content/uploads/2024/03/image-38-300x184.png 300w, https://lycos7560.com/wp-content/uploads/2024/03/image-38-768x470.png 768w" sizes="(max-width: 1164px) 100vw, 1164px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="확대하기"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">MasterStack에 블록추가 / 호환되지 않는 경우에는 해당 block은 설정이 지원될 때까지 <strong>비활성화</strong></figcaption></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>
<p>The post <a href="https://lycos7560.com/unity/getting-started-with-shader-graph-create-node-menu/38017/">Getting started with Shader Graph &#8211; Create Node Menu</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/getting-started-with-shader-graph-create-node-menu/38017/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity Manual / Job system (2023.3) 번역</title>
		<link>https://lycos7560.com/unity/unity-manual-job-system-2023-3-%eb%b2%88%ec%97%ad/37818/</link>
					<comments>https://lycos7560.com/unity/unity-manual-job-system-2023-3-%eb%b2%88%ec%97%ad/37818/#comments</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Tue, 26 Dec 2023 07:34:17 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[2023.3]]></category>
		<category><![CDATA[job]]></category>
		<category><![CDATA[Job system]]></category>
		<category><![CDATA[Manual]]></category>
		<category><![CDATA[multi]]></category>
		<category><![CDATA[multi thread]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[thread]]></category>
		<category><![CDATA[Unity Manual]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[공식 문서]]></category>
		<category><![CDATA[번역]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=37818</guid>

					<description><![CDATA[<p>Unity Manual의 Job system 파트를 번역한 글입니다.</p>
<p>The post <a href="https://lycos7560.com/unity/unity-manual-job-system-2023-3-%eb%b2%88%ec%97%ad/37818/">Unity Manual / Job system (2023.3) 번역</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-6d9129b1      "
					data-scroll= "1"
					data-offset= "0"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차													<svg xmlns="https://www.w3.org/2000/svg" viewBox= "0 0 384 512"><path d="M192 384c-8.188 0-16.38-3.125-22.62-9.375l-160-160c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L192 306.8l137.4-137.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-160 160C208.4 380.9 200.2 384 192 384z"></path></svg>
																			</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#job-system" class="uagb-toc-link__trigger">Job system</a><li class="uagb-toc__list"><a href="#잡-시스템-개요-job-system-overview" class="uagb-toc-link__trigger">잡 시스템 개요 (Job System Overview)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#멀티스레딩-multithreading" class="uagb-toc-link__trigger">멀티스레딩 (Multithreading)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#작업-훔치기-work-stealing" class="uagb-toc-link__trigger">작업 훔치기 (Work stealing)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#안전-시스템-safety-system" class="uagb-toc-link__trigger">안전 시스템 (Safety System)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#컬렉션-패키지-collections-package" class="uagb-toc-link__trigger">컬렉션 패키지 (Collections package)</a></li></ul></li><li class="uagb-toc__list"><a href="#잡-개요-job-overview" class="uagb-toc-link__trigger">잡 개요 (Job Overview)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#잡-타입-job-types" class="uagb-toc-link__trigger">잡 타입 (Job types)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ijob" class="uagb-toc-link__trigger">IJob</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ijobparallelfor" class="uagb-toc-link__trigger">IJobParallelFor</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ijobparallelfortransform" class="uagb-toc-link__trigger">IJobParallelForTransform</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ijobfor" class="uagb-toc-link__trigger">IJobFor</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#요약-summary" class="uagb-toc-link__trigger">요약 (Summary)</a></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#스레드-세이프-타입-thread-safe-types" class="uagb-toc-link__trigger">스레드 세이프 타입 (Thread safe types)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#nativecontainer-객체의-종류-types-of-nativecontainers" class="uagb-toc-link__trigger">NativeContainer 객체의 종류 (Types of NativeContainers)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#읽기-및-쓰기-액세스-read-and-write-access" class="uagb-toc-link__trigger">읽기 및 쓰기 액세스 (Read and Write Access)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#메모리-할당자-memory-allocators" class="uagb-toc-link__trigger">메모리 할당자 (Memory Allocators)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#nativecontainer-안전-시스템-nativecontainer-safety-system" class="uagb-toc-link__trigger">NativeContainer 안전 시스템 (NativeContainer safety system)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#추가-리소스-additional-resources" class="uagb-toc-link__trigger">추가 리소스 (Additional resources)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#커스텀-네이티브-컨테이너-구현-implement-a-custom-native-container" class="uagb-toc-link__trigger">커스텀 네이티브 컨테이너 구현 (Implement a custom native container)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#사용량-추적-구현-implement-usage-tracking" class="uagb-toc-link__trigger">사용량 추적 구현 (Implement usage tracking)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#누출-추적-구현-implement-leak-tracking" class="uagb-toc-link__trigger">누출 추적 구현 (Implement leak tracking)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#중첩된-네이티브-컨테이너-nested-native-containers" class="uagb-toc-link__trigger">중첩된 네이티브 컨테이너 (Nested native containers)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#안전-id-및-오류-메시지-safety-ids-and-error-messages" class="uagb-toc-link__trigger">안전 ID 및 오류 메시지 (Safety IDs and error messages)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#추가-리소스-additional-resources" class="uagb-toc-link__trigger">추가 리소스 (Additional resources)</a></li></ul><li class="uagb-toc__list"><a href="#nativecontainer-구조-복사-copying-nativecontainer-structures" class="uagb-toc-link__trigger">NativeContainer 구조 복사 (Copying NativeContainer structures)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#버전-번호-version-numbers" class="uagb-toc-link__trigger">버전 번호 (Version numbers)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#동적-네이티브-컨테이너의-정적-보기-static-views-of-dynamic-native-containers" class="uagb-toc-link__trigger">동적 네이티브 컨테이너의 정적 보기 (Static views of dynamic native containers)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#보조-버전-번호-secondary-version-numbers" class="uagb-toc-link__trigger">보조 버전 번호 (Secondary version numbers)</a></li></ul><li class="uagb-toc__list"><a href="#특수-손잡이-special-handles" class="uagb-toc-link__trigger">특수 손잡이 (Special handles)</a></li></ul><li class="uagb-toc__list"><a href="#사용자-정의-nativecontainer-예제-custom-nativecontainer-example" class="uagb-toc-link__trigger">사용자 정의 NativeContainer 예제 (Custom NativeContainer example)</a></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#작업-생성-및-실행-create-and-run-a-job" class="uagb-toc-link__trigger">작업 생성 및 실행 (Create and run a job)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#작업-생성-create-a-job" class="uagb-toc-link__trigger">작업 생성 (Create a job)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#작업-예약-schedule-a-job" class="uagb-toc-link__trigger">작업 예약 (Schedule a job)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#작업-완료-complete-the-job" class="uagb-toc-link__trigger">작업 완료 (Complete the job)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#잡-예시-job-examples" class="uagb-toc-link__trigger">잡 예시 (Job examples)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#예약-및-완료-모범적인-사례-schedule-and-complete-best-practices" class="uagb-toc-link__trigger">예약 및 완료 모범적인 사례 (Schedule and Complete best practices)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#장기-실행-작업-사용-방지-avoid-using-long-running-jobs" class="uagb-toc-link__trigger">장기 실행 작업 사용 방지 (Avoid using long running jobs)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#추가-리소스-additional-resources" class="uagb-toc-link__trigger">추가 리소스 (Additional resources)</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#잡-의존성-job-dependencies" class="uagb-toc-link__trigger">잡 의존성 (Job dependencies)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#종속성-결합-combining-dependencies" class="uagb-toc-link__trigger">종속성 결합 (Combining dependencies)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#다중-작업-및-종속성-예제-an-example-of-multiple-jobs-and-dependencies" class="uagb-toc-link__trigger">다중 작업 및 종속성 예제 (An example of multiple jobs and dependencies)</a></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#병렬-작업-parallel-jobs" class="uagb-toc-link__trigger">병렬 작업 (Parallel jobs)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#parallelfor-작업-예약-schedule-a-parallelfor-job" class="uagb-toc-link__trigger">ParallelFor 작업 예약 (Schedule a ParallelFor job)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#parallelfortransform-jobs" class="uagb-toc-link__trigger">ParallelForTransform jobs</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ijobparallelfortransform" class="uagb-toc-link__trigger">IJobParallelForTransform</a></ul></ul></ul></ul></ul></ul></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystem.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystem.html</a></p>



<h1 class="wp-block-heading">Job system</h1>



<p>job system을 사용하면 간단하고 안전한 멀티 스레드 코드를 작성할 수 있으므로 응용 프로그램이 사용 가능한 모든 CPU 코어를 사용하여 코드를 실행할 수 있습니다.<br>The job system lets you write simple and safe multithreaded code so that your application can use all available CPU cores to execute your code.</p>



<p>이것은 응용 프로그램의 성능을 향상시키는 데 도움이 될 수 있습니다<br>This can help improve the performance of your application.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-table"><table><thead><tr><th><strong>Topic</strong></th><th><strong>Description</strong></th></tr></thead><tbody><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html" target="_blank" rel="noreferrer noopener">Job system overview</a></td><td>Understand Unity’s job system.</td></tr><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-jobs.html" target="_blank" rel="noreferrer noopener">Jobs overview</a></td><td>Understand the type of jobs available.</td></tr><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">Thread safe types</a></td><td>Understand thread safe types, such as NativeContainer objects.</td></tr><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer.html" target="_blank" rel="noreferrer noopener">Implement a custom NativeContainer</a></td><td>Implement custom native containers.</td></tr><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-copy-nativecontainer.html" target="_blank" rel="noreferrer noopener">Copying NativeContainer structures</a></td><td>Copy and reference multiple native containers.</td></tr><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer-example.html" target="_blank" rel="noreferrer noopener">Custom NativeContainer example</a></td><td>Use a real world custom NativeContainer example.</td></tr><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemCreatingJobs.html" target="_blank" rel="noreferrer noopener">Create a job</a></td><td>Create and schedule a job.</td></tr><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemJobDependencies.html" target="_blank" rel="noreferrer noopener">Job dependencies</a></td><td>Understand job dependencies.</td></tr><tr><td><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemParallelForJobs.html" target="_blank" rel="noreferrer noopener">Parallel jobs</a></td><td>Use parallel jobs to schedule multiple jobs at once.</td></tr></tbody></table></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-aab169e9 wp-block-columns-is-layout-flex" style="border-width:3px;margin-top:0;margin-bottom:0;padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html</a></p>



<h1 class="wp-block-heading">잡 시스템 개요 (Job System Overview)</h1>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p>Unity의 Job System을 활용하면 <strong>멀티스레드 코드를 작성하여 애플리케이션에서 사용 가능한 모든 CPU 코어를 최적으로 활용</strong>할 수 있습니다.<br>Unity’s job system lets you create multithreaded code so that your application can use all available CPU cores to execute your code.</p>



<p>이는 애플리케이션이 하나의 CPU 코어에서 모든 코드를 실행하는 것보다 <strong>모든 CPU 코어를 효율적으로 활용함으로써 성능을 향상</strong>시킬 수 있습니다.<br>This provides improved performance because your application uses the capacity of all the CPU cores it’s running on more efficiently, rather than running all code on one CPU core.</p>



<p>Job System만 단독으로 사용할 수 있지만 성능 향상을 위해서는 Unity의 <strong>Job System에 최적화된&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.burst@latest/" target="_blank" rel="noreferrer noopener">버스트 컴파일러</a>를 함께 사용</strong>해야 합니다.<br>You can use the job system by itself, but for improved performance, you should also use the&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.burst@latest/" target="_blank" rel="noreferrer noopener">Burst compiler</a>, which is specifically designed to compile jobs for Unity’s job system.</p>



<p>버스트 컴파일러는 코드 생성을 개선하여 모바일 디바이스의 성능을 향상시키고 배터리 소모를 줄이는 데 도움을 줍니다.<br>The Burst compiler has improved code generation, which results in increased performance and a reduction of battery consumption on mobile devices.</p>



<p>또한 Unity의<strong> <a href="https://docs.unity3d.com/Packages/com.unity.entities@1.2/manual/index.html" target="_blank" rel="noreferrer noopener">엔티티 컴포넌트 시스템</a></strong>과 결합하여 고성능 데이터 지향 코드를 생성할 수도 있습니다.<br>You can also use the job system with Unity’s&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.entities@latest/" target="_blank" rel="noreferrer noopener"><strong>Entity Component System</strong></a>&nbsp;to create high performance data-oriented code.</p>



<p><strong>( Entity Component System(ECS)</strong> +<strong> Job System</strong> + <strong>Burst compiler</strong> )</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-cad298ab wp-block-columns-is-layout-flex" style="border-width:2px;border-radius:0px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">멀티스레딩 (Multithreading) </h2>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p>Unity는 자체 <strong>Native job system</strong>을 사용하여 응용 프로그램이 실행되는 기기의 CPU 코어 수에 따라 여러 <strong>worker thread</strong>에서 Native code를 처리합니다.<br>Unity uses its own Native job system to process its own native code over multiple&nbsp;<strong>worker threads</strong>, which are dependent on the number of CPU cores available on the device your application runs on.</p>



<p>일반적으로 Unity는 프로그램 시작 시 기본적으로 실행되는&nbsp;<strong>Main thr<strong>ead</strong></strong>에서 코드를 실행합니다.<br>Usually Unity executes your code on one thread which runs by default at the start of the program, called the&nbsp;<strong>main thread</strong></p>



<p>그러나 <strong>Job System</strong>을 사용하면 Unity는 <strong>multithreading</strong>, 즉 <strong>worker thread</strong>를 통해 코드를 실행합니다.<br>However, when you use the job system, Unity executes your code over the worker threads, which is called&nbsp;<strong>multithreading.</strong></p>



<p><strong>Multithreading</strong>은 CPU가 여러 코어에서 동시에 많은 스레드를 처리할 수 있는 기능을 활용합니다.<br>Multithreading takes advantage of a CPU’s capability to process a lot of threads at the same time across multiple cores.</p>



<p>작업이나 명령이 차례로 실행되는 대신 동시에 실행되며, <strong>Worker thread는 서로 병렬로 실행되고 완료될 때 결과를 Main thread와 동기화</strong>합니다.<br>The worker threads run in parallel to one another, and synchronize their results with the main thread once completed.</p>



<p><strong>Job System</strong>은 CPU 코어의 용량에 맞는 충분한 <strong> thr<strong>ead</strong></strong>만 확보하여 사용 가능한 CPU 코어 수를 구체적으로 파악하지 않아도 필요한 작업을 유연하게 예약할 수 있습니다.<br>The job system ensures that there are only enough threads to match the capacity of the CPU cores, which means that you can schedule as many tasks as you need without specifically needing to know how many CPU cores are available.</p>



<p>이것은 다른 잡 시스템이 CPU 코어보다 더 많은  thread를 비효율적으로 생성하는 <a href="https://en.wikipedia.org/wiki/Thread_pool" target="_blank" rel="noreferrer noopener"><strong>스레드 풀링</strong></a>과 같은 기술에 의존하는 것과 차별화됩니다.<br>This differs from other job systems that rely on techniques such as&nbsp;<a href="https://en.wikipedia.org/wiki/Thread_pool" target="_blank" rel="noreferrer noopener">thread pooling</a>, where it’s easier to inefficiently create more threads than CPU cores.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">작업 훔치기 (Work stealing)</h2>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p> <strong>Job System</strong>은 작업 훔치기를 스케줄링 전략의 일환으로 활용하여 <strong>worker thread 간에 공유되는 작업 양을 균등하게 조절</strong>합니다.<br>The job system uses work stealing as part of its scheduling strategy to even out the amount of tasks shared across worker threads.</p>



<p><strong><strong>Worker thread</strong> </strong>간에는 작업을 빠르게 처리하는 경우가 있기 때문에 <strong><strong>하나의 worker thread</strong></strong>가 모든 작업을 완료하면 <br>다른 <strong><strong>worker thread</strong></strong>의 대기열을 확인하고, 그 후 해당 <strong><strong> thread</strong></strong>에 할당된 작업을 처리합니다.<br>Worker threads might process tasks faster than others, so once a worker thread has finished processing all of its tasks, <br>it looks at the other worker threads’ queues and then processes tasks assigned to another worker thread.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">안전 시스템 (Safety System)</h2>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p>멀티스레드 코드를 보다 쉽게 작성할 수 있도록, Job System은 <strong>모든 잠재적인 경쟁 상태를 감지</strong>하고 이로 인한 발생 가능한 버그를 예방합니다.<br>To make it easier to write multithreaded code, the job system has a safety system that detects all potential race conditions and protects you from the bugs they can cause.</p>



<p>경쟁 상태는 한 <strong>작업의 결과가 제어할 수 없는 다른 프로세스의 실행 타이밍에 영향</strong>을 받을 때 발생합니다.<br>A race condition happens when the output of one operation depends on the timing of another process outside of its control.</p>



<p>예를 들어, 잡 시스템이 Main thread의 코드에서 데이터에 대한 레퍼런스를 잡으로 전달하는 경우, <br>잡이 데이터를 쓰는 동시에 Main thread가 데이터를 읽고 있는지 확인할 수 없습니다.<br>For example, if the job system sends a reference to data from your code in the main thread to a job, <br>it can’t verify whether the main thread is reading the data at the same time the job is writing to it.&nbsp;</p>



<p>이러한 상황은 <strong>경쟁 상태</strong>를 야기합니다.<br>This scenario creates a race condition.</p>



<p>이 문제를 해결하기 위해 잡 시스템은 각 잡이 필요로 하는 데이터에 대한 레퍼런스를 <strong>Main thread의 데이터 레퍼런스가 아닌 데이터 사본으로 전송</strong>합니다.<br>To solve this problem, the job system sends each job a copy of the data it needs to operate on rather than a reference to the data in the main thread.</p>



<p>이 사본은 데이터를 격리하여 경쟁 상태를 제거합니다.<br>this copy isolates the data, which eliminates the race condition.</p>



<p>Job System이 데이터를 복사하는 방식에 따라 Job은&nbsp;<a href="https://en.wikipedia.org/wiki/Blittable_types" target="_blank" rel="noreferrer noopener">blittable 데이터 타입</a>에만 액세스할 수 있습니다.<br>The way that the job system copies data means that a job can only access&nbsp;<a href="https://en.wikipedia.org/wiki/Blittable_types" target="_blank" rel="noreferrer noopener">blittable data types</a>. (<a href="https://learn.microsoft.com/ko-kr/dotnet/framework/interop/blittable-and-non-blittable-types" target="_blank" rel="noreferrer noopener">blittable data Type</a>)</p>



<p>이러한 타입은 관리되는 코드와 네이티브 코드 간에 <strong>전달할 때 변환이 필요하지 않습니다.</strong><br>These types don’t need conversion when passed between managed and native code.</p>



<p>Job System은&nbsp;<a href="http://www.cplusplus.com/reference/cstring/memcpy/" target="_blank" rel="noreferrer noopener">memcpy</a>를 사용하여 blittable 타입을 복사하고 Unity의 관리되는 부분과 네이티브 부분 간에 데이터를 전송합니다.<br>The job system uses&nbsp;<a href="http://www.cplusplus.com/reference/cstring/memcpy/" target="_blank" rel="noreferrer noopener">memcpy</a>&nbsp;to copy blittable types and transfer the data between the managed and native parts of Unity.</p>



<p>잡을 예약할 때 memcpy를 이용하여 <strong>데이터를 기본 메모리에 저장</strong>하고, 잡을 실행할 때 해당 <strong>사본에 대한 관리되는 측의 액세스 권한을 제공</strong>합니다.<br>It uses memcpy to put data into native memory when scheduling jobs and gives the managed side access to that copy when executing jobs.</p>



<p>자세한 내용은&nbsp;<a href="https://docs.unity3d.com/kr/2023.2/Manual/JobSystemCreatingJobs.html#schedule-a-job" target="_blank" rel="noreferrer noopener">잡 예약</a>을 참조하십시오.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">컬렉션 패키지 (Collections package)</h2>



<p>컬렉션 패키지는 핵심 Unity 엔진에서 제공하는 job system 외에도 많은&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-jobs.html" target="_blank" rel="noreferrer noopener">job types</a>과&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">native containers</a>를 확장합니다.<br>In addition to the job system provided in the core Unity engine, the Collections package extends many of the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-jobs.html">job typ</a><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-jobs.html" target="_blank" rel="noreferrer noopener">es</a>&nbsp;and&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html">native contain</a><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">ers</a>.</p>



<p>자세한 내용은&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.collections@latest" target="_blank" rel="noreferrer noopener">컬렉션 문서</a>를 참조하십시오.<br>For more information, see the&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.collections@latest" target="_blank" rel="noreferrer noopener">Collections documentation</a>.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9b070ed1 wp-block-columns-is-layout-flex" style="border-width:3px;padding-top:0;padding-right:var(--wp--preset--spacing--60);padding-bottom:0;padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-jobs.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-jobs.html</a></p>



<h1 class="wp-block-heading">잡 개요 (Job Overview)</h1>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p>잡(Job)은 하나의 구체적인 작업을 수행하는 <strong>작은 작업 단위</strong>입니다.<br>A job is a small unit of work that does one specific task.</p>



<p>잡은 매개변수를 받아들이고 데이터에 작업을 수행하는데, <strong>메서드 호출과 유사한 동작</strong>을 합니다.<br>A job receives parameters and operates on data, similar to how a method call behaves.</p>



<p>잡은 독립적으로 실행될 수도 있고, 또는 다른 잡이 완료되어야만 실행될 수도 있습니다.<br>Jobs can be self-contained, or they can depend on other jobs to complete before they can run.</p>



<p>Unity에서 잡은<strong>&nbsp;<a href="https://docs.unity3d.com/kr/2023.2/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener"><code>IJob</code>&nbsp;인터페이스</a>를 구현하는 모든 구조체</strong>를 의미합니다.<br>In Unity, a job refers to any struct that implements&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener">the&nbsp;<code>IJob</code>&nbsp;interface.</a></p>



<p>오직 <strong>Main thread</strong> 에서만 잡을 예약하고 완료할 수 있습니다.<br>Only the main thread can schedule and complete jobs.</p>



<p><strong>Main thread는 실행 중인 잡의 내용에 액세스할 수 없으며, 두 잡이 동시에 하나의 잡 내용에 액세스할 수 없습니다.</strong><br>It can’t access the content of any running jobs, and two jobs can’t access the contents of a job at the same time.</p>



<p>잡이 효율적으로 실행되도록 하려면 <strong>서로 종속적</strong>으로 만들 수 있습니다.<br>To ensure efficient running of jobs, you can make them dependent on each other.</p>



<p>Unity의 잡 시스템을 사용하면 복잡한 <strong>종속성 체인을 생성</strong>하여 잡이 올바른 순서로 완료되도록 할 수 있습니다.<br>Unity’s job system allows you to create complex dependency chains to ensure that your jobs complete in the correct order.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex" style="border-width:2px;border-radius:0px">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">잡 타입 (Job types)</h2>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener"><strong>IJob</strong></a><br>작업 스레드에서 단일 작업을 실행합니다.<br>Runs a single task on a job thread.</li>



<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobParallelFor.html" target="_blank" rel="noreferrer noopener"><strong>IJobParallelFor</strong></a><br>작업을 병렬로 실행합니다.<br>Runs a task in parallel.<br>각각의 병렬로 실행되는 worker thread는 안전하게 worker thread 간에 공유된 데이터에 액세스하기 위한 <strong>독점적인 인덱스</strong>를 갖습니다.<br>Each worker thread that runs in parallel has an exclusive index to access shared data between worker threads safely.</li>



<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Jobs.IJobParallelForTransform.html" target="_blank" rel="noreferrer noopener"><strong>IJobParallelForTransform</strong></a><br>작업을 병렬로 실행합니다.<br>Runs a task in parallel.<br>병렬로 실행되는 <strong>각각의 worker thread는 독점적인 Transform을 가지고 작업을 수행</strong>합니다.<br>Each worker thread running in parallel has an exclusive Transform from the transform hierarchy to operate on.</li>



<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobFor.html" target="_blank" rel="noreferrer noopener"><strong>IJobFor</strong></a><br>IJobParallelFor와 동일하지만, <strong>작업이 병렬로 실행되지 않도록 작업을 예약</strong>할 수 있습니다.<br>The same as&nbsp;<code>IJobParallelFor</code>, but allows you to schedule the job so that it doesn’t run in parallel.</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">IJob</h3>



<p>interface in Unity.Jobs</p>



<p><a href="https://docs.unity3d.com/kr/2023.2/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/kr/2023.2/ScriptReference/Unity.Jobs.IJob.html</a></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>설명</strong></p>



<p>IJob을 사용하여 <strong>다른 작업 및 기본 스레드와 병렬로 실행되는 단일 작업을 예약</strong>합니다.<br>An interface that allows you to schedule a single job that runs in parallel to other jobs and the main thread.</p>



<p>작업이 예약되면 해당 작업의 실행 메서드가 <strong>worker thread</strong>에서 호출됩니다.<br>After a job is scheduled, the job&#8217;s Execute method is invoked on a worker thread.&nbsp;</p>



<p>반환된 <strong>JobHandle</strong>을 사용하여 작업이 완료되었는지 확인할 수 있습니다.<br>You can use the returned&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.html"><strong>JobH</strong></a><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.html" target="_blank" rel="noreferrer noopener"><strong>andle</strong></a>&nbsp;to make sure that the job has completed.</p>



<p>종속성으로 다른 작업에 전달될 수도 있으므로 <strong>worker thread</strong>에서 작업이 차례로 실행되도록 할 수 있습니다.<br>You can also pass the JobHandle to other jobs as a dependency, which ensures that jobs are executed one after another on the worker threads.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">ApplyVelocitySample.cs</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="ApplyVelocitySample" data-enlighter-group="">using UnityEngine;
using Unity.Collections;
using Unity.Jobs;

class ApplyVelocitySample : MonoBehaviour
{
    // 작업 구조체 정의
    struct VelocityJob : IJob
    {
        // 작업에서 액세스할 모든 데이터를 선언
        // 읽기 전용으로 선언함으로써 여러 작업이 데이터에 병렬로 액세스할 수 있게 함
        [ReadOnly]
        public NativeArray&lt;Vector3> velocity;

        // 기본적으로 컨테이너는 읽기 및 쓰기로 가정됨
        public NativeArray&lt;Vector3> position;

        // 델타 타임은 일반적으로 작업이 프레임 개념을 가지지 않기 때문에 작업에 복사되어야 함
        // 메인 스레드는 동일한 프레임 또는 다음 프레임에 작업을 기다리지만, 작업은 워커 스레드에서 실행될 때 결정적이고 독립적인 방식으로 작업을 수행해야 함
        public float deltaTime;
         
        // 작업에서 실행되는 코드
        public void Execute()
        {
            // 델타 타임과 속도에 기반하여 위치 이동
            for (var i = 0; i &lt; position.Length; i++)
                position[i] = position[i] + velocity[i] * deltaTime;
        }
    }

    public void Update()
    {
        var position = new NativeArray&lt;Vector3>(500, Allocator.Persistent);

        var velocity = new NativeArray&lt;Vector3>(500, Allocator.Persistent);

        int _l = velocity.Length;
        for (var i = 0; i &lt; _l; i++)
            velocity[i] = new Vector3(0, 10, 0);

        // 작업 데이터 초기화
        var job = new VelocityJob()
        {
            deltaTime = Time.deltaTime,
            position = position,
            velocity = velocity
        };

        // 작업 예약, 나중에 대기할 수 있는 JobHandle 반환
        JobHandle jobHandle = job.Schedule();

        // 작업이 완료될 때까지 대기
        // 작업을 즉시 완료하는 것은 권장되지 않으며,
        // 실제로 병렬성을 제공하지 않음
        // 작업을 프레임 초기에 예약하고 나중에 프레임 중에 대기하는 것이 최적임
        jobHandle.Complete();

        Debug.Log(job.position[0]);

        // Native 배열은 수동으로 Dispose해야 함
        position.Dispose();
        velocity.Dispose();
    }
}
</pre>



<div style="height:80px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">IJobParallelFor</h3>



<p>interface in Unity.Jobs</p>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobParallelFor.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobParallelFor.html</a></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>설명</strong></p>



<p>각 Native Container의 요소 또는 고정된 반복 횟수에 대해 동일한 독립적인 작업을 수행하는 작업을 나타내는 인터페이스입니다.<br>Interface that represents a job that performs the same independent operation for each element of a native container or for a fixed number of iterations.</p>



<p><code>IJobParallelFor</code> 작업을 예약하면 해당 작업의 <code>Execute(int index)</code><strong> 메서드가 여러 Worker Thread에서 서로 병렬로 호출</strong>됩니다.<br>When you schedule an&nbsp;<code>IJobParallelFor</code>&nbsp;job, its&nbsp;<code>Execute(int index)</code>&nbsp;method is invoked on multiple worker threads in parallel to each other.</p>



<p><code>Execute(int index)</code>는 0부 제공된 길이까지 <strong>각 인덱스에 대해 한 번 실행</strong>됩니다.<br><code>Execute(int index)</code>&nbsp;is executed once for each index from 0 to the provided length.</p>



<p>각 반복은 다른 반복과 독립적이어야 하며, 안전 시스템은 이 규칙을 강제합니다. <br>Each iteration must be independent from other iterations and the safety system enforces this rule for you.</p>



<p>인덱스에는 <strong>보장된 순서가 없으며 여러 코어에서 병렬로 실행</strong>됩니다.<br>The indices have no guaranteed order and are executed on multiple cores in parallel.</p>



<p>Unity는 제공된 배치 크기 이상으로 작업을 청크로 자동 분할하고 Worker Thread 수, 배열 길이 및 배치 크기에 따라 적절한 수의 작업을 예약합니다.<br>Unity automatically splits the work into chunks no less than the provided&nbsp;<code>batchSize</code>, and schedules an appropriate number of jobs based on the number of worker threads, the length of the array, and the batch size.</p>



<p>배치 크기는 작업에서 수행되는 작업 양에 따라 선택해야 합니다. <br>Choose the batch size depending on the amount of work performed in the job.</p>



<p>예를 들어 Vector3를 더하는 <strong>간단한 작업은 배치 크기가 32에서 128이어야 합니다.</strong><br>A simple job, for example adding a couple of Vector3 to each other should have a batch size of 32 to 128.</p>



<p>그러나 수행되는 <strong>작업이 매우 비용이 많이 드는 경우 작은 배치 크기를 사용하는 것이 가장 좋습니다. </strong>예를 들어 배치 크기가 1인 경우입니다. <br>However if the work performed is very expensive then it&#8217;s best practice to use a small batch size, for example a batch size of 1.</p>



<p>IJobParallelFor는 작업 훔치기를 수행하기 위해 극소의 연산을 사용합니다. 배치 크기는 작을 수 있지만 무료는 아닙니다.<br>IJobParallelFor uses atomic operations to perform work stealing. Batch sizes can be small but they are not for free.</p>



<p>반환된 <code>JobHandle</code>을 사용하여 작업이 완료되었는지 확인하거나 다른 작업에 종속성으로 전달하여 Worker Thread에서 작업이 서로 차례대로 실행되도록 할 수 있습니다.<br>You can use the returned&nbsp;<code>JobHandle</code>&nbsp;to make sure that the job has completed, or you can pass it to other jobs as a dependency to make sure that the jobs are executed one after another on the worker threads.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">ApplyVelocityParallelForSample.cs</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="ApplyVelocityParallelForSample " data-enlighter-group="">using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

class ApplyVelocityParallelForSample : MonoBehaviour
{
    struct VelocityJob : IJobParallelFor
    {
        // 작업에서 액세스될 모든 데이터를 선언합니다.
        // 읽기 전용으로 선언함으로써 여러 작업이 데이터에 병렬로 액세스할 수 있습니다.
        [ReadOnly]
        public NativeArray&lt;Vector3> velocity;

        // 기본적으로 컨테이너는 읽기 및 쓰기로 가정됩니다.
        public NativeArray&lt;Vector3> position;

        // 작업은 일반적으로 프레임의 개념이 없기 때문에 델타 타임은 작업으로 복사되어야 합니다.
        // 주 스레드는 작업이 동일한 프레임이나 다음 프레임에 실행되기를 기다리지만,
        // 작업은 언제 워커 스레드에서 실행될지에 관계없이 결정론적으로 독립적으로 작업해야 합니다.
        public float deltaTime;

        // 실제로 작업에서 실행되는 코드
        public void Execute(int i)
        {
            // 델타 타임과 속도에 기반하여 위치를 이동합니다.
            position[i] = position[i] + velocity[i] * deltaTime;
        }
    }

    public void Update()
    {
        // 위치에 대한 네이티브 배열 초기화
        var position = new NativeArray&lt;Vector3>(500, Allocator.Temp);

        // 속도에 대한 네이티브 배열 초기화
        var velocity = new NativeArray&lt;Vector3>(500, Allocator.Temp);
        for (var i = 0; i &lt; velocity.Length; i++)
            velocity[i] = new Vector3(0, 10, 0);

        // 작업 데이터 초기화
        var job = new VelocityJob()
        {
            deltaTime = Time.deltaTime,
            position = position,
            velocity = velocity
        };

        // 병렬 작업 예약. 첫 번째 매개변수는 각 반복(iteration)을 수행할 횟수이며,
        // 두 번째 매개변수는 배치 크기(batch size)로,
        // 내부 루프에서 Execute(i)를 불러오는 오버헤드가 없는 값입니다.
        // 각 반복에서 수행할 작업이 많은 경우에는 1의 값을 사용할 수 있습니다.
        // 작업이 매우 적은 경우에는 32 또는 64의 값이 적절합니다.
        JobHandle jobHandle = job.Schedule(position.Length, 64);

        // 작업이 완료될 때까지 대기합니다.
        // 작업을 즉시 완료하는 것은 권장되지 않습니다.
        // 왜냐하면 그렇게 되면 다른 작업이 병렬로 실행되는 기회가 줄어들기 때문입니다.
        // 작업을 프레임 초반에 예약하고, 프레임 후반에 완료되길 기다리는 것이 최적입니다.
        jobHandle.Complete();

        Debug.Log(job.position[0]);

        // 네이티브 배열은 수동으로 해제되어야 합니다.
        position.Dispose();
        velocity.Dispose();
    }
}
</pre>



<div style="height:80px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">IJobParallelForTransform</h3>



<p>interface in UnityEngine.Jobs</p>



<p><a href="https://docs.unity3d.com/kr/2023.2/ScriptReference/Jobs.IJobParallelForTransform.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/kr/2023.2/ScriptReference/Jobs.IJobParallelForTransform.html</a></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>설명</strong><br>Description</p>



<p>변환을 위한 병렬 작업을 사용하면 작업에 전달된 모든 변환의 각 <strong>위치, 회전 및 배율에 대해 동일한 독립적 작업을 수행</strong>할 수 있습니다.<br>An interface that allows you to perform the same independent operation for each position, rotation and scale of all the transforms passed into a job.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">ApplyVelocitySample.cs</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="ApplyVelocityParallelForSample " data-enlighter-group="">using UnityEngine;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine.Jobs;

class ApplyVelocitySample : MonoBehaviour
{
    public struct VelocityJob : IJobParallelForTransform
    {
        // Jobs는 작업에서 액세스 될 모든 데이터를 선언합니다.
        // 읽기 전용으로 선언함으로써 여러 작업이 데이터에 병렬로 액세스할 수 있게 합니다.
        [ReadOnly]
        public NativeArray&lt;Vector3> velocity;

        // 작업에서는 일반적으로 프레임의 개념이 없기 때문에 델타 타임은 작업으로 복사되어야 합니다.
        // 메인 스레드는 작업이 동작하는 동안 같은 프레임 또는 다음 프레임에 대기하지만,
        // 작업은 워커 스레드에서 실행될 때에도 작업이 실행되는 시기에 독립적으로 작업을 수행해야 합니다.
        public float deltaTime;

        // 실제로 작업에서 실행되는 코드
        public void Execute(int index, TransformAccess transform)
        {
            // 델타 타임과 속도를 기반으로 변환을 이동합니다.
            var pos = transform.position;
            pos += velocity[index] * deltaTime;
            transform.position = pos;
        }
    }

    // 인스펙터에서 작업할 변환을 할당합니다.
    [SerializeField] public Transform[] m_Transforms;
    TransformAccessArray m_AccessArray;

    void Awake()
    {
        // 변환을 TransformAccessArray 인스턴스에 저장하여
        // 작업에서 액세스할 수 있도록 합니다.
        m_AccessArray = new TransformAccessArray(m_Transforms);
    }

    void OnDestroy()
    {
        // TransformAccessArray는 수동으로 폐기해야 합니다.
        m_AccessArray.Dispose();
    }

    public void Update()
    {
        var velocity = new NativeArray&lt;Vector3>(m_Transforms.Length, Allocator.Persistent);

        for (var i = 0; i &lt; velocity.Length; ++i)
            velocity[i] = new Vector3(0f, 10f, 0f);

        // 작업 데이터를 초기화합니다.
        var job = new VelocityJob()
        {
            deltaTime = Time.deltaTime,
            velocity = velocity
        };

        // 병렬-for-변환 작업을 예약합니다.
        // 메서드는 작업에서 동작될 TransformAccessArray를 취합니다.
        JobHandle jobHandle = job.Schedule(m_AccessArray);

        // 작업이 완료될 때까지 대기합니다.
        // 작업을 즉시 완료하는 것은 권장되지 않습니다.
        // 왜냐하면 이렇게하면이 작업과 병렬로 다른 작업이 실행될 가능성이 줄어듭니다.
        // 최적으로는 프레임 초반에 작업을 예약한 다음 프레임 중후반에 대기해야 합니다.
        jobHandle.Complete();

        Debug.Log(m_Transforms[0].position);

        // Native 배열은 수동으로 폐기해야 합니다.
        velocity.Dispose();
    }
}
</pre>



<div style="height:80px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">IJobFor</h3>



<p>interface in Unity.Jobs</p>



<p><a href="https://docs.unity3d.com/ScriptReference/Unity.Jobs.IJobFor.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/ScriptReference/Unity.Jobs.IJobFor.html</a></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>설명</strong><br>Description</p>



<p>Jobs는 Native Container의 각 요소 또는 고정된 반복 횟수에 대해 동일한 독립적인 작업을 수행할 수 있게 해줍니다. <br>An interface that represents a job that performs the same independent operation for each element of a native container or for a fixed number of iterations.</p>



<p>이 작업은 작업을 어떻게 스케줄하길 원하는지에 대한 여러 옵션을 허용합니다:<br>This job type has the following options to schedule work:</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobForExtensions.Run.html" target="_blank" rel="noreferrer noopener">IIJobForExtensions.Run</a><br>작업을 주 스레드에서 실행하고 즉시 완료합니다.<br>runs the job on the main thread and finishes immediately.</li>



<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobForExtensions.Schedule.html" target="_blank" rel="noreferrer noopener">IJobForExtensions.Schedule</a><br>작업을 Worker Thread(또는 주 스레드)에서 실행하도록 예약하지만 작업이 단일 스레드에서 수행되어야 함을 나타냅니다.<br>schedules the job to run on a worker thread or the main thread, but indicates that the work should happen in a single thread.<br>이 옵션은 주 스레드 이외에서 작업을 수행할 수 있게 해주지만, 작업이 순차적으로 수행되기 때문에 이해하기 쉽습니다.</li>



<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobForExtensions.ScheduleParallel.html" target="_blank" rel="noreferrer noopener">IJobForExtensions.ScheduleParallel</a><br>작업을 병렬로 실행되도록 예약합니다. <br>schedules the job to run on multiple worker threads concurrently.<br>이 스케줄링 옵션은 최상의 성능을 제공할 수 있지만, 동시에 여러 Worker Thread에서 동일한 데이터에 접근할 때 발생할 수 있는 충돌을 이해해야 합니다.<br>This option allows for work to be done off the main thread, but the work is performed sequentially.</li>



<li><code>Execute(int index)</code><br>제공된 길이에 대해 0 에서부터 각 인덱스까지 한 번씩 실행됩니다.<br>is executed once for each index from 0 to the provided length.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><code>Run</code> and <code>Schedule</code> 은 작업의 <code>Execute(intindex)</code> 메서드가 순차적으로 호출됨을 보장합니다.<br><code>Run</code>&nbsp;and&nbsp;<code>Schedule</code>&nbsp;guarantees that the the job&#8217;s&nbsp;<code>Execute(int index)</code>&nbsp;method is invoked sequentially.</p>



<p><code>Schedule Parallel</code>은 작업의 <code>Execute</code> 메서드를 여러 개의 워커 스레드에서 서로 병렬로 호출하므로 순차적으로 호출하지 않습니다.<br><code>ScheduleParallel</code>&nbsp;doesn&#8217;t invoke the job&#8217;s&nbsp;<code>Execute</code>&nbsp;method sequentially because it&#8217;s called from multiple worker threads in parallel to each other.</p>



<p>각 반복은 다른 반복과 독립적이어야 하며 안전 시스템이 이 규칙을 강제합니다. <br>Each iteration must be independent from other iterations and the safety system enforces this rule for you.</p>



<p>인덱스에는 보장된 순서가 없으며 여러 코어에서 병렬로 실행됩니다.<br>The indices have no guaranteed order and are executed on multiple cores in parallel.</p>



<p></p>



<p></p>



<p>Unity는 작업을 제공된 <code>batchSize</code> 이상의 크기로 자동으로 나누고 워커 스레드 수, 배열의 길이 및 배치 크기에 따라 적절한 수의 작업을 예약합니다.<br>Unity automatically splits the work into chunks of no less than the provided&nbsp;<code>batchSize</code>, <br>and schedules an appropriate number of jobs based on the number of worker threads, the length of the array and the batch size.</p>



<p>배치 크기는 일반적으로 작업에서 수행되는 작업 양에 따라 선택되어야 합니다.<br>You should choose the batch size based on the amount of work performed in the job.</p>



<p>예를 들어 몇 개의 Vector3를 더하는 간단한 작업은 일반적으로 32에서 128의 배치 크기를 가질 수 있습니다.<br>A simple job, for example adding a couple of Vector3 to each other should have a batch size of 32 to 128.</p>



<p>그러나 수행되는 작업이 매우 비용이 많이 들 경우 작은 배치 크기를 사용하는 것이 좋습니다. 비용이 많이 드는 작업의 경우 배치 크기 1도 충분합니다. <br>However, if the work performed is very expensive then it&#8217;s best practice to use a small batch size, for example, a batch size of 1.</p>



<p>IJobFor는 atomic 연산을 사용하여 작업 스틸링을 수행합니다. 배치 크기는 작지만 무료가 아닙니다.<br>&nbsp;IJobFor performs work stealing using atomic operations. Batch sizes can be small but they are not for free.</p>



<p>반환된 <code>JobHandle</code>은 작업이 완료되었는지를 확인하는 데 사용할 수 있습니다.<br>You can use the returned&nbsp;<code>JobHandle</code>&nbsp;to check that the job has completed, or pass it to other jobs as a dependency.</p>



<p><code>JobHandle</code>을 종속성으로 전달하면 작업이 워커 스레드에서 하나씩 순차적으로 실행되도록 보장됩니다.<br>When you pass a&nbsp;<code>JobHandle</code>&nbsp;as a dependency, it ensures that the jobs are executed one after another on the worker threads.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">ApplyVelocityParallelForSample.cs</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Unity.Collections;
using Unity.Jobs;

class ApplyVelocityParallelForSample : MonoBehaviour
{
    struct VelocityJob : IJobFor
    {
        // Jobs는 작업에서 액세스할 모든 데이터를 선언합니다.
        // 읽기 전용으로 선언함으로써 여러 작업이 데이터에 병렬로 액세스할 수 있습니다.
        [ReadOnly]
        public NativeArray&lt;Vector3> velocity;

        // 기본적으로 컨테이너는 읽기 및 쓰기로 가정됩니다.
        public NativeArray&lt;Vector3> position;

        // 델타 타임은 일반적으로 프레임의 개념이 없는 작업에서 작업이 수행됩니다.
        // 메인 스레드는 작업이 동일한 프레임 또는 다음 프레임에 실행되기를 기다립니다.
        // 그러나 작업은 워커 스레드에서 실행될 때에 프레임의 개념을 가지지 않아야 합니다.
        public float deltaTime;

        // 작업에서 실행되는 실제 코드
        public void Execute(int i)
        {
            // 델타 타임과 속도를 기반으로 위치를 이동시킵니다.
            position[i] = position[i] + velocity[i] * deltaTime;
        }
    }

    public void Update()
    {
        var position = new NativeArray&lt;Vector3>(500, Allocator.Persistent);

        var velocity = new NativeArray&lt;Vector3>(500, Allocator.Persistent);
        for (var i = 0; i &lt; velocity.Length; i++)
            velocity[i] = new Vector3(0, 10, 0);

        // 작업 데이터 초기화
        var job = new VelocityJob()
        {
            deltaTime = Time.deltaTime,
            position = position,
            velocity = velocity
        };

        // 작업을 즉시 메인 스레드에서 실행하도록 예약합니다. 첫 번째 매개 변수는 각각의 반복 횟수입니다.
        job.Run(position.Length);

        // 나중에 단일 워커 스레드에서 작업을 예약합니다.
        // 첫 번째 매개 변수는 각각의 반복 횟수입니다.
        // 두 번째 매개 변수는 이 작업의 종속성에 사용할 JobHandle입니다.
        // 종속성은 작업이 종속성이 완료된 후에 워커 스레드에서 실행되도록 보장합니다.
        // 이 경우 작업이 어떤 것에도 의존하지 않기 때문에 기본 값을 사용할 수 있습니다.
        JobHandle scheduleJobDependency = new JobHandle();
        JobHandle scheduleJobHandle = job.Schedule(position.Length, scheduleJobDependency);

        // 병렬 워커 스레드에서 작업을 실행하도록 예약합니다.
        // 첫 번째 매개 변수는 각각의 반복 횟수입니다.
        // 두 번째 매개 변수는 배치 크기이며,
        // 본질적으로는 Execute(i)를 루프에서 호출하는 오버헤드가 없는 내부 루프입니다.
        // 각 반복에서 많은 작업이 있는 경우 값이 1이 합리적일 수 있습니다.
        // 매우 적은 작업이 있는 경우 32 또는 64의 값이 합리적일 수 있습니다.
        // 세 번째 매개 변수는 이 작업의 종속성에 사용할 JobHandle입니다.
        // 종속성은 작업이 종속성이 완료된 후에 워커 스레드에서 실행되도록 보장합니다.
        JobHandle scheduleParallelJobHandle = job.ScheduleParallel(position.Length, 64, scheduleJobHandle);

        // 작업이 완료될 때까지 기다립니다.
        // 작업을 즉시 완료하는 것은 권장되지 않습니다.
        // 왜냐하면 이렇게 하면이 작업과 병렬로 다른 작업이 실행되는 기회가 줄어들기 때문입니다.
        // 최적으로는 프레임 초반에 작업을 예약하고 나중에 프레임에서 기다리는 것이 좋습니다.
        scheduleParallelJobHandle.Complete();

        Debug.Log(job.position[0]);

        // Native 배열은 수동으로 해제되어야 합니다.
        position.Dispose();
        velocity.Dispose();
    }
}
</pre>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">요약 (Summary)</h3>



<ol class="wp-block-list">
<li><strong>IJob:</strong>
<ul class="wp-block-list">
<li><strong>단일 스레드 방식으로 작업을 실행</strong>합니다.</li>



<li><strong>병렬화가 필요하지 않은 작업</strong>에 적합합니다.</li>



<li><code>IJob</code> 인터페이스를 구현하며 <code>Execute()</code> 메서드를 제공합니다.</li>
</ul>
</li>



<li><strong>IJobParallelFor:</strong>
<ul class="wp-block-list">
<li>일련의 <strong>인덱스에 대해 병렬로 작업을 실행</strong>합니다.</li>



<li>각 인덱스에 대해 <strong>병렬로 호출되는 작업에 유용</strong>합니다.</li>



<li><code>IJobParallelFor</code> 인터페이스를 구현하며 <code>Execute(int index)</code> 메서드를 제공합니다.</li>



<li><strong>지정된 범위 내의 각 인덱스</strong>에 대해 <code>Execute</code> 메서드가 <strong>병렬로 호출</strong>됩니다.</li>
</ul>
</li>



<li><strong>IJobParallelForTransform:</strong>
<ul class="wp-block-list">
<li><strong><code>Transform</code> 구성 요소에 대한 병렬화된 작업</strong>을 수행하는 특수한 작업입니다.</li>



<li>여러 개체의 변환에 대한 작업을 <strong>병렬화하려는 경우에 사용</strong>됩니다.</li>



<li><code>IJobParallelForTransform</code> 인터페이스를 구현하며 <code>Execute(int index, TransformAccess transform)</code> 메서드를 제공합니다.</li>



<li><strong><code>Transform</code> 구성 요소를 병렬로 수정</strong>할 수 있습니다.</li>
</ul>
</li>



<li><strong>IJobFor:</strong>
<ul class="wp-block-list">
<li><strong>단일 스레드 방식으로 작업을 실행</strong>하지만 인덱스의 범위를 반복합니다.</li>



<li>병렬화는 이루어지지 않지만 <strong>여러 인덱스에 대해 순차적으로 작업을 수행</strong>합니다.</li>



<li><code>IJobFor</code> 인터페이스를 구현하며 <code>Execute(int index)</code> 메서드를 제공합니다.</li>



<li><strong>지정된 범위 내의 각 인덱스에 대해</strong> <code>Execute</code> 메서드가 순차적으로 호출됩니다.</li>
</ul>
</li>
</ol>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-cad298ab wp-block-columns-is-layout-flex" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html</a></p>



<h1 class="wp-block-heading">스레드 세이프 타입 (Thread safe types)</h1>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p>작업 시스템은 <strong>Burst 컴파일러</strong>와 함께 사용될 때 가장 효과적으로 작동합니다.<br>The job system works best when you use it with the&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.burst@latest/" target="_blank" rel="noreferrer noopener">Burst compiler</a>.</p>



<p>Burst는 관리되는 객체를 지원하지 않기 때문에 작업에서 데이터에 액세스하려면 <strong>관리되지 않는 타입을 사용</strong>해야 합니다.<br>Because Burst doesn’t support managed objects, you need to use unmanaged types to access the data in jobs.</p>



<p>이를 위해<strong> blittable 타입</strong>을 사용하거나 <strong>Unity에서 기본으로 제공하는 스레드 안전 C# 래퍼</strong> <strong>NativeContainer 객체</strong>를 사용할 수 있습니다.<br>You can do this with&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types" target="_blank" rel="noreferrer noopener">blittable types</a>, or use Unity’s built-in&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerAttribute.html" target="_blank" rel="noreferrer noopener"><code>NativeContainer</code></a>&nbsp;objects, which are a thread-safe C# wrapper for native memory.</p>



<p><code>NativeContainer</code> 객체는 <strong>작업에서 복사본으로 작업하는 대신 <a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html#multithreading" target="_blank" rel="noreferrer noopener">Main thread</a>와 공유하는 데이터에 액세스</strong>할 수도 있습니다.<br><code>NativeContainer</code>&nbsp;objects also allow a job to access data shared with the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html#multithreading" target="_blank" rel="noreferrer noopener">main thread</a>&nbsp;rather than working with a copy.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">NativeContainer 객체의 종류 (Types of NativeContainers)</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><code>Unity.Collections</code> 네임스페이스에는 다음과 같은 기본 제공 <code>NativeContainer </code>객체가 포함되어 있습니다:<br>The&nbsp;<code>Unity.Collections</code>&nbsp;namespace contains the following built-in&nbsp;<code>NativeContainer</code>&nbsp;objects:</p>



<ul class="wp-block-list">
<li>NativeArray :<br>관리되지 않는 배열로, 관리 코드에 네이티브 메모리 버퍼를 노출시킵니다.<br>An unmanaged array which exposes a buffer of native memory to managed code</li>



<li>NativeSlice :<br>특정 위치부터 특정 길이까지의 <code>NativeArray</code>의 하위 집합을 가져옵니다.<br>Gets a subset of a&nbsp;<code>NativeArray</code>&nbsp;from a particular position to a certain length.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>참고</strong><br><a href="https://docs.unity3d.com/Packages/com.unity.collections@latest/" target="_blank" rel="noreferrer noopener">Collections package</a>에는 추가적인 <code>NativeContainer</code>가 포함되어 있습니다. <br>The&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.collections@latest/" target="_blank" rel="noreferrer noopener">Collections package</a>&nbsp;contains additional&nbsp;<code>NativeContainer</code>s.<br>추가 유형의 전체 목록은 Collection types에서 <a href="https://docs.unity3d.com/Packages/com.unity.collections@1.2/manual/collection-types.html" target="_blank" rel="noreferrer noopener">Collections 문서를 참조</a>하세요.<br>For a full list of the additional types, see the Collections documentation on&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.collections@latest/index.html?subfolder=/manual/collection-types.html" target="_blank" rel="noreferrer noopener">Collection types</a>.</p>



<div style="height:60px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">읽기 및 쓰기 액세스 (Read and Write Access)</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>기본적으로 작업이 <code>NativeContainer</code>&nbsp; 인스턴스에 <strong>액세스할 때 읽기 및 쓰기 액세스 권한이 모두 부여</strong>됩니다. <br>By default, when a job has access to a&nbsp;<code>NativeContainer</code>&nbsp;instance, it has both read and write access. </p>



<p>이 구성은 <strong>성능을 떨어뜨릴 수 있습니다.</strong><br>This configuration can slow performance. </p>



<p>작업 시스템은 <strong>동시에 두 개 이상의 작업이 동일한 <code>NativeContainer</code> 인스턴스에 쓰기 액세스하는 것을 허용하지 않기 때문</strong>입니다.<br>This is because the job system doesn’t allow you to schedule a job that has write access to a&nbsp;<code>NativeContainer</code>&nbsp;instance at the same time as another job that’s writing to it.</p>



<p>그러나 작업이 <code>NativeContainer</code> 인스턴스에 기록할 필요가 없는 경우 다음과 같이 <code>NativeContainer</code>를 <code>[ReadOnly]</code> 속성으로 표시할 수 있습니다:<br>However, If a job doesn’t need to write to a&nbsp;<code>NativeContainer</code>&nbsp;instance, you can mark the&nbsp;<code>NativeContainer</code>&nbsp;with the&nbsp;<code>[ReadOnly]</code>&nbsp;attribute, like so:</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[ReadOnly]
public NativeArray&lt;int> input;</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>위의 예에서는 첫 번째 <code>NativeArray</code>에 대한 <strong>읽기 전용 액세스 권한</strong>이 있는 다른 작업과 동시에 작업을 실행할 수 있습니다.<br>In the above example, you can execute the job at the same time as other jobs that also have read-only access to the first&nbsp;<code>NativeArray</code>.</p>



<div style="height:60px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">메모리 할당자 (Memory Allocators)</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><code>NativeContainer</code> 인스턴스를 생성할 때는 필요한 <strong>메모리 할당 유형을 지정</strong>해야 합니다. <br>When you create a&nbsp;<code>NativeContainer</code> instance, you must specify the memory allocation type that you need.</p>



<p>사용하는 할당 유형은 해당 <strong>네이티브 컨테이너를 얼마 동안 유지하고 싶은지에 따라 다릅니다.</strong><br>The allocation type you use depends on how long you would like to keep the native container available for.</p>



<p>이렇게 함으로써 각 상황에서 최상의 성능을 얻을 수 있습니다.<br>This way you can tailor the allocation to get the best performance possible in each situation.</p>



<p><code>NativeContainer</code> 메모리 할당 및 해제에는 세 가지 Allocator 유형이 있습니다. <br>There are three&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.Allocator.html">Allocator</a>&nbsp;types for&nbsp;<code>NativeContainer</code>&nbsp;memory allocation and release.</p>



<p><code>NativeContainer</code> 인스턴스를 인스턴스화할 때 적절한 것을 지정해야 합니다:<br>You must specify the appropriate one when instantiating a&nbsp;<code>NativeContainer</code>&nbsp;instance:</p>



<ol class="wp-block-list">
<li><strong>Allocator.Temp:</strong>
<ul class="wp-block-list">
<li>가장 <strong>빠른 할당</strong> 방식입니다.<br>The fastest allocation.</li>



<li>수명이 <strong>한 프레임 이하인 할당</strong>에 사용합니다.<br>Use it for allocations with a lifespan of one frame or fewer.</li>



<li>Temp를 사용하여 작업의 멤버 필드에 저장된 <strong>NativeContainer instance로 할당을 전달할 수 없습니다.</strong><br>You can’t use Temp to pass allocations to NativeContainer instances stored in a job’s member field.</li>
</ul>
</li>



<li><strong>Allocator.TempJob:</strong>
<ul class="wp-block-list">
<li>Temp보다는 느린 할당 방식이지만 Persistent보다는 빠릅니다. (중간)<br>A slower allocation than Temp but faster than Persistent.</li>



<li><strong>최대 4프레임 동안의 수명</strong>을 가진 스레드 안전한 할당에 사용합니다.<br>Use it for thread-safe allocations within a lifespan of four frames.</li>



<li>중요: 이 할당 유형은 <strong>4프레임 이내에 Dispose해야 하며</strong>, 그렇지 않으면 콘솔에 경고가 표시되며 네이티브 코드에서 생성됩니다. <br>Important: You must Dispose of this allocation type within four frames, or the console prints a warning, generated from the native code.<br>대부분의 작은 작업은 이 할당 유형을 사용합니다.<br>Most small jobs use this allocation type.</li>
</ul>
</li>



<li><strong>Allocator.Persistent:</strong>
<ul class="wp-block-list">
<li>가장 느린 할당 방식이지만<strong> 필요한 경우 응용 프로그램 수명 전체 또는 필요한 기간 동안 지속</strong>될 수 있습니다.<br>The slowest allocation but can last as long as you need it to, and if necessary, throughout the application’s lifetime.</li>



<li>malloc에 직접 호출하는 래퍼입니다.<br>It’s a wrapper for a direct call to malloc.</li>



<li>긴 작업에는 이 NativeContainer 할당 유형을 사용할 수 있습니다. <br>Longer jobs can use this NativeContainer allocation type.<br>성능이 중요한 경우에는 Persistent를 사용하지 않는 것이 좋습니다.<br>Don’t use Persistent where performance is essential.</li>
</ul>
</li>
</ol>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>예를 들어 :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">NativeArray&lt;float> result = new NativeArray&lt;float>(1, Allocator.TempJob);</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>참고 : 위의 예제에서 숫자 1은 NativeArray의 크기를 나타냅니다.  이 경우 결과에 저장되는 데이터가 하나이므로 배열 요소가 하나만 있습니다.<br><strong>Note:</strong>&nbsp;The number 1 in the example above indicates the size of the NativeArray. In this case, it has only one array element because it only stores one piece of data in its result.</p>



<div style="height:60px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">NativeContainer 안전 시스템 (NativeContainer safety system)</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>안전 시스템은 모든 NativeContainer 인스턴스에 <strong>내장</strong>되어 있습니다.<br>The safety system is built into all NativeContainer instances.</p>



<p>이 시스템은 어떤 NativeContainer 인스턴스에 대한 <strong>읽기 또는 쓰기를 추적</strong>하고<br>It tracks what reads or writes to any NativeContainer instance,</p>



<p>이 정보를 사용하여 여러 작업 및 스레드에서 NativeContainer의 사용에 특정 규칙을 강제합니다.<br>이로써 NativeContainer는 다중 작업 및 스레드에서 결정론적으로 작동하도록 보장됩니다. (동일한 입력에 대해 동일한 출력을 생성)<br>and uses that information to enforce certain rules on the use of NativeContainers that makes them behave in a deterministic way across multiple jobs and threads.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>예를 들어, 두 개의 독립적인 예약 작업이<strong> 동일한 NativeArray에 쓰기를 시도하면 예측할 수 없기 때문에 이는 안전하지 않습니다. </strong><br>For example, if two independent scheduled jobs write to the same NativeArray, this is unsafe because you can’t predict which job executes first.</p>



<p>어떤 작업이 먼저 실행될지 예측할 수 없으므로 두 작업 중 어떤 것이 다른 작업에서의 데이터를 덮어쓸지 알 수 없습니다.<br>This means that you won’t know which of the jobs will overwrite data from the other.</p>



<p>두 번째 작업을 예약할 때, 안전 시스템은 문제를 설명하는 명확한 오류 메시지와 문제를 해결하는 방법을 제시하는 예외를 throw합니다.<br>The safety system throws an exception with a clear error message that explains why and how to solve the problem, when you schedule the second job.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>만약 동일한 NativeContainer 인스턴스에 <strong>쓰기 작업을 하는 두 작업을 예약하려면, 작업을 종속성을 가지도록 예약</strong>할 수 있습니다. <br>If you want to schedule two jobs that write to the same NativeContainer instance, you can schedule the jobs with a dependency.</p>



<p><strong>첫 번째 작업</strong>이 NativeContainer에 쓰기를 수행하고 나면 <strong>다음 작업</strong>이 동일한 NativeContainer에 안전하게 읽기 및 쓰기를 수행합니다.<br>The first job writes to the NativeContainer, and once it has finished executing, the next job safely reads and writes to that same NativeContainer.</p>



<p>종속성을 도입함으로써 <strong>작업이 항상 일관된 순서로 실행되고 NativeContainer의 결과 데이터가 결정론적으로 유지</strong>됩니다.<br>Introducing the dependency guarantees that the jobs always execute in a consistent order and that the resulting data in the NativeContainer is deterministic.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>안전 시스템은 여러 작업이 동시에 동일한 데이터를 읽을 수 있도록 허용합니다.<br>The safety system allows multiple jobs to read from the same data in parallel.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>이러한 <strong>읽기 및 쓰기 제한은 데이터에 메인 스레드에서 액세스할 때도 적용</strong>됩니다.<br>These read and write restrictions also apply when accessing data from the main thread.</p>



<p>예를 들어, NativeContainer에 쓰기를 완료하기 전에 해당 NativeContainer의 내용을 읽으려고 하면 안전 시스템에서 오류가 발생합니다.<br>For example, if you try to read the contents of a NativeContainer before the job that writes to it has completed, the safety system throws an error.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>마찬가지로 해당 NativeContainer에 대해 아직 처리되지 않은 읽기 또는 쓰기 작업이 있는 동안 해당 NativeContainer에 쓰려고 하면 안전 시스템에서도 오류가 발생합니다.<br>Likewise, if you try to write to a NativeContainer while there are still pending jobs that read or write to it, then the safety system also throws an error.</p>



<p>또한 NativeContainers는 ref return을 구현하지 않기 때문에 NativeContainer의 내용을 직접 변경할 수 없습니다.<br>Also, because NativeContainers don’t implement ref return, you can’t directly change the contents of a NativeContainer.</p>



<p>예를 들어 <code>nativeArray[0]++;</code>는 <code>var temp = nativeArray[0]; temp++;</code>와 동일하며, 이는<strong> nativeArray의 값이 업데이트되지 않습니다.</strong><br>For example, nativeArray[0]++; is the same as writing var temp = nativeArray[0]; temp++; which doesn’t update the value in nativeArray.</p>



<p>대신, 해당 인덱스의 데이터를 <strong>지역 임시 복사본으로 복사하고 해당 복사본을 수정한 다음 다시 저장</strong>해야 합니다. <br>Instead, you must copy the data from the index into a local temporary copy, modify that copy, and save it back. For example:</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>예를 들면:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">MyStruct temp = myNativeArray[i];
temp.memberVariable = 0;
myNativeArray[i] = temp;</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">추가 리소스 (Additional resources)</h2>



<p><a href="https://docs.unity3d.com/kr/2023.2/Manual/job-system-custom-nativecontainer.html" target="_blank" rel="noreferrer noopener">커스텀&nbsp;<code>NativeContainer</code>&nbsp;구현</a><br><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer.html" target="_blank" rel="noreferrer noopener">Implement a custom&nbsp;<code>NativeContainer</code></a></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex" style="border-width:2px;border-radius:0px">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer.html</a></p>



<h2 class="wp-block-heading">커스텀 네이티브 컨테이너 구현 (Implement a custom native container)</h2>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p>사용자 정의 네이티브 컨테이너를 구현하려면 해당 유형에 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerAttribute.html" target="_blank" rel="noreferrer noopener">NativeContainer 속성</a>을 부여해야 합니다. <br>To implement a custom native container, you must annotate your type with the the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerAttribute.html" target="_blank" rel="noreferrer noopener"><code>NativeContainer</code></a>&nbsp;attribute.</p>



<p>또한 네이티브 컨테이너가 안전 시스템과 통합되는 방식을 이해해야 합니다.<br>You should also understand how native containers are integrated with&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html#safety-system" target="_blank" rel="noreferrer noopener">the safety system</a>.</p>



<p>구현해야 할 두 가지 주요 요소가 있습니다:<br>There are two major elements to implement:</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>사용 추적(Usage Tracking) :</strong>
<ul class="wp-block-list">
<li>Unity가 <code>NativeContainer</code> 인스턴스를 사용하는 <strong>예약된 작업을 추적하도록 허용</strong>하여 <br>두 작업이 동시에 <strong>동일한 네이티브 컨테이너에 쓰기를 시도</strong>하는 등의 <strong>충돌을 감지</strong>하고 방지합니다.<br>Allows Unity to keep track of scheduled jobs that use a&nbsp;<code>NativeContainer</code>&nbsp;instance, <br>so that it can detect and prevent potential conflicts, such as two jobs writing to the same native container at the same time.</li>
</ul>
</li>



<li><strong>누수 추적(Leak Tracking) :</strong>
<ul class="wp-block-list">
<li><code>NativeContainer</code> 가 제대로 <strong>Dispose되지 않은 경우를 감지</strong>합니다. <br>Detects when a&nbsp;<code>NativeContainer</code>&nbsp;isn’t disposed of properly. <br>이러한 상황에서는 <strong>메모리 누수가 발생</strong>하여 <code>NativeContainer</code>&nbsp;에 할당된 메모리가 프로그램의 나머지 수명 동안 사용할 수 없게 됩니다.<br>&nbsp;In this situation, a memory leak happens, where the memory allocated to the&nbsp;<code>NativeContainer</code>&nbsp;becomes unavailable for the entire remaining lifetime of the program.</li>
</ul>
</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">사용량 추적 구현 (Implement usage tracking)</h3>



<p>사용 추적을 구현하려면 코드에서<strong> <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.html" target="_blank" rel="noreferrer noopener">AtomicSafetyHandle</a> 클래스를 사용</strong>합니다.<br>To access usage tracking in your code, use the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.html" target="_blank" rel="noreferrer noopener"><code>AtomicSafetyHandle</code></a>&nbsp;class.</p>



<p><code>AtomicSafetyHandle</code>은 주어진 <code>NativeContainer</code>에 대해<strong> 안전 시스템이 저장하는 중앙 정보에 대한 참조</strong>를 보유하며, <br><code>NativeContainer</code>의 메서드가 안전 시스템과 상호 작용하는 주요 방법입니다. <br><code>AtomicSafetyHandle</code> holds a reference to the central information that the safety system stores for a given <code>NativeContainer</code>, <br>and is the main way that the methods of a <code>NativeContainer</code> interact with the safety system.</p>



<p>따라서 모든 <strong><code>NativeContainer</code> 인스턴스는 m_Safety라는 이름의 <code>AtomicSafetyHandle</code> 필드를 포함</strong>해야 합니다.<br>Because of this, every&nbsp;<code>NativeContainer</code>&nbsp;instance must contain an&nbsp;<code>AtomicSafetyHandle</code>&nbsp;field named&nbsp;<code>m_Safety</code>.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>각 <code>AtomicSafetyHandle</code>은 현재 컨텍스트에서 NativeContainer에 <strong>수행할 수 있는 작업 유형을 나타내는 플래그 집합을 저장</strong>합니다.<br>Each&nbsp;<code>AtomicSafetyHandle</code>&nbsp;stores a set of flags that indicate what types of operation can be performed on the native container in the current context.</p>



<p>작업이 <code>NativeContainer</code> 인스턴스를 포함하는 경우 작업 시스템은 자동으로 <code>AtomicSafetyHandle</code>의 플래그를 구성하여 <br>해당 작업에서  NativeContainer를 사용할 수 있는 방식을 반영합니다.<br>When a job contains a&nbsp;<code>NativeContainer</code>&nbsp;instance, the job system automatically configures <br>the flags in the&nbsp;<code>AtomicSafetyHandle</code>&nbsp;to reflect the way that the native container can be used in that job.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>작업이 <code>NativeContainer</code> 인스턴스에서 읽기를 시도할 때 작업 시스템은 읽기 전에 <strong><code>CheckReadAndThrow</code> 메서드를 호출</strong>하여 <br>작업이 NativeContainer에 대한 <strong>읽기 액세스 권한이 있는지 확인</strong>합니다. <br>When a job tries to read from a&nbsp;<code>NativeContainer</code>&nbsp;instance, the job system calls the&nbsp;<code>CheckReadAndThrow</code>&nbsp;method before reading, <br>to confirm that the job has read access to the native container.</p>



<p>마찬가지로 작업이 NativeContainer에 쓰기를 시도할 때 작업 시스템은 쓰기 전에 <strong><code>CheckWriteAndThrow</code>를 호출</strong>하여 <br>작업이 NativeContainer에 대한 <strong>쓰기 액세스 권한이 있는지 확인</strong>합니다. <br>Similarly, when a job tries to write to a native container, the job system calls&nbsp;<code>CheckWriteAndThrow</code>&nbsp;before writing, to check that the job has write access to the native container.&nbsp;</p>



<p>두 작업이 동일한 <code>NativeContainer</code> 인스턴스를 할당 받은 경우에도, 해당 네이티브 컨테이너에 대해 별도의 <code>AtomicSafetyHandle</code> 객체를 갖습니다. <br>Two jobs that have been assigned the same&nbsp;<code>NativeContainer</code>&nbsp;instance have separate&nbsp;<code>AtomicSafetyHandle</code>&nbsp;objects for that native container, </p>



<p>따라서 두 작업은 동일한 중앙 정보를 참조하더라도, <br>각각이 네이티브 컨테이너에 대한 읽기 및 쓰기 액세스를 나타내는 별도의 플래그를 유지할 수 있습니다.<br>so although they both reference the same set of central information, <br>they can each hold separate flags that indicate what read and write access each job has to the native container.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">누출 추적 구현 (Implement leak tracking)</h3>



<p>Unity’s native code는 주로 누수 추적을 구현합니다. <br>Unity’s native code primarily implements leak tracking.</p>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.UnsafeUtility.MallocTracked.html" target="_blank" rel="noreferrer noopener"><strong>UnsafeUtility.MallocTracked</strong> </a>메서드를 사용하여 <code>NativeContainer</code> 데이터를 저장하는 데 필요한 메모리를 할당하고, <br>이를 해제하기 위해 <strong><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.UnsafeUtility.FreeTracked.html" target="_blank" rel="noreferrer noopener">UnsafeUtility.FreeTracked</a></strong>를 사용합니다.<br> It uses the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.UnsafeUtility.MallocTracked.html" target="_blank" rel="noreferrer noopener"><code>UnsafeUtility.MallocTracked</code></a>&nbsp;method to allocate the memory needed to store&nbsp;<code>NativeContainer</code>&nbsp;data, <br>and then uses&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.UnsafeUtility.FreeTracked.html" target="_blank" rel="noreferrer noopener"><code>UnsafeUtility.FreeTracked</code></a>&nbsp;to dispose of it.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>이전 유니티 버전에서는 DisposeSentinel 클래스가 누수 추적을 제공했습니다.<br>In earlier versions of Unity the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.DisposeSentinel.html" target="_blank" rel="noreferrer noopener"><code>DisposeSentinel</code></a>&nbsp;class provides leak tracking.</p>



<p>가비지 컬렉터가 <code>DisposeSentinel</code> 객체를 수집할 때 유니티는 메모리 누수를 보고합니다.<br>Unity reports a memory leak when the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/performance-garbage-collector.html" target="_blank" rel="noreferrer noopener">garbage collector</a>&nbsp;collects the&nbsp;<code>DisposeSentinel</code>&nbsp;object.</p>



<p><code>DisposeSentinel</code>을 만들려면 <code>Create</code> 메서드를 사용하며, 이 메서드를 사용하면 <code>AtomicSafetyHandle</code>을 동시에 초기화할 필요가 없습니다.<br>To create a&nbsp;<code>DisposeSentinel</code>, use the&nbsp;<code>Create</code>&nbsp;method, which also initializes the&nbsp;<code>AtomicSafetyHandle</code>&nbsp;at the same time.</p>



<p><code>ativeContainer</code>가 Dispose될 때 Dispose 메서드는 <code>DisposeSentinel</code>과 <code>AtomicSafetyHandle</code>을 한 번에 처리합니다.<br>When the&nbsp;<code>NativeContainer</code>&nbsp;is disposed of, the&nbsp;<code>Dispose</code>&nbsp;method disposes of both the&nbsp;<code>DisposeSentinel</code>&nbsp;and the&nbsp;<code>AtomicSafetyHandle</code>&nbsp;in a single call.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>누수가 발생한 NativeContainer가 생성된 위치를 식별하려면 메모리가 원래 할당된 위치의 스택 트레이스를 캡처할 수 있습니다. <br>To identify where the leaked&nbsp;<code>NativeContainer</code>&nbsp;was created, you can capture the stack trace of where the memory was originally allocated. </p>



<p>이를 위해 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.NativeLeakDetection.Mode.html" target="_blank" rel="noreferrer noopener">NativeLeakDetection.Mode</a> 속성을 사용하고 에디터에서는<strong> </strong><br><strong>Preferences &gt; Jobs &gt; Leak Detection Level</strong>로 이동하여 필요한 누수 검출 수준을 선택할 수 있습니다.<br>To do this, use the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.NativeLeakDetection.Mode.html" target="_blank" rel="noreferrer noopener"><code>NativeLeakDetection.Mode</code></a>&nbsp;property. You can also access this property in the Editor. <br>To do this, go to&nbsp;<strong>Preferences</strong>&nbsp;&gt;&nbsp;<strong>Jobs</strong>&nbsp;&gt;&nbsp;<strong>Leak Detection Level</strong>&nbsp;and choose the leak detection level you need.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">중첩된 네이티브 컨테이너 (Nested native containers)</h3>



<p>안전 시스템은 작업에서 <strong>중첩된 NativeContainer를 지원하지 않습니다. </strong><br>The safety system doesn’t support nested native containers in jobs,</p>



<p>To prevent scheduling jobs that use nested native containers, use&nbsp;<code>SetNestedContainer</code>, which flags a&nbsp;<code>NativeContainer</code>&nbsp;as nested when they contain other&nbsp;<code>NativeContainer</code>&nbsp;instances.</p>



<p>이는 작업 시스템이 큰 NativeContainer 인스턴스 내의 <strong>각 개별 NativeContainer에 대한 AtomicSafetyHandle을 올바르게 구성할 수 없기 때문</strong>입니다.<br>because the job system can’t correctly configure the&nbsp;<code>AtomicSafetyHandle</code>&nbsp;for each individual&nbsp;<code>NativeContainer</code>&nbsp;inside the larger&nbsp;<code>NativeContainer</code>&nbsp;instance.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>중첩된 NativeContainer를 사용하는 작업을 예약하지 않도록 방지하려면 <code>SetNestedContainer</code> 플래그를 사용하십시오. <br>To prevent scheduling jobs that use nested native containers, use&nbsp;<code>SetNestedContainer</code>,</p>



<p>이 메서드는 다른 <code>NativeContainer</code> 인스턴스를 포함할 때 해당 <code>NativeContainer</code>를 중첩된 것으로 플래그 지정합니다.<br>which flags a&nbsp;<code>NativeContainer</code>&nbsp;as nested when they contain other&nbsp;<code>NativeContainer</code>&nbsp;instances.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">안전 ID 및 오류 메시지 (Safety IDs and error messages)</h3>



<p>Safety system은 코드가 안전성 제약을 준수하지 않을 때 발생하는 오류 메시지를 제공합니다. <br>The safety system provides error messages that indicate when your code doesn’t adhere to safety constraints. </p>



<p>오류 메시지를 <strong>더 명확하게 만들기 위해 <code>NativeContainer</code> 객체의 이름을 safety system에 등록</strong>할 수 있습니다.<br>To help make the error messages clearer, you can register a&nbsp;<code>NativeContainer</code>&nbsp;object’s name with the safety system.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>이름을 등록하려면 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.NewStaticSafetyId.html" target="_blank" rel="noreferrer noopener"><code>NewStaticSafetyId</code></a>를 사용하고, 이는 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.SetStaticSafetyIdl.html"><code>SetStaticSafetyId</code></a>에 전달할 safety ID를 반환합니다.<br>To register a name, use&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.NewStaticSafetyId.html" target="_blank" rel="noreferrer noopener"><code>NewStaticSafetyId</code></a>, which returns a safety ID that you can pass to&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.SetStaticSafetyIdl.html"><code>SetStaticSafetyId</code></a>.</p>



<p>한 번 safety ID를 생성하면 <strong><code>NativeContainer</code>의 모든 인스턴스에서 재사용</strong>할 수 있으므로<strong> </strong><br><strong>주로 컨테이너 클래스의 정적 멤버에 저장하는 것이 일반적인 패턴</strong>입니다.<br>Once you create a safety ID, you can reuse it for all instances of the&nbsp;<code>NativeContainer</code>, <br>so a common pattern is to store it in a static member of the container class.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>또한 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.SetCustomErrorMessage.html" target="_blank" rel="noreferrer noopener"><code>SetCustomErrorMessage</code></a>를 사용하여 특정 안전성 제약 위반에 대한 사용자 지정 오류 메시지를 재정의할 수도 있습니다.<br>You can also override the error messages for specific safety constraint violations with&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.SetCustomErrorMessage.html" target="_blank" rel="noreferrer noopener"><code>SetCustomErrorMessage</code></a>.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">추가 리소스 (Additional resources)</h3>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-copy-nativecontainer.html" target="_blank" rel="noreferrer noopener">NativeContainer 구조 복사</a><br><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-copy-nativecontainer.html" target="_blank" rel="noreferrer noopener">Copying NativeContainer structures</a></li>



<li><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer-example.html" target="_blank" rel="noreferrer noopener">사용자 정의 NativeContainer 예</a><br><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer-example.html" target="_blank" rel="noreferrer noopener">Custom NativeContainer example</a></li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-copy-nativecontainer.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-copy-nativecontainer.html</a></p>



<h2 class="wp-block-heading">NativeContainer 구조 복사 (Copying NativeContainer structures)</h2>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">Native containers</a>는 값 타입이기 때문에 변수에 할당될 때 Unity는 <code>NativeContainer</code> 구조체를 복사합니다.<br><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">Native containers</a>&nbsp;are value types, which means that when they’re assigned to a variable, Unity copies the&nbsp;<code>NativeContainer</code>&nbsp;structure,</p>



<p>이 구조체에는 네이티브 컨테이너의 데이터가 저장된 위치를 가리키는 포인터와 함께 해당 컨테이너의 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.html" target="_blank" rel="noreferrer noopener"><code>AtomicSafetyHandle</code></a>도 포함되어 있습니다.<br>which contains pointers to where the native container’s data is stored, including its&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.html" target="_blank" rel="noreferrer noopener"><code>AtomicSafetyHandle</code></a>.</p>



<p>하지만 전체 <code>NativeContainer</code> 내용을 복사하지는 않습니다.<br>It doesn’t copy the entire contents of the&nbsp;<code>NativeContainer</code>.</p>



<p>이러한 시나리오는 동일한 메모리 영역을 참조하는 여러 <code>NativeContainer</code> 구조체 사본이 있을 수 있으며,<br>모두 동일한 중앙 레코드를 참조하는 <code>AtomicSafetyHandle</code> 객체를 포함하고 있을 수 있음을 의미합니다.<br>This scenario means that there might be multiple copies of a&nbsp;<code>NativeContainer</code>&nbsp;structure which all reference the same region of memory,<br>and all contain&nbsp;<code>AtomicSafetyHandle</code>&nbsp;objects which reference the same central record.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="570" height="525" src="https://lycos7560.com/wp-content/uploads/2023/12/image.png" alt="" class="wp-image-37643" srcset="https://lycos7560.com/wp-content/uploads/2023/12/image.png 570w, https://lycos7560.com/wp-content/uploads/2023/12/image-300x276.png 300w" sizes="(max-width: 570px) 100vw, 570px" /><figcaption class="wp-element-caption">NativeContainer 객체의 복사본이 작동하는 방식<br>How copies of NativeContainer objects work</figcaption></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>위 다이어그램은 실제로 동일한 컨테이너를 나타내는 <strong>NativeArray 구조체의 세 가지 다른 복사본</strong>을 보여줍니다.<br>The above diagram shows three different copies of a&nbsp;<code>NativeArray</code>&nbsp;structure that all represent the same actual container. </p>



<p>각 복사본은 동일한 저장된 데이터와 원래 <code>NativeArray</code>와 동일한 안전성 데이터를 가리킵니다. <br>Each copy points to the same stored data, and the same safety data as the original&nbsp;<code>NativeArray</code>.&nbsp;</p>



<p>그러나 각 &nbsp;<code>NativeArray</code>&nbsp; 복사본은 <strong>해당 복사본에서 작업을 수행할 수 있는 지를 나타내는 다른 플래그</strong>를 갖습니다.<br>However, each copy of the&nbsp;<code>NativeArray</code>&nbsp;has different flags that indicate what a job is allowed to do with that copy.</p>



<p>안전성 데이터에 대한 포인터와 플래그는 <code>AtomicSafetyHandle</code>를 구성합니다.<br>The pointer to the safety data, combined with the flags, make up the&nbsp;<code>AtomicSafetyHandle</code>.</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">버전 번호 (Version numbers)</h3>



<p>만약 <code>NativeContainer</code>가 <strong>dispose(해제)</strong>되면 <code>NativeContainer</code>구조체의 모든 복사본은 <strong>기존의 <code>NativeContainer</code>가 무효임을 인식</strong>해야 합니다. <br>If a&nbsp;<code>NativeContainer</code>&nbsp;is disposed of, all the copies of the&nbsp;<code>NativeContainer</code>&nbsp;structure must recognize that the original&nbsp;<code>NativeContainer</code>&nbsp;is invalid. </p>



<p>원래 <code>NativeContainer</code>를 dispose하는 것은 <code>NativeContainer</code>의 데이터를 저장하던 <strong>메모리 블록이 할당 해제되었음을 의미</strong>합니다.<br>Disposing of the original&nbsp;<code>NativeContainer</code>&nbsp;means that the block of memory that used to hold the data for the&nbsp;<code>NativeContainer</code>&nbsp;has been deallocated.</p>



<p>이 상황에서 각 <code>NativeContainer</code> 복사본에 저장된 데이터에 대한 <strong>포인터는 무효화되어 있으며 사용 시 액세스 위반</strong>을 일으킬 수 있습니다.<br>In this situation, the pointer to the data which is stored in each copy of the&nbsp;<code>NativeContainer</code>&nbsp;is invalid, and might cause access violations if you use it.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>또한 <code>AtomicSafetyHandle</code>는 무효화된 <code>NativeContainer</code> 인스턴스를 가리키는 중앙 레코드를 가리킵니다.<br>The&nbsp;<code>AtomicSafetyHandle</code>&nbsp;also points at a central record which becomes invalid for the&nbsp;<code>NativeContainer</code>&nbsp;instances.</p>



<p>그러나 safety system은 중앙 레코드의 메모리를 해제하지 않으므로 액세스 위반의 위험을 피할 수 있습니다.<br>However, the safety system never deallocates the memory for the central record, so it avoids the risk of access violations.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>대신, 각 레코드에는 버전 번호가 포함되어 있습니다.<br>Instead, each record contains a version number.</p>



<p><strong>버전 번호의 복사본</strong>은 해당 기록을 참조하는 각 <code>AtomicSafetyHandle</code> 안에 저장됩니다.<br>A copy of the version number is stored inside each&nbsp;<code>AtomicSafetyHandle</code>&nbsp;that references that record.</p>



<p>NativeContainer가 dispose되면 Unity는 <strong><code>Release()</code>를 호출하며 이는 중앙 레코드의 버전 번호를 증가</strong>시킵니다.<br>When a NativeContainer is disposed of, Unity calls&nbsp;<code>Release()</code>, which increments the version number on the central record. </p>



<p>그 후 해당 레코드는 다른 <code>NativeContainer</code> 인스턴스에 재사용될 수 있습니다.<br>After this, the record can be reused for other&nbsp;<code>NativeContainer</code>&nbsp;instances.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>남아 있는<strong> 각 <code>AtomicSafetyHandle</code>는 저장된 버전 번호를 중앙 레코드의 버전 번호와 비교</strong>하여 <code>NativeContainer</code>가 dispose되었는지를 테스트합니다.<br>Each remaining&nbsp;<code>AtomicSafetyHandle</code> compares its stored version number against the version number in the central record to test whether the&nbsp;<code>NativeContainer</code>&nbsp;has been disposed of.</p>



<p>Unity는 이 테스트를 자동으로 수행하여 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrow.html" target="_blank" rel="noreferrer noopener">CheckReadAndThrow</a>, <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrow.html" target="_blank" rel="noreferrer noopener">CheckWriteAndThrow</a> 등의 메서드 호출 일부의 일환으로 처리합니다.<br>Unity performs this test automatically as part of calls to methods such as&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrow.html" target="_blank" rel="noreferrer noopener"><code>CheckReadAndThrow</code></a>, and&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrow.html" target="_blank" rel="noreferrer noopener"><code>CheckWriteAndThrow</code></a>.</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">동적 네이티브 컨테이너의 정적 보기 (Static views of dynamic native containers)</h3>



<p><strong>동적 NativeContainer는 계속해서 요소를 추가할 수 있는 변수 크기를 가진 컨테이너</strong>로, Collections 패키지에서 제공되는 <a href="https://docs.unity3d.com/Packages/com.unity.collections@latest/index.html?subfolder=/api/Unity.Collections.NativeList-1.html" target="_blank" rel="noreferrer noopener"><code>NativeList&lt;T&gt;</code></a>와 같은 예시가 있습니다.<br>A dynamic native container is one which has a variable size that you can continue to add elements to, such as&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.collections@latest/index.html?subfolder=/api/Unity.Collections.NativeList-1.html" target="_blank" rel="noreferrer noopener"><code>NativeList&lt;T&gt;</code></a>&nbsp;(which is available in the Collections package).</p>



<p>이는 <strong>크기를 변경할 수 없는 고정 크기의 NativeArray&lt;T&gt;와 같은 정적 NativeContainer 대조적</strong>입니다.<br> This is in contrast to a static native container like&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.NativeArray_1.html"><code>NativeArray&lt;T&gt;</code></a>, which has a fixed size that you can’t change.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>동적 네이티브 컨테이너를 사용할 때 뷰(view)라 불리는 다른 인터페이스를 통해 데이터에 직접 액세스할 수도 있습니다. <br>When you use a dynamic native container, you can also directly access its data through another interface, called a view.</p>



<p>뷰는 <code>NativeContainer</code> 객체의 데이터에 복사하거나 소유권을 얻지 않고 별칭(alias)을 제공합니다.<br>A view allows you to alias a&nbsp;<code>NativeContainer</code>&nbsp;object’s data without copying or taking ownership of the data.</p>



<p>뷰의 예시로는 열거자(enumerator) 객체가 있습니다.<br>Examples of views include enumerator objects,</p>



<p>이를 사용하여 네이티브 컨테이너의 데이터에 요소별로 액세스할 수 있으며 <a href="https://docs.unity3d.com/Packages/com.unity.collections@latest/index.html?subfolder=/api/Unity.Collections.NativeList-1.html#Unity_Collections_NativeList_1_AsArray" target="_blank" rel="noreferrer noopener"><code>NativeList&lt;T&gt;.AsArray</code></a>와 같은 메서드를 사용하여 <code>NativeList</code>를 <code>NativeArray</code>처럼 처리할 수 있습니다.<br>which you can use to access the data in a native container element-by-element, and methods such as&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.collections@latest/index.html?subfolder=/api/Unity.Collections.NativeList-1.html#Unity_Collections_NativeList_1_AsArray" target="_blank" rel="noreferrer noopener"><code>NativeList&lt;T&gt;.AsArray</code></a>, which you can use to treat a&nbsp;<code>NativeList</code>&nbsp;as if it were a&nbsp;<code>NativeArray</code>.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>그러나 동적 네이티브 컨테이너의 크기가 변경되면 뷰가 <strong>일반적으로 스레드 안전하지 않습니다.</strong><br>Views aren’t typically thread safe if the size of the dynamic native container changes.</p>



<p>이는<strong> NativeContainer 의 크기가 변경되면 Unity가 메모리에서 데이터를 재배치하고,</strong><br>This is because when the size of the native container changes, Unity relocates where the data is stored in memory,</p>



<p>이로 인해 <strong>뷰가 저장하는 포인터가 무효화</strong>되기 때문입니다.<br>which causes any pointers that a view stores to become invalid.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">보조 버전 번호 (Secondary version numbers)</h4>



<p>동적 네이티브 컨테이너의 크기가 변경되는 상황을 지원하기 위해 안전성 시스템은 <strong><code>AtomicSafetyHandle</code></strong> <strong>에 보조 버전 번호를 포함</strong>합니다.<br>To support situations when the size of the dynamic native container changes, the safety system includes a secondary version number in an&nbsp;<code>AtomicSafetyHandle</code>. </p>



<p>이 메커니즘은 버전 관리 메커니즘과 유사하지만 <strong>첫 번째 버전 번호와 독립적으로 증가시킬 수 있는 중앙 레코드에 저장된 두 번째 버전 번호를 사용</strong>합니다.<br>This mechanism is similar to the versioning mechanism, but uses a second version number stored in the central record which can be incremented independently of the first version number.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>보조 버전 번호를 사용하려면 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.UseSecondaryVersion.html" target="_blank" rel="noreferrer noopener"><code>UseSecondaryVersion</code></a>을 사용하여 <code>NativeContainer</code>에 저장된 데이터에 대한 뷰를 구성할 수 있습니다.<br>To use a secondary version number, you can use&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.UseSecondaryVersion.html"><code>U</code></a><code><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.UseSecondaryVersion.html" target="_blank" rel="noreferrer noopener">seSecondaryVersion</a></code>&nbsp;to configure the views into the data stored in a&nbsp;<code>NativeContainer</code>. </p>



<p>NativeContainer의 크기를 변경하거나 기존 뷰를 무효화하는 작업에 대해 <code>CheckWriteAndThrow</code> 대신 <strong><code><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion.html" target="_blank" rel="noreferrer noopener">CheckWriteAndBumpSecondaryVersion</a></code>을 사용</strong>합니다.<br>For operations that change the size of the native container, or otherwise make existing views invalid, use&nbsp;<code><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion.html" target="_blank" rel="noreferrer noopener">CheckWriteAndBumpSecondaryVersion</a></code>&nbsp;instead of&nbsp;<code>CheckWriteAndThrow</code>.</p>



<p>또한 NativeContainer에 <strong>S<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.SetBumpSecondaryVersionOnScheduleWrite.html"><code>etBumpSecondaryVersionOnScheduleWrite</code></a>를 설정하여 <code>NativeContainer</code>에 쓰기 작업이 예약될 때마다 자동으로 뷰를 무효화</strong>해야 합니다.<br>You also need to set&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.SetBumpSecondaryVersionOnScheduleWrite.html"><code>SetBumpSecondaryVersionOnScheduleWrite</code></a>&nbsp;on the&nbsp;<code>NativeContainer</code>&nbsp;to automatically invalidate views whenever a job is scheduled that writes to the native container.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>뷰를 만들고 <code>AtomicSafetyHandle</code>를 복사할 때는 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckGetSecondaryDataPointerAndThrow.html"><code>CheckGetSecondaryDataPointerAndThrow</code></a> 를 사용하여 NativeContainer의 메모리 포인터를 뷰로 안전하게 복사할 수 있는지 확인합니다.<br>When you create a view and copy the&nbsp;<code>AtomicSafetyHandle</code>&nbsp;to it, use&nbsp;<code><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckGetSecondaryDataPointerAndThrow.html" target="_blank" rel="noreferrer noopener">CheckGetSecondaryDataPointerAndThro</a></code><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckGetSecondaryDataPointerAndThrow.html"><code>w</code></a>&nbsp;to confirm that it’s safe to copy the pointer to the native container’s memory into the view.</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">특수 손잡이 (Special handles)</h3>



<p>임시 네이티브 컨테이너를 사용할 때 두 가지 특수한 핸들이 있습니다 :<br>There are two special handles, which you can use when working with temporary native containers:</p>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.GetTempMemoryHandle.html" target="_blank" rel="noreferrer noopener"><code>GetTempMemoryHandle</code></a> :<br><code>Allocator.Temp</code> 으로 할당된 NativeContainer에서 사용할 수 있는 <code>AtomicSafetyHandle</code>을 반환합니다.<br>Returns an&nbsp;<code>AtomicSafetyHandle</code>&nbsp;which you can use in native containers which are allocated with&nbsp;<code>Allocator.Temp</code>.<br>Unity는 현재 임시 메모리 범위가 종료될 때 이 핸들을 자동으로 무효화하므로 직접 해제할 필요가 없습니다.<br>Unity automatically invalidates this handle when the current temporary memory scope exits, so you don’t need to release it yourself.<br>특정 <code>AtomicSafetyHandle</code>이 <code>GetTempMemoryHandle</code>에서 반환된 핸들인지 테스트하려면 <code>IsTempMemoryHandle</code>을 사용합니다.<br>To test whether a particular&nbsp;<code>AtomicSafetyHandle</code>&nbsp;is the handle returned by&nbsp;<code>GetTempMemoryHandle</code>, use&nbsp;<code>IsTempMemoryHandle</code>.</li>



<li><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.GetTempUnsafePtrSliceHandle.html" target="_blank" rel="noreferrer noopener"><code>GetTempUnsafePtrSliceHandle</code></a>:<br><strong>안전하지 않은 메모리에서 지원되는 임시 네이티브 컨테이너에 사용할 수 있는 전역 핸들을 반환</strong>합니다.<br>Returns a global handle you can use for temporary native containers which are backed by unsafe memory.<br>예를 들어, 스택 메모리에서 생성된 <code>NativeSlice</code> 입니다.<br>For example, a&nbsp;<code>NativeSlice</code>&nbsp;constructed from stack memory.<br>이 핸들을 사용하는 컨테이너를 작업에 전달할 수 없습니다.<br>You can’t pass containers that use this handle into jobs.</li>
</ul>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div style="margin-top:0;margin-bottom:0;height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer-example.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/job-system-custom-nativecontainer-example.html</a></p>



<h2 class="wp-block-heading">사용자 정의 NativeContainer 예제 (Custom NativeContainer example)</h2>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p><code>NativeContainer</code>다음은 추가 전용 목록인&nbsp;사용자 정의의 전체 예입니다 .<br>The following is a complete example of a custom&nbsp;<code>NativeContainer</code>&nbsp;as an append-only list.</p>



<p>읽기 및 쓰기 작업의 기본 보호는 물론 앨리어싱 뷰 생성 및 무효화를 보여줍니다.<br>It demonstrates basic protection of read and write operations, as well as creating and invalidating aliasing views.</p>



<p>다른 예는&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerAttribute.html" target="_blank" rel="noreferrer noopener"><code>NativeContainerAttribute</code></a> API 설명서를 참조하세요.<br>For another example, see the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerAttribute.html" target="_blank" rel="noreferrer noopener"><code>NativeContainerAttribute</code></a>&nbsp;API documentation.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System;
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Collections;

// NativeContainer로 구조체를 표시합니다. 이는 job 시스템에 AtomicSafetyHandle이 포함되어 있음을 나타냅니다.
[NativeContainer]
public unsafe struct NativeAppendOnlyList&lt;T> : IDisposable where T : unmanaged
{
    // 원시 포인터는 일반적으로 job에 전달되는 구조체 내에서 허용되지 않지만, 안전 시스템으로 보호되므로 이 제한을 해제할 수 있습니다.
    [NativeDisableUnsafePtrRestriction]
    internal void* m_Buffer;
    internal int m_Length;
    internal Allocator m_AllocatorLabel;

    // ENABLE_UNITY_COLLECTIONS_CHECKS 정의로만 안전 시스템 멤버를 선언하고 사용해야 합니다.
    // 프로젝트의 최종 빌드에서는 성능상의 이유로 안전 시스템이 비활성화되므로 이러한 API는 해당 빌드에서 사용할 수 없습니다.
#if ENABLE_UNITY_COLLECTIONS_CHECKS

    // AtomicSafetyHandle 필드는 'm_Safety'로 정확히 명명되어야 합니다.
    internal AtomicSafetyHandle m_Safety;

    // 이 유형을 해당 유형에서 파생된 이름을 사용하여 정적으로 안전 시스템에 등록합니다.
    internal static readonly int s_staticSafetyId = AtomicSafetyHandle.NewStaticSafetyId&lt;NativeAppendOnlyList&lt;T>>();
#endif

    public NativeAppendOnlyList(Allocator allocator, params T[] initialItems)
    {
        m_Length = initialItems.Length;
        m_AllocatorLabel = allocator;

        // 초기 버퍼의 크기(바이트)를 계산하고 할당합니다.
        int totalSize = UnsafeUtility.SizeOf&lt;T>() * m_Length;
        m_Buffer = UnsafeUtility.MallocTracked(totalSize, UnsafeUtility.AlignOf&lt;T>(), m_AllocatorLabel, 1);

        // 배열에서 데이터를 버퍼로 복사합니다.
        var handle = GCHandle.Alloc(initialItems, GCHandleType.Pinned);
        try
        {
            UnsafeUtility.MemCpy(m_Buffer, handle.AddrOfPinnedObject().ToPointer(), totalSize);
        }
        finally
        {
            handle.Free();
        }

#if ENABLE_UNITY_COLLECTIONS_CHECKS
        // AtomicSafetyHandle 및 DisposeSentinel 생성
        m_Safety = AtomicSafetyHandle.Create();

        // AtomicSafetyHandle에 안전 ID 설정하여 오류 메시지가 이 컨테이너 유형을 올바르게 설명하도록 함
        AtomicSafetyHandle.SetStaticSafetyId(ref m_Safety, s_staticSafetyId);

        // 이 컨테이너가 중첩 컨테이너인지 확인하고 중첩 컨테이너 플래그 설정
        if (UnsafeUtility.IsNativeContainerType&lt;T>())
            AtomicSafetyHandle.SetNestedContainer(m_Safety, true);
#endif
    }

    public int Length
    {
        get
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            // 컨테이너에 대한 정보를 읽을 수 있는지 확인합니다.
            // 이는 원시 컨테이너에서 읽을 수 없거나 네이티브 컨테이너가 해제된 경우 InvalidOperationException을 throw합니다.
            AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
#endif
            return m_Length;
        }
    }

    public T this[int index]
    {
        get
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            // 현재 네이티브 컨테이너에서 읽을 수 있는지 확인합니다.
            AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
#endif

            // 버퍼에서 값을 읽어 반환합니다.
            return UnsafeUtility.ReadArrayElement&lt;T>(m_Buffer, index);
        }

        set
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            // 현재 네이티브 컨테이너에 쓸 수 있는지 확인합니다.
            AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
#endif
            // 값을 버퍼에 씁니다.
            UnsafeUtility.WriteArrayElement(m_Buffer, index, value);
        }
    }

    public void Add(T value)
    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        // 현재 네이티브 컨테이너를 수정(쓰기)할 수 있는지 확인하고 그렇다면 보조 버전을 증가시켜서
        // 뷰가 무효화되도록 합니다. 왜냐하면 크기와 버퍼에 대한 포인터를 변경할 것이기 때문입니다.
        AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif

        // 현재 버퍼를 원소 하나를 추가할 공간이 있는 새로운 버퍼로 교체합니다.
        int newTotalSize = (m_Length + 1) * UnsafeUtility.SizeOf&lt;T>();
        void* newBuffer = UnsafeUtility.MallocTracked(newTotalSize, UnsafeUtility.AlignOf&lt;T>(), m_AllocatorLabel, 1);
        UnsafeUtility.MemCpy(newBuffer, m_Buffer, m_Length * UnsafeUtility.SizeOf&lt;T>());
        UnsafeUtility.FreeTracked(m_Buffer, m_AllocatorLabel);
        m_Buffer = newBuffer;

        // 새 원소를 버퍼 끝에 넣고 길이를 증가시킵니다.
        UnsafeUtility.WriteArrayElement(m_Buffer, m_Length++, value);
    }

    public NativeArray&lt;T> AsArray()
    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        // 현재 버퍼 포인터를 사용하여 뷰를 만들 수 있는지 안전하게 확인합니다.
        AtomicSafetyHandle.CheckGetSecondaryDataPointerAndThrow(m_Safety);

        // AtomicSafetyHandle의 복사본을 만들고 해당 복사본을 기본 대신 보조 버전을 사용하도록 표시합니다.
        AtomicSafetyHandle handleForArray = m_Safety;
        AtomicSafetyHandle.UseSecondaryVersion(ref handleForArray);
#endif

        // 현재 크기를 사용하여 버퍼에 별칭을 설정하는 새 NativeArray를 만듭니다.
        // 이 작업은 데이터를 할당하거나 복사하지 않고 현재 버퍼를 가리키는 NativeArray&lt;T>를 설정합니다.
        var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray&lt;T>(m_Buffer, m_Length, Allocator.None);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
        // 새로 만든 NativeArray에 AtomicSafetyHandle을 설정합니다. 설정한 핸들은 앞서 복사한 핸들을 사용합니다.
        NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, handleForArray);
#endif

        return array;
    }

    public void Dispose()
    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        AtomicSafetyHandle.CheckDeallocateAndThrow(m_Safety);
        AtomicSafetyHandle.Release(m_Safety);
#endif

        // 버퍼를 해제합니다.
        UnsafeUtility.FreeTracked(m_Buffer, m_AllocatorLabel);
        m_Buffer = null;
        m_Length = 0;
    }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-cad298ab wp-block-columns-is-layout-flex" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemCreatingJobs.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemCreatingJobs.html</a></p>



<h1 class="wp-block-heading">작업 생성 및 실행 (Create and run a job)</h1>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p>작업 생성 및 실행을 성공적으로 수행하려면 다음과 같은 단계를 따라야 합니다 :<br>To create and successfully run a job, you must do the following:</p>



<ol class="wp-block-list">
<li>작업 생성 : <br><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener"><code>IJob</code></a> 인터페이스를 구현합니다.<br>Implement the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener"><code>IJob</code></a>&nbsp;interface.</li>



<li>작업 예약 :<br>작업에 대한 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobExtensions.Schedule.html" target="_blank" rel="noreferrer noopener"><code>Schedule</code></a> 메서드를 호출합니다.<br>Call the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobExtensions.Schedule.html" target="_blank" rel="noreferrer noopener"><code>Schedule</code></a>&nbsp;method on the job.</li>



<li>작업 완료 대기 : <br>작업이 이미 완료된 경우 즉시 반환되며, 데이터에 액세스하려면 작업에 대한 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.Complete.html" target="_blank" rel="noreferrer noopener"><code>Complete</code></a> 메서드를 호출합니다.<br>It returns immediately if the job is already complete, and you can call the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.Complete.html" target="_blank" rel="noreferrer noopener"><code>Complete</code></a>&nbsp;method on the job when you want to access the data.</li>
</ol>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><strong>작업 생성</strong> (Create a job)</h2>



<p>Unity에서 작업을 생성하려면&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener"><code>IJob</code></a> 인터페이스를 구현합니다. <br>To create a job in Unity, implement the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener"><code>IJob</code></a>&nbsp;interface.</p>



<p><code>IJob</code> 구현을 사용하여 병렬로 실행되는 다른 작업과 함께 단일 작업을 예약할 수 있습니다.<br>You can use your&nbsp;<code>IJob</code>&nbsp;implementation to schedule a single job that runs in parallel to any other jobs that are running.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><code>IJob</code>은 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.Execute.html" target="_blank" rel="noreferrer noopener"><code>Execute</code></a>라는 하나의 필수 메서드를 갖추고 있으며, 이 메서드는 작업이 실행되는 동안 <a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html#multithreading" target="_blank" rel="noreferrer noopener">worker thread</a>가 호출하는 메서드입니다.<br><code>IJob</code>&nbsp;has one required method:&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.Execute.html" target="_blank" rel="noreferrer noopener"><code>Execute</code></a>, which Unity invokes whenever a&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html#multithreading" target="_blank" rel="noreferrer noopener">worker thread</a>&nbsp;runs the job.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>작업을 생성할 때 해당 작업에 대한<strong> </strong><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.html" target="_blank" rel="noreferrer noopener"><code>JobHandle</code></a>도 생성할 수 있으며, 다른 메서드에서 <strong>작업을 참조하는 데 사용</strong>됩니다.<br>When you create a job, you can also create a&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.html" target="_blank" rel="noreferrer noopener"><code>JobHandle</code></a>&nbsp;for it, which other methods need to use to reference the job.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>중요 (Important:) : </strong><br>작업 내에서<strong> </strong>readonly가 아닌 또는 가변적인 static 데이터에 액세스하는 것에 대한 보호가 없습니다.<br>There’s no protection against accessing non-readonly or&nbsp;<strong>mutable</strong> static data from within a job.<br>이러한 종류의 데이터에 액세스하는 것은 모든 안전 시스템을 우회하며 응용 프로그램이나 Unity 에디터를 충돌시킬 수 있습니다.<br>Accessing this kind of data circumvents all safety systems and might crash your application or the Unity Editor.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Unity가 실행될 때 작업 시스템은 예약된 작업 데이터의 복사본을 만들어 여러 스레드가 동일한 데이터를 읽거나 쓰지 못하도록 합니다.<br>When Unity runs, the job system makes a copy of scheduled job data, which prevents more than one thread from reading or writing the same data.</p>



<p>작업이 완료된 후에는 <code>NativeContainer</code>에 쓰여진 데이터만 액세스할 수 있습니다.<br>Only data written to a&nbsp;<code>NativeContainer</code>&nbsp;can be accessed after the job finishes.</p>



<p>이는 작업이 사용하는 <code>NativeContainer</code>의 복사본과 원래 <code>NativeContainer</code> 객체가 동일한 메모리를 가리키기 때문입니다.<br>This is because both the copy of the&nbsp;<code>NativeContainer</code>&nbsp;that the job uses and the original&nbsp;<code>NativeContainer</code>&nbsp;object point to the same memory.</p>



<p>자세한 내용은 <a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">쓰레드 안전한 유형</a>에 대한 문서를 참조하세요.<br>For more information, see the documentation on&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">Thread safe types</a>.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>작업 시스템이 작업을 작업 큐에서 가져오면 <code>Execute</code> 메서드를 단일 스레드에서 한 번 실행합니다.<br>When the job system picks up a job from its job queue, it runs the&nbsp;<code>Execute</code>&nbsp;method once on a single thread.</p>



<p>일반적으로 작업 시스템은 백그라운드 스레드에서 작업을 실행하지만, <strong>만약 메인 스레드가 유휴 상태가 되면 메인 스레드에서도 실행될 수 있습니다.</strong><br>Typically, the job system runs jobs on background threads, but it can choose the main thread if it becomes idle. </p>



<p>따라서 작업을 <strong>한 프레임 내에 완료되도록 설계</strong>해야 합니다.<br>For this reason, you should design your jobs to complete in under a frame.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><strong>작업 예약</strong> (Schedule a job)</h2>



<p>작업을 예약하려면 Schedule을 호출하세요.<br>To schedule a job, call&nbsp;<code>Schedule</code>.</p>



<p>이렇게 하면 작업이 작업 큐에 들어가며 작업 시스템은 해당 작업의 모든 종속성(있는 경우)이 완료되면 작업을 실행하기 시작합니다.<br>This puts the job into the job queue, and the job system begins executing the job once all its dependencies, if any, complete.</p>



<p>예약되면 작업을 중단할 수 없습니다. Schedule은 주 스레드에서만 호출할 수 있습니다.<br>Once scheduled, you can’t interrupt a job. You can only call Schedule from the main thread.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>팁 (Tip) : </strong><br>작업에는 <strong>주 스레드에서 즉시 작업을 실행</strong>하는 데 사용할 수 있는 Run 메서드가 있습니다. <br>Jobs have a Run method that you can use in place of Schedule to immediately execute the job on the main thread.</p>



<p>이는 디버깅 목적으로 사용할 수 있습니다.<br>You can use this for debugging purposes.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">작업 완료 (Complete the job)</h2>



<p><code>Schedule</code>을 호출하고 작업 시스템이 작업을 실행한 후에는 작업에 대한 <code>JobHandle</code>에서 <strong><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.Complete.html" target="_blank" rel="noreferrer noopener"><code>Complete</code></a> 메서드를 호출하여 데이터에 액세스할 수 있습니다. </strong><br>Once you call&nbsp;<code>Schedule</code>&nbsp;and the job system has executed a job, you can call the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.Complete.html" target="_blank" rel="noreferrer noopener"><code>Complete</code></a>&nbsp;method on the&nbsp;<code>JobHandle</code>&nbsp;to access the data in the job.</p>



<p><code>Complete</code>&nbsp;를 호출하는 것은 코드에서 가능한 늦게 호출하는 것이 좋습니다.<br>It’s best practice to call&nbsp;<code>Complete</code>&nbsp;as late as possible in your code.</p>



<p>Complete를 호출하면 메인 스레드가 작업이 사용했던 <a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener"><code>NativeContainer</code></a> 인스턴스에 안전하게 액세스할 수 있습니다.<br>When you call&nbsp;<code>Complete</code>, the main thread can safely access the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener"><code>NativeContainer</code></a>&nbsp;instance that the job was using. </p>



<p><code>Complete</code> 를 호출하면 안전 시스템의 상태도 정리됩니다.<br>Calling&nbsp;<code>Complete</code>&nbsp;also cleans up the state in the safety system.</p>



<p>이를 하지 않으면 메모리 누수가 발생할 수 있습니다.<br>Not doing so introduces a memory leak.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">잡 예시 (Job examples)</h2>



<p>다음은 두 개의 부동 소수점 값을 더하는 작업의 예시입니다.<br>The following is an example of a job that adds two floating point values together.</p>



<p>이 작업은<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener"><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html"> <code>IJob</code></a></a>을 구현하며, 작업 결과를 얻기 위해 <code>NativeArray</code>를 사용하며, 작업 구현은 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.Execute.html" target="_blank" rel="noreferrer noopener"><code>Execute</code></a> 메서드 내에 포함되어 있습니다 :<br>It implements <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html"><code>IJo</code></a><code><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.html" target="_blank" rel="noreferrer noopener">b</a></code>, uses a <code>NativeArray</code> to get the results of the job, and uses the <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.Execute.html" target="_blank" rel="noreferrer noopener"><code>Execute</code></a> method with the implementation of the job inside it:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Unity.Collections;
using Unity.Jobs;

// Job adding two floating point values together
public struct MyJob : IJob
{
    public float a;
    public float b;
    public NativeArray&lt;float> result;

    public void Execute()
    {
        result[0] = a + b;
    }
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p>다음 예제는&nbsp;<code>MyJob</code>기본 스레드에서 작업을 예약하기 위해 작업을 기반으로 합니다.<br>The following example builds on the&nbsp;<code>MyJob</code>&nbsp;job to schedule a job on the main thread:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Unity.Collections;
using Unity.Jobs;

public class MyScheduledJob : MonoBehaviour
{
    // 결과를 저장할 단일 float의 NativeArray 를 생성합니다.
    // NativeArray만이 작업 결과를 얻을 수 있는 유일한 방법입니다 
    // 하나의 값 또는 일련의 값을 얻게 됩니다.
    NativeArray&lt;float> result;
    // Create a JobHandle for the job
    JobHandle handle;

    // Set up the job
    public struct MyJob : IJob
    {
        public float a;
        public float b;
        public NativeArray&lt;float> result;

        public void Execute()
        {
            result[0] = a + b;
        }
    }

    // 업데이트는 프레임당 1회 호출
    void Update()
    {
        // Set up the job data
        result = new NativeArray&lt;float>(1, Allocator.TempJob);

        MyJob jobData = new MyJob
        {
            a = 10,
            b = 10,
            result = result
        };

        // Schedule the job
        handle = jobData.Schedule();
    }

    private void LateUpdate()
    {
        // 나중에 프레임에서 작업이 완료될 때까지 기다렸다가 결과에 액세스합니다.
        handle.Complete();

        // NativeArray의 모든 복사본은 동일한 메모리를 가리키며, 
        // NativeArray의 "당신의" 복사본에서 결과에 액세스할 수 있습니다
        // float aPlusB = result[0];

        // 할당된 메모리를 해제합니다.
        result.Dispose();
    }
}</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">예약 및 완료 모범적인 사례 (Schedule and Complete best practices)</h2>



<p>작업이 필요한 데이터가 준비되면 즉시 해당 작업에 <code>Schedule</code>을 호출하고, 결과가 필요한 시점까지 <code>Complete</code>를 호출하지 않는 것이 좋은 실천 방법입니다.<br>It’s best practice to call&nbsp;<code>Schedule</code>&nbsp;on a job as soon as you have the data it needs, and don’t call&nbsp;<code>Complete</code>&nbsp;on it until you need the results.</p>



<p>덜 중요한 작업은 더 중요한 작업과 경쟁하지 않는 프레임 부분에 예약하는 것이 좋습니다.<br>You can schedule less important jobs in a part of the frame where they aren’t competing with more important jobs.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>예를 들어, 한 프레임이 끝나고 다음 프레임이 시작하기 전에 작업이 실행되지 않는 기간이 있고, <br>For example, if there is a period between the end of one frame and the beginning of the next frame where no jobs are running,</p>



<p>한 프레임의 지연이 허용되는 경우, 해당 작업을 프레임 끝 부분에 예약하고 결과를 다음 프레임에서 사용할 수 있습니다.<br>and a one frame latency is acceptable, you can schedule the job towards the end of a frame and use its results in the following frame.</p>



<p>반대로 응용 프로그램이 해당 변경 기간을 다른 작업으로 가득 채우고 프레임의 다른 곳에서 미사용 기간이 있는 경우 해당 부분에 작업을 예약하는 것이 더 효율적입니다.<br>Alternatively, if your application saturates that changeover period with other jobs, and there’s an under-utilized period somewhere else in the frame, <br>it’s more efficient to schedule your job there instead.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/Profiler.html" target="_blank" rel="noreferrer noopener">Profi</a><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/Profiler.html">ler</a>를 사용하여 Unity가 작업 완료를 대기하는 위치를 확인할 수도 있습니다.<br>You can also use the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/Profiler.html" target="_blank" rel="noreferrer noopener">Profiler</a> to see where Unity is waiting for jobs to complete.</p>



<p>주 스레드에서 <code>WaitForJobGroupID</code> 마커가 이를 나타냅니다. <br>The marker&nbsp;<code>WaitForJobGroupID</code>&nbsp;on the main thread indicates this.</p>



<p>이 마커는 데이터 의존성을 도입한 것으로 간주될 수 있어 이를 해결해야 할 수도 있습니다.<br>This marker might mean that you’ve introduced a data dependency somewhere that you should resolve.</p>



<p>데이터 의존성이 메인 스레드를 대기하게 만드는 위치를 추적하려면<strong> </strong><code>JobHandle.Complete</code>를 찾아보세요.<br>Look for&nbsp;<code>JobHandle.Complete</code>&nbsp;to track down where you have data dependencies that are forcing the main thread to wait.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">장기 실행 작업 사용 방지 (Avoid using long running jobs)</h2>



<p>쓰레드와 달리 job들은 실행을 양보하지 않습니다.<br>Unlike threads, jobs don’t yield execution.</p>



<p>한 번 작업이 시작되면 해당 작업 워커 쓰레드는 다른 작업을 실행하기 전에 해당 작업을 완료하기로 약속합니다.<br>Once a job starts, that job worker thread commits to completing the job before running any other job.</p>



<p>따라서 시스템의 다른 작업에 비해 오랜 시간이 걸리는 작업을 전송하는 대신 <a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemJobDependencies.html" target="_blank" rel="noreferrer noopener">서로 의존하는 작은 작업</a>으로 긴 작업을 분할하는 것이 좋은 실천 방법입니다.<br>As such, it’s best practice to break up long running jobs into smaller jobs that&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemJobDependencies.html" target="_blank" rel="noreferrer noopener">depend on one another</a>, <br>instead of submitting jobs that take a long time to complete relative to other jobs in the system.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>작업 시스템은 일반적으로 여러 작업 의존 체인을 실행하므로 긴 작업을 여러 부분으로 나누면 여러 작업 체인이 진행될 수 있는 기회가 생깁니다.<br>The job system usually runs multiple chains of job dependencies, so if you break up long running tasks into multiple pieces there is a chance for multiple job chains to progress.</p>



<p>반면에 작업 시스템이 긴 작업으로 가득 차 있으면 완전히 모든 워커 쓰레드를 소비하고 독립적인 작업이 실행되지 못하게 할 수 있습니다.<br>If instead the job system is filled with long running jobs, they might completely consume all worker threads and block independent jobs from executing.</p>



<p>이는 메인 스레드가 명시적으로 기다리는 중요한 작업의 완료 시간을 밀어올려 메인 스레드에서 생기지 않았을 진행 지연을 일으킬 수 있습니다.<br>This might push out the completion time of important jobs that the main thread explicitly waits for, resulting in stalls on the main thread that otherwise wouldn’t exist.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>특히, 긴 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobParallelFor.html" target="_blank" rel="noreferrer noopener"><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobParallelFor.html" target="_blank" rel="noreferrer noopener"><code>IJobParallelFor</code></a></a> 작업은 작업 배치 크기에 대해 가능한 한 많은 워커 쓰레드에서 실행하려고 하기 때문에 작업 시스템에 부정적인 영향을 미칩니다.<br>In particular, long running <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobParallelFor.html" target="_blank" rel="noreferrer noopener"><code>IJobParallelFor</code></a> jobs impact negatively on the job system <br>because these job types intentionally try to run on as many worker threads as possible for the job batch size.</p>



<p>긴 병렬 작업을 나눌 수 없는 경우 해당 작업을 예약할 때 배치 크기를 증가시켜 긴 작업을 수행하는 워커를 제한하는 것을 고려해보세요.<br>If you can’t break up long parallel jobs, consider increasing the batch size of your job when scheduling it to limit how many workers pick up the long running job.</p>



<div style="height:26px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">MyParallelJob jobData = new MyParallelJob();
jobData.Data = someData;  
jobData.Result = someArray;  

/ 사용 가능한 워커 쓰레드의 절반을 사용하되, 최소 1개의 워커 쓰레드로 제한합니다
const int numBatches = Math.Max(1, JobsUtility.JobWorkerCount / 2); 
const int totalItems = someArray.Length;
const int batchSize = totalItems / numBatches;

// 작업을 예약하고 결과 배열의 각 인덱스에 대해 하나의 Execute 및 batchSize 항목을 처리합니다
JobHandle handle = jobData.Schedule(result.Length, totalItems, batchSize);</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">추가 리소스 (Additional resources)</h2>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemJobDependencies.html" target="_blank" rel="noreferrer noopener">직업 의존성</a> (Job dependencies)</li>



<li><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemNativeContainer.html" target="_blank" rel="noreferrer noopener">스레드 안전 유형</a> (Thread safe types)</li>
</ul>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-cad298ab wp-block-columns-is-layout-flex" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemJobDependencies.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemJobDependencies.html</a></p>



<h1 class="wp-block-heading">잡 의존성 (Job dependencies)</h1>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p>자주 하나의 작업이 다른 작업의 결과에 의존합니다.<br>Often, one job depends on the results of another job.</p>



<p>예를 들어, 작업 A는 <code>NativeArray</code>에 쓸 수 있고 작업 B는 그것을 입력으로 사용할 수 있습니다.<br>For example, Job A might write to a&nbsp;<code>NativeArray</code>&nbsp;that job B uses as input.</p>



<p>의존 작업을 예약할 때 이러한 종속성에 대해 작업 시스템에 알려야 합니다.<br>You must tell the job system about such a dependency when you schedule a dependent job.</p>



<p>작업 시스템은 종속 작업이 종료될 때까지 종속 작업을 실행하지 않습니다.<br>The job system won’t run the dependent job until the job it depends upon is finished.</p>



<p>하나의 작업은 여러 작업에 의존할 수 있습니다.<br>One job can depend on more than one job.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>또한 각 작업이 이전 작업에 의존하는 작업 체인을 가질 수 있습니다.<br>You can also have a chain of jobs in which each job depends on the previous one.</p>



<p>그러나 의존성은 작업 실행을 지연시킵니다. 작업이 실행되기 전에 해당 작업의 모든 의존성이 완료되어야 하기 때문입니다.<br>However, dependencies delay job execution because you must wait for any dependencies of a job to complete before it can run.</p>



<p>의존 작업을 완료하려면 먼저 해당 작업이 의존하는 작업 및 해당 작업이 의존하는 모든 작업을 완료해야 합니다.<br>Completing a dependent job must first complete any job it depends on, and any jobs those jobs depend on.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>작업의 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobExtensions.Schedule.html" target="_blank" rel="noreferrer noopener"><code>Schedule</code></a> 메서드를 호출하면 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.html"><code>JobHandle</code></a>이 반환됩니다. <br>When you call the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJobExtensions.Schedule.html" target="_blank" rel="noreferrer noopener"><code>Schedule</code></a>&nbsp;method of a job it returns a&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.html"><code>JobHandle</code></a>.</p>



<p><code>JobHandle</code>을 다른 작업의 종속성으로 사용할 수 있습니다.<br>You can use a&nbsp;<code>JobHandle</code>&nbsp;as a dependency for other jobs.</p>



<p>작업이 다른 작업의 결과에 의존해야 하는 경우 첫 번째 작업의 <code>JobHandle</code>을 두 번째 작업의 <code>Schedule</code> 메서드에 매개변수로 전달할 수 있습니다.<br> If a job depends on the results of another job, you can pass the first job’s&nbsp;<code>JobHandle</code>&nbsp;as a parameter to the second job’s&nbsp;<code>Schedule</code>&nbsp;method, like so:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">JobHandle firstJobHandle = firstJob.Schedule();
secondJob.Schedule(firstJobHandle);</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">종속성 결합 (Combining dependencies)</h2>



<p>작업이 많은 종속성을 가지고 있다면 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.CombineDependencies.html" target="_blank" rel="noreferrer noopener"><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.CombineDependencies.html" target="_blank" rel="noreferrer noopener"><code>JobHandle.CombineDependencies</code></a> </a> 메서드를 사용하여 이를 병합할 수 있습니다.<br>If a job has a lot of dependencies, you can use the method <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.JobHandle.CombineDependencies.html" target="_blank" rel="noreferrer noopener"><code>JobHandle.CombineDependencies</code></a> to merge them.</p>



<p><code>CombineDependencies</code> 를 사용하면 종속성을 <code>Schedule</code> 메서드로 전달할 수 있습니다.<br><code>CombineDependencies</code>&nbsp;allows you to pass dependencies onto the&nbsp;<code>Schedule</code>&nbsp;method.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">NativeArray&lt;JobHandle> handles = new NativeArray&lt;JobHandle>(numJobs, Allocator.TempJob);

// Populate `handles` with `JobHandles` from multiple scheduled jobs...

JobHandle jh = JobHandle.CombineDependencies(handles);</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">다중 작업 및 종속성 예제 (An example of multiple jobs and dependencies)</h2>



<p>다음은 여러 작업이 여러 종속성을 가진 예제입니다.<br>The following is an example of multiple jobs that have multiple dependencies. </p>



<p>작업 코드(<code>MyJob</code> 및 <code>AddOneJob</code>)를 <code>Update</code> 및 <code>LateUpdate</code> 코드와 별도의 파일에 두는 것이 좋지만 명확성을 위해 이 예제는 하나의 파일에<strong> 포</strong>함되어 있습니다.<br>It’s best practice to put the job code (<code>MyJob</code>&nbsp;and&nbsp;<code>AddOneJob</code>) in a separate file to the&nbsp;<code>Update</code>&nbsp;and&nbsp;<code>LateUpdate</code>&nbsp;code, but for the purposes of clarity, this example is one file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Unity.Collections;
using Unity.Jobs;

public class MyDependentJob : MonoBehaviour
{
    // 결과를 저장할 하나의 float를 담는 NativeArray 생성. 이 예제는 작업이 완료될 때까지 기다립니다.
    NativeArray&lt;float> result;
    // 결과에 액세스하기 위한 JobHandle 생성
    JobHandle secondHandle;

    // 첫 번째 작업 설정
    public struct MyJob : IJob
    {
        public float a;
        public float b;
        public NativeArray&lt;float> result;

        public void Execute()
        {
            result[0] = a + b;
        }
    }

    // 값에 1을 더하는 두 번째 작업 설정
    public struct AddOneJob : IJob
    {
        public NativeArray&lt;float> result;

        public void Execute()
        {
            result[0] = result[0] + 1;
        }
    }

    // 매 프레임마다 호출되는 업데이트 메서드
    void Update()
    {
        // 첫 번째 작업에 대한 작업 데이터 설정
        result = new NativeArray&lt;float>(1, Allocator.TempJob);

        MyJob jobData = new MyJob
        {
            a = 10,
            b = 10,
            result = result
        };

        // 첫 번째 작업 예약
        JobHandle firstHandle = jobData.Schedule();

        // 두 번째 작업에 대한 데이터 설정
        AddOneJob incJobData = new AddOneJob
        {
            result = result
        };

        // 두 번째 작업 예약
        secondHandle = incJobData.Schedule(firstHandle);
    }

    private void LateUpdate()
    {
        // 프레임 내 나중에 작업이 완료될 때까지 대기
        secondHandle.Complete();

        // NativeArray의 모든 복사본이 동일한 메모리를 가리키므로 "당신의" NativeArray 복사본에서 결과에 액세스할 수 있습니다.
        // float aPlusBPlusOne = result[0];

        // 결과 배열이 할당한 메모리 해제
        result.Dispose();
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-cad298ab wp-block-columns-is-layout-flex" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemParallelForJobs.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemParallelForJobs.html</a></p>



<h1 class="wp-block-heading">병렬 작업 (Parallel jobs)</h1>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemCreatingJobs.html#schedule-a-job" target="_blank" rel="noreferrer noopener">schedule a job</a> 할 때는 한 번에 하나의 작업만이 특정 작업을 수행할 수 있습니다.<br>When you&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemCreatingJobs.html#schedule-a-job" target="_blank" rel="noreferrer noopener">schedule a job</a>&nbsp;there can only be one job doing one task.</p>



<p>그러나 많은 객체에서 동일한 작업을 수행해야 하는 경우가 있습니다.<br>However, there will be times where you need to perform the same operation on a lot of objects.</p>



<p>이런 경우에는 <a href="Unity.Jobs.IJobParallelFor" target="_blank" rel="noreferrer noopener"><code>IJobParallelFor</code></a>에서 파생된 ParallelFor 작업 유형을 사용합니다.<br>To do this, use a ParallelFor job type, which inherits from&nbsp;<a href="Unity.Jobs.IJobParallelFor" target="_blank" rel="noreferrer noopener"><code>IJobParallelFor</code></a>.</p>



<p>ParallelFor 작업은 데이터 원본으로 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.NativeArray_1.html" target="_blank" rel="noreferrer noopener"><code>NativeArray</code></a>를 사용합니다. ParallelFor 작업은 여러 CPU 코어에서 실행됩니다.<br>A ParallelFor job uses a&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Collections.NativeArray_1.html" target="_blank" rel="noreferrer noopener"><code>NativeArray</code></a>&nbsp;of data to act on as its data source.  ParallelFor jobs run across multiple CPU cores.</p>



<p>각 코어 당 하나의 작업이 있으며 각 작업은 작업 부하의 일부를 처리합니다.<br>There’s one job per core, with each handling a subset of the workload.</p>



<p><code>IJobParallelFor</code>는 <a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobsOverview" target="_blank" rel="noreferrer noopener"><code>IJob</code></a>과 유사하지만 단일 <code><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.Execute.html" target="_blank" rel="noreferrer noopener">Execute</a></code> 메서드 대신 데이터 원본의 각 항목당 한 번씩 <code>Execute</code> 메서드를 호출합니다.<br><code>IJobParallelFor</code>&nbsp;behaves like&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobsOverview" target="_blank" rel="noreferrer noopener"><code>IJob</code></a>, but instead of a single&nbsp;<code><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Unity.Jobs.IJob.Execute.html" target="_blank" rel="noreferrer noopener">Execute</a></code>&nbsp;method, it invokes the&nbsp;<code>Execute</code>&nbsp;method once per item in the data source. </p>



<p><code>Execute</code> 메서드에는 데이터 소스 내의 단일 요소에 액세스하고 작업을 수행할 수 있는 정수 매개변수 index도 있습니다.<br>There’s also an integer parameter index in the&nbsp;<code>Execute</code>&nbsp;method, which you can use to access and operate on a single element of the data source within the job implementation.</p>



<p>다음은 ParallelFor 작업 정의의 예시입니다 :<br>The following is an example of a ParallelFor job definition:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">struct IncrementByDeltaTimeJob: IJobParallelFor
{
    public NativeArray&lt;float> values;
    public float deltaTime;

    public void Execute (int index)
    {
        float temp = values[index];
        temp += deltaTime;
        values[index] = temp;
    }
}</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="border-width:2px;padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">ParallelFor 작업 예약 (Schedule a ParallelFor job)</h2>



<p><code>ParallelFor</code> 작업을 예약하려면 사용할 <code>NativeArray</code> 데이터 소스의 길이를 지정해야 합니다.<br>To schedule a&nbsp;<code>ParallelFor</code>&nbsp;job, you must specify the length of the&nbsp;<code>NativeArray</code>&nbsp;data source that you want to split.</p>



<p>구조체에 여러 개가 있을 경우 데이터 소스로 사용할 NativeArray를 작업 시스템이 알 수 없습니다..<br>The job system doesn’t know which&nbsp;<code>NativeArray</code>&nbsp;you want to use as the data source if there are several in the struct.</p>



<p>길이는 또한 작업 시스템에게 기대할 <code>Execute</code> 메서드의 수를 알려줍니다.<br>The length also tells the job system how many&nbsp;<code>Execute</code>&nbsp;methods to expect.</p>



<p>In Unity’s native code, the scheduling of&nbsp;<code>ParallelFor</code>&nbsp;jobs is more complicated.<br>유니티의 네이티브 코드에서 <code>ParallelFor</code> 작업을 예약하는 것은 더 복잡합니다.</p>



<p>유니티가 <code>ParallelFor</code> 작업을 예약하면 작업 시스템은 작업을 코어 간에 분배하기 위해 작업을 일련의 배치로 나눕니다.<br>When Unity schedules a&nbsp;<code>ParallelFor</code>&nbsp;job, the job system divides the work into batches to distribute between cores.</p>



<p>각 배치에는 <code>Execute</code> 메서드의 하위 집합이 포함되어 있습니다.<br>Each batch contains a subset of&nbsp;<code>Execute</code>&nbsp;methods. </p>



<p>그런 다음 job system은 유니티의 네이티브 작업 시스템에서 CPU 코어 당 하나의 작업을 예약하고 해당 네이티브 작업을 배치에 전달하여 완료합니다.<br>The job system then schedules one job in Unity’s native job system per CPU core and passes that native job to the batches to complete.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure data-wp-context="{&quot;imageId&quot;:&quot;69c29fb487754&quot;}" data-wp-interactive="core/image" data-wp-key="69c29fb487754" class="wp-block-image size-full is-resized wp-lightbox-container"><img decoding="async" width="720" height="784" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://lycos7560.com/wp-content/uploads/2023/12/image-1.png" alt="" class="wp-image-37652" style="width:1101px;height:auto" srcset="https://lycos7560.com/wp-content/uploads/2023/12/image-1.png 720w, https://lycos7560.com/wp-content/uploads/2023/12/image-1-276x300.png 276w" sizes="(max-width: 720px) 100vw, 720px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			aria-label="확대하기"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.imageButtonRight"
			data-wp-style--top="state.imageButtonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">여러 코어에 걸쳐 배치를 나누는 ParallelFor 작업<br>A ParallelFor job dividing batches across cores</figcaption></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p>다른 Native 작업보다 네이티브 작업이 일부 배치를 먼저 완료하면 남은 배치를 다른 네이티브 작업에서 <a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html#work-stealing" target="_blank" rel="noreferrer noopener">빼앗아 갑니다. </a><br>When a native job completes its batches before others, it&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/JobSystemOverview.html#work-stealing" target="_blank" rel="noreferrer noopener">steals</a>&nbsp;remaining batches from the other native jobs. </p>



<p>이 때 <a href="https://en.wikipedia.org/wiki/Locality_of_reference" target="_blank" rel="noreferrer noopener">캐시 지역성</a>을 보장하기 위해 네이티브 작업의 남은 배치의 절반만을 한 번에 빼앗습니다.<br>It only steals half of a native job’s remaining batches at a time, to ensure&nbsp;<a href="https://en.wikipedia.org/wiki/Locality_of_reference" target="_blank" rel="noreferrer noopener">cache locality</a>.</p>



<p>이 프로세스를 최적화하려면 배치 카운트를 지정해야 합니다.<br>To optimize the process, you need to specify a batch count.</p>



<p>배치 카운트는 얼마나 많은 작업을 얻을지 및 스레드 간 작업 재분배가 얼마나 미세한지를 제어합니다.<br>The batch count controls how many jobs you get, and how fine-grained the redistribution of work between threads is. </p>



<p>낮은 배치 카운트(예: 1)는 스레드 간 작업을 균등하게 분배합니다.<br>Having a low batch count, such as 1, gives you an even distribution of work between threads.</p>



<p>그러나 이에는 어느 정도의 오버헤드가 따르므로 때로는 배치 수를 늘리는 것이 더 나을 수 있습니다.<br>However, it comes with some overhead, so sometimes it’s better to increase the batch count.</p>



<p>1에서 시작하여 성능 향상이 미미할 때까지 배치 수를 늘리는 것이 좋은 전략입니다.<br>Starting at 1 and increasing the batch count until there are negligible performance gains is a good strategy.</p>



<p>다음은 ParallelFor 작업을 예약하는 예시입니다.<br>The following is an example of scheduling a ParallelFor job</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>Job code:</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Job adding two floating point values together
public struct MyParallelJob : IJobParallelFor
{
    [ReadOnly]
    public NativeArray&lt;float> a;
    [ReadOnly]
    public NativeArray&lt;float> b;
    public NativeArray&lt;float> result;

    public void Execute(int i)
    {
        result[i] = a[i] + b[i];
    }
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>Main thread code:</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">NativeArray&lt;float> a = new NativeArray&lt;float>(2, Allocator.TempJob);

NativeArray&lt;float> b = new NativeArray&lt;float>(2, Allocator.TempJob);

NativeArray&lt;float> result = new NativeArray&lt;float>(2, Allocator.TempJob);

a[0] = 1.1;
b[0] = 2.2;
a[1] = 3.3;
b[1] = 4.4;

MyParallelJob jobData = new MyParallelJob();
jobData.a = a;
jobData.b = b;
jobData.result = result;

// 결과 배열의 각 인덱스에 대해 하나의 Execute로 작업을 예약하고 각 처리 배치당 항목은 1개
JobHandle handle = jobData.Schedule(result.Length, 1);

// 작업이 완료될 때까지 기다립니다.
handle.Complete();

// 배열에 할당된 메모리를 해제합니다.
a.Dispose();
b.Dispose();
result.Dispose();</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">ParallelForTransform jobs</h2>



<p><code>ParallelForTransform</code> 작업은 <a href="https://docs.unity3d.com/2023.3/Documentation/Manual/class-Transform.html" target="_blank" rel="noreferrer noopener">Transforms</a>에 특화된 또 다른 <code>ParallelFor</code> 작업 유형입니다.<br>A&nbsp;<code>ParallelForTransform</code>&nbsp;job is another type of&nbsp;<code>ParallelFor</code>&nbsp;job designed specifically for operating on&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/Manual/class-Transform.html" target="_blank" rel="noreferrer noopener">Transforms</a>.</p>



<p>이는 작업에서 Transform 작업을 효율적으로 수행하는 데 유용합니다.<br>It’s useful for working on Transform operations from jobs efficiently. </p>



<p>더 많은 정보는 <a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Jobs.IJobParallelForTransform.html" target="_blank" rel="noreferrer noopener">ParallelForTransform API </a>문서를 참조하세요.<br>For more information, see the&nbsp;<a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Jobs.IJobParallelForTransform.html" target="_blank" rel="noreferrer noopener">ParallelForTransform</a>&nbsp;API documentation.</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<p><a href="https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Jobs.IJobParallelForTransform.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/2023.3/Documentation/ScriptReference/Jobs.IJobParallelForTransform.html</a></p>



<h3 class="wp-block-heading">IJobParallelForTransform</h3>



<p>interface in UnityEngine.Jobs</p>



<p>Job에 전달된 모든 변환의 위치, 회전 및 크기에 대해 동일한 독립적인 작업을 수행할 수 있도록 하는 인터페이스입니다.<br>An interface that allows you to perform the same independent operation for each position, rotation and scale of all the transforms passed into a job.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine.Jobs;

class ApplyVelocitySample : MonoBehaviour
{
    public struct VelocityJob : IJobParallelForTransform
    {
        // 작업에서 액세스될 모든 데이터를 선언합니다.
        // 읽기 전용으로 선언함으로써 여러 작업에서 데이터에 병렬로 액세스할 수 있습니다.
        [ReadOnly]
        public NativeArray&lt;Vector3> velocity;

        // 작업에서 프레임 개념이 일반적으로 없기 때문에 델타 타임을 작업으로 복사해야 합니다.
        // 메인 스레드는 동일한 프레임이나 다음 프레임에 작업을 기다리지만,
        // 작업은 작업자 스레드에서 실행되는 시점에 상관없이 작업을 결정적으로 수행해야 합니다.
        public float deltaTime;

        // 작업에서 실제로 실행되는 코드
        public void Execute(int index, TransformAccess transform)
        {
            // 델타 타임과 속도를 기반으로 변환을 이동시킵니다.
            var pos = transform.position;
            pos += velocity[index] * deltaTime;
            transform.position = pos;
        }
    }

    // 작업에서 조작할 변환을 인스펙터에서 할당합니다.
    [SerializeField] public Transform[] m_Transforms;
    TransformAccessArray m_AccessArray;

    void Awake()
    {
        // 변환을 TransformAccessArray 인스턴스에 저장하여 작업에서 액세스할 수 있도록 합니다.
        m_AccessArray = new TransformAccessArray(m_Transforms);
    }

    void OnDestroy()
    {
        // TransformAccessArrays는 수동으로 Dispose해야 합니다.
        m_AccessArray.Dispose();
    }

    public void Update()
    {
        var velocity = new NativeArray&lt;Vector3>(m_Transforms.Length, Allocator.Persistent);

        for (var i = 0; i &lt; velocity.Length; ++i)
            velocity[i] = new Vector3(0f, 10f, 0f);

        // 작업 데이터 초기화
        var job = new VelocityJob()
        {
            deltaTime = Time.deltaTime,
            velocity = velocity
        };

        // 병렬로 변환 작업을 예약합니다.
        // 이 메서드는 작업에서 조작할 변환을 포함하는 TransformAccessArray를 취합니다.
        JobHandle jobHandle = job.Schedule(m_AccessArray);

        // 작업이 완료되었는지 확인합니다.
        // 작업을 즉시 완료하면 이와 병렬로 다른 작업이 실행될 가능성이 감소합니다.
        // 작업을 프레임 초반에 예약하고 나중에 프레임에서 기다리는 것이 좋습니다.
        jobHandle.Complete();

        Debug.Log(m_Transforms[0].position);

        // Native 배열은 수동으로 Dispose해야 합니다.
        velocity.Dispose();
    }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>
</div>
</div>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/unity-manual-job-system-2023-3-%eb%b2%88%ec%97%ad/37818/">Unity Manual / Job system (2023.3) 번역</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-manual-job-system-2023-3-%eb%b2%88%ec%97%ad/37818/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Error) A failure occurred while executing com.android.build.gradle.internal.tasks.workers$actionfacade</title>
		<link>https://lycos7560.com/unity/error-a-failure-occurred-while-executing-com-android-build-gradle-internal-tasks-workersactionfacade/35551/</link>
					<comments>https://lycos7560.com/unity/error-a-failure-occurred-while-executing-com-android-build-gradle-internal-tasks-workersactionfacade/35551/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Fri, 23 Jun 2023 06:32:56 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[A failure occurred while executing com.android.build.gradle.internal.tasks.workers$actionfacade]]></category>
		<category><![CDATA[actionfacade]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[Keystore]]></category>
		<category><![CDATA[workers]]></category>
		<category><![CDATA[빌드]]></category>
		<category><![CDATA[빌드 오류]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=35551</guid>

					<description><![CDATA[<p>A failure occurred while executing com.android.build.gradle.internal.tasks.workers$actionfacade 유니티로 빌드할 때 발생하는 오류입니다. 원인은 Keystore의 비밀번호가 올바르지&#160;않은 경우에 발생합니다.</p>
<p>The post <a href="https://lycos7560.com/unity/error-a-failure-occurred-while-executing-com-android-build-gradle-internal-tasks-workersactionfacade/35551/">Error) A failure occurred while executing com.android.build.gradle.internal.tasks.workers$actionfacade</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5698326622209671" crossorigin="anonymous"></script>
<!-- HorizontalAD -->
<ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-5698326622209671" data-ad-slot="6908948342" data-ad-format="auto" data-full-width-responsive="true"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>



<div style="height:62px" aria-hidden="true" class="wp-block-spacer"></div>



<h1 class="wp-block-heading">A failure occurred while executing com.android.build.gradle.internal.tasks.workers$actionfacade</h1>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="420" height="150" src="https://lycos7560.com/wp-content/uploads/2023/06/image-38.png" alt="" class="wp-image-35552" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-38.png 420w, https://lycos7560.com/wp-content/uploads/2023/06/image-38-300x107.png 300w" sizes="(max-width: 420px) 100vw, 420px" /></figure>



<div style="height:35px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1620" height="230" src="https://lycos7560.com/wp-content/uploads/2023/06/image-39.png" alt="" class="wp-image-35554" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-39.png 1620w, https://lycos7560.com/wp-content/uploads/2023/06/image-39-300x43.png 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-39-768x109.png 768w, https://lycos7560.com/wp-content/uploads/2023/06/image-39-1536x218.png 1536w" sizes="(max-width: 1620px) 100vw, 1620px" /></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p>유니티로 빌드할 때 발생하는 오류입니다.</p>



<p><strong>원인은 Keystore의 비밀번호가 올바르지&nbsp;않은 경우에 발생합니다.</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1920" height="581" src="https://lycos7560.com/wp-content/uploads/2023/06/image-41.png" alt="" class="wp-image-35556" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-41.png 1920w, https://lycos7560.com/wp-content/uploads/2023/06/image-41-300x91.png 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-41-768x232.png 768w, https://lycos7560.com/wp-content/uploads/2023/06/image-41-1536x465.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></figure>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5698326622209671" crossorigin="anonymous"></script>
<ins class="adsbygoogle" style="display:block" data-ad-format="autorelaxed" data-ad-client="ca-pub-5698326622209671" data-ad-slot="4245812909"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
<p>The post <a href="https://lycos7560.com/unity/error-a-failure-occurred-while-executing-com-android-build-gradle-internal-tasks-workersactionfacade/35551/">Error) A failure occurred while executing com.android.build.gradle.internal.tasks.workers$actionfacade</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/error-a-failure-occurred-while-executing-com-android-build-gradle-internal-tasks-workersactionfacade/35551/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Oculus Unity-Integration &#8211; Snap Interactions</title>
		<link>https://lycos7560.com/unity/unity-vr/oculus-unity-integration-snap-interactions/35453/</link>
					<comments>https://lycos7560.com/unity/unity-vr/oculus-unity-integration-snap-interactions/35453/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Wed, 14 Jun 2023 08:41:53 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[Unity-VR]]></category>
		<category><![CDATA[Interactions]]></category>
		<category><![CDATA[MovementProvider]]></category>
		<category><![CDATA[Oculus]]></category>
		<category><![CDATA[Oculus Quest]]></category>
		<category><![CDATA[Oculus Unity-Integration]]></category>
		<category><![CDATA[Quest2]]></category>
		<category><![CDATA[Snap]]></category>
		<category><![CDATA[Snap Interactions]]></category>
		<category><![CDATA[SnapInteractable]]></category>
		<category><![CDATA[SnapInteractor]]></category>
		<category><![CDATA[SnapPosesProvider]]></category>
		<category><![CDATA[Trigger collider]]></category>
		<category><![CDATA[Unity-Integration]]></category>
		<category><![CDATA[오큘러스]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=35453</guid>

					<description><![CDATA[<p>Oculus Unity-Integration SDK를 정리한 내용입니다. (This is a summary of the Oculus Unity-Integration SDK.)</p>
<p>The post <a href="https://lycos7560.com/unity/unity-vr/oculus-unity-integration-snap-interactions/35453/">Oculus Unity-Integration &#8211; Snap Interactions</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5698326622209671" crossorigin="anonymous"></script>
<ins class="adsbygoogle" style="display:block" data-ad-format="autorelaxed" data-ad-client="ca-pub-5698326622209671" data-ad-slot="4245812909"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-4963675b      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							Oculus Unity-Integration						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#snap-interactions" class="uagb-toc-link__trigger">Snap Interactions</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#snapinteractor" class="uagb-toc-link__trigger">SnapInteractor</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#snapinteractable" class="uagb-toc-link__trigger">SnapInteractable</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#trigger-collider" class="uagb-toc-link__trigger">Trigger collider</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#movementprovider" class="uagb-toc-link__trigger">MovementProvider</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#snapposesprovider" class="uagb-toc-link__trigger">SnapPosesProvider</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h1 class="wp-block-heading">Snap Interactions</h1>



<p class="has-small-font-size"><a href="https://developer.oculus.com/documentation/unity/unity-isdk-snap-interaction/" target="_blank" rel="noreferrer noopener">https://developer.oculus.com/documentation/unity/unity-isdk-snap-interaction/</a></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Snap interactions allow items to automatically snap to poses in the environment. <br>스냅 상호 작용을 사용하면 항목이 환경의 포즈에 자동으로 스냅될 수 있습니다.</p>



<p>The&nbsp;<strong>DistanceGrabExample</strong>&nbsp;scene uses them to simply have the items snap back to their original position when not in use,<br>but it is possible to create custom behaviors so the objects snap to inventories, cells in a board game, slots around the user body, etc.<br><strong>DistanceGrabExample</strong>&nbsp;씬은 사용하지 않을 때 단순히 아이템을 원래 위치로 되돌리기 위해 이를 사용하지만, <br>오브젝트가 인벤토리, 보드 게임의 셀, 사용자 몸 주위의 슬롯 등에 스냅되도록 커스텀 동작을 만들 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-video"><video height="1016" style="aspect-ratio: 1864 / 1016;" width="1864" controls muted src="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_16_42_19_590.mp4"></video></figure>



<div style="height:150px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">SnapInteractor</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>The SnapInteractor is the Interactor class for this interaction. <br>SnapInteractor는 이 상호 작용에 대한 Interactor 클래스입니다.</p>



<p>This component is placed in the item that we want to be able to snap, e.g. a chess piece, <br>and will take care of detecting nearby SnapInteractables and move the item towards the best available pose provided by them.<br>이 컴포넌트는 스냅할 수 있는 아이템(예: 체스 말)에 배치되며,<br>근처의 SnapInteractables를 감지하고 아이템이 제공하는 최상의 포즈로 아이템을 이동합니다.</p>



<p>When the Optional&nbsp;<strong>TimeOutInteractable</strong>&nbsp;and&nbsp;<strong>TimeOut</strong>&nbsp;are provided, <br>the Interactor will automatically move to said interactable after TimeOut seconds <br>if the Grabbable is not being Selected or Hovered by any other interactor.</p>



<p>선택적&nbsp;<strong>TimeOutInteractable</strong>&nbsp;및 TimeOut이 제공되면 다른 인터랙터가 <br>Grabbable을 선택하거나 가리키지 않는 경우 인터랙터는&nbsp;<strong>TimeOut</strong>(초) 후에 자동으로 해당 인터랙터로 이동합니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://lycos7560.com/wp-content/uploads/2023/06/image-30.jpg" alt="" class="wp-image-35462" width="1714" height="1053" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-30.jpg 1714w, https://lycos7560.com/wp-content/uploads/2023/06/image-30-300x184.jpg 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-30-768x472.jpg 768w, https://lycos7560.com/wp-content/uploads/2023/06/image-30-1536x944.jpg 1536w" sizes="(max-width: 1714px) 100vw, 1714px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-video"><video height="1016" style="aspect-ratio: 1864 / 1016;" width="1864" controls muted src="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_16_56_43_18.mp4"></video></figure>



<div style="height:150px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">SnapInteractable</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>The SnapInteractable component is the Interactable class for this interaction.<br>SnapInteractable 구성 요소는 이 상호 작용에 대한 Interactable 클래스입니다.</p>



<p>When used as-is it provides a single pose in space to which the interactors can snap too, but optionally it can be enhanced in several ways.<br>있는 그대로 사용하면 상호 작용자가 스냅할 수 있는 공간에서 단일 포즈를 제공하지만 선택적으로 여러 가지 방법으로 향상시킬 수 있습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><strong>Trigger collider</strong></h3>



<p>when a&nbsp;<strong>Trigger</strong>&nbsp;volume is present in the same gameobject, <br>Interactors entering the volume will be tracked and automatically snap to the interactable pos as soon as their state becomes equal to Normal.<br><strong>트리거</strong>&nbsp;볼륨이 동일한 게임 오브젝트에 있는 경우 볼륨에 진입하는 인터랙터가 추적되고 <br>상태가 Normal이 되는 즉시 상호 작용 가능한 위치에 자동으로 스냅됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://lycos7560.com/wp-content/uploads/2023/06/image-30.png" alt="" class="wp-image-35468" width="938" height="390" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-30.png 938w, https://lycos7560.com/wp-content/uploads/2023/06/image-30-300x125.png 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-30-768x319.png 768w" sizes="(max-width: 938px) 100vw, 938px" /></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://lycos7560.com/wp-content/uploads/2023/06/image-31.jpg" alt="" class="wp-image-35469" width="1145" height="930" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-31.jpg 1145w, https://lycos7560.com/wp-content/uploads/2023/06/image-31-300x244.jpg 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-31-768x624.jpg 768w" sizes="(max-width: 1145px) 100vw, 1145px" /></figure>



<figure class="wp-block-video"><video height="1016" style="aspect-ratio: 1896 / 1016;" width="1896" controls muted src="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_17_15_38_779.mp4"></video></figure>



<div style="height:60px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><strong>MovementProvider</strong></h3>



<p>by referencing a&nbsp;<strong>MovementProvider</strong>&nbsp;the method for snapping can be fully customized. <br><strong>MovementProvider</strong>를 참조하여 스냅 메서드를&nbsp;완전히 사용자 지정할 수 있습니다.</p>



<p>By default the interactor will follow the slot at a fixed speed, but following the different MovementProvider it could trace a curve, add easing, etc.<br>기본적으로 인터랙터는 고정된 속도로 슬롯을 따라가지만 다른 MovementProvider를 따라 커브를 추적하고 부드럽게를 추가하는 등의 작업을 수행할 수 있습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://lycos7560.com/wp-content/uploads/2023/06/image-31.png" alt="" class="wp-image-35473" width="1205" height="687" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-31.png 1205w, https://lycos7560.com/wp-content/uploads/2023/06/image-31-300x171.png 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-31-768x438.png 768w" sizes="(max-width: 1205px) 100vw, 1205px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-video"><video height="1016" style="aspect-ratio: 2552 / 1016;" width="2552" controls muted src="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_17_25_26_898.mp4"></video></figure>



<div style="height:60px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><strong>SnapPosesProvider</strong></h3>



<p>the&nbsp;<strong>ISnapPoseProvider</strong>&nbsp;interface allows creating multiple poses within a SnapInteractable. <br><strong>ISnapPoseProvider</strong>&nbsp;인터페이스를 사용하면 SnapInteractable 내에서 여러 포즈를 만들 수 있습니다.&nbsp;</p>



<p>Implementing and providing this interface is useful for using a single SnapInteractable for all the cells within a board in a board game, <br>or to define all the different slots in an inventory system, allowing to even move snapped items when hovering new interactors to make room.<br>이 인터페이스를 구현하고 제공하면 보드 게임의 보드 내의 모든 셀에 대해 단일 SnapInteractable을 사용하거나 인벤토리 시스템에서 모든 다른 슬롯을 정의하는 데 유용하며, <br>공간을 만들기 위해 새 상호 작용기를 마우스로 가리킬 때 스냅된 항목을 이동할 수도 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1670" height="803" src="https://lycos7560.com/wp-content/uploads/2023/06/image-32-1.jpg" alt="" class="wp-image-35480" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-32-1.jpg 1670w, https://lycos7560.com/wp-content/uploads/2023/06/image-32-1-300x144.jpg 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-32-1-768x369.jpg 768w, https://lycos7560.com/wp-content/uploads/2023/06/image-32-1-1536x739.jpg 1536w" sizes="(max-width: 1670px) 100vw, 1670px" /></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="878" height="711" src="https://lycos7560.com/wp-content/uploads/2023/06/image-32.png" alt="" class="wp-image-35481" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-32.png 878w, https://lycos7560.com/wp-content/uploads/2023/06/image-32-300x243.png 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-32-768x622.png 768w" sizes="(max-width: 878px) 100vw, 878px" /></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;

namespace Oculus.Interaction
{
    /// &lt;summary>
    /// SnapPoseDelegate는 맞춤형 SnapPose 로직을 제공하는 데 사용할 수 있습니다
    /// 추적되거나 스냅되는 요소 집합이 주어집니다.
    /// &lt;/summary>
    public interface ISnapPoseDelegate
    {
        /// &lt;summary>
        /// 새 요소가 추적 중임을 나타냅니다.
        /// &lt;/summary>
        /// &lt;param name="id">추적할 요소 ID입니다.&lt;/param>
        /// &lt;param name="params">요소의 포즈입니다.&lt;/param>
        void TrackElement(int id, Pose p);
        /// &lt;summary>
        /// 요소가 더 이상 추적되지 않음을 나타냅니다.
        /// &lt;/summary>
        /// &lt;param name="id">추적을 중지할 요소 ID입니다.&lt;/param>
        void UntrackElement(int id);
        /// &lt;summary>
        /// 추적된 요소가 스냅되어야 함을 나타냅니다.
        /// &lt;/summary>
        /// &lt;param name="id">스냅할 요소 ID입니다.&lt;/param>
        /// &lt;param name="params">요소의 포즈입니다.&lt;/param>
        void SnapElement(int id, Pose pose);
        /// &lt;summary>
        /// 요소가 더 이상 스냅되지 않아야 함을 나타냅니다.
        /// &lt;/summary>
        /// &lt;param name="id">스냅을 중지할 요소 ID입니다.&lt;/param>
        void UnsnapElement(int id);
        /// &lt;summary>
        /// 추적된 요소 포즈가 업데이트되었음을 나타냅니다.
        /// &lt;/summary>
        /// &lt;param name="id">요소 ID.&lt;/param>
        /// &lt;param name="params">새로운 요소 포즈.&lt;/param>
        void MoveTrackedElement(int id, Pose p);
        /// &lt;summary>
        /// 쿼리된 요소 ID에 대한 대상 스냅 포즈입니다.
        /// &lt;/summary>
        /// &lt;param name="id">요소 ID.&lt;/param>
        /// &lt;param name="params">타깃 포즈.&lt;/param>
        /// &lt;returns>요소에 스냅할 포즈가 있으면 참입니다.&lt;/returns>
        bool SnapPoseForElement(int id, Pose pose, out Pose result);
    }
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-video"><video height="1016" style="aspect-ratio: 1936 / 1016;" width="1936" controls muted src="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_17_35_02_372.mp4"></video></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5698326622209671" crossorigin="anonymous"></script>
<!-- HorizontalAD -->
<ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-5698326622209671" data-ad-slot="6908948342" data-ad-format="auto" data-full-width-responsive="true"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
<p>The post <a href="https://lycos7560.com/unity/unity-vr/oculus-unity-integration-snap-interactions/35453/">Oculus Unity-Integration &#8211; Snap Interactions</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-vr/oculus-unity-integration-snap-interactions/35453/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_16_42_19_590.mp4" length="9771598" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_16_56_43_18.mp4" length="16439396" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_17_15_38_779.mp4" length="13835677" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_17_25_26_898.mp4" length="9707333" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2023/06/녹화_2023_06_14_17_35_02_372.mp4" length="16034540" type="video/mp4" />

			</item>
		<item>
		<title>Oculus Unity-Integration &#8211; Hand Pose Detection</title>
		<link>https://lycos7560.com/unity/unity-vr/oculus-hand-pose-detection-%ec%86%90-%ed%8f%ac%ec%a6%88-%ea%b0%90%ec%a7%80/34843/</link>
					<comments>https://lycos7560.com/unity/unity-vr/oculus-hand-pose-detection-%ec%86%90-%ed%8f%ac%ec%a6%88-%ea%b0%90%ec%a7%80/34843/#comments</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Mon, 22 May 2023 15:49:57 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[Unity-VR]]></category>
		<category><![CDATA[Abduction]]></category>
		<category><![CDATA[Curl]]></category>
		<category><![CDATA[Finger Features]]></category>
		<category><![CDATA[FingerFeatureStateProvider]]></category>
		<category><![CDATA[FingerFeatureStateThresholds]]></category>
		<category><![CDATA[Flexion]]></category>
		<category><![CDATA[Hand]]></category>
		<category><![CDATA[Hand Pose]]></category>
		<category><![CDATA[Hand Pose Detection]]></category>
		<category><![CDATA[Integration]]></category>
		<category><![CDATA[Meta]]></category>
		<category><![CDATA[Meta Quest VR]]></category>
		<category><![CDATA[Oculus]]></category>
		<category><![CDATA[Oculus Quest]]></category>
		<category><![CDATA[Oculus Unity-Integration]]></category>
		<category><![CDATA[Pose Prefabs]]></category>
		<category><![CDATA[ShapeRecognizer]]></category>
		<category><![CDATA[ShapeRecognizerActiveState]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Unity-Integration]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=34843</guid>

					<description><![CDATA[<p>이론이 필요없고 적용하는 과정이 궁금하다면 아래글로 Oculus Hand Pose Detection https://developer.oculus.com/documentation/unity/unity-isdk-hand-pose-detection/?ref=blog.immersive-insiders.com Hand Pose Detection uses multiple components and configurators to detect hand poses. 손 포즈 감지는 여러 컴포넌트와 구성 요소를 사용하여 손의 동작을 감지하는 기술입니다. A hand pose is defined by shapes and transforms.이를 판단하기 위해 형태(shape)와 변환(transform)이라는 두 가지 요소를 사용합니다. Shapes are boolean [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/unity-vr/oculus-hand-pose-detection-%ec%86%90-%ed%8f%ac%ec%a6%88-%ea%b0%90%ec%a7%80/34843/">Oculus Unity-Integration &#8211; Hand Pose Detection</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5698326622209671" crossorigin="anonymous"></script>
<!-- HorizontalAD -->
<ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-5698326622209671" data-ad-slot="6908948342" data-ad-format="auto" data-full-width-responsive="true"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">이론이 필요없고 적용하는 과정이 궁금하다면 아래글로</p>



<figure class="wp-block-embed is-type-wp-embed is-provider-어제와-내일의-나-그-사이의-이야기 wp-block-embed-어제와-내일의-나-그-사이의-이야기"><div class="wp-block-embed__wrapper">
<blockquote class="wp-embedded-content" data-secret="vbVz6GAD9S"><a href="https://lycos7560.com/unity/unity-vr/oculus-hand-pose-detection-%ec%97%b0%ec%8a%b5/35047/">Oculus Hand Pose Detection 연습</a></blockquote><iframe loading="lazy" class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;Oculus Hand Pose Detection 연습&#8221; &#8212; 어제와 내일의 나 그 사이의 이야기" src="https://lycos7560.com/unity/unity-vr/oculus-hand-pose-detection-%ec%97%b0%ec%8a%b5/35047/embed/#?secret=IB6B3qIX84#?secret=vbVz6GAD9S" data-secret="vbVz6GAD9S" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</div></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-fddbe69c      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차 테이블						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#oculus-hand-pose-detection" class="uagb-toc-link__trigger">Oculus Hand Pose Detection</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#pose-prefabs" class="uagb-toc-link__trigger">Pose Prefabs</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#shaperecognizer" class="uagb-toc-link__trigger">ShapeRecognizer</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#shaperecognizeractivestate" class="uagb-toc-link__trigger">ShapeRecognizerActiveState</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#shaperecognizer" class="uagb-toc-link__trigger">ShapeRecognizer</a></li></ul><li class="uagb-toc__list"><a href="#fingerfeaturestateprovider" class="uagb-toc-link__trigger">FingerFeatureStateProvider</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#fingerfeaturestatethresholds" class="uagb-toc-link__trigger">FingerFeatureStateThresholds</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#fingerfeaturestatethresholds-example" class="uagb-toc-link__trigger">FingerFeatureStateThresholds Example</a></li></ul><li class="uagb-toc__list"><a href="#finger-features" class="uagb-toc-link__trigger">Finger Features</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#curl" class="uagb-toc-link__trigger">Curl</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#flexion" class="uagb-toc-link__trigger">Flexion</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#abduction" class="uagb-toc-link__trigger">Abduction</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#opposition" class="uagb-toc-link__trigger">Opposition</a></li></ul></li></ul></li></ul><li class="uagb-toc__list"><a href="#transform-recognition" class="uagb-toc-link__trigger">Transform Recognition</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#transformrecognizeractivestate" class="uagb-toc-link__trigger">TransformRecognizerActiveState</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#transformfeaturestateprovider" class="uagb-toc-link__trigger">TransformFeatureStateProvider</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#transformconfig" class="uagb-toc-link__trigger">TransformConfig</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#velocity-recognition" class="uagb-toc-link__trigger">Velocity Recognition</a></li></ul><li class="uagb-toc__list"><a href="#sequences" class="uagb-toc-link__trigger">Sequences</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#sequence-classes" class="uagb-toc-link__trigger">Sequence Classes</a></li></ul><li class="uagb-toc__list"><a href="#debugging-pose-recognition-포즈-인식-디버깅" class="uagb-toc-link__trigger">Debugging Pose Recognition (포즈 인식 디버깅)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#activestatedebugtree" class="uagb-toc-link__trigger">ActiveStateDebugTree</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#fingerfeatureskeletaldebugvisual" class="uagb-toc-link__trigger">FingerFeatureSkeletalDebugVisual</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#handshapeskeletaldebugvisual" class="uagb-toc-link__trigger">HandShapeSkeletalDebugVisual</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#transformfeaturedebugvisual" class="uagb-toc-link__trigger">TransformFeatureDebugVisual</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#transformfeaturevectordebugparentvisual" class="uagb-toc-link__trigger">TransformFeatureVectorDebugParentVisual</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#transformfeaturevectordebugvisual" class="uagb-toc-link__trigger">TransformFeatureVectorDebugVisual</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#transformrecognizerdebugvisual" class="uagb-toc-link__trigger">TransformRecognizerDebugVisual</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#jointrotationdebugvisual" class="uagb-toc-link__trigger">JointRotationDebugVisual</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#jointvelocitydebugvisual" class="uagb-toc-link__trigger">JointVelocityDebugVisual</a></li></ul><li class="uagb-toc__list"><a href="#internal-implementation-classes" class="uagb-toc-link__trigger">Internal Implementation Classes</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#featurestateprovider" class="uagb-toc-link__trigger">FeatureStateProvider</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#featurestatethresholdseditor" class="uagb-toc-link__trigger">FeatureStateThresholdsEditor</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#featuredescriptionattribute" class="uagb-toc-link__trigger">FeatureDescriptionAttribute</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ifeaturestatethreshold" class="uagb-toc-link__trigger">IFeatureStateThreshold</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ifeaturestatethresholds" class="uagb-toc-link__trigger">IFeatureStateThresholds</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ifeature-thresholds" class="uagb-toc-link__trigger">IFeature Thresholds</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#collidercontainshandjointactivestate" class="uagb-toc-link__trigger">ColliderContainsHandJointActiveState</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#hmdoffset" class="uagb-toc-link__trigger">HmdOffset</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h1 class="wp-block-heading has-large-font-size">Oculus Hand Pose Detection</h1>



<p><a href="https://developer.oculus.com/documentation/unity/unity-isdk-hand-pose-detection/?ref=blog.immersive-insiders.com" target="_blank" rel="noreferrer noopener">https://developer.oculus.com/documentation/unity/unity-isdk-hand-pose-detection/?ref=blog.immersive-insiders.com</a></p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">Hand Pose Detection uses multiple components and configurators to detect hand poses. <br>손 포즈 감지는 여러 컴포넌트와 구성 요소를 사용하여 손의 동작을 감지하는 기술입니다.</p>



<p class="has-medium-font-size">A hand pose is defined by shapes and transforms.<br>이를 판단하기 위해 형태(shape)와 변환(transform)이라는 두 가지 요소를 사용합니다.</p>



<p class="has-medium-font-size">Shapes are boolean conditions about the required position of the hand’s finger joints.<br>형태는 손가락 관절의 위치에 대한 부울 조건을 나타냅니다.</p>



<p class="has-medium-font-size">Transforms are boolean conditions about the required orientation of the hand in the world space. <br>Transform은 세계 공간에서 손의 요구되는 방향에 대한 bool 조건입니다.</p>



<p class="has-medium-font-size">A pose is detected when the tracked hand matches that pose&#8217;s required shapes and transforms. <br>추적된 손이 해당 포즈의 요구 형태와 Transform이 일치할 때 포즈가 감지됩니다.</p>



<p class="has-medium-font-size">This topic explains poses, shape and transform recognition, and the criteria used to determine if a pose is detected. <br>이 글에서는 포즈, 형태 및 Transform 인식, 그리고 포즈가 감지되는지 여부를 결정하는 기준에 대해 설명합니다.</p>



<p class="has-medium-font-size">It also describes debug components you can use to visually debug poses. <br>시각적으로 포즈를 디버깅하기 위해 사용할 수 있는 debug components에 대해서도 설명합니다.</p>



<p class="has-medium-font-size">To learn how to detect a hand pose, see Build a Hand Pose Recognizer. (나중에 링크)<br>손 포즈를 감지하는 방법을 알아보려면 &#8220;손 포즈 인식기 만들기&#8221;를 참조하세요.</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading has-large-font-size">Pose Prefabs</h2>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">Interaction SDK includes 6 ready to use example pose prefabs.<br>Interaction SDK에는 6개의 준비된 예제 포즈 프리팹이 포함되어 있습니다.</p>



<p class="has-medium-font-size">You can define your own poses using the patterns defined in these prefabs.<br>이러한 프리팹에서 정의된 패턴을 사용하여 직접 포즈를 정의할 수 있습니다.</p>



<p class="has-medium-font-size">You can experiment with pose detection using these pose prefabs in the PoseExamples sample scene.<br>PoseExamples 샘플 씬에서 이러한 포즈 prefab을 사용하여 포즈 감지를 실험해 볼 수 있습니다.</p>



<div style="height:19px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li>RockPose</li>



<li>PaperPose</li>



<li>ScissorsPose</li>



<li>ThumbsUpPose</li>



<li>ThumbsDownPose</li>



<li>StopPose</li>
</ul>



<div style="height:19px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1363" height="352" src="https://lycos7560.com/wp-content/uploads/2023/05/image-94.jpg" alt="" class="wp-image-34862" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-94.jpg 1363w, https://lycos7560.com/wp-content/uploads/2023/05/image-94-300x77.jpg 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-94-768x198.jpg 768w" sizes="(max-width: 1363px) 100vw, 1363px" /></figure>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">Each pose prefab has these components:<br>각 pose prefab에는 다음과 같은 구성 요소가 있습니다</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">A <strong>HandRef</strong> is a component that takes an <strong>IHand</strong> as input.<br>이 <strong>HandRef</strong>는 <strong>IHand</strong>를 입력 값으로 받는 component입니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="814" height="390" src="https://lycos7560.com/wp-content/uploads/2023/05/image-95.png" alt="" class="wp-image-34864" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-95.png 814w, https://lycos7560.com/wp-content/uploads/2023/05/image-95-300x144.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-95-768x368.png 768w" sizes="(max-width: 814px) 100vw, 814px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="796" height="459" src="https://lycos7560.com/wp-content/uploads/2023/05/image-94.png" alt="" class="wp-image-34863" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-94.png 796w, https://lycos7560.com/wp-content/uploads/2023/05/image-94-300x173.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-94-768x443.png 768w" sizes="(max-width: 796px) 100vw, 796px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">The other components on this prefab will read hand state via this reference.<br>이 프리팹의 다른 컴포넌트들은 이 참조를 통해 손의 상태를 읽습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1268" height="957" src="https://lycos7560.com/wp-content/uploads/2023/05/image-99.jpg" alt="" class="wp-image-34868" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-99.jpg 1268w, https://lycos7560.com/wp-content/uploads/2023/05/image-99-300x226.jpg 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-99-768x580.jpg 768w" sizes="(max-width: 1268px) 100vw, 1268px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>ShapeRecognizerActiveState</strong> is a component that becomes active when the criteria of a specified Shape is met.<br><strong>ShapeRecognizerActiveState</strong>는 지정된 형태의 조건이 충족되면 활성화되는 component입니다.</p>



<p class="has-medium-font-size"><strong>TransformRecognizerActive</strong> is a component that becomes active when a transform feature, such as a particular wrist orientation, is detected.<br><strong>TransformRecognizerActive</strong>은 특정 손목 방향과 같은 변환 기능이 감지되었을 때 활성화되는 component입니다.</p>



<p class="has-medium-font-size"><strong>ActiveStateGroup</strong> is a component that returns true when all dependent ActiveStates are true.<br><strong>ActiveStateGroup</strong>은 종속적인 ActiveState가 모두 true일 때 true를 반환하는 컴포넌트입니다.</p>



<p class="has-medium-font-size"><strong>ActiveStateSelector</strong> and <strong>SelectorUnityEventWrapper</strong> are components that can invoke events when a pose is detected.<br><strong>ActiveStateSelector</strong>와 <strong>SelectorUnityEventWrapper</strong>는 포즈가 감지되었을 때 이벤트를 호출할 수 있는 component입니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="761" height="300" src="https://lycos7560.com/wp-content/uploads/2023/05/image-135.png" alt="" class="wp-image-35043" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-135.png 761w, https://lycos7560.com/wp-content/uploads/2023/05/image-135-300x118.png 300w" sizes="(max-width: 761px) 100vw, 761px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="733" height="327" src="https://lycos7560.com/wp-content/uploads/2023/05/image-136.png" alt="" class="wp-image-35045" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-136.png 733w, https://lycos7560.com/wp-content/uploads/2023/05/image-136-300x134.png 300w" sizes="(max-width: 733px) 100vw, 733px" /></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="698" height="632" src="https://lycos7560.com/wp-content/uploads/2023/05/image-99.png" alt="" class="wp-image-34871" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-99.png 698w, https://lycos7560.com/wp-content/uploads/2023/05/image-99-300x272.png 300w" sizes="(max-width: 698px) 100vw, 698px" /></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">A pose includes required transforms (which are bundled in TransformRecognizerActiveState) and shapes (which are bundled in ShapeRecognizerActiveState).<br>한 pose에는 필요한 transforms(이는 TransformRecognizerActiveState에서 묶여 있음)와 shapes(이는 ShapeRecognizerActiveState에서 묶여 있음)가 포함됩니다.</p>



<p class="has-medium-font-size">These are combined using ActiveStateGroup to define the pose.<br>이들은 ActiveStateGroup을 사용하여 결합되어 pose를 정의합니다.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="1175" height="1202" src="https://lycos7560.com/wp-content/uploads/2023/05/image-100.png" alt="" class="wp-image-34874" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-100.png 1175w, https://lycos7560.com/wp-content/uploads/2023/05/image-100-293x300.png 293w, https://lycos7560.com/wp-content/uploads/2023/05/image-100-768x786.png 768w" sizes="(max-width: 1175px) 100vw, 1175px" /></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">wrist up =&gt; 손목을 위로 향하게</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-video"><video height="808" style="aspect-ratio: 1432 / 808;" width="1432" controls muted src="https://lycos7560.com/wp-content/uploads/2023/05/녹화_2023_05_22_21_16_30_889.mp4"></video></figure>



<div style="height:150px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading has-large-font-size">ShapeRecognizer</h2>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">Poses include one or more shapes. <br>포즈에는 하나 이상의 형태가 포함됩니다.</p>



<p class="has-medium-font-size">A shape is a set of boolean conditions about the position of one or more fingers. <br>형태는 하나 이상의 손가락 위치에 대한 boolean 조건의 집합입니다.</p>



<p class="has-medium-font-size">The conditions are defined using Finger Features states. <br>이러한 조건은 Finger Features 상태를 사용하여 정의됩니다.</p>



<p class="has-medium-font-size">If a tracked hand meets these conditions, then the shape becomes active.<br>추적된 손이 이러한 조건을 충족하면 형태가 활성화됩니다.</p>



<p class="has-medium-font-size">If all the shapes in the pose are active and the transform is also active, the pose is detected. <br>포즈의 모든 형태가 활성화되고 변형도 활성화된 경우, 포즈가 감지됩니다.</p>



<p class="has-medium-font-size">A pose’s shapes are stored as ShapeRecognizer assets in the pose’s ShapeRecognizerActiveState component.<br>포즈의 형태는 포즈의 ShapeRecognizerActiveState component에 저장되는 ShapeRecognizer 자산으로 저장됩니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="695" height="520" src="https://lycos7560.com/wp-content/uploads/2023/05/image-101.png" alt="" class="wp-image-34879" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-101.png 695w, https://lycos7560.com/wp-content/uploads/2023/05/image-101-300x224.png 300w" sizes="(max-width: 695px) 100vw, 695px" /></figure>



<div style="height:150px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading has-large-font-size">ShapeRecognizerActiveState</h3>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1186" height="581" src="https://lycos7560.com/wp-content/uploads/2023/05/image-103.png" alt="" class="wp-image-34885" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-103.png 1186w, https://lycos7560.com/wp-content/uploads/2023/05/image-103-300x147.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-103-768x376.png 768w" sizes="(max-width: 1186px) 100vw, 1186px" /></figure>



<p class="has-medium-font-size"><strong>ShapeRecognizerActiveState</strong>&nbsp;takes a hand, the current state of the hand’s fingers, and a list of shape configs. <br><strong>ShapeRecognizerActiveState</strong>&nbsp;는 손, 손 손가락의 현재 상태 및 셰이프 구성 목록을 사용합니다.</p>



<p class="has-medium-font-size">To get the current state of the fingers, it uses the&nbsp;method to retrieve the&nbsp;<strong>FingerFeatureStateProvider</strong>&nbsp;component from the hand. <br>손가락의 현재 상태를 가져오기 위해 이 메서드를 사용하여 손에서&nbsp;<strong>FingerFeatureStateProvider</strong>&nbsp;구성 요소를 검색합니다.</p>



<p class="has-medium-font-size">If the state of every finger matches the states in the listed shapes,&nbsp;<strong>ShapeRecognizerActiveState</strong>&nbsp;becomes active.&nbsp;<br>모든 손가락의 상태가 나열된 도형의 상태와 일치하면&nbsp;<strong>ShapeRecognizerActiveState</strong>가 활성화됩니다.</p>



<p class="has-medium-font-size"><strong>ShapeRecognizerActiveState</strong>&nbsp;implements the&nbsp;<strong>IActiveState</strong>&nbsp;interface.<code>GetHandAspect</code><br>Shape RecognizerActiveState는 the IActiveState interface.GetHandAspect를 구현합니다</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-left" data-align="left">Property</th><th class="has-text-align-left" data-align="left">Description</th></tr></thead><tbody><tr><td class="has-text-align-left" data-align="left">Hand</td><td class="has-text-align-left" data-align="left">A&nbsp;<strong>Hand Ref</strong>&nbsp;component. Determines which hand is read for state data.<br><strong>Hand Ref</strong>&nbsp;구성 요소입니다.  데이터를 읽을 Hand를 결정합니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Finger Feature State Provider</td><td class="has-text-align-left" data-align="left">A&nbsp;<strong>FingerFeatureStateProvider</strong>&nbsp;component, which provides the current state of the tracked hand’s fingers.<br>추적된 손 손가락의 현재 상태를 제공하는&nbsp;<strong>FingerFeatureStateProvider&nbsp;</strong>구성 요소입니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Shapes</td><td class="has-text-align-left" data-align="left">A list of shape configs (<a href="https://developer.oculus.com/documentation/unity/unity-isdk-hand-pose-detection/?ref=blog.immersive-insiders.com#shape-recognizer">ShapeRecognizer</a>&nbsp;assets) that define the pose. <br>포즈를 정의하는 셰이프 구성(<a href="https://developer.oculus.com/documentation/unity/unity-isdk-hand-pose-detection/?ref=blog.immersive-insiders.com#shape-recognizer">ShapeRecognizer</a>&nbsp;자산)의 목록입니다.<br><br>The states in these shape configs are compared to the finger states from the&nbsp;<strong>Finger Feature State Provider</strong>&nbsp;property.<br>&nbsp;이러한 셰이프 구성의 상태는&nbsp;<strong>Finger Feature State Provider</strong>&nbsp;속성의 손가락 상태와 비교됩니다.</td></tr></tbody></table></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading has-large-font-size" id="shape-recognizer">ShapeRecognizer</h4>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1893" height="738" src="https://lycos7560.com/wp-content/uploads/2023/05/image-106.png" alt="" class="wp-image-34901" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-106.png 1893w, https://lycos7560.com/wp-content/uploads/2023/05/image-106-300x117.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-106-768x299.png 768w, https://lycos7560.com/wp-content/uploads/2023/05/image-106-1536x599.png 1536w" sizes="(max-width: 1893px) 100vw, 1893px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>ShapeRecognizer</strong>&nbsp;is a that defines a shape. <br><strong>ShapeRecognizer</strong>는 도형을 정의하는 것입니다.</p>



<p class="has-medium-font-size">To define a shape, it uses a set of rules&nbsp;called Feature Configs. <br>&nbsp;shape를 정의하기 위해&nbsp;Feature Configs라는 rules을 사용합니다.</p>



<p class="has-medium-font-size">Feature Configs specify a required position (state) for each of the five fingers. <br>기능 구성은 다섯 손가락 각각에 필요한 위치(상태)를 지정합니다.</p>



<p class="has-medium-font-size">Feature Configs define state using at least one of the Finger Features: Curl, Flexion, Abduction, and Opposition.&nbsp;<br>기능 구성은 손가락 기능(Curl, Flexion, Abduction, Opposition) 중 하나 이상을 사용하여 상태를 정의합니다.</p>



<p class="has-medium-font-size"><strong>ShapeRecognizer</strong>&nbsp;is referenced by the&nbsp;<strong>ShapeRecognizerActiveState</strong>&nbsp;component to determine if a pose is active.<code>ScriptableObject</code><br><strong>ShapeRecognizer</strong>는&nbsp;<strong>ShapeRecognizerActiveState</strong>&nbsp;구성 요소에서 참조하여 포즈가 활성 상태인지 확인합니다.<code>ScriptableObject</code></p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading has-large-font-size">FingerFeatureStateProvider</h3>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1190" height="681" src="https://lycos7560.com/wp-content/uploads/2023/05/image-104.png" alt="" class="wp-image-34897" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-104.png 1190w, https://lycos7560.com/wp-content/uploads/2023/05/image-104-300x172.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-104-768x440.png 768w" sizes="(max-width: 1190px) 100vw, 1190px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>Finger&nbsp;Feature&nbsp;State Provider</strong>&nbsp;provides the finger states of the tracked hands and&nbsp;contains the state transition thresholds for each finger. <br><strong>손가락&nbsp;기능&nbsp;상태 공급자</strong>는 추적된 손의 손가락 상태를 제공하고 각 손가락에 대한 상태 전환 임계값을 포함합니다.</p>



<p class="has-medium-font-size">It’s referenced by the&nbsp;ShapeRecognizerActiveState&nbsp;component.<br>ShapeRecognizerActiveState&nbsp;구성 요소에서 참조합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-left" data-align="left">Property</th><th class="has-text-align-left" data-align="left">Description</th></tr></thead><tbody><tr><td class="has-text-align-left" data-align="left">Hand</td><td class="has-text-align-left" data-align="left">The&nbsp;<strong>Hand</strong>&nbsp;component to use for finger state data.<br>손가락 상태 데이터에 사용할&nbsp;<strong>Hand</strong>&nbsp;구성 요소입니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Finger State Thresholds</td><td class="has-text-align-left" data-align="left">A list of five elements, one for each finger. <br>각 손가락에 하나 씩 5개의 요소 목록입니다. <br><br>Each element has two properties, a&nbsp;<strong>Finger</strong>&nbsp;(Thumb, Index, Middle, Ring, Pinky), and a&nbsp;<strong>State Thresholds</strong>&nbsp;(FingerFeatureStateThresholds).<br>각 요소에는 Finger(Thumb,&nbsp;Index, Middle, Ring, Pinky)와 <strong>State Thresholds</strong>(FingerFeatureStateThresholds)의 두 가지 속성이 있습니다.</td></tr></tbody></table></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading has-large-font-size" id="finger-feature-state-thresholds">FingerFeatureStateThresholds</h4>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>FingerFeatureStateThresholds</strong>&nbsp;is a&nbsp;that defines the state thresholds for each&nbsp;Finger Feature.<br><strong>FingerFeatureStateThresholds</strong>는 각&nbsp;손가락 특징에 대한 상태 임계값을 정의하는 것입니다.</p>



<p class="has-medium-font-size"> A <strong>state threshold</strong> is a set of boundaries that determine when a finger has transitioned between states. <br>&nbsp;<strong>state threshold</strong> 는 손가락이 상태 간에 전환된 시기를 결정하는 경계 집합입니다.&nbsp;</p>



<p class="has-medium-font-size">For example, the curl feature has 3 states: Open, Neutral, and Closed.<br>예를 들어 curl 기능에는 3가지 상태(Open, Neutral 및 Closed)가 있습니다.</p>



<p class="has-medium-font-size"> So the state thresholds for curl use an angle in degrees to define when the finger’s state has changed from Open to Neutral, Neutral to Closed, or vice-versa.<code>ScriptableObject</code><br>따라서 curl의 상태 임계값은 각도(도)를 사용하여 손가락의 상태가 열림에서 보통으로, 보통에서 닫힘으로 또는 그 반대로 변경된 시기를 정의합니다.<code>ScriptableObject</code></p>



<p class="has-medium-font-size">Interaction SDK provides four sets of default state thresholds, which are under&nbsp;:<code>DefaultSettings/PoseDetection</code><br>Interaction SDK는 아래에 있는 4개의 기본 상태 임계값 집합을 제공합니다.<code>DefaultSettings/PoseDetection</code></p>



<ul class="wp-block-list">
<li>DefaultThumbFeatureStateThresholds (for the thumb)(엄지 손가락의 경우)</li>



<li>IndexFingerFeatureStateThresholds (for the Index finger)(집게 손가락의 경우)</li>



<li>MiddleFingerFeatureStateThresholds (for the Middle finger)(가운데 손가락의 경우)</li>



<li>DefaultFingerFeatureStateThresholds (for the Ring &amp; Pinky fingers)(약지 및 새끼손가락용)</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1920" height="991" src="https://lycos7560.com/wp-content/uploads/2023/05/image-107.jpg" alt="" class="wp-image-34908" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-107.jpg 1920w, https://lycos7560.com/wp-content/uploads/2023/05/image-107-300x155.jpg 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-107-768x396.jpg 768w, https://lycos7560.com/wp-content/uploads/2023/05/image-107-1536x793.jpg 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="473" height="380" src="https://lycos7560.com/wp-content/uploads/2023/05/image-107.png" alt="" class="wp-image-34909" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-107.png 473w, https://lycos7560.com/wp-content/uploads/2023/05/image-107-300x241.png 300w" sizes="(max-width: 473px) 100vw, 473px" /></figure>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">The thumb’s curl state threshold.<br>엄지 손가락의 curl 상태 임계값입니다.</p>



<p class="has-medium-font-size">For curl, the value is an angle in degrees.<br>curl의 경우 값은 각도(도)입니다.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-left" data-align="left">Property</th><th class="has-text-align-left" data-align="left">Description</th></tr></thead><tbody><tr><td class="has-text-align-left" data-align="left">Min Time In State</td><td class="has-text-align-left" data-align="left">How long the value must be in the new state before the feature will actually change to that state. <br>기능이 실제로 해당 상태로 변경되기 전에 값이 새로운 상태에 있어야 하는 기간입니다.&nbsp;<br><br>This is to prevent rapid flickering at transition edges. <br>이는 전환 가장자리에서 빠른 깜박임을 방지하기 위한 것입니다.&nbsp;<br><br>This value applies to all features.<br>이 값은 모든 기능에 적용됩니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Expected Value Range</td><td class="has-text-align-left" data-align="left">A rough guide that indicates what range of motion the average human will be able to achieve.<br>평균적인 인간이 달성할 수 있는 동작 범위를 나타내는 대략적인 가이드입니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Midpoint</td><td class="has-text-align-left" data-align="left">The value at which a state will transition from A &gt; B (or B &gt; A).<br>상태가 A에서 B(또는 B&gt; A)&gt; 전환되는 값입니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Width</td><td class="has-text-align-left" data-align="left">How far the value must exceed the midpoint until the transition can occur. <br>전환이 발생할 수 있을 때까지 값이 중간점을 초과해야 하는 거리입니다.<br><br>This is to prevent rapid flickering at transition edges.<br>이는 전환 가장자리에서 빠른 깜박임을 방지하기 위한 것입니다.</td></tr></tbody></table></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading has-large-font-size" id="fingerfeaturestatethresholds-example">FingerFeatureStateThresholds Example</h5>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">Given the transition between two states, A &lt;&gt; B:<br>두 상태 간의 전환할 때 A&lt;&gt; B는 다음과 같습니다.</p>



<p class="has-medium-font-size">If the current state is “A”, to transition up to “B” then the angle must rise above the midpoint for that pairing by at least (width / 2.0) for “Min Time In State” seconds.<br>현재 상태가 &#8220;A&#8221;인 경우 &#8220;B&#8221;로 전환하려면 각도가 &#8220;Min Time In State&#8221; 초 동안 해당 페어링의 중간점 이상으로 최소(너비/2.0) 상승해야 합니다.</p>



<p class="has-medium-font-size">If the current state is “B”, to transition down to “A” then the angle must drop below the midpoint for that pairing by at least (width / 2.0) for “Min Time In State” seconds.<br>현재 상태가 &#8220;B&#8221;인 경우 &#8220;A&#8221;로 전환하려면 각도가 &#8220;Min Time In State&#8221; 초 동안 해당 페어링의 중간점 아래로 최소(너비 / 2.0) 떨어져야 합니다.</p>



<p class="has-medium-font-size">So for Curl, to transition:<br>따라서 Curl의 경우 전환하려면 다음을 수행하십시오:</p>



<ul class="wp-block-list">
<li>From Open &gt; Neutral: value must be above 195 for 0.0222 seconds</li>



<li>From Neutral &gt; Open: value must be below 185 for 0.0222 seconds</li>



<li>From Neutral &gt; Closed: value must be above 210 for 0.0222 seconds</li>



<li>From Closed &gt; Neutral: value must be below 200 for 0.0222 seconds</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li>개방에서 중립&gt;: 값은 195.0초 동안 0222보다 커야 합니다.</li>



<li>중립에서 시&gt;까지: 값은 185.0초 동안 0222 미만이어야 합니다.</li>



<li>중립에서 닫힘으로&gt;: 값은 210.0초 동안 0222보다 커야 합니다.</li>



<li>닫힘에서 중립&gt;: 값은 200.0초 동안 0222 미만이어야 합니다.</li>
</ul>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading has-large-font-size" id="finger-features">Finger Features</h4>



<p class="has-medium-font-size">Finger Features are specific finger positions that let you define a shape. There are four features:<br>손가락 기능은 모양을 정의할 수 있는 특정 손가락 위치입니다. 네 가지 기능이 있습니다.</p>



<ul class="wp-block-list">
<li>Curl </li>



<li>Flexion</li>



<li>Abduction</li>



<li>Opposition</li>
</ul>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="664" height="429" src="https://lycos7560.com/wp-content/uploads/2023/05/image-115.png" alt="" class="wp-image-34938" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-115.png 664w, https://lycos7560.com/wp-content/uploads/2023/05/image-115-300x194.png 300w" sizes="(max-width: 664px) 100vw, 664px" /></figure>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading has-large-font-size" id="curl">Curl</h5>



<p class="has-medium-font-size">Represents how bent the top two joints of the finger or thumb are. <br>손가락 또는 엄지손가락의 위쪽 두 관절이 얼마나 구부러졌는지를 나타냅니다.</p>



<p class="has-medium-font-size">This feature doesn’t take the Proximal (knuckle) joint into consideration.<br>이 기능은 근위부(너클) 조인트를 고려하지 않습니다.</p>



<p class="has-medium-font-size">States:</p>



<ul class="wp-block-list">
<li><strong>Open</strong>: Fingers are fully extended straight.</li>



<li><strong>Neutral</strong>: Fingers are slightly curled inwards, as if they were wrapped around a coffee mug.</li>



<li><strong>Closed</strong>&nbsp;(pictured): Fingers are tightly curled inwards such that the tips are almost touching the palm.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>열림</strong>: 손가락을 완전히 똑바로 뻗습니다.</li>



<li><strong>중립</strong>: 손가락이 마치 커피 머그잔을 감싼 것처럼 안쪽으로 약간 말려 있습니다.</li>



<li><strong>닫힘</strong>&nbsp;(사진) : 손가락이 안쪽으로 단단히 말려서 끝이 손바닥에 거의 닿을 정도입니다.</li>
</ul>



<div style="height:18px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="291" height="529" src="https://lycos7560.com/wp-content/uploads/2023/05/image-108.png" alt="" class="wp-image-34913" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-108.png 291w, https://lycos7560.com/wp-content/uploads/2023/05/image-108-165x300.png 165w" sizes="(max-width: 291px) 100vw, 291px" /></figure>



<div style="height:18px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">The joints used to measure the curl feature.<br>컬 형상을 측정하는 데 사용되는 조인트.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading has-large-font-size" id="flexion">Flexion</h5>



<p class="has-medium-font-size">The extent that the Proximal (knuckle) joint is bent. <br>근위부(너클) 관절이 구부러진 정도.&nbsp;</p>



<p class="has-medium-font-size">Flexion is only reliable on the 4 fingers.<br>굴곡은 4개의 손가락에서만 신뢰할 수 있습니다.&nbsp; (엄지 X )</p>



<p class="has-medium-font-size"> It can provide false positives on the thumb.<br>이것은 엄지 손가락에 잘못된 긍정을 제공 할 수 있습니다.</p>



<p class="has-medium-font-size"><strong>States:</strong></p>



<ul class="wp-block-list">
<li><strong>Open</strong>: The first bone on the fingers is fully extended and is parallel to the palm.</li>



<li><strong>Neutral</strong>: Somewhat bent.</li>



<li><strong>Closed</strong>: Knuckle joint is fully bent (pictured).</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>열림</strong>: 손가락의 첫 번째 뼈가 완전히 확장되고 손바닥과 평행합니다.</li>



<li><strong>중립:</strong>&nbsp;약간 구부러져 있습니다.</li>



<li><strong>닫힘</strong>: 너클 조인트가 완전히 구부러져 있습니다(사진).</li>
</ul>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>Warning</strong></p>



<p class="has-medium-font-size">Flexion is only reliable on the 4 fingers.<br>굴곡은 4개의 손가락에서만 신뢰할 수 있습니다. </p>



<p class="has-medium-font-size"> It can provide false positives on the thumb.<br>엄지 손가락에 잘못된 긍정을 제공 할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://scontent-ssn1-1.xx.fbcdn.net/v/t39.2365-6/309860470_1137837473813430_4556848194095159268_n.png?_nc_cat=109&amp;ccb=1-7&amp;_nc_sid=ad8a9d&amp;_nc_ohc=ZKwYFdpy-J0AX9zGOWy&amp;_nc_ht=scontent-ssn1-1.xx&amp;oh=00_AfDCf0AgRjvTKySJl0nN4zFee__gKeLgnJJPAy0aTXlzJQ&amp;oe=64703882" alt="Four fingers bent perpendicular to the palm"/></figure>



<p class="has-medium-font-size">An example of flexion where the knuckle joint is in the&nbsp;<strong>Closed</strong>&nbsp;state.<br>너클 관절이&nbsp;<strong>닫힌</strong>&nbsp;상태인 굴곡의 예.</p>



<div style="height:99px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading has-large-font-size">Abduction</h5>



<p class="has-medium-font-size">The angle between two adjacent fingers, measured at the base of those two fingers.<br>인접한 두 손가락 사이의 각도로, 두 손가락의 밑면에서 측정됩니다.</p>



<p class="has-medium-font-size">Abduction measures the angle between the given finger and the adjacent finger that’s closer to the pinky. <br>외전은 주어진 손가락과 새끼 손가락에 더 가까운 인접한 손가락 사이의 각도를 측정합니다.</p>



<p class="has-medium-font-size">For example, Abduction for the index finger is the angle between the index and middle finger.<br>예를 들어, 집게 손가락의 외전은 집게 손가락과 가운데 손가락 사이의 각도입니다.</p>



<p class="has-medium-font-size"><strong>States:</strong></p>



<ul class="wp-block-list">
<li><strong>Open</strong>&nbsp;The two fingers are spread apart (pictured for index).</li>



<li><strong>Closed</strong>: The two fingers are tightly compressed together (pictured for thumb, middle, ring).</li>



<li><strong>None</strong>: Not currently used.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>열다</strong>&nbsp;두 손가락이 벌어져 있습니다(인덱스 사진).</li>



<li><strong>닫힘</strong>: 두 손가락이 함께 단단히 압축됩니다(엄지, 가운데, 반지 사진).</li>



<li><strong>없음</strong>: 현재 사용되지 않습니다.</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>Note</strong></p>



<p class="has-medium-font-size">Abduction on Pinkie is not supported.<br>핑키의 외전은 지원되지 않습니다. (새끼 손가락)</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="395" height="564" src="https://lycos7560.com/wp-content/uploads/2023/05/image-109.png" alt="" class="wp-image-34921" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-109.png 395w, https://lycos7560.com/wp-content/uploads/2023/05/image-109-210x300.png 210w" sizes="(max-width: 395px) 100vw, 395px" /></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">An example of abduction. <br>The index finger is in the&nbsp;<strong>Open</strong>&nbsp;state.<br>집게 손가락이&nbsp;<strong>열린</strong>&nbsp;상태입니다. </p>



<p class="has-medium-font-size">The thumb, middle, and ring fingers are in the&nbsp;<strong>Closed</strong>&nbsp;state.<br>엄지, 중지, 약지가&nbsp;<strong>닫힌</strong>&nbsp;상태입니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading has-large-font-size"><strong>Opposition</strong></h5>



<p class="has-medium-font-size">How close a given fingertip is to the thumb tip. <br>주어진 손가락 끝이 엄지 손가락 끝에 얼마나 가까운지.</p>



<p class="has-medium-font-size">Can only be used on index, middle, ring, and pinky fingers.<br>검지, 중지, 약지, 새끼손가락에만 사용할 수 있습니다.</p>



<p class="has-medium-font-size">States:</p>



<ul class="wp-block-list">
<li><strong>Touching</strong>: The fingertip joints are within ~1.5cm (pictured for index).</li>



<li><strong>Near</strong>: The fingertip joints are between ~1.5cm and ~15cm apart.</li>



<li><strong>None</strong>: The fingertip joints are greater than ~15cm apart.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>만지기</strong>: 손가락 끝 관절은 ~1.5cm 이내입니다(인덱스 사진).</li>



<li><strong>근거리</strong>: 손가락 끝 관절은 ~1.5cm에서 ~15cm 떨어져 있습니다.</li>



<li><strong>없음</strong>: 손가락 끝 관절이 ~15cm 이상 떨어져 있습니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="438" height="596" src="https://lycos7560.com/wp-content/uploads/2023/05/image-110.png" alt="" class="wp-image-34922" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-110.png 438w, https://lycos7560.com/wp-content/uploads/2023/05/image-110-220x300.png 220w" sizes="(max-width: 438px) 100vw, 438px" /></figure>



<p class="has-medium-font-size">An example of opposition. The index finger is in the&nbsp;<strong>Touching</strong>&nbsp;state.<br>반대의 예. 집게 손가락이&nbsp;<strong>Touching</strong>&nbsp;상태입니다.</p>



<div style="height:150px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading has-large-font-size" id="transform-recognition">Transform Recognition</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">Poses consist of one or more transforms. <br>포즈는 하나 이상의 변환으로 구성됩니다.</p>



<p class="has-medium-font-size">The transform of the hand only represents the orientation and position.<br>손의 변형은 방향과 위치만 나타냅니다.</p>



<p class="has-medium-font-size">The orientation is only evaluated relative to the WristUp, WristDown, PalmDown, PalmUp, PalmTowardsFace, PalmsAwayFromFace, FingersUp, FingersDown, and PinchClear transforms.<br>방향은 WristUp, WristDown, PalmDown, PalmUp, PalmTowardsFace, PalmsAwayFromFace, FingersUp, FingersDown 및 PinchClear 변환을 기준으로만 평가됩니다.</p>



<p class="has-medium-font-size">A pose’s required transforms are listed in the pose’s&nbsp;TransformRecognizerActiveState&nbsp;component.<br>포즈의 필수 변환은 포즈의&nbsp;TransformRecognizerActiveState&nbsp;구성 요소에 나열됩니다.&nbsp;</p>



<p class="has-medium-font-size">During hand tracking, the hand’s transforms are compared to the pose’s transforms. <br>핸드 트래킹 중에 손의 변형이 포즈의 변형과 비교됩니다.</p>



<p class="has-medium-font-size">If both sets of transforms match and all the shapes in the pose are active, then the pose is detected.<br>두 변환 집합이 모두 일치하고 포즈의 모든 shape가 활성 상태이면 포즈가 감지됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="568" height="328" src="https://lycos7560.com/wp-content/uploads/2023/05/image-111.png" alt="" class="wp-image-34926" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-111.png 568w, https://lycos7560.com/wp-content/uploads/2023/05/image-111-300x173.png 300w" sizes="(max-width: 568px) 100vw, 568px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">The axes that define the hand’s fingers, wrist, and palm.<br>손의 손가락, 손목 및 손바닥을 정의하는 축입니다.</p>



<div style="height:150px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading has-large-font-size">TransformRecognizerActiveState</h4>



<figure class="wp-block-image size-full"><img decoding="async" width="1195" height="315" src="https://lycos7560.com/wp-content/uploads/2023/05/image-114.png" alt="" class="wp-image-34934" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-114.png 1195w, https://lycos7560.com/wp-content/uploads/2023/05/image-114-300x79.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-114-768x202.png 768w" sizes="(max-width: 1195px) 100vw, 1195px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>TransformRecognizerActiveState</strong>&nbsp;takes a hand, the current state of the hand’s transforms, and a list of transform feature configs, and a transform config.<br><strong>TransformRecognizerActiveState</strong>&nbsp;는 손 변환의 현재 상태, 변환 기능 구성 목록 및 변환 구성을 사용합니다.</p>



<p class="has-medium-font-size">To get the current state of the hand’s transforms, it uses the&nbsp;method to retrieve the&nbsp;<strong>TransformFeatureStateProvider</strong>&nbsp;component.<br>손 변환의 현재 상태를 가져오기 위해 method를 사용하여&nbsp;<strong>TransformFeatureStateProvider</strong>&nbsp;구성 요소를 검색합니다.</p>



<p class="has-medium-font-size">That component reads the raw feature values and quantizes them into&nbsp;<strong>TransformFeatureStates</strong>&nbsp;using the&nbsp;<strong>Transform Config</strong>&nbsp;you provide in this component.<code>GetHandAspect</code><br>이 구성 요소는 raw 기능 값을 읽고 이 구성 요소에서 제공하는&nbsp;<strong>변환 구성을</strong>&nbsp;사용하여&nbsp;<strong>TransformFeatureStates</strong>로 정량화 합니다.<code>GetHandAspect</code></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-left" data-align="left">Property</th><th class="has-text-align-left" data-align="left">Description</th></tr></thead><tbody><tr><td class="has-text-align-left" data-align="left">Hand</td><td class="has-text-align-left" data-align="left">A&nbsp;<strong>Hand Ref</strong>&nbsp;component. Determines which hand is read for state data.<br><strong>Hand Ref</strong>&nbsp;구성 요소입니다. 상태 데이터를 읽을 핸드를 결정합니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Transform Feature State Provider</td><td class="has-text-align-left" data-align="left">A&nbsp;TransformFeatureStateProvider&nbsp;component, which provides the current state of the tracked hand’s transforms.<br>추적된 손 변환의 현재 상태를 제공하는&nbsp;TransformFeatureStateProvider&nbsp;구성 요소입니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Transform Feature Configs</td><td class="has-text-align-left" data-align="left">A list of required transforms that the tracked hand must match for the pose to become active (assuming all shapes are also active). <br>포즈가 활성화되기 위해 추적된 손이 일치해야 하는 필수 변환 목록입니다(모든 셰이프도 활성 상태라고 가정).<br><br>Each transform is an orientation and a boolean (ex.&nbsp;<strong>PalmTowardsFace</strong>&nbsp;is&nbsp;<strong>True</strong>.)<br>각 변환은 방향과 부울입니다(예:&nbsp;<strong>PalmTowardsFace</strong>는&nbsp;<strong>True</strong>임).</td></tr><tr><td class="has-text-align-left" data-align="left">Transform Config</td><td class="has-text-align-left" data-align="left">See&nbsp;TransformConfig.<br>TransformConfig를 참조하세요.</td></tr></tbody></table></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading has-large-font-size" id="transform-feature-state-provider">TransformFeatureStateProvider</h4>



<figure class="wp-block-image size-full"><img decoding="async" width="1200" height="255" src="https://lycos7560.com/wp-content/uploads/2023/05/image-113.png" alt="" class="wp-image-34933" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-113.png 1200w, https://lycos7560.com/wp-content/uploads/2023/05/image-113-300x64.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-113-768x163.png 768w" sizes="(max-width: 1200px) 100vw, 1200px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>TransformFeatureStateProvider</strong>&nbsp;provides the transform states of the tracked hand. <br><strong>TransformFeatureStateProvider</strong>는 추적된 손의 변환 상태를 제공합니다.</p>



<p class="has-medium-font-size">It’s referenced by the&nbsp;TransformRecognizerActiveState&nbsp;component.<br>TransformRecognizerActiveState&nbsp;구성 요소에서 참조합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-left" data-align="left">Property</th><th class="has-text-align-left" data-align="left">Description</th></tr></thead><tbody><tr><td class="has-text-align-left" data-align="left">Hand</td><td class="has-text-align-left" data-align="left">The&nbsp;<strong>Hand</strong>&nbsp;component to use for finger state data.<br>손가락 상태 데이터에 사용할&nbsp;<strong>Hand</strong>&nbsp;구성 요소입니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Hmd</td><td class="has-text-align-left" data-align="left">The&nbsp;<strong>Hmd</strong>&nbsp;component.<br><strong>Hmd</strong>&nbsp;구성 요소입니다.</td></tr><tr><td class="has-text-align-left" data-align="left">Tracking to World Transformer</td><td class="has-text-align-left" data-align="left">The&nbsp;<strong>OVRInteraction</strong>&nbsp;GameObject from&nbsp;Set up Camera Rig.<br>OVR카메라 릭 셋업의&nbsp;<strong>내부 액션</strong>&nbsp;게임 오브젝트입니다.</td></tr></tbody></table></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading has-large-font-size" id="transform-config">TransformConfig</h4>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>Transform Config</strong>&nbsp;influences state transitions computed via&nbsp;TransformFeatureStateProvider. <br><strong>변환 구성은</strong>&nbsp;TransformFeatureStateProvider를 통해 계산된 상태 전환에 영향을 줍니다.</p>



<p class="has-medium-font-size">It implements the&nbsp;<strong>IActiveState</strong>&nbsp;interface and becomes active whenever all of the listed transform states are active.<br><strong>IActiveState</strong>&nbsp;인터페이스를 구현하고 나열된 모든 변환 상태가 활성화될 때마다 활성화됩니다.</p>



<p class="has-medium-font-size">Its&nbsp;<strong>Feature Thresholds</strong>&nbsp;property takes a&nbsp;,&nbsp;<strong>TransformFeatureStateThresholds</strong>, that defines the transform feature thresholds for each orientation. <br><strong>해당 Feature</strong>&nbsp;Thresholds 속성은 각 방향에 대한 변환 기능 임계값을 정의하는&nbsp;<strong>TransformFeatureStateThresholds</strong>를 사용합니다.</p>



<p class="has-medium-font-size">The transform feature thresholds use the same properties as the&nbsp;FingerFeatureStateThresholds.<code>ScriptableObject</code><br>변환 기능 임계값은&nbsp;FingerFeatureStateThresholds와 동일한 속성을 사용합니다.<code>ScriptableObject</code></p>



<p class="has-medium-font-size"><strong>Note</strong></p>



<p class="has-medium-font-size">Once you register a specific configuration, the&nbsp;method can then query the state of each state tracked for configuration. <br>특정 구성을 등록하면 메서드는 구성을 위해 추적된 각 상태의 상태를 쿼리할 수 있습니다.</p>



<p class="has-medium-font-size">It leverages&nbsp;<strong>FeatureStateProvider</strong>&nbsp;to drive state-changing logic.<code>RegisterConfig</code><br><strong>FeatureStateProvider</strong>를 활용하여 상태 변경 논리를 구동합니다.<code>RegisterConfig</code></p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading has-large-font-size">Velocity Recognition</h4>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">Velocity recognition components detect motion, whereas shape recognition only detects static poses. <br>속도 인식 구성 요소는 동작을 감지하는 반면 모양 인식은 정적 포즈만 감지합니다.</p>



<p class="has-medium-font-size">For example, shape recognition can detect a hand in a thumbs-up pose, <br>예를 들어 모양 인식은 엄지손가락을 위로 올리는 포즈에서 손을 감지할 수 있지만</p>



<p class="has-medium-font-size">but cannot determine if the hand is moving upward while in that pose.<br>해당 포즈에서 손이 위로 움직이는지 여부는 확인할 수 없습니다.</p>



<p class="has-medium-font-size">There are two velocity recognition components. <br>속도 인식 구성 요소에는 두 가지가 있습니다.&nbsp;</p>



<p class="has-medium-font-size">Both components get joint data from the&nbsp;<strong>JointDeltaProvider</strong>&nbsp;component.<br>두 구성 요소 모두&nbsp;<strong>JointDeltaProvider</strong>&nbsp;구성 요소에서 조인트 데이터를 가져옵니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>JointVelocityActiveState</strong>&nbsp;tracks velocities (position deltas over the last two frames) for a list of joints and compares them to a velocity target along the provided axes. <br><strong>JointVelocityActiveState</strong>는 조인트 목록에 대한 속도(마지막 두 프레임에 대한 위치 델타)를 추적하고 제공된 축을 따라 속도 목표와 비교합니다.&nbsp;<br><br>If the velocity target (units per second) is met for the minimum time threshold, the state becomes Active.<br>속도 목표(초당 단위)가 최소 시간 임계값에 충족되면 상태가 활성이 됩니다.</li>



<li><strong>JointRotationActiveState</strong>&nbsp;tracks angular velocities (rotation deltas over the last two frames) for a list of joints and compares them to a rotation target around the provided axes. <br><strong>JointRotationActiveState</strong>는 조인트 목록에 대한 각속도(마지막 두 프레임의 회전 델타)를 추적하고 제공된 축 주위의 회전 대상과 비교합니다.<br><br>If the rotation target (degrees per second) is met for the minimum time threshold, the state becomes Active.<br>최소 시간 임계값에 대해 회전 목표(초당 도)가 충족되면 상태가 활성이 됩니다.</li>
</ul>



<figure class="wp-block-image size-full"><img decoding="async" width="1534" height="528" src="https://lycos7560.com/wp-content/uploads/2023/05/image-116.png" alt="" class="wp-image-34945" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-116.png 1534w, https://lycos7560.com/wp-content/uploads/2023/05/image-116-300x103.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-116-768x264.png 768w" sizes="(max-width: 1534px) 100vw, 1534px" /></figure>



<div style="height:150px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading has-large-font-size">Sequences</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>IActiveState</strong>&nbsp;components can be chained together using the&nbsp;<strong>Sequence</strong>&nbsp;component. <br><strong>IActiveState</strong>&nbsp;구성 요소는&nbsp;<strong>Sequence</strong>&nbsp;구성 요소를 사용하여 함께 연결할 수 있습니다.&nbsp;</p>



<p class="has-medium-font-size">Because&nbsp;<strong>Sequences</strong>&nbsp;can recognize a series of&nbsp;<strong>IActiveStates</strong>&nbsp;over time, they can be used to compose complex gestures. <br><strong>시퀀스는</strong>&nbsp;시간이 지남에 따라 일련의&nbsp;<strong>IActiveStates</strong>를 인식할 수 있으므로 복잡한 제스처를 작성하는 데 사용할 수 있습니다.</p>



<p class="has-medium-font-size">For examples of complex gestures, see the&nbsp;GestureExamples&nbsp;sample scene.<br>복잡한 제스처의 예는&nbsp;GestureExamples&nbsp;샘플 장면을 참조하세요.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-video"><video height="948" style="aspect-ratio: 1688 / 948;" width="1688" controls muted src="https://lycos7560.com/wp-content/uploads/2023/05/녹화_2023_05_23_00_24_04_459.mp4"></video></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1513" height="762" src="https://lycos7560.com/wp-content/uploads/2023/05/image-118.png" alt="" class="wp-image-34947" srcset="https://lycos7560.com/wp-content/uploads/2023/05/image-118.png 1513w, https://lycos7560.com/wp-content/uploads/2023/05/image-118-300x151.png 300w, https://lycos7560.com/wp-content/uploads/2023/05/image-118-768x387.png 768w" sizes="(max-width: 1513px) 100vw, 1513px" /></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading has-large-font-size">Sequence Classes</h3>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size"><strong>Sequence</strong>&nbsp;takes a list of&nbsp;<strong>ActivationSteps</strong>&nbsp;and iterates through them as they become active. <br><strong>Sequence</strong>는&nbsp;<strong>ActivationSteps</strong>의 목록을 가져와서 활성화될 때 반복합니다.</p>



<p>Each&nbsp;<strong>ActivationStep</strong>&nbsp;consists of an&nbsp;<strong>IActiveState</strong>, a minimum active time, and a maximum step time. <br><strong>ActivationStep</strong>은&nbsp;<strong>IActiveState</strong>, 최소 활성 시간 및 최대 단계 시간으로 구성됩니다.</p>



<p class="has-medium-font-size">These steps function as follows:</p>



<ul class="wp-block-list">
<li>The&nbsp;<strong>IActiveState</strong>&nbsp;must be active for at least the minimum active time before the&nbsp;<strong>Sequence</strong>&nbsp;proceeds to the next step.</li>



<li>If an&nbsp;<strong>IActiveState</strong>&nbsp;is active for longer than the maximum step time, the step will fail and the&nbsp;<strong>Sequence</strong>&nbsp;will restart.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>IActiveState</strong>는&nbsp;<strong>시퀀스</strong>가 다음 단계로 진행하기 전에 최소 활성 시간 이상 활성 상태여야 합니다.</li>



<li><strong>IActiveState</strong>가 최대 단계 시간보다 오래 활성 상태이면 단계가 실패하고&nbsp;<strong>시퀀스</strong>가 다시 시작됩니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">Once the final&nbsp;<strong>ActivationStep</strong>&nbsp;in the&nbsp;<strong>Sequence</strong>&nbsp;has completed, the&nbsp;<strong>Sequence</strong>&nbsp;becomes active. <br><strong>시퀀스</strong>의 마지막&nbsp;<strong>ActivationStep</strong>이 완료되면&nbsp;<strong>시퀀스</strong>가 활성화됩니다.</p>



<p class="has-medium-font-size">If an optional KeepActiveWhile&nbsp;<strong>IActiveState</strong>&nbsp;has been provided, the&nbsp;<strong>Sequence</strong>&nbsp;will remain active as long as KeepActiveWhile is active.<br>선택적 KeepActiveWhile&nbsp;<strong>IActiveState</strong>가 제공된 경우 KeepActiveWhile이 활성화되어 있는 한&nbsp;<strong>시퀀스</strong>는 활성 상태로 유지됩니다.</p>



<p class="has-medium-font-size">The last phase of a&nbsp;<strong>Sequence</strong>&nbsp;is the optional cooldown phase, the duration of which can be set in the RemainActiveCooldown field. <br><strong>시퀀스</strong>의 마지막 단계는 선택적 휴지 단계이며, 지속 시간은 RemainActiveCooldown 필드에서 설정할 수 있습니다.</p>



<p class="has-medium-font-size">A&nbsp;<strong>Sequence</strong>&nbsp;that is deactivating will wait for this cooldown timer to elapse before finally becoming inactive.<br>비활성화 중인&nbsp;<strong>시퀀스</strong>는 이 재사용 대기시간 타이머가 경과할 때까지 기다렸다가 최종적으로 비활성화됩니다.</p>



<p class="has-medium-font-size"><strong>SequenceActiveState</strong>&nbsp;is an&nbsp;<strong>IActiveState</strong>&nbsp;wrapper for a&nbsp;<strong>Sequence</strong>, and can either report active once the Sequence has started, once the&nbsp;<strong>Sequence</strong>&nbsp;steps have finished, or both.<br><strong>SequenceActiveState</strong>는 시퀀스에 대한&nbsp;<strong>IActiveState</strong>&nbsp;래퍼이며, 시퀀스가 시작되거나,&nbsp;<strong>시퀀스</strong>&nbsp;단계가 완료되거나, 둘 다 활성으로 보고될 수 있습니다.</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">Debugging Pose Recognition (포즈 인식 디버깅)</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">The following classes let you visually debug elements of the pose recognition system.<br>다음 클래스를 사용하면 포즈 인식 시스템의 요소를 시각적으로 디버깅할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="activestatedebugtree">ActiveStateDebugTree</h3>



<p class="has-medium-font-size">Builds a visual representation of an IActiveState tree on a UI canvas, based on a provided root IActiveState. <br>제공된 루트 IActiveState를 기반으로 UI 캔버스에서 IActiveState 트리의 시각적 표현을 빌드합니다.</p>



<p class="has-medium-font-size">Two different node layout types are provided,&nbsp;<strong>ActiveStateDebugTreeHorizontal</strong>&nbsp;(for a left-to-right representation) and **ActiveStateDebugTreeVertical **(for a more compact top to bottom tree view).<br><strong>ActiveStateDebugTreeHorizontal</strong>(왼쪽에서 오른쪽 표현용) 및 ActiveStateDebugTreeVertical(보다 간결한 위에서 아래쪽 트리 보기)의 두 가지 노드 레이아웃 유형이 제공됩니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="fingerfeatureskeletaldebugvisual">FingerFeatureSkeletalDebugVisual</h3>



<p class="has-medium-font-size">Uses a line renderer to indicate if a finger feature is active on a specific finger (green) or not (red).<br>라인 렌더러를 사용하여 손가락 기능이 특정 손가락에서 활성화되어 있는지(녹색) 또는 활성화되지 않았는지(빨간색)를 나타냅니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="handshapeskeletaldebugvisual">HandShapeSkeletalDebugVisual</h3>



<p class="has-medium-font-size">Creates a series of&nbsp;<strong>FingerFeatureSkeletalDebugVisuals</strong>&nbsp;for the features belonging to a&nbsp;<strong>ShapeRecognizerActiveState</strong>.<br><strong>ShapeRecognizerActiveState</strong>에 속하는 기능에 대한 일련의&nbsp;<strong>FingerFeatureSkeletalDebugVisuals</strong>를 만듭니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="transformfeaturedebugvisual">TransformFeatureDebugVisual</h3>



<p class="has-medium-font-size">Changes the color of a target renderer to green if the specific&nbsp;<strong>TransformFeatureState</strong>&nbsp;is active; red if not.<br>특정&nbsp;<strong>TransformFeatureState</strong>가 활성 상태인 경우 대상 렌더러의 색을 녹색으로 변경합니다. 그렇지 않은 경우 빨간색.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="transformfeaturevectordebugparentvisual">TransformFeatureVectorDebugParentVisual</h3>



<p class="has-medium-font-size">Creates vector debug views for the&nbsp;<strong>FeatureStates</strong>&nbsp;belonging to a&nbsp;<strong>TransformRecognizerActiveState</strong>; one vector for the feature and another vector for the hand. <br><strong>TransformRecognizerActiveState</strong>에 속하는&nbsp;<strong>FeatureStates</strong>에 대한 벡터 디버그 뷰를 만듭니다. 하나의 벡터는 기능에 대한 것이고 다른 하나는 손에 대한 벡터입니다. </p>



<p class="has-medium-font-size">When both vectors are visualized, one can see how close the (blue) hand vector is to the (black) feature vector that it is being tested against in&nbsp;<strong>TransformFeatureValueProvider</strong>.<br>두 벡터를 모두 시각화하면 손 벡터(파란색)가&nbsp;<strong>TransformFeatureValueProvider</strong>에서 테스트 중인 (검은색) 기능 벡터에 얼마나 가까운지 확인할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="transformfeaturevectordebugvisual">TransformFeatureVectorDebugVisual</h3>



<p class="has-medium-font-size">Uses a line renderer to visualize a simple vector.<br>라인 렌더러를 사용하여 간단한 벡터를 시각화합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="transformrecognizerdebugvisual">TransformRecognizerDebugVisual</h3>



<p class="has-medium-font-size">Creates a series of&nbsp;<strong>TransformFeatureDebugVisuas</strong>&nbsp;to visually debug the&nbsp;<strong>TransformFeatureStates</strong>&nbsp;belonging to a collection of&nbsp;<strong>TransformRecognizerActiveState</strong>.<br><strong>TransformRecognizerActiveState</strong>&nbsp;컬렉션에 속하는&nbsp;<strong>TransformFeatureStates</strong>를 시각적으로 디버깅하기 위해 일련의&nbsp;<strong>TransformFeatureDebugVisuas</strong>를 만듭니다.</p>



<p class="has-medium-font-size">This allows one to visually debug the active state of each transform feature via the created instances of&nbsp;<strong>TransformFeatureDebugVisual</strong>.<br>이렇게 하면&nbsp;<strong>TransformFeatureDebugVisual</strong>의 생성된 인스턴스를 통해 각 변환 기능의 활성 상태를 시각적으로 디버그할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="jointrotationdebugvisual">JointRotationDebugVisual</h3>



<p class="has-medium-font-size">Renders lines along the rotation axes tracked by the&nbsp;<strong>JointRotationActiveState</strong>. <br><strong>JointRotationActiveState</strong>에 의해 추적되는 회전 축을 따라 선을 렌더링합니다.</p>



<p class="has-medium-font-size">Lines are red while not rotating along that axis, and they fill up yellow as rotation amount increases toward the target, at which point they become green.<br>선은 해당 축을 따라 회전하지 않는 동안 빨간색으로 표시되며, 대상을 향해 회전량이 증가함에 따라 노란색으로 채워지며, 이때 녹색이 됩니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="jointvelocitydebugvisual">JointVelocityDebugVisual</h3>



<p class="has-medium-font-size">Renders lines along the velocity axes tracked by the&nbsp;<strong>JointVelocityActiveState</strong>. <br><strong>JointRotationActiveState</strong>에 의해 추적되는 회전 축을 따라 선을 렌더링합니다.&nbsp;</p>



<p class="has-medium-font-size">Lines are red while not moving along that axis, and they fill up yellow as velocity increases toward the target, at which point they become green.<br>선은 해당 축을 따라 회전하지 않는 동안 빨간색으로 표시되며, 대상을 향해 회전량이 증가함에 따라 노란색으로 채워지며, 이때 녹색이 됩니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="internal-implementation-classes">Internal Implementation Classes</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-medium-font-size">The classes described here implement the underlying functionality, but will not need to be modified in order to use Pose Recognition.<br>여기에 설명된 클래스는 기본 기능을 구현하지만 포즈 인식을 사용하기 위해 수정할 필요는 없습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="featurestateprovider">FeatureStateProvider</h3>



<p class="has-medium-font-size">A generic helper class that keeps track of the current state of features, and uses thresholds to determine state changes.<br>기능의 현재 상태를 추적하고 임계값을 사용하여 상태 변경을 확인하는 제네릭 도우미 클래스입니다.</p>



<p class="has-medium-font-size">The class uses buffers to state changes to ensure that features do not switch rapidly between states.<br>이 클래스는 버퍼를 사용하여 상태 변경이 상태 간에 빠르게 전환되지 않도록 합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="featurestatethresholdseditor">FeatureStateThresholdsEditor</h3>



<p class="has-medium-font-size">A generic editor class that defines the look and feel of dependent editor classes such as&nbsp;<strong>FingerFeatureStateThresholdsEditor</strong>&nbsp;and&nbsp;<strong>TransformStatesThresholdsEditor</strong>.<br><strong>FingerFeatureStateThresholdsEditor</strong>&nbsp;및&nbsp;<strong>TransformStatesThresholdsEditor</strong>와 같은 종속 편집기 클래스의 모양과 느낌을 정의하는 제네릭 편집기 클래스입니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="featuredescriptionattribute">FeatureDescriptionAttribute</h3>



<p class="has-medium-font-size">Lets you define editor-visible descriptions and hints and values to aid users in setting thresholds for features.<br>사용자가 기능에 대한 임계값을 설정하는 데 도움이 되도록 편집기에서 볼 수 있는 설명과 힌트 및 값을 정의할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="ifeaturestatethreshold">IFeatureStateThreshold</h3>



<p class="has-medium-font-size"><strong>IFeatureStateThreshold</strong>&nbsp;is a generic interface that defines the functionality of all thresholds used in hand pose detection.<br><strong>IFeatureStateThreshold</strong>는 손 자세 감지에 사용되는 모든 임계값의 기능을 정의하는 제네릭 인터페이스입니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="ifeaturestatethresholds">IFeatureStateThresholds</h3>



<p class="has-medium-font-size">Defines a collection of IFeatureStateThresholds, specific to a feature type, whether that is finger features or transform features.<br>손가락 기능이든 변환 기능이든 기능 형식과 관련된 IFeatureStateThresholds의 컬렉션을 정의합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="ifeature-thresholds">IFeature Thresholds</h3>



<p class="has-medium-font-size">Provides an interface to a collection of&nbsp;<strong>IFeatureStateThresholds</strong>&nbsp;as well as&nbsp;<strong>MinTimeInState</strong>&nbsp;(i.e. a minimum threshold of time a feature can be in a certain state before transitioning to another state).<br><strong>IFeatureStateThresholds</strong>&nbsp;및&nbsp;<strong>MinTimeInState</strong>&nbsp;컬렉션에 대한 인터페이스를 제공합니다(즉, 다른 상태로 전환하기 전에 기능이 특정 상태에 있을 수 있는 최소 임계값).</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="collidercontainshandjointactivestate">ColliderContainsHandJointActiveState</h3>



<p class="has-medium-font-size">An&nbsp;<strong>IActiveState</strong>&nbsp;that tests to see if a hand joint is inside a collider. <br>손 관절이 콜라이더 내부에 있는지 테스트하는&nbsp;<strong>IActiveState</strong>입니다.</p>



<p class="has-medium-font-size">If a SphereCollider is specified then its radius is used for checking, otherwise the script relies on the collider’s bounds. <br>SphereCollider가 지정되면 해당 반경이 검사에 사용되고, 그렇지 않으면 스크립트가 콜라이더의 경계에 의존합니다.&nbsp;</p>



<p class="has-medium-font-size">This class is useful in case a developer wishes to see if the hand joint exists within a certain volume when a pose is active.<br>이 클래스는 개발자가 포즈가 활성 상태일 때 손 관절이 특정 볼륨 내에 존재하는지 확인하려는 경우에 유용합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" id="hmdoffset">HmdOffset</h3>



<p class="has-medium-font-size">Can be attached to an object that needs to be anchored from the center eye. <br>중앙 눈에서 고정해야 하는 물체에 부착할 수 있습니다.</p>



<p class="has-medium-font-size">Position and rotation offsets can be specified, along with options to toggle the roll, pitch and yaw of the latter. <br>위치 및 회전 오프셋을 지정할 수 있으며, 후자의 롤, 피치 및 요를 토글하는 옵션도 지정할 수 있습니다.</p>



<p class="has-medium-font-size">One can combine this with a&nbsp;<strong>ColliderContainsHandJointActiveState</strong>to position a collider relative to the center eye.<br>이를&nbsp;<strong>ColliderContainsHandJointActiveState</strong>와 결합하여 중심 눈을 기준으로 콜라이더를 배치할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5698326622209671" crossorigin="anonymous"></script>
<ins class="adsbygoogle" style="display:block" data-ad-format="autorelaxed" data-ad-client="ca-pub-5698326622209671" data-ad-slot="4245812909"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
<p>The post <a href="https://lycos7560.com/unity/unity-vr/oculus-hand-pose-detection-%ec%86%90-%ed%8f%ac%ec%a6%88-%ea%b0%90%ec%a7%80/34843/">Oculus Unity-Integration &#8211; Hand Pose Detection</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-vr/oculus-hand-pose-detection-%ec%86%90-%ed%8f%ac%ec%a6%88-%ea%b0%90%ec%a7%80/34843/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		<enclosure url="https://lycos7560.com/wp-content/uploads/2023/05/녹화_2023_05_22_21_16_30_889.mp4" length="13747023" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2023/05/녹화_2023_05_23_00_24_04_459.mp4" length="16054352" type="video/mp4" />

			</item>
		<item>
		<title>Unity &#8211; Debug.Log 색상 변경</title>
		<link>https://lycos7560.com/unity/unity-debug-log-%ec%83%89%ec%83%81-%eb%b3%80%ea%b2%bd/35443/</link>
					<comments>https://lycos7560.com/unity/unity-debug-log-%ec%83%89%ec%83%81-%eb%b3%80%ea%b2%bd/35443/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sat, 13 May 2023 19:20:20 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[Color]]></category>
		<category><![CDATA[console]]></category>
		<category><![CDATA[Debug]]></category>
		<category><![CDATA[Debug.Log]]></category>
		<category><![CDATA[Debug.Log 색상 변경]]></category>
		<category><![CDATA[변경]]></category>
		<category><![CDATA[색상]]></category>
		<category><![CDATA[유니티]]></category>
		<category><![CDATA[콘솔]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=35443</guid>

					<description><![CDATA[<p>Unity Console창에서 Debug.Log의 글자 색상을 변경하는 방법에 대한 글입니다.<br />
(This article describes how to change the color of the letters in Debug.Log in the Unity Console window.)</p>
<p>The post <a href="https://lycos7560.com/unity/unity-debug-log-%ec%83%89%ec%83%81-%eb%b3%80%ea%b2%bd/35443/">Unity &#8211; Debug.Log 색상 변경</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5698326622209671" crossorigin="anonymous"></script>
<!-- HorizontalAD -->
<ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-5698326622209671" data-ad-slot="6908948342" data-ad-format="auto" data-full-width-responsive="true"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Default
Debug.Log("Default");

Debug.Log("&lt;color=white>White&lt;/color>");
Debug.Log("&lt;color=grey>Grey&lt;/color>");
Debug.Log("&lt;color=black>Black&lt;/color>");
Debug.Log("&lt;color=red>Red&lt;/color>");
Debug.Log("&lt;color=green>Green&lt;/color>");
Debug.Log("&lt;color=blue>Blue&lt;/color>");
Debug.Log("&lt;color=yellow>Yellow&lt;/color>");
Debug.Log("&lt;color=cyan>Cyan&lt;/color>");
Debug.Log("&lt;color=brown>Brown&lt;/color>");

// Hex Color
Debug.Log("&lt;color=#fa56d6> Hex Color1 &lt;/color>");
Debug.Log("&lt;color=#74fa56> Hex Color1 &lt;/color>");
Debug.LogFormat("&lt;color=yellow> Yellow &lt;/color>" + "&lt;color=black> Black &lt;/color>");</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://lycos7560.com/wp-content/uploads/2023/06/image-29.png" alt="" class="wp-image-35445" width="1106" height="402" srcset="https://lycos7560.com/wp-content/uploads/2023/06/image-29.png 1475w, https://lycos7560.com/wp-content/uploads/2023/06/image-29-300x109.png 300w, https://lycos7560.com/wp-content/uploads/2023/06/image-29-768x279.png 768w" sizes="(max-width: 1106px) 100vw, 1106px" /></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<script async="" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5698326622209671" crossorigin="anonymous"></script>
<ins class="adsbygoogle" style="display:block" data-ad-format="autorelaxed" data-ad-client="ca-pub-5698326622209671" data-ad-slot="4245812909"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
<p>The post <a href="https://lycos7560.com/unity/unity-debug-log-%ec%83%89%ec%83%81-%eb%b3%80%ea%b2%bd/35443/">Unity &#8211; Debug.Log 색상 변경</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-debug-log-%ec%83%89%ec%83%81-%eb%b3%80%ea%b2%bd/35443/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
