glTF は Khronos Group Inc. が提唱しているファイルフォーマット、シーンディスクリプタ。
最初からストリーミング機構などをサポートしているため、Web 利用などと相性が良く、近年普及が進んできている。
昨年の SIGGRAPH 2023 では glTF の今後のフォーマットに関してのセッションやフォーラムも数多くあった。
参加者には、Khronos Group の人に加え、Meta、Adobe、NVIDIA、Autodesk、Epic Games などが参加しており、今後は、XR や 3D 広告での利用をもっと広めていく狙いもあるとみられる。
useGltfAnimations
通常のファイルロードに加えて、アニメーションやシーン周りのサポートもあるため、諸々を説明するより先に Threlte での glTF の扱い方を紹介した方がモノにしやすいというのもあり、この段階での glTF の扱い方についてまとめるに至った。
では、まずは簡易ロードの仕方から。
glTF 関連モジュールの使い方
<GLTF>
- glTF ファイルの簡易ロード
<GLTF>
を使用すると、それ単体での glTF ファイルの簡易ロードが可能。
<script lang="ts">
import { T } from '@threlte/core';
+ import { ContactShadows, GLTF, Grid, OrbitControls, Environment } from '@threlte/extras';
</script>
<T.PerspectiveCamera makeDefault position={[5, 2, 13]} fov={15}>
<OrbitControls enableZoom={true} enableDamping target.y={1.5} />
</T.PerspectiveCamera>
<Environment
files={'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/equirectangular/venice_sunset_1k.hdr'}
isBackground={true}
position.y={-0.001}
cellColor="#ffffff"
sectionColor="#ffffff"
sectionThickness={0}
fadeDistance={30.0}
cellSize={2}
<ContactShadows scale={10} blur={2} far={2.5} opacity={0.5} />
<!-- 今回は glTF のサンプルモデルを直接 static 以下に配置して使用 -->
<T.Mesh position={[0, 1.3, 0]}>
+ <GLTF
+ url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf"
</T.Mesh>
useGltf
- glTF ファイルの操作利用
glTF シーンをロードして、そのシーンをコントロールしながら描画する場合は useGltf
フックでロードして使用する。
Web アプリとして実装する場合はこちらでの利用が多くなると思われる。
useGltf を使用すると、glTF を取り回しができるインスタンスオブジェクトとして扱えるようになる。
Scene.svelte
<script lang="ts">
import { T } from '@threlte/core'
+ import { Grid, OrbitControls, useGltf, Environment } from '@threlte/extras'
const gltf = useGltf("./models/DamagedHelmet.glb", { useDraco: true })
</script>
{#if $gltf}
+ <T is={$gltf.nodes['node_damagedHelmet_-6514']} />
{/if}
glTF オブジェクトにすると、シーン内の詳細にもアクセスできる様になる。
なので、例えばマテリアルを差し替えるなども可能。
Scene.svelte
<script lang="ts">
import { T } from '@threlte/core'
import { Grid, OrbitControls, useGltf, Environment } from '@threlte/extras'
+ import { MeshStandardMaterial, Color } from 'three'
const gltf = useGltf("./models/DamagedHelmet.glb", { useDraco: true })
</script>
{#if $gltf}
<T.Mesh
+ geometry={$gltf.nodes['node_damagedHelmet_-6514'].geometry}
+ material={new MeshStandardMaterial({roughness: 0.0,
+ color: new Color("rgb(255, 0, 0)")})}
rotation={[1.5, 0, 0]}
{/if}
useGltfAnimations
- glTF でのアニメーションを再生する
Three.js の場合でもそうだが、大体の 3D フレームワーク同様、メッシュとアニメーションの処理は柔軟に扱えるよう、別々に取り扱うように設計されている。Mesh : Aimation = 1:1 ではないのである。
なので、これらを取り扱う場合には、ワンステップ踏む必要がある。
Threlte では、これを @threlte/extras
の useGltfAnimations
などを使って実現する。
Scene.svelte
<script lang="ts">
import { T } from '@threlte/core'
+ import { useGltf, useGltfAnimations, GLTF } from '@threlte/extras'
+ const { gltf, actions } = useGltfAnimations()
+ $: $actions['Take 001']?.play()
</script>
<!-- その他シーンセットアップは省略 -->
+<GLTF
+ bind:gltf={$gltf}
+ url="/models/LittlestTokyo.glb"
+ useDraco={true}
glTf のアニメーションは、一つの glTF ファイルに複数内包されいてる可能性がある。
そのため、アニメーションを再生する際には、アニメーションのトラック名を指定して、再生してあげる必要がある。
こういったところが、アニメーションを扱う上で意図手間かかる所以。
@threlte/gltf
- glTF コンポーネント出力ツール
glTF の内部構造にアクセスする場合は名前解決が必要だったりする。
それを上手く解析して表示するには、3D エディタ的な機能まで必要だったりするが、Threlte では、glTF ファイルを読み込むためのコンパクトな svelte コンポーネントを出力しくれるツールが提供されている。
それが @threlte/gltf
である。
例えば、DamagedHelmet の場合、
npx @threlte/gltf@latest DamagedHelmet.glb
といったコマンドを実行することによって、以下のような Svelte コンポーネントを出力してくれる。
DamagedHelmet.svelte
<script>
import { Group } from 'three'
import { T, forwardEventHandlers } from '@threlte/core'
import { useGltf } from '@threlte/extras'
export const ref = new Group()
const gltf = useGltf('/DamagedHelmet.glb')
const component = forwardEventHandlers()
</script>
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
{#await gltf}
<slot name="fallback" />
{:then gltf}
<T.Mesh
geometry={gltf.nodes['node_damagedHelmet_-6514'].geometry}
material={gltf.materials.Material_MR}
rotation={[Math.PI / 2, 0, 0]}
{:catch error}
<slot name="error" {error} />
{/await}
<slot {ref} />
あとは、これをコンポーネントとして再利用するだけ。
Scene.svelte
<script lang="ts">
import Model from '$lib/models/DamagedHelmet.svelte';
</script>
<!-- シーン設定は省略 -->
<Model />
読み込むファイルが決まっていたり、コンパクトなローダーで収めたり、対象ハックする参考としてこれを利用するという手がある。
glTF を扱う上での付随知識
DRACO ローダーの使用
glTF は、際してコンパクトに取り回しが行える様に圧縮がかけられている事がままある。
その圧縮形式は今のところ DRACO が頻繁に使われている(現状は、実質一択)。
その DRACO 解凍 を行いつつロードしてくれる仕組みが DRACO ローダー として用意されている。
この Draco 圧縮がかかったものを、ローダーを通さずにロードしようとするとエラーを起こす。
Error in asyncWritable: THREE.GLTFLoader: No DRACOLoader instance provided.
そのため、エラー回避も含めてローダーを使用してロードしておく。
以下の様に複数やり方があるので、状況に応じて選択する。
Scene.svelte
<script lang="ts">
import { userGltf } from "@threlte/extras"
const gltf = useGltf('/model.glb', { useDraco: true })
</script>
Scene.svelte
url="/models/LittlestTokyo.glb"
useDraco={true}
また、true
を渡すとライブラリ標準のものがロードされてくるが、ローダーを直接指定することも可能。
特別、ローダーを変更したい場合に指定すると良い。
Scene.svelte
url="/models/LittlestTokyo.glb"
useDraco="https://www.gstatic.com/draco/v1/decoders/"
もう一つとしては Meshpot が存在する。
ただ今のところ僕は使っているところを見たことがないので、要調査。
使い方としては、DRACO と同じで、useMeshpot
を指定する。
url="/models/LittlestTokyo.glb"
useMeshpot={true}
次のシリーズを読む
Svelte で 3D 表示を行うライブラリ Threlte #4: シーンコントロールツールセット Theatre.js for Threlte