search
LoginSignup
0

More than 1 year has passed since last update.

posted at

updated at

USD で usdz データを読むメモ

背景

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 表示もいけそう)

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
What you can do with signing up
0