-
-
Notifications
You must be signed in to change notification settings - Fork 35.2k
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
GLTFExporter: Prevent exporting empty geometry #13681
Conversation
@@ -484,6 +478,13 @@ THREE.GLTFExporter.prototype = { | |||
|
|||
} | |||
|
|||
// Skip creating an accessor if the attribute doesn't have data to export | |||
if ( count === 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: missing space after 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
@@ -1119,8 +1130,20 @@ THREE.GLTFExporter.prototype = { | |||
|
|||
} | |||
|
|||
if ( primitives.length === 0 ) { | |||
|
|||
return -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In processNode
we're returning null
when no node is created. Would probably vote for null
over -1
personally but either way let's make it consistent.
examples/misc_exporter_gltf.html
Outdated
empty.name = 'Custom buffered empty (drawrange)'; | ||
scene1.add( empty ); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about putting this case in GLTFExporter.tests.js
instead? I think that might be a better fit than in the example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah! I was thinking about it actually, but I didn't know we already had a GLTFExporter.tests.js
👼 I'll take a look and include it there thanks!
|
||
} | ||
|
||
if ( geometry.index !== null ) { | ||
// Skip meshes without exportable attributes | ||
if ( Object.keys(primitive.attributes).length > 0 ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need spaces after and before primitive.attributes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! done
return null; | ||
|
||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding
if ( Object.keys( attributes ).length === 0 ) {
return null;
}
after
for ( var attributeName in geometry.attributes ) {
....
}
above instead isn't good?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any use case where you could have just morph attributes but no other attribute?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, no. At least, glTF validator seems to raise MESH_PRIMITIVE_MORPH_TARGET_NO_BASE_ACCESSOR "No base accessor for this attribute semantic." error if corresponding attribute isn't in attributes
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah makes sense, added! thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. So I think you can remove this check here now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mrdoob I believe he's referring to this #13681 (review) right? /cc @takahirox
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. I think we can remove here
if ( primitives.length === 0 ) {
return null;
}
because we added above
if ( Object.keys( attributes ).length === 0 ) {
return null;
}
Or you care the case where groups
is an empty array? (In other words, how can primitives.length
be zero here?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could have buffer geometries without groups
eg: the sphere in the example https://github.com/mrdoob/three.js/blob/dev/examples/misc_exporter_gltf.html#L248 or a custom buffergeometry: https://github.com/mrdoob/three.js/blob/dev/examples/misc_exporter_gltf.html#L312-L337 but I haven't worked with multimaterial before so I'm not sure how that case would be handled here.
Because if you have one of the previous objects with a multimaterial.
var groups = isMultiMaterial ? mesh.geometry.groups : [ { materialIndex: 0, start: undefined, count: undefined } ];
groups
would be mesh.geometry.groups
that would be empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I confirmed rendering nothing for multi-material with empty groups.
So how about
if ( isMultiMaterial && mesh.geometry.groups.length === 0 ) return null;
it'd be more straightforward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@donmccurdy added unit test, although I can't get it running, are the examples test broken? I believe we should include three build on them or am I missing something? |
|
||
} | ||
|
||
if ( geometry.index !== null ) { | ||
// Skip meshes without exportable attributes | ||
if ( Object.keys( primitive.attributes ).length > 0 ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this check here now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch! removed!
@fernandojsg They should be able to run in the browser if you use |
@donmccurdy thanks! I've just fixed it and test passed ^_^ |
Thanks! |
I've just found a bug when exporting empty buffer geometries. eg in a-painter I create a buffer geometry for each kind of material but maybe I don't use one of them so drawRange will be 0. If you try to export it it will generate the following glTF:
The accessors has an invalid range and the bufferviews are empty.
This PR prevents it to happens by skipping attributes that has no values, and primitives that has no attributes, and meshes that has no primitives.
I added a empty node and a button to test it. The expected output for the previous example will be: