Giter VIP home page Giter VIP logo

gltf-transform's Introduction

glTF Transform

Latest NPM release npm bundle size License Build Status Coverage

glTF 2.0 SDK for JavaScript and TypeScript, on Web and Node.js.

Introduction

glTF Transform supports reading, editing, and writing 3D models in glTF 2.0 format. Unlike 3D modeling tools — which are ideal for artistic changes to geometry, materials, and animation — glTF Transform provides fast, reproducible, and lossless control of the low-level details in a 3D model. The API automatically manages array indices and byte offsets, which would otherwise require careful management when editing files. These traits make it a good choice for bundling, splitting, or optimizing an existing model. It can also be used to apply quick fixes for common issues, to build a model procedurally, or to easily develop custom extensions on top of the glTF format. Because the core SDK is compatible with both Node.js and Web, glTF Transform may be used to develop offline workflows and web applications alike.

Packages:

  • @gltf-transform/core: Core SDK, providing an expressive API to read, edit, and write glTF files.
  • @gltf-transform/extensions: Extensions (optional glTF features) for the Core SDK.
  • @gltf-transform/functions: Functions for common glTF modifications, written using the core API.
  • @gltf-transform/cli: Command-line interface (CLI) to apply functions to glTF files quickly or in batch.

Function symbol, f(📦) → 📦, where the argument and output are a box labeled 'glTF'.

Commercial Use

Using glTF Transform for a personal project? That's great! Sponsorship is neither expected nor required. Feel free to share screenshots if you've made something you're excited about — I enjoy seeing those!

Using glTF Transform in for-profit work? That's wonderful! Your support is important to keep glTF Transform maintained, independent, and open source under MIT License. Please consider a subscription or GitHub sponsorship.

Learn more in the glTF Transform Pro FAQs.

Scripting API

Install the scripting packages:

npm install --save @gltf-transform/core @gltf-transform/extensions @gltf-transform/functions

Read and write glTF scenes with platform I/O utilities WebIO, NodeIO, or DenoIO:

import { Document, NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import draco3d from 'draco3dgltf';

// Configure I/O.
const io = new NodeIO()
    .registerExtensions(ALL_EXTENSIONS)
    .registerDependencies({
        'draco3d.decoder': await draco3d.createDecoderModule(), // Optional.
        'draco3d.encoder': await draco3d.createEncoderModule(), // Optional.
    });

// Read from URL.
const document = await io.read('path/to/model.glb');

// Write to byte array (Uint8Array).
const glb = await io.writeBinary(document);

To perform changes to an existing glTF Document, import off-the-shelf scripts from the Functions package, or write your own using API classes like Material, Primitive, and Texture.

import { resample, prune, dedup, draco, textureCompress } from '@gltf-transform/functions';
import sharp from 'sharp'; // Node.js only.

await document.transform(
    // Losslessly resample animation frames.
    resample(),
    // Remove unused nodes, textures, or other data.
    prune(),
    // Remove duplicate vertex or texture data, if any.
    dedup(),
    // Compress mesh geometry with Draco.
    draco(),
    // Convert textures to WebP (Requires glTF Transform v3 and Node.js).
    textureCompress({
        encoder: sharp,
        targetFormat: 'webp',
        resize: [1024, 2024],
    }),
    // Custom transform.
    backfaceCulling({cull: true}),
);

// Custom transform: enable/disable backface culling.
function backfaceCulling(options) {
    return (document) => {
        for (const material of document.getRoot().listMaterials()) {
            material.setDoubleSided(!options.cull);
        }
    };
}

To learn how glTF Transform works, and the architecture of the scripting API, start with Concepts. To try out the scripting API without installing anything, visit gltf.report/, load a glTF model, and open the Script tab.

Command-line API

Install the CLI, supported in Node.js LTS versions.

npm install --global @gltf-transform/cli

List available CLI commands:

gltf-transform --help

Optimize everything all at once:

gltf-transform optimize input.glb output.glb --texture-compress webp

Or pick and choose your optimizations, building a custom pipeline.

Compress mesh geometry with Draco or Meshoptimizer:

# Draco (compresses geometry).
gltf-transform draco input.glb output.glb --method edgebreaker

# Meshopt (compresses geometry, morph targets, and keyframe animation).
gltf-transform meshopt input.glb output.glb --level medium

Resize and compress textures with Sharp, or improve VRAM usage and performance with KTX2 and Basis Universal:

# Resize textures.
gltf-transform resize input.glb output.glb --width 1024 --height 1024

# Compress textures with WebP.
gltf-transform webp input.glb output.glb --slots "baseColor"

# Compress textures with KTX2 + Basis Universal codecs, UASTC and ETC1S.
gltf-transform uastc input.glb output1.glb \
    --slots "{normalTexture,occlusionTexture,metallicRoughnessTexture}" \
    --level 4 --rdo --rdo-lambda 4 --zstd 18 --verbose
gltf-transform etc1s output1.glb output2.glb --quality 255 --verbose

... and much more.

Credits

See Credits.

License

Copyright 2023, MIT License.

gltf-transform's People

Contributors

06wj avatar arthurrmp avatar citizendot avatar dependabot[bot] avatar donmccurdy avatar gmadges avatar harrycollin avatar hexafield avatar jo-chemla avatar johannesvollmer avatar lhelps avatar makio64 avatar marwie avatar mikejurka avatar ptc-mrucci avatar rawnsley avatar reedcopsey avatar renovate-bot avatar renovate[bot] avatar robertlong avatar robertoranon avatar romanfrom710 avatar rotu avatar snagy avatar subho57 avatar timknip avatar trygveaa avatar xlsfs avatar y-71 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gltf-transform's Issues

Build only cjs and modern output.

Remove legacy module and umd output. Should resolve the warnings of the form No name was provided for external module, and make building faster.

Create @gltf-transform/inspect package.

There's a basic "inspect()" function checked into the CLI package, but I'd like to put that into its own npm package so it's available both in web and node.js. The current script prints a number of tables describing the content of the file, and is intended to be useful for understanding performance behavior, and whether the model follows basic best practice1. For example:

  • how many meshes and materials are there?
  • how many materials use alpha blending?
  • how many textures are included, and how large is each texture?

Screen Shot 2020-07-16 at 10 59 30 AM

The goal for a @gltf-transform/inspect package would be to abstract that into something that returns JSON. Users can read the JSON on Web/Node.js, and the CLI tool can use it to print the same tables it does today. Example usage:

import { WebIO } from '@gltf-transform/core';
import { inspect } from '@gltf-transform/inspect';

const doc = await new WebIO().read('path/to/model.glb');
const report = inspect(doc);
console.log(report);

1 Best practice, as opposed to whether it's a technically valid glTF file. The glTF-Validator already covers the latter case very well.

Move CLI to TypeScript

I think I originally used JS here for easier debugging or something? Practically the unit tests seem to be working well for that, I'd rather have the CLI use TS and ts-node at this point.

Fails to read glb files

Hi; I know this is in development, so feel free to close if this isn't expected to be working yet. I came here because of the de-duplication idea (based on Matt Deslaurier's gist).
I cloned the repo, did npm install, lerna bootstrap, and npm run dist, then ran node_modules/.bin/gltf-transform analyze DamagedHelmet.glb and got this error:

/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:600
        if (bufferView.byteLength > 0) {
                       ^

TypeError: Cannot read property 'byteLength' of undefined
    at Function.removeBufferView (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:600:24)
    at forEach (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:236:22)
    at Array.forEach (<anonymous>)
    at PackedGLTFContainer.unpack (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:231:29)
    at Function.fromGLB (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:338:54)
    at NodeIO.readGLB (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:766:25)
    at NodeIO.read (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:761:29)
    at Command.program.command.argument.action [as _action] (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/src/cli.js:26:30)
    at Command._run (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/node_modules/caporal/lib/command.js:413:40)
    at Program._run (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/node_modules/caporal/lib/program.js:170:16)
    at Program.parse (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/node_modules/caporal/lib/program.js:276:17)
    at Object.<anonymous> (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/src/cli.js:99:6)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)

If I load my own model, I get a slightly different error:

/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:91
                throw new Error(`Empty top-level array, "${this.json[key]}".`);
                ^

Error: Empty top-level array, "".
    at GLTFContainer.validate (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:91:23)
    at PackedGLTFContainer.unpack (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:241:19)
    at Function.fromGLB (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:338:54)
    at NodeIO.readGLB (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:766:25)
    at NodeIO.read (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/node_modules/@gltf-transform/core/dist/gltf-transform-core.js:761:29)
    at Command.program.command.argument.action [as _action] (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/src/cli.js:26:30)
    at Command._run (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/node_modules/caporal/lib/command.js:413:40)
    at Program._run (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/node_modules/caporal/lib/program.js:170:16)
    at Program.parse (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/node_modules/caporal/lib/program.js:276:17)
    at Object.<anonymous> (/c/DSS/Product/Horizon/WebProjects/horizon-project/horizon-data-converters/glTF-Transform/packages/cli/src/cli.js:99:6)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)

(I tried modifying packages/core/src/packed-container.ts to see if I could print the "key" it's looking for, and re-running npm run dist but it didn't pick up my changes -- I'm not a lerna person so I assume I missed a step.)

Scoped packages

Consider:

@gltf-transform/cli
@gltf-transform/util

@gltf-transform/occlusion-vertex
@gltf-transform/prune
@gltf-transform/split
@gltf-transform/atlas
...

Convert spec/gloss → metal/rough

Details in KhronosGroup/glTF#1719 (comment). May need get-pixels to rewrite glossiness->roughness.

Usage:

gltf-transform metalrough input.glb output.glb
import {metalRough} from '@gltf-transform/lib';
import {NodeIO} from '@gltf-transform/core';

const io = new NodeIO(fs, path);
const doc = io.read('input.glb');
metalRough(doc);
io.write('output.glb', doc);

Similar API to existing unlit function.

Clean up extra files

  • tsconfig.json
  • LICENSE
  • rollup.config.js
  • typings/
  • scripts/
  • dist/
  • static/ (to package)

Install

After cloning the repository, run: yarn install

This produce error:" [Errno 2] No such file or directory: 'install'"
Could you help with newbie how to proceed with installation?

Add 'debug' or 'doctor' package

Intended to look for common validity issues in the Document that would prevent its being exported, before the Document is written to a file (after which glTF-Validator is the better thing to use). Things like:

  • cyclic dependencies
  • unassigned buffers
  • unassigned but required properties
  • ...

Writing Accessors Min/Max null

When reading the attatched lamp.gltf file and then writing it, some accessors' min and max arrays will have null values. (This prevents the next tool in our pipeline to convert it to usdz). We know that the original .gltf file has some issues, but we would expect that upon successful reading of the file that it would also write a correct file.

lamp.zip

const io = new NodeIO(fs, path);  
var doc = io.read("lamp/lamp.gltf");  
io.write("lamp/lampOut.gltf", doc);

gltf-transform/core version: 0.3.2

[screenshot] Support screenshot generation on Web and Node.js

Related links:

Usage:

gltf-transform screenshot model.glb --options ...
import { screenshot } from '@gltf-transform/screenshot';
import { NodeIO } from '@gltf-transform/core';


const doc = new NodeIO().read('model.glb');
const screenshotBuffer = screenshot(doc);
fs.writeFileSync('screenshot.png', screenshotBuffer);

Support extensions

Hey, I know support for extensions is in development in the v0.4 branch but according to the comment, the only thing missing is documentation.

Can I start using this branch? Is there anything else I can do to help with it?

I'm using glTF-Transform to extract the 3D models from a proprietary format and I'd like to use the KHR_materials_unlit extension.

Update Caporal.js

The new version is a breaking change, but has an improved API, and supports sections in the help output that look useful to me.

Sections in CLI --help output

Looks like Caporal now supports sections in its --help output, which could be nice:

general

  • analyze
  • validate
  • repack

modify

  • unlit
  • colorspace
  • ao

clean

  • prune
  • deduplicate

compress

  • ktx
  • gzip
  • draco

Consolidate transforms into a 'lib' package.

Keeping a package for each transform (ao, colorspace, prune, split, ...) is messy, I often find myself wanting to rename things, or add something quickly, and because NPM packages can't be deleted there's an aspect of "cluttering" the namespace as that goes on. I think all of these could be consolidated into a single package (perhaps "lib"?) that provides functions built on top of the core and extension APIs. In dependency order:

cli > lib > extensions > core

Revisit "Scripting & CLI" page

CLI preview is already out of date and will probably keep becoming so unless I automate it. The "transforms" should probably go into a "library page". Maybe that leaves "installation" and "scripting"?

[core] abstract api away from accessor/bufferview/buffer syntax

Not ideal for an SDK, which is what the core lib seems to be headed toward. Perhaps something like:

  • accessors, images are automatically unpacked and can be written and read individually
  • repack at export, defragmenting, splitting, and compressing
  • handle references without indices. Augment typings? Point directly to objects? Helper methods?

CLI methods should all warn about unknown extensions.

Basic snippet:

	// Warn for unknown extensions.
	const extensionsRecognized = new Set();
	doc.getRoot().listExtensionsUsed().forEach((ext) => extensionsRecognized.add(ext.extensionName));
	extensionsUsed.forEach((extensionName) => {
		if (!extensionsRecognized.has(extensionName)) {
			logger.warn(`Extension "${extensionName}" not recognized by this tool.`);
		}
	});

Not sure if this belongs in CLI or core I/O.

Function to flatten node hierarchy, merge meshes

Plan —

  • (1) Add transformPrimitive(prim, matrix), transformMesh(mesh, matrix)
  • (2) Add clearNodeParent(node), clearNodeTransform(node). Requires (1).
    • Detaches node from its parent, applies world transform to node.mesh
    • #784
  • (3) Add document.transform(flatten()). Requires (1) and (2).
    • #790
    • Deletes unneeded empties (with options to keep them)
    • Keeps armatures
    • Clears parents and transforms of nodes where possible
  • (4) Add joinPrimitives(prim: Primitive[]).
  • (5) Add document.transform(join()). Requires (1), (2), (3), (4).
    • Assumes node hierarchy has already been flattened as desired, using (3).
    • Joins all compatible meshes that are siblings in the scene hierarchy.
    • Maximum vertex counts per draw? Spatial locality?
    • #658

Other considerations —

  • Update IBMs if node is a joint?
  • clearNodeTransform must warn on attached camera or light
  • Apply world transforms to TRS animations?
  • Apply world transforms to volumetric properties?
  • Detach shared vertex streams? Deal with detached accessors?

CLI 'inspect' command can list only extensions it recognizes.

Ideally it would print the first table with basic information it can get from a NativeDocument, before trying to parse and showing the error. The other tables could be omitted.

I think this requires editing the i/o classes a bit, so that they have methods to create a NativeDocument from a URI, and convert that to a Document as a second step.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.