0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Svelte で 3D 表示を行うライブラリ Threlte #3: glTF シーンを扱う

Last updated at Posted at 2024-01-22

シリーズ

glTF について

glTF は Khronos Group Inc. が提唱しているファイルフォーマット、シーンディスクリプタ。
最初からストリーミング機構などをサポートしているため、Web 利用などと相性が良く、近年普及が進んできている。

昨年の SIGGRAPH 2023 では glTF の今後のフォーマットに関してのセッションやフォーラムも数多くあった。
参加者には、Khronos Group の人に加え、Meta、Adobe、NVIDIA、Autodesk、Epic Games などが参加しており、今後は、XR や 3D 広告での利用をもっと広めていく狙いもあるとみられる。

glTF のデータ構造

データ構造を理解していると、コード上でのアクセスもしやすい。
なので、一応のデータ構造に関してもここで扱っておく。

.gltf/.glb
{
    animations: AnimationClip[],
    asset: {generator: string, version: number},
    cameras: Camera[],
    materials: 'Materials'[],
    nodes: (Group | Mesh | SkkinedMesh)[],
    parser: GLTFParser,
    scenes: Group[]
    userData: {}
}
  • animations
    • アニメーション(クリップ)情報が保存されている
  • asset
    • glTF ファイル自体の情報
  • cameras
    • カメラ情報が保存されている
  • materials
    • マテリアル情報が保存されている
  • nodes
    • メッシュやスキンメッシュ(アニメーションする際に必要なメッシュタイプ)、内包シーン情報が保存される
  • parser
    • GLTF のパース情報。JSON 形式もこちら経由で取得できる。
  • scenes
    • シーン情報を保存
  • userData
    • ユーザー固有のデータの保存領域

glTF の種類

glTF には、大きく分けて、

  • Ascii タイプ
    • 拡張子は .gltf
    • テキストで構成されているファイルタイプ。一般的なテキストエディタで中身を見ることができる。
    • 文字列のパースを含むので、ファイルサイズが大きければ大きいほどロードに時間がかかる。
  • Binary タイプ
    • 拡張子は .glb
    • 内容がバイナリで構成されていてファイルの中身を通常のテキストエディタ等では閲覧できない。
    • ファイルサイズが抑えられるのと、ロードの速度が速い。

が存在する。

ファイルによってはテクスチャ等が分かれているので、それら不随ファイルが足りないと、以下の機構で利用するさいはロードエラーを起こすので注意する。

Threlte における glTF

Threlte では、他のファイルフォーマットに比べて最初からサポートがある。

通常のファイルロードに加えて、アニメーションやシーン周りのサポートもあるため、諸々を説明するより先に Threlte での glTF の扱い方を紹介した方がモノにしやすいというのもあり、この段階での glTF の扱い方についてまとめるに至った。

では、まずは簡易ロードの仕方から。

glTF 関連モジュールの使い方

<GLTF> - glTF ファイルの簡易ロード

<GLTF> を使用すると、それ単体での glTF ファイルの簡易ロードが可能。

Scene.svelte
<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}
/>

<Grid
	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>

image.png

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}

image.png

useGltfAnimations - glTF でのアニメーションを再生する

Three.js の場合でもそうだが、大体の 3D フレームワーク同様、メッシュとアニメーションの処理は柔軟に扱えるよう、別々に取り扱うように設計されている。Mesh : Aimation = 1:1 ではないのである。
なので、これらを取り扱う場合には、ワンステップ踏む必要がある。

Threlte では、これを @threlte/extrasuseGltfAnimations などを使って実現する。

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}
+/>

output2.gif

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} />
</T>

あとは、これをコンポーネントとして再利用するだけ。

Scene.svelte
<script lang="ts">
  import Model from '$lib/models/DamagedHelmet.svelte';
</script>

<!-- シーン設定は省略 -->

<Model />

image.png

読み込むファイルが決まっていたり、コンパクトなローダーで収めたり、対象ハックする参考としてこれを利用するという手がある。

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
<GLTF
  url="/models/LittlestTokyo.glb"
  useDraco={true}
/>

また、true を渡すとライブラリ標準のものがロードされてくるが、ローダーを直接指定することも可能。
特別、ローダーを変更したい場合に指定すると良い。

Scene.svelte
<GLTF
  url="/models/LittlestTokyo.glb"
  useDraco="https://www.gstatic.com/draco/v1/decoders/"
/>

もう一つとしては Meshpot が存在する。
ただ今のところ僕は使っているところを見たことがないので、要調査。

使い方としては、DRACO と同じで、useMeshpot を指定する。

<GLTF
  url="/models/LittlestTokyo.glb"
  useMeshpot={true}
/>

:point_right:次のシリーズを読む
Svelte で 3D 表示を行うライブラリ Threlte #4: シーンコントロールツールセット Theatre.js for Threlte

0
1
0

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
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?