Problem with GLTF2export on Nodejs with Nullengine

I want to combine different glb files to one to dynamically combine different 3d rooms into one. I’m doing this on server side with the Nullengine. If I want to export the scene the result is empty { glTFFiles: { 'Test.glb': {} } }. If I execute the same code on client side it works so I guess this is a bug. This is my complete code:

BABYLON = require('babylonjs');
var LOADERS = require('babylonjs-loaders');
require('babylonjs-serializers');
var fs = require('fs');
global.XMLHttpRequest = require('xhr2').XMLHttpRequest;

var createScene = function() {
  var scene = new BABYLON.Scene(engine);
  var camera = new BABYLON.FlyCamera('FlyCamera', new BABYLON.Vector3(0, 5, -10), scene);
  camera.setTarget(BABYLON.Vector3.Zero());
  var light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene);

  BABYLON.SceneLoader.ImportMesh('', 'http://localhost:9966/', 'SceneTest.glb', scene, function(meshes) {
    for (var index = 0; index < meshes.length; index++) {
      var mesh = meshes[index];
      if (mesh.name === '__root__') {
        var axis = new BABYLON.Vector3(0, 1, 0);
        axis.normalize();
        var theta = Math.PI / 2;

        mesh.rotationQuaternion = new BABYLON.Quaternion.RotationAxis(axis, theta);

        mesh.position = new BABYLON.Vector3(-10, 0, 0);
      }
    }
  });

  BABYLON.SceneLoader.ImportMesh('', 'http://localhost:9966/SceneTest.glb', null, scene, function(
    meshes
  ) {});

  return scene;
};
var engine = new BABYLON.NullEngine();
var scene = createScene();

BABYLON.GLTF2Export.GLBAsync(scene, 'Test.glb').then(data => {
  console.log(data);
});

engine.runRenderLoop(function() {
  if (scene) {
    scene.render();
  }
});

Hi BumbleBeeBro,

Welcome to Babylon!

I don’t have an easy way to run your code, but this looks like an async issue. ImportMesh is an asynchronous function, so the code you’ve written there won’t actually be executed in the order it appears on the page. I think what’s happening is that your calls to ImportMesh are being executed, which starts the import process, but execution is continuing without waiting for the import to succeed. Execution then reaches the GLBAsync call and tries to export the scene, but the scene is still empty because the import process is ongoing.

If that’s the issue, you can fix it in a number of ways (callbacks, Promises, etc.), but probably the cleanest way will be to use the async-await syntax described in the first link I pasted above. You can declare your createScene function to be async, then await your ImportMesh calls, then await createScene(), and so on until your code has the execution order you’re going for.

1 Like

I changed the code to to await everything, but the exported data is still not there. Im not sure what else to do. This is my tested code:
const BABYLON = require(‘babylonjs’);
require(‘babylonjs-loaders’);
const SERIALIZER = require(‘babylonjs-serializers’);
const fs = require(‘fs’);
global.XMLHttpRequest = require(‘xhr2’).XMLHttpRequest;

var createScene = async function() {
  var scene = new BABYLON.Scene(engine);
  var camera = new BABYLON.FlyCamera('FlyCamera', new BABYLON.Vector3(0, 5, -10), scene);
  camera.setTarget(BABYLON.Vector3.Zero());
  var light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene);

  const meshes = await new Promise(resolve =>
    BABYLON.SceneLoader.ImportMesh('', 'http://localhost:9966/', 'SceneTest.glb', scene, resolve)
  );

  for (var index = 0; index < meshes.length; index++) {
    var mesh = meshes[index];
    if (mesh.name === '__root__') {
      var axis = new BABYLON.Vector3(0, 1, 0);
      axis.normalize();
      var theta = Math.PI / 2;

      mesh.rotationQuaternion = new BABYLON.Quaternion.RotationAxis(axis, theta);

      mesh.position = new BABYLON.Vector3(-10, 0, 0);
    }
  }

  await new Promise(resolve =>
    BABYLON.SceneLoader.ImportMesh('', 'http://localhost:9966/', 'SceneTest.glb', scene, resolve)
  );

  return scene;
};

async function awaitCall() {
  var scene = await createScene();
  const data = await SERIALIZER.GLTF2Export.GLBAsync(scene, 'Test.glb');
  console.log(data);
}

var engine = new BABYLON.NullEngine();

awaitCall();

This is not a promise function so it won’t work

You must use ImportMeshAsync()