KOSME Example 2‐2 - SmartX-Team/Omniverse GitHub Wiki

RYU,HYUN SEOK-OpenUSD 기초 실습

OpenUSD실습- Nvidia의 자료를 참고하였습니다.

OpenUSD 학습: Stage, Prims, Attributes 알아보기

OpenUSD 학습: 스테이지, 프림 및 속성에 대해 알아보기의 주피터 노트에 오신 것을 환영합니다. 여기에서 이 과정과 관련된 모든 파이썬 활동을 확인할 수 있습니다. 활동 1을 시작하기 전에 아래 셀을 실행해야 합니다.

참고: 시작하기 전에 Omniverse 에서 USDCompose를 실행해야 합니다. 이렇게 하면 이 노트북에서 사용할 관련 OpenUSD 라이브러리를 사용할 수 있습니다. 상단의 window를 누르고 아래에 있는 Script 머시기를 클릭

활동 1: USD 파일 만들기

OpenUSD는 Stage, Prims, Attributes로 구성됩니다. Stage는 Prim이라는 요소의 계층 구조를 구성하기 위한 컨테이너 역할을 하는 최상위 USD 파일을 의미합니다. Stage는 데이터로써, 파일이 아닙니다. 이는 Layers로 불리는 여러 데이터 소스에서 채워진 통합 장면 그래프들을 쌓아 만들어진 데이터 입니다. 우리는 이를 렌더링하여 시각화해서 보고 있습니다.

스테이지에 액세스하는 데 사용할 기능 중 일부는 다음과 같습니다:

  • 'USD.Stage.CreateNew()' : 3D 장면이 조립되는 빈 USD 스테이지를 새로 만듭니다.
  • 'USD.Stage.Open()' : 기존 USD 파일을 스테이지로 엽니다.
  • 'USD.Stage.Save()' : USD 스테이지의 현재 스테이지를 파일로 다시 저장합니다. 스테이지에 여러 레이어가 있는 경우 스테이지에 기여하는 모든 편집된 레이어가 저장됩니다. 저희의 경우 모든 편집이 단일 레이어에서 수행되고 있습니다.
# Import the `Usd` module from the `pxr` package:
from pxr import Usd

# Define a file path name:
file_path = "<my_path>/first_stage.usda"

# Create a stage at the given `file_path`:
stage: Usd.Stage = Usd.Stage.CreateNew(file_path)
print(stage.ExportToString())

stage.Save()

이렇게 스크립트를 수행하여 지정된 <my_path>에 usda파일이 생성되게 됩니다. usda는 usd 데이터를 담은 파일로 유저가 보다 읽기 쉬운형태의 데이터를 저장하고 있는 파일입니다. 이는 수행속도가 느리기 때문에 실제로 제품전 개발단계에서 주로 활용됩니다. 파일은 .usd, .usda, .usdc, .usdz와 같은 종류가 있습니다.

Activity 2: Cube를 Stage에 만들어보기

from pxr import Usd, UsdGeom

file_path = "<my_path>/first_stage.usda"
stage: Usd.Stage = Usd.Stage.Open(file_path)

# Define a prim of type `Cube` at path `/hello`:
UsdGeom.Cube.Define(stage, "/hello")
# Save the stage:
stage.Save()

위의 코드를 수행하며 omniverse 상에서 어떤 큐브가 보입니다. 여러분이 위에서 직접 만든 큐브에요! "Hello world!"

Activity 3: Hierarchy, 계층만들기

프림에는 namespace 계층 구조를 만들기 위해 다른 프림이 포함될 수 있습니다.

from pxr import Usd, UsdGeom

file_path = "<my_path>/second_stage.usda"
stage: Usd.Stage = create_new_stage(file_path)
# Define a `Scope` Prim in stage at `/Geometry`:
geom_scope: UsdGeom.Scope = UsdGeom.Scope.Define(stage, "/Geometry")
# Define an `Xform` Prim in stage as a child of `geom_scope` called `GroupTransform`:
xform: UsdGeom.Xform = UsdGeom.Xform.Define(stage, geom_scope.GetPath().AppendPath("GroupTransform"))
# Define a `Cube` in the stage as a child of `xform`, called `Box`:
cube: UsdGeom.Cube = UsdGeom.Cube.Define(stage, xform.GetPath().AppendPath("Box"))

stage.Save()

저희가 만든 계층 구조는 다음과 같습니다:

  • Geometry
    • GroupTransform
      • Cube

이 예제에서 'Geometry'은 루트 prim 입니다. 여기서는 세 가지 유형의 prims도 정의합니다: 'scope', 'xform', 및 'cube'.

  • 'Xform'은 변환(번역, 회전, 축척)을 정의합니다.
  • 'Scope'는 변환 데이터를 저장하지 않는 간단한 컨테이너입니다.
  • 'Cube'는 원시 직선 큐브를 정의합니다.

Activity 4: Stage에 빛 만들기

지금까지 우리는 'USDGeom'을 사용하여 prim을 만들었습니다. 이것은 3D 그래픽 관련 prim을 및 속성 스키마를 정의하는 'schema' 입니다. USD에는 조명 및 관련 구성 요소에 대한 표현을 제공하는 'USDLux'와 같은 다른 스키마도 함께 제공됩니다.

우리는 두 개의 새로운 prim을 정의할 것입니다: 'SphereLight''DistantLight'

from math import pi
from pxr import Gf, Usd, UsdGeom, UsdLux

file_path = "<my_path>/second_stage.usda"
stage: Usd.Stage = Usd.Stage.Open(file_path)

geom_scope: UsdGeom.Scope = UsdGeom.Scope.Define(stage, "/Geometry")
xform: UsdGeom.Xform = UsdGeom.Xform.Define(stage, geom_scope.GetPath().AppendPath("GroupTransform"))
cube: UsdGeom.Cube = UsdGeom.Cube.Define(stage, xform.GetPath().AppendPath("Box"))
# Define a `Scope` Prim in stage at `/Lights`:
lights_scope: UsdGeom.Scope = UsdGeom.Scope.Define(stage, "/Lights")
# Define a `Sun` prim in stage as a child of `lights_scope`, called `Sun`:
distant_light = UsdLux.DistantLight.Define(stage, lights_scope.GetPath().AppendPath("Sun"))
# Define a `SphereLight` prim in stage as a child of lights_scope called `SphereLight`:
sphere_light = UsdLux.SphereLight.Define(stage, lights_scope.GetPath().AppendPath("SphereLight"))

# Configure the distant light's emissive attributes:
distant_light.GetColorAttr().Set(Gf.Vec3f(1.0, 0.0, 0.0)) # Light color (red)
distant_light.GetIntensityAttr().Set(120.0) # Light intensity
# Position the distant light in the 3D scene:
distant_light_transform = distant_light.GetTransformOp()
if not distant_light_transform:
    distant_light_transform = distant_light.AddTransformOp()
distant_light_transform.Set(Gf.Matrix4d((pi/4, 0, -pi/4, 0), (0, 1, 0, 0), (pi/4, 0, pi/4, 0), (10, 0, 10, 1)))
distant_light.GetXformOpOrderAttr().Set([distant_light_transform.GetName()])

# Configure the sphere light's emissive attributes:
sphere_light.GetColorAttr().Set(Gf.Vec3f(0.0, 0.0, 1.0)) # Light color (blue)
sphere_light.GetIntensityAttr().Set(50000.0) # Light intensity
# Position the sphere light in the 3D scene:
sphere_light_transform = sphere_light.GetTransformOp()
if not sphere_light_transform:
    sphere_light_transform = sphere_light.AddTransformOp()
sphere_light_transform.Set(Gf.Matrix4d((pi/4, 0, pi/4, 0), (0, 1, 0, 0), (-pi/4, 0, pi/4, 0), (-10, 0, 10, 1)))
sphere_light.GetXformOpOrderAttr().Set([sphere_light_transform.GetName()])

stage.Save()

이제 저희의 계층 구조는 다음과 같습니다:

  • Geometry
    • GroupTransform
      • Box
  • Lights
    • Sun
    • SphereLight

두 가지 새로운 prim들을 소개했습니다: 'USDLux.SphereLight''USDLux.DistantLight' .

Activity 5: Prim에 Attributes를 추가해 봅시다.

'attribute' 은 대부분의 USD 장면에서 작성되는 가장 일반적인 유형의 속성입니다. 속성은 type과 기본값으로 구성됩니다. 또한 타임 샘플링된 값도 포함할 수 있습니다.

Here is an example of a Cube prim with an attribute called weight:

def Cube "Box" 
{
    double weight = 50
}
from pxr import Usd, UsdGeom

file_path = "<my_path>/second_stage.usda"
stage: Usd.Stage = Usd.Stage.Open(file_path)

# Get the Cube prim at path: `/Geometry/GroupTransform/Box`:
cube: UsdGeom.Cube = UsdGeom.Cube(stage.GetPrimAtPath("/Geometry/GroupTransform/Box"))
# Get all attribute names associated with Cube:
cube_attrs = cube.GetSchemaAttributeNames()
# Print out all the attribute names for Cube:
for attr in cube_attrs:
    print(attr)
# Get the Attribute for "Display Color":
cube_color_attr: Usd.Attribute = cube.GetDisplayColorAttr()
# Set the "Display Color" attribute to red:
cube_color_attr.Set([(1.0, 0.0, 0.0)])

stage.Save()

스키마에 의해 정의된 모든 attribute을 보려면 'GetSchemaAttributeNames()'를 참조하세요. 각 스키마에는 고유한 미리 정해진 attribute이 포함됩니다.

attribute을 검색한 후 'Set()' 을 사용하여 값을 설정할 수 있습니다. attribute을 가져온다고 해서 속성의 값을 검색하는 것은 아닙니다.

따라서 이제 속성값을 읽어들여보는 법을 배울 계획입니다.

Activity 6: 현 Attribute의 값 가져오기

각 스키마에는 고유한 속성 집합과 이를 검색할 수 있는 해당 함수가 있습니다. 자세한 내용을 보려면 'USDGoomCube' 공용 회원 함수를 참조하세요. 함수 이름은 일반적으로 Attr로 끝납니다.

다른 속성을 설정하고 속성에서 값을 얻는 방법에 대해 살펴보겠습니다.

from pxr import Usd, UsdGeom

file_path = "<my_path>/second_stage.usda"
stage: Usd.Stage = Usd.Stage.Open(file_path)

cube: UsdGeom.Cube = UsdGeom.Cube(stage.GetPrimAtPath("/Geometry/GroupTransform/Box"))
cube_color_attr: Usd.Attribute = cube.GetDisplayColorAttr()
cube_color_attr.Set([(1.0, 0.0, 0.0)])

# Get the Cube's `size` attribute:
cube_size_attr: Usd.Attribute = cube.GetSizeAttr()
# Get the value of the Cube's `Size` attribute, double it and set it as the new value for the `Size` attribute:
cube_size_attr.Set(cube_size_attr.Get() * 2)
# Get the prim at the path: `/Geometry/GroupTransform`:
geom_scope: UsdGeom.Scope = stage.GetPrimAtPath("/Geometry/GroupTransform")
# Define a Cube Prim in stage as a child of geom_scope called `Small_Box`:
small_box: UsdGeom.Cube = UsdGeom.Cube.Define(stage, geom_scope.GetPath().AppendPath("Small_Box"))
# Set the position of the `small_box` to x: 4, y: 5, z: 4
UsdGeom.XformCommonAPI(small_box).SetTranslate((4, 5, 4))

stage.Save()

여기서는 'GetSizeAttr()'을 사용하여 큐브의 크기를 정의하는 속성을 검색했습니다. 이 함수는 'USDGeomCube'에 정의된 공용 멤버 함수이기도 합니다. 속성의 값을 얻으려면 'Get()'을 사용합니다. 각 'USDAttribute' 에는 해당 값에 대한 'Set()' 및 'Get()' 함수가 포함되어 있습니다.

'XformCommonAPI' 는 스케일, 회전, 스케일 rotate 피벗 및 변환과 같은 변환 구성 요소를 설정하고 가져오는 데 사용됩니다. 이러한 속성은 고려되지만 변환 값을 편집할 때는 'XformCommonAPI'를 사용하는 것이 가장 좋습니다. 'XformCommonAPI'는 새로운 변환을 부트스트랩 설정하는 좋은 방법입니다. 향후 과정에서는 고급 xformOps 사용법에 대해 자세히 설명합니다. 아래는 'XformCommonAPI'가 Prim과 호환되는지 확인하는 예입니다.

from pxr import Usd, UsdGeom

# Create a stage and define a prim path
stage = Usd.Stage.CreateNew('example.usda')
prim = UsdGeom.Xform.Define('/ExamplePrim')

# Check if the XformCommonAPI is compatible with the prim using the bool operator 
if not (xform_api := UsdGeom.XformCommonAPI(prim)):
    raise Exception("Prim not compatible with XformCommonAPI")

# Set transformations
xform_api.SetTranslate((10.0, 20.0, 30.0))
xform_api.SetRotate((45.0, 0.0, 90.0), UsdGeom.XformCommonAPI.RotationOrderXYZ)
xform_api.SetScale((2.0, 2.0, 2.0))

Activity 7: Stage 탐색하기

우리는 USD stage를 탐색하기 위해 다음을 사용할 수 있습니다. Usd.Stage.Traverse(). 이는 USD 파일을 사용할때 기초적이며, 특히 복잡해질수록 이에 대한 이해가 필요할 것 입니다.

Add the following code to the cell below, then run the cell:

for prim in stage.Traverse():
    print(prim.GetPath())
from pxr import Usd

file_path = "<my_path>/second_stage.usda"
stage: Usd.Stage = Usd.Stage.Open(file_path)

for prim in stage.Traverse():
    print(prim.GetPath())

탐색은 깊이 우선 검색을 수행하며 전체 단계뿐만 아니라 전체 트리의 가지를 통과하는 데 사용할 수 있습니다.

Activity 8: Prim 존재하는지 확인하는법

많은 양의 데이터로 작업할 때는 프림을 작성하기 전에 prim이 존재하는지 확인하는 것이 중요합니다. 'GetChild()' 를 사용하여 prim이 자식을 얻을 수 있습니다. 자식을 찾을 수 없는 경우 유효하지 않은 'UdsPrim'을 반환합니다. 'Ud.Object.IsValid()'prim 을 사용하여 prim이 유효한지 또는 존재하는지 확인할 수 있습니다. 이는 프로젝트의 규모가 커질때 더욱 중요해 집니다.ㄴ

from pxr import Usd

file_path = "<my_path>/second_stage.usda"
stage: Usd.Stage = Usd.Stage.Open(file_path)

prim: Usd.Prim = stage.GetPrimAtPath("/Geometry")
child_prim: Usd.Prim
if child_prim := prim.GetChild("Box"):
    print("Child prim exists")
else:
    print("Child prim DOES NOT exist")

'Box'는 'Geometry'의 하위 항목이 아닙니다. 'Box'를 'GroupTransform'으로 바꾸면 '자식 프라이머리가 존재한다(Child prim exists)'가 출력됩니다. 그 이유는 'GetChild()'가 중첩된 자식이 아닌 prim의 직접 자식을 검색하기 때문입니다.

⚠️ **GitHub.com Fallback** ⚠️