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 を公開しています. ありがとうございます.

https://developer.nvidia.com/usd

### python で調べる.

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

https://developer.apple.com/augmented-reality/quick-look/

からサンプルの 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)
```

## 手順

https://github.com/syoyo/USD-build-aarch64

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

https://github.com/PixarAnimationStudios/USD/blob/master/BUILDING.md#linker-options

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

### HdEmbree, hdOSPRay を参考にする

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

https://github.com/PixarAnimationStudios/USD/tree/master/pxr/imaging/plugin/hdEmbree

https://github.com/ospray/hdospray



## TODO

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