From 69e60061d46f753aab5dda76de289f64e83cc2b2 Mon Sep 17 00:00:00 2001 From: Elouan Poupard-Cosquer Date: Thu, 28 May 2020 18:42:04 +0200 Subject: [PATCH 1/2] feat: integrate the blender script --- src/config.ts | 4 +-- src/convert.py | 47 ++++++++++++++++++++++++++++++++++ src/index.ts | 68 +++++++++++++++++++++++++++++++------------------- 3 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 src/convert.py diff --git a/src/config.ts b/src/config.ts index 545a3a0..c9ecd46 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,9 +1,9 @@ export interface IChuckIfcConfig { - ifcConvertPath: string; + blenderPath: string; } const config: IChuckIfcConfig = { - ifcConvertPath: process.env.CHUCK_IFC_IFCCONVERTPATH || 'IfcConvert' + blenderPath: process.env.CHUCK_BLENDER_BLENDERPATH || 'blender' }; export default config; diff --git a/src/convert.py b/src/convert.py new file mode 100644 index 0000000..b192c88 --- /dev/null +++ b/src/convert.py @@ -0,0 +1,47 @@ +import sys +import bpy + +# -- STEP Import -- + +# Dependencies : +# - https://gumroad.com/l/stepper +# - https://blenderartists.org/t/step-import/1203804/199 + +# How we proceed: +# 1. First, we use the very good plugin by ambi: https://gumroad.com/l/stepper +# 2. Then, we use a second one by vink to take the color from the vertices and put them as material +# 3. Finally, we export the file as FBX + +# 0. Extract the src/dest paths. +# The argv look like this. We don't care about whats before the "--" +# blender -b --python .\step_to_fbx.py -- "Source (STEP)/LUMINAIRE AIRLIE N°1 PORTE.stp" "Blender (FBX)/LUMINAIRE AIRLIE N°1 PORTE.fbx" +argv = sys.argv +separator_index = argv.index("--") +src = None +dest = None + +if separator_index and len(argv) >= separator_index + 3: + argv = argv[separator_index + 1:] + src = argv[0] + dest = argv[1] + +if src is None or dest is None: + print('\nYou must provide the file to process and the destination folder like this:', file=sys.stderr) + print('> blender -b --python .\step_to_fbx.py -- "Source (STEP)/LUMINAIRE AIRLIE N°1 PORTE.stp" "Blender (FBX)"', file=sys.stderr) + exit(1) + +# And remove the cube, while we're at it +print('\nRemoving the damn cube...') +bpy.ops.object.delete() + +# 1. Import the STEP file +print('\nSTEP import starting... \'' + src + '\'') +bpy.ops.import_scene.occ_import_step(filepath=src) + +# 2. Vertex color => materials +bpy.ops.wi_cadtools.vertexc_mat() + +# 3. Export as FBX +bpy.ops.export_scene.fbx(filepath = dest, use_selection = True) + +print('\nFinished!') diff --git a/src/index.ts b/src/index.ts index 4f8c067..ec9794e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,57 +5,75 @@ import * as os from 'os'; import * as path from 'path'; import config from './config'; -export interface IExecIfcStepsContext extends IDownloadAssetsStepsContext { +export interface IExecBlenderStepsContext extends IDownloadAssetsStepsContext { convertedAssetsDir: string; } export function describe(): IStepDescription { return { - code: 'exec-ifcopenshell', - name: 'Execute IfcOpenShell to convert IFC files into Collada files', + code: 'exec-blender', + name: 'Execute Blender to convert STEP files into FBX files', priority: 11, // after assets download }; } -export function shouldProcess(conv: IConversion, context: IExecIfcStepsContext) { +/** + * The predicate to process only STEP/STP files + * @param path + */ +function isStep(path: string) { + const lowerCasePath = path.toLowerCase(); + return lowerCasePath.endsWith('.step') || lowerCasePath.endsWith('.stp'); +} + +export function shouldProcess(conv: IConversion, context: IExecBlenderStepsContext) { + console.log(context, context.assetsPaths.some(isStep)); return context.assetsPaths && context.assetsPaths.length && - context.assetsPaths.some(assetPath => assetPath.toLowerCase().endsWith('.ifc')); + context.assetsPaths.some(isStep); } -export async function process(conv: IConversion, context: IExecIfcStepsContext, progress: ProgressFn): Promise { +export async function process(conv: IConversion, context: IExecBlenderStepsContext, progress: ProgressFn): Promise { //=> Create a temporary folder for the assets - const tmpDir = path.resolve(`${os.tmpdir()}/chuck/exec-ifcopenshell-${Date.now()}`); + const tmpDir = path.resolve(`${os.tmpdir()}/chuck/exec-blender-${Date.now()}`); await fs.mkdirp(tmpDir); context.convertedAssetsDir = tmpDir; const convertOptions = conv.conversionOptions; //=> Execute each conversion sequentially - // @todo If IfcConvert is mono-threaded, we could make it concurrent + // @todo If Blender is mono-threaded, we could make it concurrent for (const assetPath of context.assetsPaths) { - if (assetPath.toLowerCase().endsWith('.ifc')) { - await progress('convert-start', `Converting "${assetPath}" from IFC to Collada`); + if (isStep(assetPath)) { + await progress('convert-start', `Converting "${assetPath}" from STEP to FBX`); await convertAndStoreAssets(convertOptions, context, assetPath); } } } -export async function cleanup(context: IExecIfcStepsContext): Promise { +export async function cleanup(context: IExecBlenderStepsContext): Promise { await fs.remove(context.convertedAssetsDir); } async function convertAndStoreAssets( convertOptions: string[], - context: IExecIfcStepsContext, - ifcFilePath: string + context: IExecBlenderStepsContext, + stepFilePath: string ): Promise { - const colladaFileName = path.parse(ifcFilePath).name + '.dae'; - const colladaFilePath = path.resolve(`${context.convertedAssetsDir}/${colladaFileName}`); + const fbxFileName = path.parse(stepFilePath).name + '.fbx'; + const fbxFilePath = path.resolve(`${context.convertedAssetsDir}/${fbxFileName}`); - const spawnArgs = [ifcFilePath, colladaFilePath, '-y'].concat(convertOptions); + // Expected command: + // blender -b --python .\step_to_fbx.py --python-exit-code 1 -- "path/file.stp" "path/file.fbx" + const spawnArgs = [ + '-b', + '--python', path.join(__dirname, '..', 'src', 'convert.py').toString(), + '--python-exit-code', '1', + '--', + stepFilePath, + fbxFilePath].concat(convertOptions); - const converterProcess = spawn(config.ifcConvertPath, spawnArgs); + const converterProcess = spawn(config.blenderPath, spawnArgs); //=> Watch process' stdout to log in real time, and keep the complete output in case of crash let stdoutAggregator = ''; @@ -70,22 +88,22 @@ async function convertAndStoreAssets( //=> Watch for the process to terminate, check return code converterProcess.once('close', (code) => { if (code !== 0) { - const message = `Conversion of IFC file ${path.basename(ifcFilePath)} to Collada has failed!`; - return reject(new IfcConvertCrashError(message, stdoutAggregator)); + const message = `Conversion of STEP file ${path.basename(stepFilePath)} to FBX has failed!`; + return reject(new BlenderCrashError(message, stdoutAggregator)); } - const index = context.assetsPaths.findIndex(path => path === ifcFilePath); - context.assetsPaths[index] = colladaFilePath; + const index = context.assetsPaths.findIndex(path => path === stepFilePath); + context.assetsPaths[index] = fbxFilePath; - resolve(colladaFilePath); + resolve(fbxFilePath); }); }); } -export class IfcConvertCrashError extends Error { - constructor(message: string, public readonly ifcConvertLog: string) { +export class BlenderCrashError extends Error { + constructor(message: string, public readonly BlenderLog: string) { super(message); - Object.setPrototypeOf(this, IfcConvertCrashError.prototype); + Object.setPrototypeOf(this, BlenderCrashError.prototype); } } From c4cc2cee7499385068912e1979592f274727bd84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 May 2020 16:44:12 +0000 Subject: [PATCH 2/2] chore(deps): bump constantinople from 3.1.0 to 3.1.2 Bumps [constantinople](https://github.com/ForbesLindesay/constantinople) from 3.1.0 to 3.1.2. - [Release notes](https://github.com/ForbesLindesay/constantinople/releases) - [Commits](https://github.com/ForbesLindesay/constantinople/compare/3.1.0...3.1.2) Signed-off-by: dependabot[bot] --- yarn.lock | 71 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/yarn.lock b/yarn.lock index 462886a..0c16340 100644 --- a/yarn.lock +++ b/yarn.lock @@ -83,6 +83,16 @@ dependencies: compose-middleware "^2.2.0" +"@types/babel-types@*", "@types/babel-types@^7.0.0": + version "7.0.7" + resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.7.tgz#667eb1640e8039436028055737d2b9986ee336e3" + +"@types/babylon@^6.16.2": + version "6.16.5" + resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4" + dependencies: + "@types/babel-types" "*" + "@types/dotenv@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/dotenv/-/dotenv-4.0.0.tgz#bd458844cb82ada047fa87a475270ad55492d2d4" @@ -140,7 +150,7 @@ acorn-globals@^3.0.0: dependencies: acorn "^4.0.4" -acorn@^3.1.0, acorn@~3.3.0: +acorn@^3.1.0: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" @@ -326,6 +336,26 @@ babel-runtime@^6.22.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + balanced-match@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" @@ -639,11 +669,13 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" constantinople@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.0.tgz#7569caa8aa3f8d5935d62e1fa96f9f702cd81c79" + version "3.1.2" + resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.2.tgz#d45ed724f57d3d10500017a7d3a889c1381ae647" dependencies: - acorn "^3.1.0" - is-expression "^2.0.1" + "@types/babel-types" "^7.0.0" + "@types/babylon" "^6.16.2" + babel-types "^6.26.0" + babylon "^6.18.0" content-disposition@0.5.2: version "0.5.2" @@ -691,8 +723,8 @@ copy@^0.3.0: to-file "^0.2.0" core-js@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" core-util-is@^1.0.1, core-util-is@~1.0.0: version "1.0.2" @@ -913,8 +945,8 @@ esprima@~3.1.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" etag@~1.7.0: version "1.7.0" @@ -1580,13 +1612,6 @@ is-descriptor@^0.1.0: kind-of "^3.0.2" lazy-cache "^2.0.2" -is-expression@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-2.1.0.tgz#91be9d47debcfef077977e9722be6dcfb4465ef0" - dependencies: - acorn "~3.3.0" - object-assign "^4.0.1" - is-expression@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-3.0.0.tgz#39acaa6be7fd1f3471dc42c7416e61c24317ac9f" @@ -1928,10 +1953,14 @@ lodash@3.10.x, lodash@^3.10.1, lodash@^3.6.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.16.3, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.8.2: +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.16.3, lodash@^4.3.0, lodash@^4.8.2: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +lodash@^4.17.4: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + lodash@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.3.1.tgz#a4663b53686b895ff074e2ba504dfb76a8e2b770" @@ -2749,6 +2778,10 @@ regenerator-runtime@^0.10.0: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + regexp-clone@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-0.0.1.tgz#a7c2e09891fdbf38fbb10d376fb73003e68ac589" @@ -3205,6 +3238,10 @@ through@2, through@~2.3, through@~2.3.1, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + to-file@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/to-file/-/to-file-0.2.0.tgz#236c6c088065e570defbd15cf4b4e565be46ea93"