Skip to content

Instantly share code, notes, and snippets.

@donmccurdy
Last active January 15, 2025 22:26
Show Gist options
  • Save donmccurdy/9f094575c1f1a48a2ddda513898f6496 to your computer and use it in GitHub Desktop.
Save donmccurdy/9f094575c1f1a48a2ddda513898f6496 to your computer and use it in GitHub Desktop.
Example Node.js glTF conversion script, using three.js.
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const THREE = require('three');
const program = require('commander');
const Canvas = require('canvas');
const { Blob, FileReader } = require('vblob');
// Patch global scope to imitate browser environment.
global.window = global;
global.Blob = Blob;
global.FileReader = FileReader;
global.THREE = THREE;
global.document = {
createElement: (nodeName) => {
if (nodeName !== 'canvas') throw new Error(`Cannot create node ${nodeName}`);
const canvas = new Canvas(256, 256);
// This isn't working — currently need to avoid toBlob(), so export to embedded .gltf not .glb.
// canvas.toBlob = function () {
// return new Blob([this.toBuffer()]);
// };
return canvas;
}
};
// https://github.com/mrdoob/three.js/issues/9562
require('three/examples/js/exporters/GLTFExporter');
program
.version('0.0.1')
.usage('[options] <file>')
.option('-o, --output <file>', 'output filename', String)
// .option('-b, --binary', 'use binary (.glb) format (default false)')
.option('-m, --myoption', 'my custom option (default 1.0)', Number)
.parse(process.argv);
program.binary = !!program.binary;
program.myoption = program.myoption || 1;
const inputPath = program.args[0];
if (!inputPath) { program.help(); }
if (!program.output) {
program.output = path.basename(inputPath, '.foo');
program.output += program.binary ? '.glb' : '.gltf';
}
console.log(' → input: %j', program.args);
console.log(' → output: %j', program.output);
console.log(' → binary: %j', program.binary);
console.log(' → my custom option: %j', program.myoption);
console.log(`Loading "${inputPath}"`);
let mesh = new THREE.Mesh(...); // (load or create mesh here)
console.log('Converting to glTF');
const exporter = new THREE.GLTFExporter();
exporter.parse(mesh, (content) => {
console.log(`Writing to ${program.output}`);
if (typeof content === 'object') content = JSON.stringify(content);
fs.writeFileSync(program.output, content);
}, {binary: program.binary});
@dirkk0
Copy link

dirkk0 commented Jan 7, 2025

I am working on a 3D editor with nw.js. The editor part is 'normal' JS with THREE.js and right now I am using nw.js only to write the file to a specific directory. From that, I can report that

const exporter = new GLTFExporter()
exporter.parse(
  scene,
  function (gltf) {
    const destinationFolder = path.join(require("os").homedir(), "Documents")
    const filepath = path.join(destinationFolder, "example.gltf")
    fs.writeFileSync(filepath, JSON.stringify(gltf))
  },
  { binary: true }
)

properly exports gltf including textures.

@DanielAtCosmicDNA
Copy link

Hi. I was able to reduce it a little bit further:

Foo2Gltf.mjs:

import { writeFileSync } from 'fs';
import { basename } from 'path';
import { GLTFExporter }  from 'three/examples/jsm/exporters/GLTFExporter.js'
import { FileReader } from 'vblob';

// Patch global scope to imitate browser environment.
global.FileReader = FileReader;

const exportMeshToGLTF = (mesh, outputPath, options = { binary: false }) => {
  // Create an instance of the GLTFExporter
  const exporter = new GLTFExporter();

  // Define the output file name
  let output = outputPath;
  if (!output) {
    output = basename('output', '.foo');
    output += options.binary ? '.glb' : '.gltf';
  }

  console.log('Converting to glTF');
  exporter.parse(
    mesh,
    (content) => {
      console.log(`Writing to ${output}`);
      if (typeof content === 'object') content = JSON.stringify(content);
      writeFileSync(output, content);
      console.log('GLTF file has been saved.');
    },
    options
  );
};

export default exportMeshToGLTF;

and usage is:

index.mjs:

import { MeshBasicMaterial, BoxGeometry, Mesh } from 'three'
import exportMeshToGLTF from './Foo2Gltf.mjs';

// Create a geometry, for example, a box geometry
const geometry = new BoxGeometry();
const material = new MeshBasicMaterial({ color: 0x00ff00 });
const mesh = new Mesh(geometry, material);

exportMeshToGLTF(mesh, "cube.gltf")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment