背景
Android でも USDZ データを読んで AR 表示に使いたい.
時代は glTF であるが, しかしそれでも USDZ を扱わねばならぬ時もある...(本当につらい 😭😭😭😭 ぴえん )
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 表示もいけそう)