Top 8
Outer WildsストーリーMODを色々やってみた
June 18, 2023, 10:04 a.m.表面符号と戯れる【量子コンピューター Advent Calendar 2023 23 日目】
Dec. 23, 2023, 3:28 a.m.位数発見アルゴリズム ~Quantum Zooやっていく【特別編】~
Jan. 27, 2023, 2:50 p.m.ストーリー追加 Mod: The Outsider やっていく日記【Outer Wilds】
Feb. 19, 2023, 6:33 a.m.意識が量子効果で生じることを示す実験結果についてちょっと調べただけのメモ
April 21, 2022, 3:09 p.m.ストーリー追加 MOD: Astral Codec やっていく日記【Outer Wilds】
Feb. 25, 2024, 8:47 a.m.Outer Wilds の量子は計算能力が(ある程度)すごいのではという話
Jan. 15, 2022, 8:35 a.m.MacでAge of Empires 2 DE (AoE2DE)をCrossOverで動かす
May 31, 2021, 11:52 a.m.<model-viewer>でアニメーションつきモデルをAndroid【Scene Viewer】, iOS【AR Quick Look】で表示してみた
Aug. 15, 2019, 4:02 a.m. edited Dec. 21, 2019, 5:16 a.m.先日のGoogle I/OでScene Viewerが発表されました.
これでAndroid, iOSともに(一部のハイエンド限定となりますが)WebARができるようになりました.GAFAのうちのGoogleとAppleがここまで推しているのですから,簡単に実装できるのだろうと思い試してみました.
...非常に大変じゃないか?!?!?!
Android, iOSの順番でアニメーションつきモデルの表示方法を説明していきます.
ちなみに完成したものはこの記事に載せてます.
Android 【Scene Viewer】
Androidなので<model-viewer>
で呼ばれるのはARCoreによるScene Viewerです.
必要なものはモデルのglTFファイルとhttpsサーバーです.
適当にBlenderなどで3Dモデルを用意し,glTF出力できるのであればそれで出力し,できないのであればCollada (.dae)にエクスポートしてCOLLADA2GLTF(もしくはそのオンラインサービス)で変換しましょう.
glTFファイルができたら,それをhttpsサーバーに置きましょう.特に持っていないのであれば,GitHub Pagesあたりで良いかと(あとはHerokuあたりか).
そしてHTMLに
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.js"></script>
<model-viewer src="/path/to/hoge.glb"
background-color="#70BCD1"
shadow-intensity="1"
camera-controls
autoplay
interaction-prompt="auto"
auto-rotate ar magic-leap></model-viewer>
と書けば表示されます.指定したプロパティについてはドキュメントを参照してください.特にこのうちのar
でScene Viewerが動くようになります.
が,2019-08-17時点で私のXperia XZ1では動きません(以前は動いた).どうやらGalaxyなど一部のデバイスでクラッシュする不具合が起きているようです.もっとも,すごいGoogleエンジニアがクラッシュするソースコードは特定したと言っているので,もうすぐ動くようになるでしょう...
iOS 【AR Quick Look】
2019-10-04追記
もしかして答えはGoogle製ツールのgoogle/usd_from_gltf?
試してないけど,Readmeを読む限りAR Quick Lookとの互換性にかなり注力してるので,以下の苦労(特にアニメーション部分)をしなくても良さそう.
追記終わり
さて,本題のiOSです.iOSにおいて<model-viewer>
で呼ばれるのはARKit 2以降によるAR Quick Lookです.
必要なものはUSDZファイル(USDAでも動いた)です...誰?????
USDZファイルはPixarが開発しAppleが発表したARのための新しいファイルフォーマットのようです.
そうかそうか,...新しいファイルフォーマットかぁ変換が大変そうだなあ...!
まずは最も簡単なアニメーションなしの場合です.Blenderあたりで適当にobjでエクスポートし,Xcode付属のxcrun
で,
$ xcrun usdz_converter model.obj model.usdz
だけです.簡単♪
次にシンプルなトランスレーションのみのアニメーションの場合です.Blenderあたりで適当にabcでエクスポートし,同じように,
$ xcrun usdz_converter model.abc model.usdz
だけです.
ボーンアニメーションつきUSDAファイルとの闘い
ラスボスです.ヤバいです.(^o^)
武器を手に入れます.ないとゲームオーバーです.
https://developer.apple.com/jp/augmented-reality/quick-look/ にアクセスし,一番下の「usdzツールをダウンロードする(英語)」をクリックします.Apple Developerアカウントでログインし,USDPythonをダウンロードします.私は0.60
を選びました.
このUSDPythonはUSDファイルを作成するためのツール・ライブラリ群となっています.ただし,動かすためにはMacのシステムのPython (/usr/bin/python
) が必要です.brewなどで入れたPythonではクラッシュします.
$ python usdpython/usdzconvert/usdzconvert -h
------------------------ 'Python' is dying ------------------------
Python crashed. FATAL ERROR: Failed axiom: ' Py_IsInitialized() '
in operator() at line 148 of /USD/pxr/base/lib/tf/pyTracing.cpp
USDPythonにはusdpython/usdzconvert/usdzconvert
が含まれ,これを用いることでOBJもしくはglTF(!!!!)からusd/usda/usdc/usdzへ変換することができます.つまり,Androidの方で用いたアニメーションつきglTFファイルをusdzconvert
で変換するという作戦です.
usdzconvert
を動かすには,
$ export PATH=$PATH:/path/to/usdpython/USD
$ export PYTHONPATH=/path/to/usdpython/USD/lib/python/:/path/to/usdpython/USD/lib/python/pxr/Usd/:$PYTHONPATH
と事前に各種パスを通す必要があります.そして,
$ /usr/bin/python /path/to/usdpython/usdzconvert/usdzconvert -h
でヘルプが表示されればOKです.
さて,持っているglTFファイルをこれで変換するのですが,ただ変換するだけ
$ /usr/bin/python /path/to/usdpython/usdzconvert/usdzconvert model.glb
だとMac上ではアニメーションしても,いざiOSで表示してみても全然アニメーションしないということになります(私はなった.ならないならこれで終わり.お疲れ様でした).そこで,人の読めるUSDAファイルで出力してみます.
$ /usr/bin/python /path/to/usdpython/usdzconvert/usdzconvert model.glb model.usda
また,usdpython/samples/
にcd
して,
$ /usr/bin/python 108_skinnedAnimation.py > 108.usda
としてやってAR Quick Lookでも動作するボーンアニメーションつきモデルを出力します.そして,model.usda
と108.usda
を目で見比べてみます(?!?!??!?目grep?!).
ここからは具体的にBlender 2.78で作成した以下のモデルを考えます.このモデルは単純にCubeを作り,そのCubeのうち一面のみに緑色のマテリアルを割り当て,それ以外に白色のマテリアルを割り当てました.そして,2本のボーンからなるArmatureを作ってCube→Armatureの順で選択してCtrl+pからWith Automatic Weightsで関連付けました.最後に,特にDope Sheet等は開かずに単純にDefault layoutの下にあるタイムラインにて,ボーンをPose Modeで動かしたものをキーフレームで打ち込みました.このとき,全フレーム数は24にしてあります(参考にしたものが24フレームだったため.異なっていても動くかもしれない).
CubeとArmatureを選択した状態で,Colladaで出力し(このときSelection Onlyにチェックした),Androidのときと同様にglTFに変換しました(得られたファイルをmodel.glb
とする).そして,上で示したようにusdzconvert
でmodel.usda
に変換しました.
(このままだとARモードにしてもiOSデバイスでアニメーションしない)
そして,この2つを見比べてみます.
#usda 1.0
(
defaultPrim = "skinnedAnimation"
endTimeCode = 24
startTimeCode = 1
timeCodesPerSecond = 24
upAxis = "Y"
)
def Xform "skinnedAnimation" (
assetInfo = {
asset identifier = @skinnedAnimation.usd@
string name = "skinnedAnimation"
}
kind = "component"
)
{
def SkelRoot "cubeModel"
{
def Mesh "geometry" (
prepend apiSchemas = ["SkelBindingAPI"]
)
{
float3[] extent = [(-1.165, -1.165, -1.165), (1.165, 1.165, 1.165)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4]
normal3f[] normals = [(0, 0, 1), (0, 1, 0), (0, 0, -1), (0, -1, 0), (1, 0, 0), (-1, 0, 0)] (
interpolation = "uniform"
)
point3f[] points = [(-1.165, -1.165, 1.165), (1.165, -1.165, 1.165), (-1.165, 1.165, 1.165), (1.165, 1.165, 1.165), (-1.165, 1.165, -1.165), (1.165, 1.165, -1.165), (-1.165, -1.165, -1.165), (1.165, -1.165, -1.165)]
matrix4d primvars:skel:geomBindTransform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
int[] primvars:skel:jointIndices = [2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
float[] primvars:skel:jointWeights = [0.57, 0.57, 0, 0, 0.57, 0.57, 0, 0, 0.57, 0.57, 0, 0, 0.57, 0.57, 0, 0, 0.57, 0.57, 0, 0, 0.57, 0.57, 0, 0, 0.57, 0.57, 0, 0, 0.57, 0.57, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
prepend rel skel:animationSource = </skinnedAnimation/cubeModel/animation>
prepend rel skel:skeleton = </skinnedAnimation/cubeModel/SkeletonRoot>
uniform token subdivisionScheme = "none"
}
def Skeleton "SkeletonRoot"
{
uniform matrix4d[] bindTransforms = [( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 1.0231736898422241, 0, 1) ), ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, -0.9544228911399841, 0, 1) )]
uniform token[] joints = ["SkeletonRoot", "SkeletonRoot/joint1", "SkeletonRoot/joint2"]
uniform matrix4d[] restTransforms = [( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 1.0231736898422241, 0, 1) ), ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, -0.9544228911399841, 0, 1) )]
}
def SkelAnimation "animation"
{
uniform token[] joints = ["SkeletonRoot", "SkeletonRoot/joint1", "SkeletonRoot/joint2"]
quatf[] rotations.timeSamples = {
1: [(1, 0, 0, 0), (1, 0, 0, 0), (1, 0, 0, 0)],
2: [(0.99785894, 0, 0.065403126, 0), (1, 0, 0, 0), (1, 0, 0, 0)],
...
24: [(0.065403126, 0, 0.99785894, 0), (1, 0, 0, 0), (1, 0, 0, 0)],
}
half3[] scales.timeSamples = {
1: [(1, 1, 1), (1.18066, 1, 1.18066), (2.49414, 1, 2.49414)],
2: [(1, 1, 1), (0.635742, 1, 0.635742), (1.12012, 1, 1.12012)],
...
24: [(1, 1, 1), (0.014122, 1, 0.014122), (1.05176, 1, 1.05176)],
}
float3[] translations.timeSamples = {
1: [(0, 0.9395472, 0), (0, -0.26373994, 0), (0, -1, 0)],
2: [(0, 0.9395472, 0), (0, 1.695752, 0), (0, -1, 0)],
...
24: [(0, 0.9395472, 0), (0, 4.188043, 0), (0, -1, 0)],
}
}
}
}
#usda 1.0
(
customLayerData = {
string creator = "usdzconvert preview 0.6"
}
defaultPrim = "box_2_mat"
endTimeCode = 24
metersPerUnit = 1
startTimeCode = 1
timeCodesPerSecond = 24
upAxis = "Y"
)
def Xform "box_2_mat" (
assetInfo = {
string name = "box_2_mat"
}
kind = "component"
)
{
def Scope "Materials"
{
def Material "Material_001_effect"
{
token outputs:surface.connect = </box_2_mat/Materials/Material_001_effect/surfaceShader.outputs:surface>
def Shader "surfaceShader"
{
uniform token info:id = "UsdPreviewSurface"
color3f inputs:diffuseColor = (0, 0.8, 0)
color3f inputs:emissiveColor = (0, 0, 0)
float inputs:metallic = 0
float inputs:roughness = 1
token outputs:surface
}
}
def Material "Material_002_effect"
{
token outputs:surface.connect = </box_2_mat/Materials/Material_002_effect/surfaceShader.outputs:surface>
def Shader "surfaceShader"
{
uniform token info:id = "UsdPreviewSurface"
color3f inputs:diffuseColor = (0.64, 0.64, 0.64)
color3f inputs:emissiveColor = (0, 0, 0)
float inputs:metallic = 0
float inputs:roughness = 1
token outputs:surface
}
}
}
def Scope "Geom"
{
def Xform "Z_UP"
{
matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 0, -1, 0), (0, 1, 0, 0), (0, 0, 0, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
def Xform "Armature"
{
def SkelRoot "Bone"
{
def Skeleton "Skeleton"
{
uniform matrix4d[] bindTransforms = [( (1, 0, 0, 0), (0, 0, 1, 0), (0, -1, 0, 0), (0, 0, -0, 1) ), ( (1, 0, -0, 0), (0, 0, 1, 0), (0, -1, 0, 0), (-0, 0, 0.5309846997261047, 1) )]
uniform token[] joints = ["Bone", "Bone/Bone_001"]
uniform matrix4d[] restTransforms = [( (1, 0, 0, 0), (0, 3.422854177870249e-8, 0.9999999657714582, 0), (0, -0.9999999657714582, 3.422854177870249e-8, 0), (0, 0, 0, 1) ), ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0.5309846997261047, 0, 1) )]
prepend rel skel:animationSource = </box_2_mat/Animations/skelAnim_0>
}
}
}
def Xform "Cube"
{
def Mesh "primitive_0"
{
int[] faceVertexCounts = [3, 3]
int[] faceVertexIndices = [0, 1, 2, 0, 3, 1]
rel material:binding = </box_2_mat/Materials/Material_001_effect>
normal3f[] normals = [(0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0)] (
interpolation = "vertex"
)
point3f[] points = [(1, -1, 1), (-1, -1, -1), (1, -1, -1), (-1, -1, 1)]
matrix4d primvars:skel:geomBindTransform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
int[] primvars:skel:jointIndices = [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
float[] primvars:skel:jointWeights = [0.30464703, 0.695353, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.8133193, 0.1866807, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
prepend rel skel:skeleton = </box_2_mat/Geom/Z_UP/Armature/Bone/Skeleton>
uniform token subdivisionScheme = "none"
}
def Mesh "primitive_1"
{
int[] faceVertexCounts = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
int[] faceVertexIndices = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15, 1, 3, 16, 4, 6, 17, 7, 9, 18, 10, 12, 19, 13]
rel material:binding = </box_2_mat/Materials/Material_002_effect>
normal3f[] normals = [(-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (-1, 0, 0), (0, 1, 0), (1, 0, 0), (0, 0, -1), (0, 0, 1)] (
interpolation = "vertex"
)
point3f[] points = [(-1, -1, 1), (-1, 1, -1), (-1, -1, -1), (-1, 1, 1), (1, 1, -1), (-1, 1, -1), (1, 1, 1), (1, -1, -1), (1, 1, -1), (1, 1, -1), (-1, -1, -1), (-1, 1, -1), (-1, 1, 1), (1, -1, 1), (1, 1, 1), (-1, 1, 1), (1, 1, 1), (1, -1, 1), (1, -1, -1), (-1, -1, 1)]
matrix4d primvars:skel:geomBindTransform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
int[] primvars:skel:jointIndices = [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
float[] primvars:skel:jointWeights = [0.8133193, 0.1866807, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.30464703, 0.695353, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.8133193, 0.1866807, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.30464703, 0.695353, 0, 0, 0.30464703, 0.695353, 0, 0, 0.8133193, 0.1866807, 0, 0, 0.30464703, 0.695353, 0, 0, 0.8133193, 0.1866807, 0, 0, 0.30464703, 0.695353, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.8133193, 0.1866807, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
prepend rel skel:skeleton = </box_2_mat/Geom/Z_UP/Armature/Bone/Skeleton>
uniform token subdivisionScheme = "none"
}
}
}
}
def Scope "Animations"
{
def SkelAnimation "skelAnim_0"
{
uniform token[] joints = ["Bone", "Bone/Bone_001"]
quatf[] rotations.timeSamples = {
1: [(-0.70710677, -0.70710677, -0, -0), (-1, -0, -0, -0)],
12: [(-0.70710677, -0.70710677, -0, -0), (-0.6463091, -0.76307577, -0, -0)],
24: [(-0.70710677, -0.70710677, -0, -0), (-1, -0, -0, -0)],
}
half3[] scales.timeSamples = {
1: [(1, 1, 1), (1, 1, 1)],
12: [(1, 1, 1), (1, 1, 1)],
24: [(1, 1, 1), (1, 1, 1)],
}
float3[] translations.timeSamples = {
1: [(0, 0, 0), (0, 0.5309847, 0)],
12: [(0, 0, 0), (0, 0.5309847, 0)],
24: [(0, 0, 0), (0, 0.5309847, 0)],
}
}
}
}
108.usda
のアニメーション部分は長いので省略しました.この2つを見比べてわかるのは,108.usda
の方が
- 階層が浅い
SkelAnimation
とメッシュ定義部分が同じ階層にあるprepend rel skel:animationSource
がSkeleton
ではなくMesh
の方にある
ということです.したがって,こうなるように手で編集してやります(?!?!?!).すると,
#usda 1.0
(
customLayerData = {
string creator = "usdzconvert preview 0.6"
}
defaultPrim = "box_2_mat"
endTimeCode = 24
metersPerUnit = 1
startTimeCode = 1
timeCodesPerSecond = 24
upAxis = "Y"
)
def Xform "box_2_mat" (
assetInfo = {
string name = "box_2_mat"
}
kind = "component"
)
{
def Scope "Materials"
{
def Material "Material_001_effect"
{
token outputs:surface.connect = </box_2_mat/Materials/Material_001_effect/surfaceShader.outputs:surface>
def Shader "surfaceShader"
{
uniform token info:id = "UsdPreviewSurface"
color3f inputs:diffuseColor = (0, 0.8, 0)
color3f inputs:emissiveColor = (0, 0, 0)
float inputs:metallic = 0
float inputs:roughness = 1
token outputs:surface
}
}
def Material "Material_002_effect"
{
token outputs:surface.connect = </box_2_mat/Materials/Material_002_effect/surfaceShader.outputs:surface>
def Shader "surfaceShader"
{
uniform token info:id = "UsdPreviewSurface"
color3f inputs:diffuseColor = (0.64, 0.64, 0.64)
color3f inputs:emissiveColor = (0, 0, 0)
float inputs:metallic = 0
float inputs:roughness = 1
token outputs:surface
}
}
}
def Scope "Geom"
{
def SkelRoot "Bone"
{
matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 0, -1, 0), (0, 1, 0, 0), (0, 0, 0, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
def Mesh "primitive_0"
{
int[] faceVertexCounts = [3, 3]
int[] faceVertexIndices = [0, 1, 2, 0, 3, 1]
rel material:binding = </box_2_mat/Materials/Material_001_effect>
normal3f[] normals = [(0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0)] (
interpolation = "vertex"
)
point3f[] points = [(1, -1, 1), (-1, -1, -1), (1, -1, -1), (-1, -1, 1)]
matrix4d primvars:skel:geomBindTransform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
int[] primvars:skel:jointIndices = [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
float[] primvars:skel:jointWeights = [0.30464703, 0.695353, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.8133193, 0.1866807, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
prepend rel skel:animationSource = </box_2_mat/Geom/Bone/skelAnim_0>
prepend rel skel:skeleton = </box_2_mat/Geom/Bone/Skeleton>
uniform token subdivisionScheme = "none"
}
def Mesh "primitive_1"
{
int[] faceVertexCounts = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
int[] faceVertexIndices = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15, 1, 3, 16, 4, 6, 17, 7, 9, 18, 10, 12, 19, 13]
rel material:binding = </box_2_mat/Materials/Material_002_effect>
normal3f[] normals = [(-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (-1, 0, 0), (0, 1, 0), (1, 0, 0), (0, 0, -1), (0, 0, 1)] (
interpolation = "vertex"
)
point3f[] points = [(-1, -1, 1), (-1, 1, -1), (-1, -1, -1), (-1, 1, 1), (1, 1, -1), (-1, 1, -1), (1, 1, 1), (1, -1, -1), (1, 1, -1), (1, 1, -1), (-1, -1, -1), (-1, 1, -1), (-1, 1, 1), (1, -1, 1), (1, 1, 1), (-1, 1, 1), (1, 1, 1), (1, -1, 1), (1, -1, -1), (-1, -1, 1)]
matrix4d primvars:skel:geomBindTransform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
int[] primvars:skel:jointIndices = [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
float[] primvars:skel:jointWeights = [0.8133193, 0.1866807, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.30464703, 0.695353, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.8133193, 0.1866807, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.9371129, 0.06288713, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.30464703, 0.695353, 0, 0, 0.30464703, 0.695353, 0, 0, 0.8133193, 0.1866807, 0, 0, 0.30464703, 0.695353, 0, 0, 0.8133193, 0.1866807, 0, 0, 0.30464703, 0.695353, 0, 0, 0.8802035, 0.119796485, 0, 0, 0.8133193, 0.1866807, 0, 0] (
elementSize = 4
interpolation = "vertex"
)
prepend rel skel:animationSource = </box_2_mat/Geom/Bone/skelAnim_0>
prepend rel skel:skeleton = </box_2_mat/Geom/Bone/Skeleton>
uniform token subdivisionScheme = "none"
}
def Skeleton "Skeleton"
{
uniform matrix4d[] bindTransforms = [( (1, 0, 0, 0), (0, 0, 1, 0), (0, -1, 0, 0), (0, 0, -0, 1) ), ( (1, 0, -0, 0), (0, 0, 1, 0), (0, -1, 0, 0), (-0, 0, 0.5309846997261047, 1) )]
uniform token[] joints = ["Bone", "Bone/Bone_001"]
uniform matrix4d[] restTransforms = [( (1, 0, 0, 0), (0, 3.422854177870249e-8, 0.9999999657714582, 0), (0, -0.9999999657714582, 3.422854177870249e-8, 0), (0, 0, 0, 1) ), ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0.5309846997261047, 0, 1) )]
}
def SkelAnimation "skelAnim_0"
{
uniform token[] joints = ["Bone", "Bone/Bone_001"]
quatf[] rotations.timeSamples = {
1: [(-0.70710677, -0.70710677, -0, -0), (-1, -0, -0, -0)],
12: [(-0.70710677, -0.70710677, -0, -0), (-0.6463091, -0.76307577, -0, -0)],
24: [(-0.70710677, -0.70710677, -0, -0), (-1, -0, -0, -0)],
}
half3[] scales.timeSamples = {
1: [(1, 1, 1), (1, 1, 1)],
12: [(1, 1, 1), (1, 1, 1)],
24: [(1, 1, 1), (1, 1, 1)],
}
float3[] translations.timeSamples = {
1: [(0, 0, 0), (0, 0.5309847, 0)],
12: [(0, 0, 0), (0, 0.5309847, 0)],
24: [(0, 0, 0), (0, 0.5309847, 0)],
}
}
}
}
}
となります.
あとは,AndroidのScene Viewerと同様に,さらにios-src
を加えて,
<model-viewer src="/path/to/hoge.glb"
ios-src="/path/to/hoge.usda"
background-color="#70BCD1"
shadow-intensity="1"
camera-controls
autoplay
interaction-prompt="auto"
auto-rotate ar magic-leap></model-viewer>
でOKです(usdz
にしたい人はxcrun usdz_converter hoge.usda hoge.usdz -v -a -l
すれば良い.usdz
は要はzipなので拡張子をzip
にすれば開けたりする).
これでようやく
とAndroid, iOS双方で動くものが得られました.
最後に
適切なモデルさえあれば 手軽にAndroid, iOS両方でARできるのでラクですね〜〜()
とはいえ,Androidでは大体のアニメーションは動くのでほぼ問題ないですし,iOSも実機側でもMacと同じレベルで対応できれば問題なくなるので,十分期待はできると信じたいです.
あとは複数モデルの同時表示とか位置・向き・大きさ等のAPIとかが来れば良いなぁ〜〜〜
Top 8
Outer WildsストーリーMODを色々やってみた
June 18, 2023, 10:04 a.m.表面符号と戯れる【量子コンピューター Advent Calendar 2023 23 日目】
Dec. 23, 2023, 3:28 a.m.位数発見アルゴリズム ~Quantum Zooやっていく【特別編】~
Jan. 27, 2023, 2:50 p.m.ストーリー追加 Mod: The Outsider やっていく日記【Outer Wilds】
Feb. 19, 2023, 6:33 a.m.意識が量子効果で生じることを示す実験結果についてちょっと調べただけのメモ
April 21, 2022, 3:09 p.m.ストーリー追加 MOD: Astral Codec やっていく日記【Outer Wilds】
Feb. 25, 2024, 8:47 a.m.Outer Wilds の量子は計算能力が(ある程度)すごいのではという話
Jan. 15, 2022, 8:35 a.m.MacでAge of Empires 2 DE (AoE2DE)をCrossOverで動かす
May 31, 2021, 11:52 a.m.Tags
- #Python (26)
- #量子力学 (25)
- #量子情報 (23)
- #Unity (11)
- #Outer Wilds (11)
- #数学 (9)
- #Mac (9)
- #AoE2 (8)
- #Linux (7)
- #Quantum Zoo (6)
- #意識 (5)
- #シミュレーション (5)
- #NumPy (5)
- #Bash (5)
- #相対論 (4)
- #Docker (4)
- #Android (4)
- #Qiskit (4)
- #Rust (3)
- #PyO3 (3)
- #GitHub (3)
- #Django (2)
- #情報理論 (2)
- #LaTeX (2)
- #AR (2)
- #Git (2)
- #iOS (2)
- #C++ (2)
- #正規表現 (2)
- #論文 (2)
- #電磁気学 (1)
- #Google Drive (1)
- #Overleaf (1)
- #Let's Encrypt (1)
- #ポケモン (1)
- #AdMob (1)
- #Autoya (1)
- #docopt (1)
- #SymPy (1)
- #AWS (1)
- #Twitter (1)
- #URP (1)
- #iMovie (1)
- #PyTorch (1)
- #C# (1)
- #Vim (1)