42 lines
2.3 KiB
JavaScript
42 lines
2.3 KiB
JavaScript
#!/usr/bin/env node
|
||
import { spawn } from 'node:child_process';
|
||
import { access } from 'node:fs/promises';
|
||
import path from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
|
||
const args = process.argv.slice(2);
|
||
if (!args.length || args.includes('--help')) {
|
||
console.log(`Usage: npm run blender:export -- INPUT.blend --output OUTPUT.glb [options]
|
||
--blender PATH Blender binary (or FORMA_BLENDER; default: blender)
|
||
--scene NAME Scene to export
|
||
--objects GLOB Export matching objects; repeat for several patterns
|
||
--bake-materials Bake procedural/animated surface inputs to UV atlases
|
||
--resolution 128 Pixels per baked frame, 16–1024
|
||
--samples 8 Cycles samples per bake, 1–256
|
||
--lighting compat Unitless lights for Forma; spec preserves physical units
|
||
--start-frame N --end-frame N --frame-step N
|
||
--allow-lossy Accept approximations listed in OUTPUT.report.json
|
||
See docs/BLENDER.md for supported features and limitations.`);
|
||
process.exit(args.length ? 0 : 1);
|
||
}
|
||
const input = path.resolve(args.shift());
|
||
if (!/\.blend$/i.test(input)) throw Error('Input must be a .blend file');
|
||
await access(input);
|
||
const binaryFlag = args.indexOf('--blender');
|
||
let binary = process.env.FORMA_BLENDER || 'blender';
|
||
if (binaryFlag >= 0) {
|
||
if (!args[binaryFlag + 1]) throw Error('--blender requires a path');
|
||
binary = args[binaryFlag + 1]; args.splice(binaryFlag, 2);
|
||
}
|
||
const outputFlag = args.indexOf('--output');
|
||
if (outputFlag < 0 || !args[outputFlag + 1] || !/\.glb$/i.test(args[outputFlag + 1])) throw Error('--output OUTPUT.glb is required');
|
||
const output = path.resolve(args[outputFlag + 1]);
|
||
if (output === input) throw Error('Output must differ from input');
|
||
args[outputFlag + 1] = output;
|
||
const script = fileURLToPath(new URL('../blender/export_forma.py', import.meta.url));
|
||
const child = spawn(binary, ['--background', '--factory-startup', '--disable-autoexec', input, '--python-exit-code', '1', '--python', script, '--', ...args], { stdio: 'inherit', shell: false });
|
||
child.on('error', error => { console.error(`Cannot start Blender: ${error.message}. Set FORMA_BLENDER or --blender.`); process.exitCode = 1; });
|
||
child.on('exit', (code, signal) => { process.exitCode = code ?? (signal ? 1 : 0); });
|
||
process.once('SIGINT', () => child.kill('SIGINT'));
|
||
process.once('SIGTERM', () => child.kill('SIGTERM'));
|