제10부 시뮬레이션·디지털트윈·피지컬 AI
10.4 OpenUSD II — 컴포지션 아크
10.4.1 이 장에서 배우는 것 / 선수 지식
10.3에서 USD 데이터 모델(Stage·Prim·Layer)과 비파괴 합성의 기초 — 서브레이어로 의견을 겹쳐 덮어쓰기 — 를 봤다. 그리고 "누가 이기는가(강도 규칙)·자산을 어떻게 재사용하는가(참조)"는 이 장으로 미뤘다. 이 장이 USD의 합성 메커니즘 전체 — 씬을 조립하는 여섯 가지 컴포지션 아크(composition arc) 와 그들의 강도 순서(LIVRPS) — 를 실습으로 판다. 자산을 재사용하는 참조(reference)·페이로드(payload), 옵션을 담는 변형(variant), 상속·특수화·서브레이어, 그리고 여러 의견이 충돌할 때 무엇이 이기는지를 정확히. 로봇을 N번 배치하고(9.13), 도메인 랜덤화로 변형을 오버레이하고(9.14), 디지털트윈에 운영 데이터를 겹치는(10.8) 실제 메커니즘이 여기 있다.
핵심 통찰: USD의 합성은 "레고 + 우선순위 규칙"이다 — 재사용 가능한 조각(참조)을 조립하고, 충돌하면 정해진 강도 순서(LIVRPS)로 승자를 정한다. 큰 씬을 한 파일에 모두 두지 않는다 — 로봇 자산은 한 번 만들고 참조로 N번 가져오며(인스턴싱), 대용량 환경은 페이로드로 지연 로드하고, 옵션은 변형으로 담는다. 그리고 한 속성에 여러 아크가 의견을 내면, LIVRPS(Local·Inherits·Variants·References·Payloads·Specializes) 라는 고정된 강도 순서로 누가 이길지 결정된다. "내 오버라이드가 왜 안 먹지?"의 답은 거의 항상 이 강도 순서에 있다 — 합성을 이해하면 USD가 비로소 도구가 된다.
배우는 것:
- 여섯 컴포지션 아크 — sublayers·references·payloads·variants·inherits·specializes가 각각 무엇을·왜.
- References·Payloads — 자산 재사용(인스턴싱)과 지연 로드(대규모 씬·디지털트윈).
- Variants — 한 프림에 여러 명명된 옵션(그리퍼·LOD·구성), 별도 파일 없이.
- Inherits·Specializes·Sublayers — 클래스 브로드캐스트·폴백·로컬 스택.
- LIVRPS — 의견 충돌 시 강도 순서, "왜 이 값이 이기나"의 디버깅(usdview 합성 뷰).
선수 지식: 10.3(Stage·Prim·Layer·비파괴 오버라이드·.usda·edit target)·9.13(cloner — 참조/인스턴싱)·9.14(도메인 랜덤화 — 오버라이드 레이어)·10.2(협업 — 레이어). usdview·.usda 읽기는 10.3. 합성데이터는 10.5, 디지털트윈은 10.8. 이 장은 10.3의 직접 연속(데이터 모델 → 합성 작동).
정직: 컴포지션 아크·LIVRPS는 USD의 핵심이자 가장 까다로운 부분이다. 이 장은 "각 아크가 무엇을·언제, 강도 순서가 어떻게 작동하는가의 원리·실습"을 가르치되, USD 합성에는 세부 규칙·예외(목록 편집 prepend/append, 인스턴싱 의미, 활성/비활성) 가 많아 모두를 담지 못한다 — 깊은 경계는 "그 버전 USD 문서·usdview로 확인". API(
pxr.Usd)는 비교적 안정적이나 버전 의존이 있다. 코드(.usda·pxr)는 개념 골격이되 실제와 가깝게. USD는 오픈 표준(AOUSD, 10.3) — NVIDIA 전유물 아님.
10.4.2 컴포지션 아크 — 씬을 조립하는 여섯 가지 방법
컴포지션 아크는 USD가 레이어·프림을 합성해 씬을 조립하는 메커니즘들이다. 여섯 가지가 있고, 각각 다른 용도와 강도를 가진다.
여섯 컴포지션 아크(용도별):
- sublayers — 로컬 레이어 스택(10.3): 내 씬을 여러 레이어로 조직·오버라이드
- references — 다른 자산(레이어/프림)을 가져옴: 재사용·인스턴싱(로봇 N번)
- payloads — references 같되 지연 로드(load/unload): 대용량 자산·대규모 씬
- variants — 한 프림에 여러 명명된 옵션: 구성(그리퍼·LOD)을 한 자산에
- inherits — 클래스 프림에서 상속: 모든 인스턴스에 브로드캐스트 편집
- specializes — inherits 같되 가장 약함: 폴백·특수화 기본값
강도 순서(LIVRPS, 강→약): Local · Inherits · Variants · References · Payloads · Specializes
- 두 부류로 보면 쉽다: ① 재사용·조립(references·payloads — 외부 자산 가져오기, variants — 옵션 선택) ② 오버라이드·계층(sublayers — 로컬 스택, inherits·specializes — 클래스 의미). 대부분의 작업은 sublayers(오버라이드) + references(재사용) + variants(옵션) 셋으로.
- 왜 여러 아크인가: 각각 다른 문제를 푼다 — references(재사용), payloads(스케일·지연), variants(구성), inherits(브로드캐스트), sublayers(협업·오버라이드). 한 아크로 다 안 되니 여섯.
- 합성의 결과(10.3): 이 아크들이 의견을 모아 Stage(합성 결과)를 만든다. 한 속성에 여러 아크가 의견을 내면 LIVRPS 강도 순서(10.4.6)로 승자 결정.
- 로보틱스 맥락: 로봇 자산을 references로 N번(9.13 cloner)·그리퍼를 variants·대용량 공장을 payloads·도메인 랜덤화를 sublayers 오버라이드(9.14)·공통 설정을 inherits. 실제 씬은 이 아크들의 조합.
핵심: 컴포지션 아크는 씬을 조립하는 여섯 메커니즘 — sublayers(로컬 오버라이드)·references(재사용)·payloads(지연 로드)·variants(옵션)·inherits(브로드캐스트)·specializes(폴백). 재사용·조립(refs·payloads·variants)과 오버라이드·계층(sublayers·inherits·specializes)으로 묶어 보면 쉽다. 의견 충돌은 LIVRPS 강도 순서로 해결. 대부분은 sublayers+references+variants로.
10.4.3 References·Payloads — 자산 재사용과 지연 로드
가장 많이 쓰는 아크는 references — 다른 자산을 프림에 가져와 재사용한다. payloads 는 그 지연 로드 버전이다.
# 로봇 자산을 참조로 N번 재사용(인스턴싱)
def Xform "Robot_01" (
references = @./assets/robot.usd@</Robot> # robot.usd의 /Robot 프림을 가져옴
)
{
# 참조한 로봇 위에 비파괴 오버라이드(이 인스턴스만)
double3 xformOp:translate = (0, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate"] # 순서 명시 필수(없으면 translate 무효, 10.3)
over "base_link" { color3f[] primvars:displayColor = [(0,0,1)] } # 이 로봇만 파랑
}
def Xform "Robot_02" (references = @./assets/robot.usd@</Robot>) { double3 xformOp:translate = (2, 0, 0) uniform token[] xformOpOrder = ["xformOp:translate"] }
def Xform "Robot_03" (references = @./assets/robot.usd@</Robot>) { double3 xformOp:translate = (4, 0, 0) uniform token[] xformOpOrder = ["xformOp:translate"] }
# robot.usd는 한 번 정의, 세 곳에서 재사용 — 자산 수정은 robot.usd 한 곳만
# 대용량 환경은 payload로 지연 로드(필요할 때만)
def Xform "Factory" (
payload = @./assets/factory_heavy.usd@</Factory> # load 전엔 메모리에 안 올림
) {}
- References = 재사용·인스턴싱: 자산(robot.usd)을 한 번 정의하고 여러 프림이 참조한다 — 자산을 고치면 모든 인스턴스에 반영(한 곳 수정, 전체 갱신). 9.13의 cloner가 수천 환경에 로봇을 복제하는 것도 이 정신(인스턴싱). 파일 전체 또는 특정 프림(
@file@</Prim>)을 참조. - 비파괴 오버라이드와 결합(10.3): 참조한 자산 위에 이 인스턴스만의 오버라이드를 적용한다 — Robot_01만 파랑, Robot_02는 다른 위치. 자산(robot.usd)은 안 건드림. 같은 자산, 다른 변형.
- Payloads = 지연 로드(스케일): references와 거의 같되 기본적으로 로드 안 됨 —
stage.Load(path)/Unload(path)로 필요할 때만 메모리에. 대규모 씬·디지털트윈(10.8) — 도시·공장 전체를 열되 보는 부분만 로드해 메모리·성능 관리. "대용량이고 항상 필요하진 않은" 자산은 payload. - References vs Payloads 선택: 항상 필요·경량이면 reference, 대용량이고·지연 로드하고 싶으면 payload. 큰 씬은 최상위를 payload로 묶어 부분 로드.
- 인스턴싱 최적화: 같은 자산을 많이 참조하면 scenegraph instancing(
instanceable=true)으로 메모리·성능을 아낀다(수천 동일 프림 — 9.13). 단 인스턴스는 개별 오버라이드 제약이 있다(정직: 인스턴싱 의미는 문서 확인).
견해: References = 자산을 한 번 만들고 N번 재사용(인스턴싱, 한 곳 수정으로 전체 갱신) + 인스턴스별 비파괴 오버라이드. Payloads = 그 지연 로드 버전(대용량 자산·대규모 씬을 필요할 때만 load) — 디지털트윈·도시 규모(10.8)의 메모리·성능 핵심 요인. 로봇을 수천 배치(9.13)·환경 재사용이 references, 거대 씬 부분 로드가 payloads. 인스턴싱으로 스케일.
10.4.4 Variants — 한 프림의 여러 옵션
Variants(변형) 는 한 프림에 여러 명명된 옵션을 담아 하나를 선택하게 한다 — 별도 파일·분기 없이 구성(configuration)을.
# 로봇 그리퍼 옵션을 variant set으로(한 자산에 여러 구성)
def Xform "Robot" (
variants = { string gripper = "parallel" } # 현재 선택: parallel
prepend variantSets = "gripper"
)
{
variantSet "gripper" = {
"parallel" { # 옵션 1: 평행 그리퍼
def "Gripper" (references = @./parallel_gripper.usd@) {}
}
"suction" { # 옵션 2: 흡착 그리퍼
def "Gripper" (references = @./suction_gripper.usd@) {}
}
"none" {} # 옵션 3: 없음
}
}
# 선택만 바꾸면(gripper = "suction") 다른 그리퍼로 — 한 자산, 여러 구성
- Variant set = 옵션 묶음:
gripper라는 variant set에parallel·suction·none변형이 있고, 하나를 선택(variants = {gripper = "parallel"}). 선택을 바꾸면 그 변형의 내용이 합성된다. 한 자산이 여러 구성을 품는다. - 왜 variant인가(별도 파일 대비): 그리퍼 옵션마다 robot_parallel.usd·robot_suction.usd를 따로 두면 자산이 폭증·중복. variant는 한 자산에 옵션을 담아 선택만 바꾼다 — 구성 관리가 간결. 로봇 구성·차량 트림·제품 옵션·LOD(상세 수준)·재질 변형 등.
- 로보틱스·산업 활용: 로봇 그리퍼·센서 구성, 작업 셀 레이아웃 옵션, 제품 변형(디지털트윈 10.8의 "what-if"), LOD(거리별 상세). 도메인 랜덤화(9.14)도 변형으로 옵션화 가능.
- 중첩·다중 variant set: 한 프림에 여러 variant set(gripper·sensor·color)을, 각각 독립 선택 → 조합 폭발 없이 구성. variant 안에 또 variant(중첩).
- API:
vset = prim.GetVariantSets().AddVariantSet("gripper")·vset.AddVariant("parallel")·vset.SetVariantSelection("parallel")·with vset.GetVariantEditContext(): ...(변형 내용 정의).
견해: Variants는 한 프림에 여러 명명된 옵션을 담아 선택하게 한다 — 그리퍼·LOD·구성·제품 트림을 별도 파일 없이 한 자산에. 옵션마다 파일을 두는 중복·폭증을 피하고, 선택만 바꿔 구성 전환. 다중 variant set으로 직교 구성(gripper×sensor×color). 디지털트윈 what-if(10.8)·도메인 랜덤화(9.14) 옵션화에. usdview로 변형 선택·미리보기.
10.4.5 Inherits·Specializes·Sublayers — 나머지 아크
남은 세 아크 — sublayers(10.3에서 봤음)·inherits·specializes — 는 계층·브로드캐스트·폴백을 담당한다.
sublayers (Local, 가장 강함):
· 내 씬을 여러 레이어로 쌓음(루트가 서브레이어 포함) → LayerStack
· 협업(팀별 레이어 10.2)·오버라이드(랜덤화 9.14). 10.3의 그것.
inherits (강함 — 클래스 브로드캐스트):
· 프림이 "클래스(class)" 프림을 상속 → 클래스 변경이 모든 상속 프림에 전파
· 예: 모든 "나무" 프림이 _class_Tree를 상속 → 나무 공통 속성을 한 곳에서
· "이 종류 전부에 적용" 의미. references보다 강함.
specializes (가장 약함 — 폴백·특수화):
· inherits 같되 가장 약함 → "기본값/폴백"으로, 다른 의견이 없을 때만 적용
· 특수화(specialization) 의미: 일반 → 특수로 다듬되 베이스 폴백 유지
- Sublayers(Local — 최강): 10.3의 로컬 레이어 스택. 내 씬을 레이어로 조직하고 오버라이드. 협업(10.2)·랜덤화(9.14)의 오버라이드 레이어가 여기. LIVRPS의 L(가장 강함).
- Inherits(클래스 브로드캐스트): 여러 프림이 공통 클래스(class) 를 상속하면, 클래스를 바꿀 때 모든 상속 프림에 전파된다 — "이 종류 전부에 공통 속성·오버라이드". 예: 모든 신호등 프림이
_class_TrafficLight를 상속 → 신호등 공통 동작을 한 곳에서 수정. references(개별 인스턴스)보다 강해(LIVRPS의 I), 참조로 들어온 인스턴스 의견을 이긴다(단, 로컬 오버라이드 L은 inherits보다 강함 — L>I). - Specializes(폴백 — 최약): inherits와 비슷하나 가장 약함 — "다른 의견이 없을 때만 적용되는 기본값/폴백". 일반 자산을 특수화하되 베이스 폴백을 유지하는 의미. 드물게 쓰이나 강도 체계의 바닥(LIVRPS의 S).
- 언제 무엇: 대부분은 sublayers(오버라이드)·references(재사용)·variants(옵션) 로 충분하고, inherits는 "한 종류 전체에 브로드캐스트"가 필요할 때, specializes는 폴백 기본값이 필요한 드문 경우. inherits·specializes는 고급·라이브러리 설계에 주로.
- 목록 편집(prepend/append/delete): 아크는 목록이라
prepend(앞에 — 더 강하게)·append(뒤에)·delete로 편집 — 강도·순서에 영향(고급, 문서 확인).
견해: sublayers(최강 — 로컬 오버라이드·협업)·inherits(강함 — 클래스 브로드캐스트 "이 종류 전부에")·specializes(최약 — 폴백 기본값)가 계층·전파·폴백을 담당. 일상은 sublayers·references·variants로 충분하고, inherits는 공통 속성 브로드캐스트, specializes는 폴백 — 라이브러리·고급 설계에. 이들의 상대 강도가 다음 절 LIVRPS.
10.4.6 LIVRPS — 누가 이기는가
한 속성에 여러 아크가 의견을 내면 무엇이 이기나? USD는 LIVRPS라는 고정된 강도 순서로 결정한다 — 이것이 합성의 핵심 규칙이자 디버깅의 핵심 요인.
LIVRPS — 강도 순서(강 → 약):
L Local — 로컬 레이어 스택(sublayers·직접 의견) ← 가장 강함
I Inherits — 상속(클래스)
V Variants — 선택된 변형
R References — 참조한 자산
P Payloads — 페이로드(지연 로드 자산)
S Specializes — 특수화(폴백) ← 가장 약함
규칙: 더 강한 아크의 의견이 약한 것을 이긴다.
한 아크 내에서는 레이어 순서(위가 강함)로.
예: 참조한 robot.usd(R)가 색=빨강, 로컬 오버라이드(L)가 색=파랑
→ L > R → 색 = 파랑 (로컬이 참조를 이김 = 비파괴 오버라이드 10.3)
- 왜 이 순서가 중요한가: "내 오버라이드가 왜 안 먹지?" "이 값이 왜 여기서 오지?"의 답이 거의 항상 LIVRPS다. 로컬(L)이 가장 강하므로 로컬 오버라이드는 참조·변형을 이긴다(10.3 비파괴 오버라이드가 되는 이유 = L > R). 반대로 inherits(I)는 references(R)보다 강해 클래스 브로드캐스트가 참조 자산의 의견을 이긴다(단, 로컬 오버라이드 L은 클래스를 이김 — L>I).
- 요지: ① 로컬(내 직접 편집)이 최강 — 내가 지금 쓴 것이 가져온 자산을 이김(상식적). ② inherits(이 종류 전부)는 references(개별 자산)보다 강함 — 종류 전체 규칙이 개별을 이김. ③ specializes는 최약 — 폴백이라 다른 의견이 있으면 짐.
- 아크 내 순서: 같은 아크(예: 여러 sublayer)에선 레이어 스택 순서(위가 강함)로 — 협업서 위 레이어가 아래를 이김(10.2).
- 디버깅(usdview 합성 뷰): usdview의 "Composition" / prim 합성 탭이 한 프림의 모든 아크와 각 의견의 출처 레이어·강도를 보여준다 — "이 값이 어느 레이어·아크에서 오나"를 정확히. "오버라이드 안 먹음"은 ① edit target이 약한 레이어 ② 더 강한 아크가 이김(inherits·강한 sublayer) → usdview로 확인.
- 정직: LIVRPS는 핵심 골격이고, 세부(목록 편집 강도·인스턴싱·활성)는 더 미묘하다 — 정확한 판정은 usdview 합성 뷰로(추측 금지).
견해: LIVRPS(Local·Inherits·Variants·References·Payloads·Specializes, 강→약) 가 의견 충돌의 승자를 정한다 — 합성의 핵심 규칙. 로컬(L) 최강이라 비파괴 오버라이드가 참조를 이기고(10.3), inherits(I)>references(R)라 클래스 브로드캐스트가 인스턴스를 이긴다. "오버라이드 왜 안 먹나"의 90%가 이 순서·edit target — usdview 합성 뷰로 출처를 보는 것이 디버깅. 추측 말고 합성 뷰로.
10.4.7 워크스루 — 참조·변형·오버라이드·합성 디버깅
아크들을 Python으로 조립하고 usdview로 합성을 디버깅하는 흐름.
# 컴포지션 아크 조립(개념 — pxr API, 버전 확인)
from pxr import Usd, UsdGeom, Sdf, Gf
stage = Usd.Stage.CreateNew("scene.usda")
# 1) Reference — 로봇 자산을 N번 재사용 + 인스턴스별 오버라이드(10.4.3)
for i in range(3):
robot = UsdGeom.Xform.Define(stage, f"/World/Robot_{i:02d}")
robot.GetPrim().GetReferences().AddReference("./assets/robot.usd", "/Robot")
UsdGeom.XformCommonAPI(robot).SetTranslate(Gf.Vec3d(i*2, 0, 0)) # 위치 오버라이드(로컬 L)
# robot.usd는 한 번 정의 → 자산 수정은 한 곳, 모든 인스턴스 갱신
# 2) Variant set — 그리퍼 옵션(10.4.4)
robot0 = stage.GetPrimAtPath("/World/Robot_00")
vset = robot0.GetVariantSets().AddVariantSet("gripper")
for name, asset in [("parallel","./parallel.usd"), ("suction","./suction.usd")]:
vset.AddVariant(name)
vset.SetVariantSelection(name)
with vset.GetVariantEditContext():
g = stage.DefinePrim(robot0.GetPath().AppendChild("Gripper"))
g.GetReferences().AddReference(asset)
vset.SetVariantSelection("parallel") # 현재 선택
# 3) Payload — 대용량 환경 지연 로드(10.4.3)
factory = stage.DefinePrim("/World/Factory")
factory.GetPayloads().AddPayload("./assets/factory_heavy.usd")
# 기본 미로드 → 필요시 stage.Load("/World/Factory") / Unload(...)
stage.GetRootLayer().Save()
# 4) 비파괴 오버라이드 — 별도 레이어에서(10.3·L이 R 이김)
over_layer = Sdf.Layer.CreateNew("override.usda")
stage.GetRootLayer().subLayerPaths.insert(0, "override.usda") # 위(강한) 서브레이어
stage.SetEditTarget(over_layer)
robot1 = stage.GetPrimAtPath("/World/Robot_01/base_link") # 색은 지오메트리(Gprim) 프림에 — displayColor는 Xform이 아닌 Gprim 속성
robot1.CreateAttribute("primvars:displayColor", Sdf.ValueTypeNames.Color3fArray).Set([(0,0,1)]) # 이 로봇만 파랑(로컬 L)
over_layer.Save()
# 5) 합성 디버깅 — usdview(10.4.6)
usdview scene.usda
# · 프림 선택 → "Composition" 탭: 이 프림의 모든 아크·각 의견 출처 레이어·강도
# · "이 색이 어디서 오나?" → 합성 뷰로 출처 레이어 확인(override.usda? robot.usd?)
# · variant 선택 드롭다운으로 그리퍼 전환 미리보기
# · payload load/unload로 메모리·표시 제어
체크포인트:
· Reference로 자산 한 번 정의·N번 재사용 — robot.usd 수정이 전부 반영되나
· 인스턴스별 로컬 오버라이드(위치·색)가 참조를 이기나(L > R, 10.4.6)
· Variant 선택 전환으로 그리퍼 바뀌나
· Payload load/unload로 대용량 환경 메모리 제어되나
· usdview 합성 뷰로 "이 값의 출처"를 추적할 수 있나(디버깅 핵심)
- 합성 디버깅이 핵심 역량: "왜 이 값이?"는 usdview 합성/prim stack 뷰로 — 각 의견의 출처 레이어·아크·강도(LIVRPS)를 보고 승자를 이해. 추측하지 말고 본다.
- edit target 확인(10.3): 오버라이드가 안 먹으면 ① edit target이 약한 레이어인지 ② 더 강한 아크(inherits·강한 sublayer)가 이기는지 — 합성 뷰로.
- 로보틱스 조립: 로봇(reference)·그리퍼(variant)·환경(payload)·랜덤화(override layer 9.14)·작업 셀 배치(reference + 위치 오버라이드) — 9.13 cloner·10.8 트윈의 실제 구성.
견해: 실습은 ① reference로 재사용(자산 한 곳, N번) + 로컬 오버라이드(L>R) ② variant로 옵션(그리퍼 전환) ③ payload로 지연 로드(대용량 환경) ④ usdview 합성 뷰로 "값의 출처" 디버깅(LIVRPS). 이 조합이 로봇 씬·작업 셀·디지털트윈(10.8)·병렬 환경(9.13)의 실제 조립법. "왜 이 값이?"는 추측 말고 합성 뷰로 출처를 본다.
10.4.8 중간 점검 (체크포인트)
- [ ] 여섯 컴포지션 아크(sublayers·references·payloads·variants·inherits·specializes)의 용도를 구분한다.
- [ ] References(재사용·인스턴싱)와 Payloads(지연 로드·스케일)의 차이와 언제 무엇인지 안다.
- [ ] Variants가 한 프림에 여러 옵션을 담아(그리퍼·LOD) 별도 파일 없이 구성함을 안다.
- [ ] Inherits(클래스 브로드캐스트, R보다 강함)·Specializes(폴백, 최약)·Sublayers(로컬, 최강)를 안다.
- [ ] LIVRPS 강도 순서로 의견 충돌이 해결됨과(L>...>S), 비파괴 오버라이드가 L>R임을 안다.
- [ ] usdview 합성 뷰로 "이 값의 출처·승자"를 추적해 합성을 디버깅할 줄 안다.
증상→의심: 오버라이드가 안 먹음 → edit target이 약한 레이어·더 강한 아크(inherits·강한 sublayer)가 이김 → usdview 합성 뷰·edit target 확인(10.4.6). 이 값이 어디서? → 합성 뷰로 출처 레이어·아크 추적. 자산 수정이 일부만 반영 → reference vs 복사·인스턴싱 제약 → 참조 구조 확인. variant 전환이 안 됨 → variant 선택·set 이름·편집 컨텍스트 → usdview. 대용량 씬이 안 열림/느림 → payload 미사용(전부 로드) → payload·부분 load(10.4.3). 인스턴스 오버라이드가 안 됨 → instanceable 인스턴싱 제약 → 문서 확인. 클래스 변경이 일부만 → inherits 구조·강도 → 합성 뷰.
10.4.9 트레이드오프·대안
| 결정 | 트레이드오프 |
|---|---|
| References vs 인라인 복사 | 재사용·한 곳 수정·인스턴싱 vs 단순·독립 |
| Payloads vs References | 지연 로드·스케일·메모리 vs 항상 로드·단순 |
| Variants vs 별도 파일 | 한 자산 구성·간결 vs 단순·명시 |
| Inherits vs References(공통) | 종류 전체 브로드캐스트 vs 개별 인스턴스 |
| Instancing vs 개별 프림 | 메모리·성능(수천) vs 인스턴스별 자유 편집 |
| 로컬 오버라이드 vs 자산 수정 | 비파괴·실험·협업 vs 영구·근본 |
견해: 대규모·재사용·협업 씬의 조립은 references(재사용)·payloads(스케일)·variants(구성)·sublayers(오버라이드)의 조합이 정석이다 — 로봇·작업 셀·디지털트윈(10.8)·병렬 환경(9.13). 인스턴싱은 수천 동일 프림의 메모리·성능에 필수이나 인스턴스별 자유 편집을 제약(트레이드오프). inherits·specializes는 강력하나 고급 — 대부분은 references+variants+sublayers로 충분, 종류 전체 브로드캐스트가 필요할 때만 inherits. 로컬 오버라이드(비파괴) 가 협업·실험의 기본(자산 수정은 근본 변경일 때만). 합성이 복잡해지면 usdview 합성 뷰가 유일한 진실 — 추측 금지.
비엔비디아 정직: 컴포지션·참조·변형의 개념은 USD 표준(픽사·AOUSD, 10.3) 의 것이지 NVIDIA 고유가 아니다 — USD를 쓰는 모든 도구가 같은 합성을 공유. 다른 씬 시스템도 참조·인스턴싱·LOD·오버라이드 개념을 갖지만(게임 엔진의 프리팹·인스턴스 등), USD의 차별점은 비파괴 레이어 합성 + 강도 규칙(LIVRPS) + 표준화·상호운용이다. 합성은 강력하나 학습 곡선·디버깅 난이도가 있어(LIVRPS·아크 상호작용), usdview·문서 의존이 크다 — 단순 씬엔 과할 수 있다. 깊은 경계는 그 버전 USD 문서로.
10.4.10 흔한 함정
- 로컬 오버라이드가 적용되지 않는다고 당황. 거의 항상 edit target이 약한 레이어·더 강한 아크(inherits) → usdview 합성 뷰·LIVRPS(10.4.6).
- References로 가져온 자산을 직접 수정. 자산(robot.usd)을 고치면 모든 인스턴스에 영향 → 인스턴스만 바꾸려면 로컬 오버라이드(10.3).
- 대용량 씬 전부 로드. payload 미사용으로 메모리·느림 → payload·부분 load(10.4.3).
- 옵션마다 파일 폭증. 그리퍼·LOD를 별도 파일로 → variants로 한 자산에(10.4.4).
- 인스턴싱 한계 무시. instanceable 프림은 인스턴스별 자유 편집 제약 → 의미 확인(문서).
- 합성을 추측으로 디버깅. "왜 이 값이?"를 짐작 → usdview 합성/prim stack 뷰로 출처 확인.
- inherits·references 강도 혼동. inherits(I)>references(R) — 클래스가 인스턴스를 이김 → LIVRPS.
- 목록 편집(prepend/append) 강도 무시. 아크 추가 순서·위치가 강도에 영향 → 문서·합성 뷰.
- variant 편집 컨텍스트 누락. 변형 내용을 컨텍스트 밖에서 정의 →
GetVariantEditContext()안에서. - USD 합성을 NVIDIA 고유로 오해. USD 표준(AOUSD) — 다른 도구도 동일(10.2·10.3).
10.4.11 연습문제
연습 1 (여섯 아크 분류). 여섯 컴포지션 아크를 용도로 분류하고, References·Payloads·Sublayers를 각각 언제 쓰는지 구체 예로 답하라.
정답
용도 분류: 재사용·조립 — ① references(외부 자산을 가져와 재사용·인스턴싱) ② payloads(references 같되 지연 로드·스케일) ③ variants(한 프림에 여러 명명 옵션, 하나 선택). 오버라이드·계층 — ④ sublayers(로컬 레이어 스택·오버라이드·협업) ⑤ inherits(클래스 상속·종류 전체 브로드캐스트) ⑥ specializes(폴백·특수화 기본값). 강도(LIVRPS): Local(sublayers)>Inherits>Variants>References>Payloads>Specializes. References 언제: 자산을 재사용·인스턴싱할 때 — 로봇 한 자산을 작업 셀에 3대 배치(각 reference + 위치 오버라이드), 환경 자산 재사용, 9.13 cloner가 수천 환경에 로봇 복제. 자산을 한 곳(robot.usd) 정의하고 N번 참조 → 자산 수정이 모든 인스턴스에 반영. 항상 필요·비교적 경량인 자산. Payloads 언제: references와 같되 대용량이라 지연 로드하고 싶을 때 — 디지털트윈(10.8)의 공장·도시 전체, 고해상도 환경. payload로 묶으면 기본 미로드, stage.Load()로 보는 부분만 메모리에 → 거대 씬을 열되 메모리·성능 관리(부분 로드). "대용량이고 항상 필요하진 않은" 자산. Sublayers 언제: 내 씬을 레이어로 조직·오버라이드할 때 — 협업(10.2)에서 라이팅 팀은 lighting.usda, 모델 팀은 model.usda로 비파괴 동시 작업; 도메인 랜덤화(9.14)에서 베이스 위에 랜덤화 오버라이드 레이어; 디지털트윈(10.8)에서 설계 위에 운영 레이어. 로컬 레이어 스택(루트 + 서브레이어), 위가 강함(LIVRPS의 L 최강). 요약: 자산 재사용=references, 대용량 지연 로드=payloads, 내 씬 조직·오버라이드=sublayers, 옵션=variants, 종류 브로드캐스트=inherits, 폴백=specializes. 대부분은 references+variants+sublayers로.
연습 2 (참조·인스턴싱). 로봇 자산 하나를 작업 셀에 4대 배치하되 각각 다른 위치·색을 주는 USD 구조를 설계하고, 자산 수정 시 무엇이 어떻게 반영되는지, 9.13 cloner와 어떻게 연결되는지 답하라.
정답
구조: 로봇 자산을 robot.usd에 한 번 정의(/Robot 프림 — 링크·조인트·물리 스키마 10.3). 작업 셀 씬에서 4개 프림이 이를 reference: /World/Robot_00~03 각각 references = @robot.usd@</Robot>. 각 프림에 로컬 오버라이드(L>R, 10.4.6)로 위치·색: Robot_00 { translate=(0,0,0); over "base_link" { displayColor=[(1,0,0)] } }, Robot_01 { translate=(2,0,0); ... 파랑 } 등. 위치는 xformOp:translate, 색은 참조 내부 프림(over "base_link")에 오버라이드. 자산 수정 반영: robot.usd를 고치면(예: 새 센서 추가·링크 형상 변경) → 4대 모두에 자동 반영(reference라 한 곳 수정, 전체 갱신). 반대로 인스턴스별 오버라이드(위치·색)는 각 프림의 로컬 레이어에만 있어 그 인스턴스만 영향 — 자산은 안 건드림. 즉 공통(자산)은 한 곳, 개별(위치·색)은 인스턴스별. 9.13 cloner 연결: Isaac Lab의 cloner가 수천 RL 환경에 로봇을 복제하는 것이 이 reference/인스턴싱 정신이다 — 로봇 자산을 한 번 정의하고 N개 환경에 참조·복제, 각 환경은 다른 초기 상태(위치·관절). 수천 동일 프림은 scenegraph instancing(instanceable=true)으로 메모리·성능 최적화(개별 자유 편집은 제약, 트레이드오프). 즉 9.13의 "N환경 병렬"이 데이터 모델 차원에선 "로봇 자산을 N번 참조·인스턴싱"이고, GPU 물리(PhysX 9.11)가 그 N개를 배치로 시뮬. 자산 수정이 전체 반영되니 로봇 디자인 반복이 쉽고, 인스턴스 오버라이드로 환경별 변형(도메인 랜덤화 9.14는 오버라이드 레이어로). 핵심: reference=공통 자산 한 곳·N번 재사용, 로컬 오버라이드=인스턴스별 변형, instancing=스케일.
연습 3 (변형). 로봇 그리퍼를 parallel·suction·none 세 옵션으로 두는 variant set을 설계하고, variant가 별도 파일(robot_parallel.usd 등) 대비 무엇이 유리하며 다중 variant set은 어떻게 쓰는지 답하라.
정답
variant set 설계: /Robot 프림에 gripper variant set을 두고 세 변형: parallel(평행 그리퍼 자산 reference), suction(흡착 그리퍼 reference), none(빈 변형). variants = {gripper="parallel"}로 현재 선택, prepend variantSets="gripper"로 등록. 각 변형 안에서 def "Gripper" (references=@해당_그리퍼.usd@)로 내용 정의(GetVariantEditContext() 안에서). 선택을 suction으로 바꾸면 합성 결과가 흡착 그리퍼로 전환 — 한 자산, 선택만 변경. API: vset=prim.GetVariantSets().AddVariantSet("gripper")·vset.AddVariant("parallel")·SetVariantSelection. 별도 파일 대비 유리: 옵션마다 robot_parallel.usd·robot_suction.usd·robot_none.usd를 따로 두면 ① 자산 폭증·중복(로봇 본체가 세 파일에 중복) ② 본체 수정 시 세 파일 모두 고쳐야(불일치 위험) ③ "어느 것이 실제 로봇?" 혼란. variant는 ① 한 자산에 옵션을 담아 본체 중복 없음(본체는 한 번, 그리퍼만 변형) ② 본체 수정이 한 곳 ③ 선택만 바꿔 구성 전환(런타임·usdview 드롭다운). 간결한 구성 관리. 다중 variant set: 한 프림에 여러 독립 variant set — 예: gripper(parallel/suction)·sensor(camera/lidar)·color(red/blue). 각각 독립 선택 → 조합(parallel+camera+red, suction+lidar+blue…)을 곱집합 파일 없이 표현(2×2×2=8 구성을 8개 파일이 아니라 3개 set로). 직교 구성. 중첩(variant 안에 또 variant)도 가능. 활용: 로봇 구성(그리퍼·센서), 차량 트림, 제품 옵션, LOD(거리별 상세 — high/mid/low variant), 디지털트윈 what-if(10.8, 레이아웃 옵션), 도메인 랜덤화(9.14) 옵션화. usdview로 변형 미리보기·선택. 핵심: variant=한 자산의 여러 명명 옵션, 별도 파일 중복·폭증 회피, 다중 set로 직교 구성. 선택은 로컬 오버라이드로도 바꿀 수 있어 인스턴스별 다른 그리퍼(reference + variant 선택 오버라이드).
연습 4 (LIVRPS 디버깅). LIVRPS 강도 순서를 설명하고, "참조한 자산 위에 로컬 오버라이드를 했는데 적용되지 않는다"·"클래스를 바꿨는데 인스턴스 오버라이드가 이긴다" 두 상황을 진단하라.
정답
LIVRPS: 한 속성에 여러 컴포지션 아크가 의견을 내면, USD는 고정된 강도 순서로 승자를 정한다 — Local(로컬 레이어 스택·sublayers·직접 의견, 최강) > Inherits(상속 클래스) > Variants(선택된 변형) > References(참조 자산) > Payloads(페이로드) > Specializes(특수화 폴백, 최약). 더 강한 아크가 약한 것을 이기고, 같은 아크 내에선 레이어 순서(위가 강함). 상황 1 — "로컬 오버라이드가 적용되지 않는다": 이론상 L > R이라 로컬 오버라이드는 참조를 이겨야 한다(비파괴 오버라이드 10.3의 원리). 안 먹으면: ① edit target이 잘못된 레이어 — 오버라이드를 약한/잘못된 레이어에 썼거나, 더 약한 sublayer에(같은 L이라도 레이어 순서로 위가 강함) → edit target 확인, 강한(위) 레이어에. ② 더 강한 아크가 이김 — 그 속성에 inherits(I) 의견이 있으면? I는 R보다 강하지만 L보다 약하니 로컬이 이겨야… 그래도 안 먹으면 ③ 경로·프림 불일치(오버라이드가 다른 프림/경로를 가리킴, 인스턴싱으로 인스턴스 편집 제약) ④ 속성 이름·네임스페이스 오타. 진단: usdview 합성/prim stack 뷰로 그 속성의 모든 의견과 출처 레이어·아크·강도를 본다 → 어디서 이기는 값이 오는지 정확히. 추측 금지. 상황 2 — "클래스를 바꿨는데 인스턴스 오버라이드가 이긴다": inherits(I) 는 references(R)보다 강하지만 Local(L)보다 약하다. 인스턴스 오버라이드를 로컬 레이어(L) 에 썼다면, L > I라 로컬 인스턴스 오버라이드가 클래스(inherits)를 이긴다 — 정상 동작! 클래스 변경을 모든 인스턴스에 강제하려면 인스턴스의 로컬 오버라이드를 제거하거나, 클래스 의견이 인스턴스 로컬보다 강해야 하는데 LIVRPS상 그럴 수 없다(L이 최강). 즉 로컬 오버라이드는 항상 클래스 브로드캐스트를 이긴다 — 의도라면 OK, 아니면 인스턴스 로컬 오버라이드를 빼야. 진단: usdview 합성 뷰로 인스턴스의 displayColor가 로컬(L)에서 오는지 클래스(I)에서 오는지 확인. 핵심: LIVRPS가 충돌 승자를 정하고, 로컬이 최강(내 직접 편집이 가져온 것·종류 규칙을 이김)·inherits>references(종류>개별). "왜 이 값이?"는 usdview 합성 뷰가 유일한 진실 — 강도와 출처를 보고 이해. 추측·짐작이 디버깅 실패의 원인.
연습 5 (스케일·디지털트윈). Payloads의 지연 로드가 대규모 씬·디지털트윈(10.8)에 왜 중요한지 설명하고, 거대한 공장 디지털트윈을 references·payloads·variants·오버라이드 레이어로 어떻게 구성할지 설계하라.
정답
Payloads 지연 로드의 중요성: 디지털트윈(10.8)·도시·공장은 수십 GB~TB 규모일 수 있다 — 모든 자산(건물·기계·로봇·파이프)을 한 번에 메모리에 적재하면 ① 메모리 초과(RTX GPU·RAM 한계) ② 로딩·렌더 느림 ③ 사용자는 보통 일부만 본다(한 라인·한 구역). Payloads는 자산을 기본 미로드로 두고 stage.Load(path)/Unload(path)로 필요한 부분만 메모리에 적재한다 → 거대 씬을 열되(구조·계층은 보임) 보는/작업하는 부분만 로드해 메모리·성능 관리. references는 항상 로드라 거대 씬엔 부적합 → payload가 스케일의 핵심 요인. 공장 디지털트윈 구성 설계: ① 자산 라이브러리(references) — 기계·로봇·컨베이어·랙을 각각 한 자산(machine.usd·robot.usd…)으로 정의, 공장 전역에 reference로 재사용·인스턴싱(같은 기계 20대 = reference 20번 + 위치 오버라이드, 10.4.3). ② 구역별 payload — 공장을 라인/구역으로 나눠 각 구역을 payload로 묶음(/Factory/LineA payload, /Factory/LineB payload…) → 사용자가 보는 구역만 load, 나머지 unload → TB 공장을 메모리 한도에서. ③ 구성 variants — 기계의 레이아웃 옵션·제품 변형·LOD를 variant set으로(10.4.4) — what-if 시나리오(라인 재배치)를 variant 전환으로. LOD variant(원거리=저폴리, 근거리=고폴리)로 성능. ④ 오버라이드 레이어(sublayers) — 설계 레이어(CAD 원본, 10.2 커넥터) 위에 운영 레이어(실시간 센서·기계 상태, 10.8)·시뮬 레이어(로봇 시뮬 9.11)·what-if 레이어(가상 변경)를 비파괴로 겹침(L 최강이라 운영이 설계 위에). 설계는 그대로, 운영·실험을 오버레이하고 제거함. ⑤ 인스턴싱 — 동일 기계 수백 대는 instanceable로 메모리·성능. ⑥ 협업(Nucleus 10.2) — 각 팀(설계·운영·로봇)이 다른 레이어에 동시 작성. 결과: references(재사용)·payloads(부분 로드 스케일)·variants(구성·LOD)·오버라이드 레이어(설계+운영+what-if 비파괴)·인스턴싱(성능)이 합쳐 TB 규모 공장을 메모리 한도에서 협업·시뮬·운영. usdview·합성 뷰로 디버깅. 이것이 디지털트윈(10.8)이 USD 위에 서는 이유 — 합성·지연 로드·비파괴가 대규모·다팀·동적 트윈을 가능케. 정직: 실제 스케일·성능은 하드웨어·구조 의존, payload 경계·인스턴싱 설계가 관건.
10.4.12 요약 · 다음 장
- 여섯 컴포지션 아크: sublayers(로컬 오버라이드·협업)·references(재사용·인스턴싱)·payloads(지연 로드·스케일)·variants(옵션)·inherits(클래스 브로드캐스트)·specializes(폴백). 대부분은 references+variants+sublayers.
- References·Payloads: 자산을 한 번 만들고 N번 재사용(인스턴싱·한 곳 수정 전체 반영, 9.13 cloner) / 대용량 자산 지연 로드(대규모 씬·디지털트윈 10.8 메모리·성능).
- Variants: 한 프림에 여러 명명 옵션(그리퍼·LOD·구성)을 담아 별도 파일 없이 선택. 다중 set로 직교 구성.
- LIVRPS: 의견 충돌의 강도 순서 Local>Inherits>Variants>References>Payloads>Specializes. 로컬 최강(비파괴 오버라이드 L>R)·inherits>references. "왜 이 값이?"의 답.
- 디버깅: usdview 합성/prim stack 뷰로 의견의 출처 레이어·아크·강도를 추적 — 추측 금지. 합성이 협업(10.2)·랜덤화(9.14)·트윈(10.8)·병렬(9.13)의 실제 메커니즘. 정직: USD 표준(AOUSD), 세부 규칙은 문서·usdview.
다음 장: 10.5 합성데이터 I — Replicator 파이프라인. OpenUSD(데이터 모델·합성)를 마쳤으니, 그 위에서 완벽한 라벨의 학습 데이터를 대량 생성하는 Replicator로 동작한다(9.11·9.12에서 맛봤다). USD 씬·RTX 센서(9.11)·도메인 랜덤화를 엮어 분할·박스·깊이 GT를 자동 생성하는 합성데이터 파이프라인을 본격적으로. 데이터 모델이 데이터 생성으로.