UNPKG

@threlte/gltf

Version:
335 lines (259 loc) 10.9 kB
<div align="right"> <a href="https://www.npmjs.com/package/@threlte/gltf"> <img alt="npm" src="https://img.shields.io/npm/v/@threlte/gltf?color=fe4100&labelColor=171d27&logo=npm&logoColor=white"/> </a> <a href="https://github.com/threlte/threlte/blob/main/LICENSE.md"> <img alt="license" src="https://img.shields.io/npm/l/@threlte/core?color=fe4100&labelColor=171d27&logo=git&logoColor=white"/> </a> <a href="https://discord.com/channels/985983540804091964"> <img alt="discord" src="https://img.shields.io/discord/985983540804091964?label=discord&color=fe4100&labelColor=171d27&logo=discord&logoColor=white"/> </a> <a href="https://threlte.xyz"> <img alt="docs" src="https://img.shields.io/website?down_color=red&down_message=offline&label=docs&color=fe4100&labelColor=171d27&up_message=online&url=https%3A%2F%2Fthrelte.xyz&logo=svelte&logoColor=white"/> </a> </div> <a href="https://threlte.xyz"> <img src="https://threlte.xyz/logo/threlte-banner.jpg"/> </a> ## Rapidly Build Interactive 3D Apps for the Web Threlte is a [Svelte](https://svelte.dev/) library that simplifies creating 3D apps for the web. It provides a **declarative**, **type-safe**, **reactive** and **interactive** API out-of-the-box. Threlte's **3D rendering** is powered by [Three.js](https://threejs.org/), and it also provides a **physics engine** through [Rapier](https://rapier.rs/) and an **animation studio** via [Theatre.js](https://www.theatrejs.com/); see [packages](#packages) for details. Check out our **[documentation](https://threlte.xyz)** and our **[Discord community](https://discord.gg/EqUBCfCaGm)**. ## @threlte/gltf [@threlte/gltf](https://threlte.xyz/docs/reference/gltf/getting-started) gives you a CLI to that turn GLTF assets into declarative and reusable Threlte components. This helps with performance optimization for asset-heavy Threlte apps. It also allows you to modify your GLTF assets as Svelte components, instead of working with 3D software like Blender. ### Motivation #### The GLTF workflow on the web is not ideal ... - GLTF is thrown wholesale into the scene which prevents re-use, in threejs objects can only be mounted once - Contents can only be found by traversal which is cumbersome and slow - Changes to queried nodes are made by mutation, which alters the source data and prevents re-use - Re-structuring content, making nodes conditional or adding/removing is cumbersome - Model compression is complex and not easily achieved - Models often have unnecessary nodes that cause extra work and matrix updates #### @threlte/gltf fixes that - 🧑‍💻 It creates a virtual graph of all objects and materials. Now you can easily alter contents and re-use. - 🏎️ The graph gets pruned (empty groups, unnecessary transforms, ...) and will perform better. - ⚡️ It will optionally compress your model with up to 70%-90% size reduction. ## Usage ```bash Usage $ npx @threlte/gltf@latest [Model.glb] [options] Options --output, -o Output file name/path --types, -t Add Typescript definitions --keepnames, -k Keep original names --keepgroups, -K Keep (empty) groups, disable pruning --meta, -m Include metadata (as userData) --shadows, -s Let meshes cast and receive shadows --printwidth, -w Prettier printWidth (default: 120) --precision, -p Number of fractional digits (default: 2) --draco, -d Draco binary path --preload -P Add preload method to module script --suspense -u Make the component suspense-ready --isolated, -i Output as isolated module (No $$restProps usage) --root, -r Sets directory from which .gltf file is served --transform, -T Transform the asset for the web (draco, prune, resize) --resolution, -R Transform resolution for texture resizing (default: 1024) --simplify, -S Transform simplification (default: false) (experimental!) --weld Weld tolerance (default: 0.0001) --ratio Simplifier ratio (default: 0.75) --error Simplifier error threshold (default: 0.001) --debug, -D Debug output ``` ### Requirements - NodeJS must be installed - The GLTF file has to be present in your projects `/public` folder - [three](https://github.com/mrdoob/three.js/) (>= 122.x) - @threlte/core > 5.0.0 - @threlte/core > 4.9.3 ### Support Have questions? Feel free to ask in our [Discord support forum](https://discord.com/channels/985983540804091964/1031843197963477002). ### A typical use-case First you run your model through `@threlte/gltf`. `npx` allows you to use npm packages without installing them. ```bash npx @threlte/gltf@latest model.gltf --transform ``` This will create a `Model.svelte` file that plots out all of the assets contents. ```svelte <!-- Auto-generated by: https://github.com/pmndrs/gltfjsx Command: npx gltfjsx@0.0.1 ./stacy.glb --> <script> import { Group } from 'three' import { T } from '@threlte/core' import { useGltf, useGltfAnimations } from '@threlte/extras' export const ref = new Group() const gltf = useGltf('/stacy.glb') export const { actions, mixer } = useGltfAnimations(gltf, ref) </script> {#if $gltf} <T is={ref} {...$$restProps} > <T.Group name="Scene"> <T.Group name="Stacy" rotation={[Math.PI / 2, 0, 0]} scale={0.01} > <T is={$gltf.nodes.mixamorigHips} /> <T.SkinnedMesh name="stacy" geometry={$gltf.nodes.stacy.geometry} material={$gltf.nodes.stacy.material} skeleton={$gltf.nodes.stacy.skeleton} rotation={[-Math.PI / 2, 0, 0]} scale={100} /> </T.Group> </T.Group> <slot {ref} /> </T> {/if} ``` Add your model to your `/public` folder as you would normally do. With the `--transform` flag it has created a compressed copy of it (in the above case `model-transformed.glb`). Without the flag just copy the original model. ```text /public model-transformed.glb ``` The component can now be dropped into your scene. ```svelte <script> import { Canvas } from '@threlte/core' import Model from './Model.svelte' </script> <Canvas> <Model /> </Canvas> ``` You can re-use it, it will re-use geometries and materials out of the box: ```svelte <Model position={[0, 0, 0]} /> <Model position={[10, 0, -10]} /> ``` Or make the model dynamic. Change its colors for example: ```svelte <T.Mesh geometry={$gltf.nodes.robot.geometry} material={$gltf.materials.metal} material.color="green" /> ``` Or exchange materials: ```svelte <T.Mesh geometry={$gltf.nodes.robot.geometry}> <T.MeshPhysicalMaterial color="hotpink" /> </T.Mesh> ``` Make contents conditional: ```svelte {#if condition} <T.Mesh geometry={$gltf.nodes.robot.geometry} material={$gltf.materials.metal} />} {/if} ``` ## Features #### ⚡️ Draco and meshopt compression ootb You don't need to do anything if your models are draco compressed, since `useGltf` defaults to a [draco CDN](https://www.gstatic.com/draco/v1/decoders/). By adding the `--draco` flag you can refer to [local binaries](https://github.com/mrdoob/three.js/tree/dev/examples/js/libs/draco/gltf) which must reside in your /public folder. #### ⚡️ Auto-transform (compression, resize) With the `--transform` flag it creates a binary-packed, draco-compressed, texture-resized (1024x1024), webp compressed, deduped, instanced and pruned \*.glb ready to be consumed on a web site. It uses [glTF-Transform](https://github.com/donmccurdy/glTF-Transform). This can reduce the size of an asset by 70%-90%. It will not alter the original but create a copy and append `[modelname]-transformed.glb`. #### ⚡️ Type-safety Add the `--types` flag and your component will be typesafe. ```svelte <!-- Auto-generated by: https://github.com/pmndrs/gltfjsx Command: npx gltfjsx@0.0.1 ./stacy.glb -t --> <script lang="ts"> import type * as THREE from 'three' import { Group } from 'three' import { T, type Props, type Events, type Slots } from '@threlte/core' import { useGltf, useGltfAnimations } from '@threlte/extras' type $$Props = Props<THREE.Group> type $$Events = Events<THREE.Group> type $$Slots = Slots<THREE.Group> export const ref = new Group() type ActionName = | 'pockets' | 'rope' | 'swingdance' | 'jump' | 'react' | 'shrug' | 'wave' | 'golf' | 'idle' type GLTFResult = { nodes: { stacy: THREE.SkinnedMesh mixamorigHips: THREE.Bone } materials: {} } const gltf = useGltf<GLTFResult>('/stacy.glb') export const { actions, mixer } = useGltfAnimations<ActionName>(gltf, ref) </script> {#if $gltf} <T is={ref} {...$$restProps} > <T.Group name="Scene"> <T.Group name="Stacy" rotation={[Math.PI / 2, 0, 0]} scale={0.01} > <T is={$gltf.nodes.mixamorigHips} /> <T.SkinnedMesh name="stacy" geometry={$gltf.nodes.stacy.geometry} material={$gltf.nodes.stacy.material} skeleton={$gltf.nodes.stacy.skeleton} rotation={[-Math.PI / 2, 0, 0]} scale={100} /> </T.Group> </T.Group> <slot {ref} /> </T> {/if} ``` #### ⚡️ Easier access to animations If your GLTF contains animations it will add [@threlte/extras's `useGltfAnimations`](https://threlte.xyz/extras/use-gltf-animations) hook, which extracts all clips and prepares them as actions: ```ts const gltf = useGltf('/stacy.glb') export const {(actions, mixer)} = useGltfAnimations(gltf, ref) ``` If you want to play an animation you can do so at any time: ```ts const onEvent = () => { $actions.jump.play() } ``` ## Using the parser stand-alone ```jsx import { parse } from '@threlte/gltf' import { GLTFLoader, DRACOLoader } from 'three-stdlib' const gltfLoader = new GLTFLoader() const dracoloader = new DRACOLoader() dracoloader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/') gltfLoader.setDRACOLoader(dracoloader) gltfLoader.load(url, (gltf) => { const component = parse(filename, gltf, config) }) ``` ## Contributing Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. - **Filing Issues** - if you have feature requestions or you think you spotted a bug, [submit an issue](https://github.com/threlte/threlte/issues/new). - **Contributing Code** - if you would like to drop us a PR, read the [contribution guide](https://github.com/threlte/threlte/blob/main/CONTRIBUTING.md) first. ## Sponsors [![Powered by Vercel](./assets/vercel/powered-by-vercel.svg)](https://vercel.com/?utm_source=threlte&utm_campaign=oss) --- ### License The MIT License (MIT). Please see the [License File](LICENSE.md) for more information.