-
-
Save donmccurdy/9f094575c1f1a48a2ddda513898f6496 to your computer and use it in GitHub Desktop.
#!/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}); |
@donmccurdy @mrdoob Really useful to work with Three outside of the browser. To get the above gist working in Node 18 a couple of tweaks are needed. Node 14 introduced a native Blob object and vblob exports global.Blob if present. However, the vblob FileReader expects a VBlob class to work properly. Workaround to force use of VBlob is to set global.Blob=null before importing the vblob module. But I guess this workaround may introduce issues if you rely on the Node Blob class for other purposes. Issue filed here: karikera/vblob#1
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.
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")
@sanghiad if you mean a three.js
THREE.Mesh
instance, then, sort of. A glTF file may have multiple meshes in it, or a combination of meshes and other things (materials, animations, lights, etc.). The typical way to turn all of that into three.js objects, including THREE.Mesh where appropriate, is THREE.GLTFLoader.If you mean turning a glTF file into some other file type, I would recommend using Blender or other 3D software to do conversions.