1. 개요
유니티(6) 현재 scene 안에서 새로운 scene을 동적으로 불러오기를 할 수 있는지 시도를 해보았다. 유니티에는 어드레서블 에셋( Addressables Asset)이 있다. 로딩을 받고자 하는 Scene을 Addressables Asset으로 만들어 사전에 서버에 미리 올리고 이를 실행 중에 받아 올 수 있다. 즉 Addressables Asset은 씬(Scene), 프리팹(Prefab), 텍스처, 애니메이션 등을 번들(Bundle) 형태로 패키징하여 서버에서 다운로드하고 런타임에 로드할 수 있는 시스템이다.
2. 서버에 올릴 씬 만들기( Addressables Asset 만들기 )
유니티에서 제공하는 VR Tempalete을 사용한다.
현재 Sample Scene을 VrTestScene.unity로 새로 저장한다. 원본을 유지하기 위함이다.

3. Addressables 패키지 설치 및 번들 만들기
아래와 같이 관련 패키지(2개)를 설치한다.

File > Build Profile을 Android 또는 Meta Quest로 설정하면 Android 용으로 어셋을 만든다.
만일 유니티 에디터에서 테스트하려면 File > Build Profile을 Windows로 설정하여야 한다.

VrTestScene.unity 파일을 Project 창에서 찾아서 클릭하고 inspector 창에서 Addressable 체크박스를 설정한다.

위 이미지(Inspector창)에서 Group "Default Local Group"을 클릭하거나 또는 아래의 이미지와 같이 Window> Asset Management > Addressables>Groups 을 선택한다.

Addressables Groups에서 New> Packed Assets를 선택하여 새로운 그룹을 만들고 현재 Defalt Local Group에 있는 VrTestScen.unity를 드래그하여 옮겨준다. 아래 그림과 같이 Addressable Name을 xrworld로 간략하게 수정한다.

아래와 같은 Addressables Groups 윈도우에서 Play Mode Script 클릭하고 "Use Existing Build(Android)" 를 선택한다.
또는 "Use Existing Build(Windows)"로 설정한다. Use Asset Database (fastest)는 Remote가 아닌 로컬에서 사용하는 것이다.

Addressables의 Settings에서 Manage Profiles 버튼을 클릭한다. 또는 위 이미지 Addressable Group에서 Profile: Default를 클릭하고 Manage Profiles를 선택하여도 된다.

[BuildTarget]은 StandaloneWindows64 또는 Android와 같이 플랫폼에 따라 폴더 이름이 달라진다.

Addressables의 Settings에서 Manage Profiles를 클릭하고 다음과 같이 설정한다,

계속 Addressables의 Settings 창에서 아래와 같이 Build & Load Paths를 Remote로 설정하고 Enable Json Catalog체크한다.

Addressable Group에서 생성한 Packed Assets의 설정을 Inspector 창에서 살펴보고 아래와 같이 설정한다.

다음과 같이 New Build를 실행한다. New Build > Default Build Script

프로젝트 폴더 아래에 ServerData 폴더가 생성되었을 것이다. 그아래 Android폴더에 원하는 파일들이 있다.
catalog_x.x.json과 catalog_x.x.hash 파일 및 여러개의 .bundle 파일이 보인다.
json과 hash파일이 안보인다면 Remote 모드가 아니라 Local모드로 빌드한 것이다. 설정부분에서 빠진 곳이 없는지 검토한다.

4. 서버에 올리기
생성된 파일을 서버에 올린다. (예) https://myserver.com/test/StandaloneWindows64 폴더에 올렸다고 가정한다.
웹브라우저에서 catalog_9.2.1.json 파일이 접근 가능한지 테스트 해본다.
5. 불러오는 Scene 만들기
서버에서 받아오는 Scene을 추가로 만든다. 만일 별도의 프로젝트 파일이라면 Addressables 패키지를 설치해 준다.
유니티에서 File > New Scene > Basic(URP) 로 scene을 만들었다. 그리고 Empty GameObject를 추가하고 스크립트 DynamicLoader를 만들어 준다. 아래 코드를 입력한다.

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.SceneManagement;
public class DynamicLoader : MonoBehaviour
{
string baseUrl = "https://myserver.com/test/StandaloneWindows64";
string catalogUrl = "https://myserver.com/test/StandaloneWindows64/catalog_9.2.1.json";
void Start()
{
SetupAddressablesUrl();
baseUrl = PlayerPrefs.GetString("AddressablesBaseUrl", catalogUrl).TrimEnd('/');
Addressables.LoadContentCatalogAsync(catalogUrl).Completed += OnCatalogLoaded;
}
private void OnCatalogLoaded(AsyncOperationHandle<IResourceLocator> handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
Debug.Log("서버 카탈로그 로드 성공!");
// 1. 기존 씬을 삭제한다.
//Addressables.LoadSceneAsync("xrworld");
// 2. 기존 씬을 유지하고 추가한다.
Addressables.LoadSceneAsync("xrworld", UnityEngine.SceneManagement.LoadSceneMode.Additive);
}
else
{
Debug.LogError("카탈로그 로드 실패: " + handle.OperationException);
}
}
private void SetupAddressablesUrl()
{
string trimmedBaseUrl = baseUrl.TrimEnd('/');
Addressables.InternalIdTransformFunc = (location) =>
{
string id = location.InternalId;
// .bundle로 끝나는 실제 파일 경로만 서버 주소로 변경합니다.
if (id.EndsWith(".bundle") || id.EndsWith(".json") || id.EndsWith(".hash"))
{
string fileName = System.IO.Path.GetFileName(id);
string transformed = $"{trimmedBaseUrl}/{fileName}";
Debug.Log($"[Addressables] 번들 경로 변환: {id} -> {transformed}");
return transformed;
}
return id;
};
}
}