Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3MF loader: Cannot read properties of undefined (reading 'target') #27947

Closed
nmattia opened this issue Mar 19, 2024 · 10 comments
Closed

3MF loader: Cannot read properties of undefined (reading 'target') #27947

nmattia opened this issue Mar 19, 2024 · 10 comments
Labels
Milestone

Comments

@nmattia
Copy link
Contributor

nmattia commented Mar 19, 2024

Description

I'm getting an error upon loading a 3MF file. I'm not 100% sure the 3MF file is well formed, but it loads fine in PrusaSlicer.

Here's the error:

 TypeError: Cannot read properties of undefined (reading 'target')
    at build (three_addons_loaders_3MFLoader__js.js?v=26fa96fd:2537:52)
    at ThreeMFLoader.parse (three_addons_loaders_3MFLoader__js.js?v=26fa96fd:2551:12)
    at Object.onLoad (three_addons_loaders_3MFLoader__js.js?v=26fa96fd:1732:22)
    at chunk-3F2VCGLV.js?v=26fa96fd:25871:20
(anonymous) @ three_addons_loaders_3MFLoader__js.js?v=26fa96fd:1737
(anonymous) @ chunk-3F2VCGLV.js?v=26fa96fd:25871
Promise.then (async)
load @ chunk-3F2VCGLV.js?v=26fa96fd:25864
load @ three_addons_loaders_3MFLoader__js.js?v=26fa96fd:1730

The 3MF has a single (manifold-3d) mesh and was exported using 3mf-export. Let me know if I should instead report the error there.

This is where the debugger places it:

function build(objects2, data3mf2) {
      const group = new Group();
      const relationship = fetch3DModelPart(data3mf2["rels"]); // This seems to be undefined
      const buildData = data3mf2.model[relationship["target"].substring(1)]["build"];
      for (let i = 0; i < buildData.length; i++) {
        const buildItem = buildData[i];
        const object3D = objects2[buildItem["objectId"]].clone();
        const transform = buildItem["transform"];
        if (transform) {
          object3D.applyMatrix4(transform);
        }
        group.add(object3D);
      }
      return group;
    }

GitHub won't let me upload a 3MF so I renamed it to .zip. See code below for a base64-encoded version.
repro.zip

Thank you for three.js!!!

Code

import { ThreeMFLoader } from "three/addons/loaders/3MFLoader.js";

const loader = new ThreeMFLoader();

const data = "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";

const mime = "application/vnd.ms-package.3dmanufacturing-3dmodel+xml";

const url = `data:${mime};base64,${data}`;

loader.load(url, () => {})

Live example

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 20, 2024

It seems something in your 3MF asset is missing. Normally, there should be a relationship definition that points to the 3D payload. All test assets in our repository have such a definition. The 3MF spec says:

The 3MF Document StartPart relationship MUST point to the 3D Model part that identifies the root of the 3D payload.

If you rename one of the assets in this repo (e.g. cube_gears.3mf) to zip and unpack it, you can see a _rels folder with a .rels file holding relationship information. The directory as well as the file is missing in your asset.

Maybe the exported 3MF is not 100% spec compliant?

@nmattia
Copy link
Contributor Author

nmattia commented Mar 20, 2024

@Mugen87 thanks, I thought it might be (though maybe we could improve the error)

@hrgdavor is this a 3mf-export error or more of a user error? edit: see also the 3mf-export example. This is the shortest thing I could get 3mf-export to work with, but while trying to simplify I might have gone too far:

import { to3dmodel } from "@jscadui/3mf-export";  

const to3mf: To3MF = {
    meshes: [],
    components: [],
    items: [],
    precision: 7,

    header: {
      unit: "millimeter",
      title: "...",
      description: "...",
      application: "...",
    },
  };

  to3mf.meshes.push({ vertices: someVertices, indices: someIndices, id: "0" });
  to3mf.items.push({ objectID: "0" });

  const model = to3dmodel(to3mf);

  const files: Zippable = {};
  files["3D/3dmodel.model"] = strToU8(model);
  const zipFile = zipSync(files);

If this is a 3mf-export error, where is the best place to create a ticket?

edit: probably here

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 20, 2024

const files: Zippable = {};
files["3D/3dmodel.model"] = strToU8(model);
const zipFile = zipSync(files);

To clarify: The problem is that the zip file you are creating does not contain the _rels folder with a .rels file. This is required to load the 3MF asset with three.js.

@nmattia
Copy link
Contributor Author

nmattia commented Mar 20, 2024

To clarify: The problem is that the zip file you are creating does not contain the _rels folder with a .rels file. This is required to load the 3MF asset with three.js.

Right, sorry I wasn't clear. I was/am not sure whether the _rels/ is part of the spec or not: if _rels/ is part of the 3MF spec then 3mf-export should probably call out to it. If it's not part of the spec, and ThreeMFLoader expects it, then it should probably be mentioned (that being said I could not find any docs for ThreeMFLoader, just a forum post).

From a quick look at the spec I could not find any mentions of the rels/ folder, and as mentioned PrusaSlicer seems to load the problematic 3MF just fine.

I have no experience with 3MF beyond basic export/import workflows, apologies if the solution is obvious!

@hrgdavor
Copy link

hrgdavor commented Mar 20, 2024

@nmattia you are missing const fileForRelThumbnail = new FileForRelThumbnail() from that example.

that is the generator for the mentioned _rels/.rels file ... I know name mentions thumbnail, but you need this even if you do not generate thumbnail.

// give the location of the 3d model
fileForRelThumbnail.add3dModel('3D/3dmodel.model')

I would advise to add also add the file for content types to make sure you are closer to spec

let staticFiles = [fileForContentTypes, fileForRelThumbnail]
staticFiles.forEach(({ name, content }) => addToZip(zip, name, content))

@nmattia
Copy link
Contributor Author

nmattia commented Mar 20, 2024

@hrgdavor ah, indeed I skipped that one because I thought it was thumbnail-related!

Thanks to both of you for the help. @Mugen87 should I still submit a PR to throw an error if the file is not found?

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 20, 2024

Yes that would be great! Handling the error situation more gracefully than before makes sense.

@WestLangley
Copy link
Collaborator

three.js does not do error handling for invalid inputs. That would be a slippery slope.

This is a user error.

@nmattia
Copy link
Contributor Author

nmattia commented Mar 20, 2024

@WestLangley I've just thrown a clearer error: #27955

No hard feelings if you close without merging!

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 20, 2024

In certain use cases we do validate things and I believe in this use case it makes absolutely sense. So I'm much in favor of the PR.

@Mugen87 Mugen87 closed this as completed Mar 21, 2024
@Mugen87 Mugen87 added this to the r163 milestone Mar 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants