kovacsv / assimpjs

The emscripten interface for the assimp library that allows you to import 40+ 3D file formats in the browser.
MIT License
111 stars 18 forks source link

Ability to export an scene #1

Open frivas opened 2 years ago

frivas commented 2 years ago

Hello, it would be good if the library can export an scene, either created or imported from a file, to another format. For example import an fbx file and export it to glb.

The documentation states this can be done as follows:

bool exporterTest() override {
    ::Assimp::Importer importer;
    ::Assimp::Exporter exporter;
    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure);
    exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.obj");
    return true;
}

I have tried it

static bool exporterTest(const aiScene* scene) {
    Assimp::Exporter exporter;
    try {
        if (AI_SUCCESS == exporter.Export(scene, "glb", "spider_out.glb")) {
                std::cout << "Exporting file...";
            };
            return true;
    } catch (const std::exception& e) {
        std::cout << e.what();
        return false;
    }
}

However it is not writing the file to the filesystem.

I call this function from the ImportFileListByMainFile for the sake of testing.

Hopefully this can be done.

Thank you very much!

kovacsv commented 2 years ago

I've added the possibility to export to glb in release 0.0.6. Check out the demos, and replace assimpjson with glb2.

frivas-at-navteca commented 2 years ago

Hello again! I have progressed just a bit.

I realized I had the exporters were disabled. After enabling them, I tried with GLTF/GLB and this is what I got:

static bool createResultGlb(const aiScene* scene) {
    Assimp::Exporter *globalExporter;
    Assimp::Exporter exp;
    globalExporter = &exp;
    const aiReturn res = globalExporter->Export(scene, "glb2", "glb_export.glb");
    if (res != AI_SUCCESS) {
        printf("Failed to write file\n");
        printf("ERROR: %s\n", globalExporter->GetErrorString());
        return false;
    }
    return true;
}

It works with files with embedded textures and materials. I tried exporting an FBX with external textures and I think it needs some more work.

frivas-at-navteca commented 2 years ago

I've added the possibility to export to glb in release 0.0.6. Check out the demos, and replace assimpjson with glb2.

Oh! wow! Awesome timing! I will check it out definitely.

Thank you very much.

frivas-at-navteca commented 2 years ago

Hello, I have just tested using node_local_load_test.js with an FBX model and its 4 textures and despite changing the export format from assjson to gltf2 and seeing the result in the console. I managed to write the file using fs.writeFileSync("./converted/bmw.glb", resultFile.GetContent()); however the resulting file is not valid and can't read it in O3DV.

This is what I am executing:

let fs = require("fs");
const assimpjs = require("../dist/assimpjs.js")();

assimpjs.then((ajs) => {
  // create new file list object
  let fileList = new ajs.FileList();

  // add model files
  fileList.AddFile(
    "M4GT4.fbx",
    fs.readFileSync("../models/bmw-m4-dtm-2017/M4GT4.fbx")
  );
  fileList.AddFile(
    "2017_bmw_m4_dtm_cab.ptc.png",
    fs.readFileSync("../models/bmw-m4-dtm-2017/2017_bmw_m4_dtm_cab.ptc.png")
  );
  fileList.AddFile(
    "2017_bmw_m4_dtm_ext.ptc.png",
    fs.readFileSync("../models/bmw-m4-dtm-2017/2017_bmw_m4_dtm_ext.ptc.png")
  );
  fileList.AddFile(
    "2017_bmw_m4_dtm_misc.ptc.png",
    fs.readFileSync("../models/bmw-m4-dtm-2017/2017_bmw_m4_dtm_misc.ptc.png")
  );
  fileList.AddFile(
    "2017_bmw_m4_dtm_wheel.ptc.png",
    fs.readFileSync("../models/bmw-m4-dtm-2017/2017_bmw_m4_dtm_wheel.ptc.png")
  );
  fileList.AddFile(
    "internal_ground_ao_texture.jpeg",
    fs.readFileSync("../models/bmw-m4-dtm-2017/internal_ground_ao_texture.jpeg")
  );

  // convert file list to assimp json
  let result = ajs.ConvertFileList(fileList, "gltf2");

  // check if the conversion succeeded
  if (!result.IsSuccess() || result.FileCount() == 0) {
    console.log(result.GetErrorCode());
    return;
  }

  // get the result file, and convert to string
  let resultFile = result.GetFile(0);
  let jsonContent = new TextDecoder().decode(resultFile.GetContent());
  fs.writeFileSync("./converted/bmw.glb", resultFile.GetContent());

  // parse the result json
  let resultJson = JSON.parse(jsonContent);
  console.log(resultJson);
});

Any pointers to why this might be happening are appreciate it.

Thank you very much in advance!

kovacsv commented 2 years ago

I don't know if it's still relevant, but you should use glb2 instead of gltf2 to get a one-file binary glTF.

rawwerks commented 2 years ago

@kovacsv - from your drag and drop demo - i am able to get this to work: let result = ajs.ConvertFileList (fileList, 'gltf2');

but this does not work: let result = ajs.ConvertFileList (fileList, 'glb2');

maybe i need to treat the result differently since it is not text?

kovacsv commented 2 years ago

The gltf2 format builds up from multiple files, and the first one happens to be a json. This is why you see it working. The glb2 format is only one binary file, so it can't be treated as a json or text file.

rawwerks commented 2 years ago

@kovacsv - would you be willing to show an example of taking the glb2 output and turning that into a blob? i want put it into model-viewer.

kovacsv commented 2 years ago

For example you can just use the file system api in node.js to write it to a file:

let resultFile = result.GetFile (0);
fs.writeFileSync ("model.glb", resultFile.GetContent ());