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

Error when serializing non-three.js object that contains three.js objects #10236

Closed
3 of 12 tasks
JaredHays opened this issue Nov 28, 2016 · 7 comments
Closed
3 of 12 tasks

Comments

@JaredHays
Copy link

JaredHays commented Nov 28, 2016

(*** This section is for bug reports and feature requests only. This is NOT a help site. Do not ask help questions here. If you need help, please use stackoverflow. ***)

Description of the problem

I have a graph structure (created with graphlib: https://github.com/cpettitt/graphlib) containing multiple objects as nodes, each of which contains a THREE.Mesh as a value; each Mesh references a shared TorusGeometry and MeshPhongMaterial.

Attempting to serialize the graph object using JSON.stringify (both with and without using graphlib's serialization functionality first) results in an error similar to this:

three.js:11083 Uncaught TypeError: Cannot read property '6D3A1274-77BB-4ED2-A74D-B088157E1021' of undefined(…)

The property string appears to be a geometry UUID being passed to:

if ( meta.geometries[ this.geometry.uuid ] === undefined ) {...}

However, meta is undefined, because toJSON is being passed in a meta value of "mesh" rather than the expected empty string (ref. #8428 and the comment on three.js line 11038). JSON.stringify immediately jumps into toJSON, so I cannot figure out where this string is being created/passed. The graph object has the structure described below. The only place where "mesh" is used is as a property name for a THREE.Mesh value, but it's still unclear to me why toJSON would receive the string "mesh" rather than the appropriate meta object.

Attempting to serialize a single Ring object (which contains a THREE.Mesh as a property) results in the same error. Serializing only the Mesh object succeeds with no error, so it appears to only be an issue when the Mesh is held by another object.

graph: Object edges: Array[1344] [0 … 99] 0: Object name: "top-left" v: "ring-0" value: "top-left" w: "ring-1" __proto__: Object ... [100 … 199] [200 … 299] [300 … 399] [400 … 499] [500 … 599] [600 … 699] [700 … 799] [800 … 899] [900 … 999] [1000 … 1099] [1100 … 1199] [1200 … 1299] [1300 … 1343] length: 1344 __proto__: Array[0] nodes: Array[379] [0 … 99] 0: Object v: "ring-0" value: Ring geometryIndex: 0 isInCamera: (frustum) mesh: Mesh nodeID: "ring-0" nodeIndex: 0 ringIndex: 0 updated: false __proto__: Object __proto__: Object ... [100 … 199] [200 … 299] [300 … 378] length: 379 __proto__: Array[0] options: Object compound: false directed: true multigraph: true __proto__: Object __proto__: Object

Three.js version
  • Dev
  • r82
  • r81 (checked r82 release notes, did not see any changes that appeared related)
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • Linux
  • Android
  • IOS
Hardware Requirements (graphics card, VR Device, ...)
@JaredHays
Copy link
Author

I'm happy to go ask on SO, but how is failing to serialize three.js objects when they're owned by a parent object not a bug?

@mrdoob
Copy link
Owner

mrdoob commented Nov 28, 2016

That's a longer conversation. A conversation I'm happy to have when it's not framed as a bug.

@JaredHays
Copy link
Author

I would love to have that conversation with you somewhere.

In the meantime, I managed to get around the issue by implementing toJSON in the containing object so that it could call toJSON on the mesh with no parameters. I'm not sure if that's the intended solution, but it appears to work.

@makc
Copy link
Contributor

makc commented Nov 28, 2016

@JaredHays

it's still unclear to me why toJSON would receive the string "mesh" rather than the appropriate meta object.

because stupid browser passes key name to value.toJSON.

JSON.stringify immediately jumps into toJSON

that's true, not even replacer has a chance to run before it.

@mrdoob this behavior is (poorly, but) documented here:

If an object being stringified has a property named toJSON whose value is a function, then the toJSON() method customizes JSON stringification behavior: instead of the object being serialized, the value returned by the toJSON() method when called will be serialized.

so people are in their right to rely on it. what @JaredHays asks here is for toJSON to validate its input...

@makc
Copy link
Contributor

makc commented Nov 28, 2016

...e g in Object3D you change

var isRootObject = ( meta === undefined || meta === '' );

to

var isRootObject = ( meta === undefined || typeOf (meta) == 'string' );

@makc
Copy link
Contributor

makc commented Nov 28, 2016

@mrdoob > A conversation I'm happy to have when it's not framed as a bug.

what if it's framed as a PR + test case?

@mrdoob
Copy link
Owner

mrdoob commented Nov 29, 2016

what if it's framed as a PR + test case?

Even better!

makc added a commit to makc/three.js.fork that referenced this issue Nov 30, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants