LoginSignup
2
1

More than 3 years have passed since last update.

USD で usdz データを読むメモ

Last updated at Posted at 2020-01-02

背景

Android でも USDZ データを読んで AR 表示に使いたい.

時代は glTF であるが, しかしそれでも USDZ を扱わねばならぬ時もある...(本当につらい 😭😭😭😭 ぴえん :cry: :cry: :cry: :cry: :cry: )

USDZ は usdc ファイルを使っており, usdc はバイナリ化されているので, 基本 USD のライブラリを使わないと読めない.

USD のビルドがめんどくさすぎる.

USD の C++ ドキュメントや例がなさすぎる.

いばらの道ではありますが, とりあえず形状データ引っこ抜くくらいはできます.

USDZ とは

実態は非圧縮の zip です(複数ファイルをまとめるのに zip を使っているだけ)
usdc(バイナリ)とテクスチャ画像から成ります.

USD ファイルを見る

NVIDIA が prebuilt package を公開しています. ありがとうございます.

python で調べる.

とりあえずは python API でいろいろ調べましょう.

からサンプルの USDZ

構造の概要

だいたい Maya, Alembic あたりと同じと考えられます.
つまりシーンは transform node -> shape -> ... のような感じで階層構造を作っている.

Mesh

/teapot        : Xform
/teapot/Teapot : Mesh
/teapot/Looks  : Scope

/teapot/Looks -> Maya でいう shading group が子として存在します. Scope はmaterial, shader をまとめたグループノードのような意味でしょうか.

/teapot/Teapot のメッシュは subdivision surface になっています. したがってきちんと処理するなら OpenSubdiv あたりで処理する(mesh smoothing)する必要があります. 今回はとりあえず頂点データだけ抜き出してみます.

from __future__ import print_function

import sys
import os

from pxr import Sdf
from pxr import Usd

stage_ref = Usd.Stage.Open(sys.argv[1])
prim = stage_ref.GetDefaultPrim()
print('root', prim.GetPath())
print('ty', prim.GetTypeName())

for child in prim.GetChildren():
    print('child', child.GetPath(), ', ty', child.GetTypeName())

    if child.GetTypeName() == 'Mesh':
        print('attr')
        for attr in child.GetAttributes():
            print(' ', attr)
  Usd.Prim(</teapot/Teapot>).GetAttribute('cornerIndices')
  Usd.Prim(</teapot/Teapot>).GetAttribute('cornerSharpnesses')
  Usd.Prim(</teapot/Teapot>).GetAttribute('creaseIndices')
  Usd.Prim(</teapot/Teapot>).GetAttribute('creaseLengths')
  Usd.Prim(</teapot/Teapot>).GetAttribute('creaseSharpnesses')
  Usd.Prim(</teapot/Teapot>).GetAttribute('doubleSided')
  Usd.Prim(</teapot/Teapot>).GetAttribute('extent')
  Usd.Prim(</teapot/Teapot>).GetAttribute('faceVaryingLinearInterpolation')
  Usd.Prim(</teapot/Teapot>).GetAttribute('faceVertexCounts')
  Usd.Prim(</teapot/Teapot>).GetAttribute('faceVertexIndices')
  Usd.Prim(</teapot/Teapot>).GetAttribute('holeIndices')
  Usd.Prim(</teapot/Teapot>).GetAttribute('interpolateBoundary')
  Usd.Prim(</teapot/Teapot>).GetAttribute('normals')
  Usd.Prim(</teapot/Teapot>).GetAttribute('orientation')
  Usd.Prim(</teapot/Teapot>).GetAttribute('points')
  Usd.Prim(</teapot/Teapot>).GetAttribute('primvars:displayColor')
  Usd.Prim(</teapot/Teapot>).GetAttribute('primvars:displayOpacity')
  Usd.Prim(</teapot/Teapot>).GetAttribute('primvars:st')
  Usd.Prim(</teapot/Teapot>).GetAttribute('primvars:st:indices')
  Usd.Prim(</teapot/Teapot>).GetAttribute('purpose')
  Usd.Prim(</teapot/Teapot>).GetAttribute('subdivisionScheme')
  Usd.Prim(</teapot/Teapot>).GetAttribute('triangleSubdivisionRule')
  Usd.Prim(</teapot/Teapot>).GetAttribute('velocities')
  Usd.Prim(</teapot/Teapot>).GetAttribute('visibility')
  Usd.Prim(</teapot/Teapot>).GetAttribute('xformOp:translate:pivot')
  Usd.Prim(</teapot/Teapot>).GetAttribute('xformOpOrder')

ノードの xform 値を取得する

prim.Get() ではなく, UsdGeom を使います.

from pxr import UsdGeom

xform = UsdGeom.Xform(prim)

手順

を使いましょう. aarch64 とありますが x86_64 でも動きます.

MONOLITHIC build オプションがありますが, Android だと link 時に undefined reference などで fail します.
static build は通るのを確認しました(動作未確認)

HdEmbree, hdOSPRay を参考にする

Embree と繋げる plugin(C++) がありますので, これらが参考になります.

TODO

  • 自前で USDZ を読むのであれば, usda データを使うというのもできるので, 自前で USD ASCII parser を作り USD ライブラリ非依存でデータを読めるようにする
  • 優秀な AR 若人さまが, USDZ を Android で扱えることで, 人類史上最速で優秀な Android + USDZ で AR 若人さまへと昇華なされるスキームを確立する旅に出たい(usda バージョンなら頑張れば WebGL 表示もいけそう)
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1