Page MenuHome

Export/STL: Add option to export objects in custom frame
AbandonedPublic

Authored by Campbell Barton (campbellbarton) on Jun 5 2021, 7:41 PM.

Details

Summary

Added an option to allow the user to export STLs using an arbitrary (custom) coordinate-space.

This is not exposed in the UI and is intended for script authors exporting content.


Problem
The current (3.1 official release) STL export tool is only able to export meshes using the global coordinate frame. For certain applications (creating URDF/SDF/MJCF files for robotics simulation tools) it is much easier to deal with meshes exported in the object's local coordinate frame.

Solution
Add an optional argument to the STL Export Python Operation to allow the user to choose a custom coordinate frame in which to export their object(s). If left unassigned, defaults to the old (global) behavior.

This argument is a FloatVectorProperty with subtype Matrix.

Diff Detail

Event Timeline

Jay Jasper (Jay_J) requested review of this revision.Jun 5 2021, 7:41 PM
Jay Jasper (Jay_J) created this revision.

Adding Campbell Barton as reviewer since he shows up frequently in the history for these files.

Campbell Barton (campbellbarton) requested changes to this revision.EditedJul 21 2021, 4:02 PM

Discussed in blender chat, summarizing here.

Firstly ignoring object matrices seems error prone since it's likely to make objects overlap in strange ways. Although this could make some sense for batch-export (one file per object).

Further, it seems like a feature that's specific to your workflow, not a generic feature we would support in all exporters.

This doesn't mean features like this can't be supported, it just means I don't think it's reasonable to expose this along with other options in the UI.


I'd suggest to add a global_space 4x4 matrix property to the exporter. This can be hidden from the UI and used in scripts.

It may be useful to export collection instances with the empty defining the world-center, or the root parent of an object hierarchy could be used in a similar way.

This keeps the UI from being cluttered with overly spesific options and gives technical users flexibility of writing files in coordinates they define.

Then there is also no reason this cant be supported by other exporters too.

This revision now requires changes to proceed.Jul 21 2021, 4:02 PM
Jay Jasper (Jay_J) retitled this revision from Export/STL: Add option to export objects in their local frame to Export/STL: Add option to export objects in custom frame.
Jay Jasper (Jay_J) edited the summary of this revision. (Show Details)

Per Campbell's request, removed the GUI elements and changed from "use object's local frame" approach to "use this custom frame" (which defaults to global; the old behavior). The custom frame is a FloatVectorProperty with subtype Matrix. Inversion and order of matrix multiplications are set so feeding in obj.matrix_world will result in using that object's local coordinate frame. Updated the diff summary to reflect this.

One aspect I am unsatisfied with but feel out of my depth to see what I am doing wrong (or fix) is that the user has to manually flatten a Matrix (4x4) into a list (16x1) in order for the operation to accept the custom frame input.

obj = bpy.context.selected_objects[0]
frame = []
for i in range(4):
    for j in range(4):
        frame.append(obj.matrix_world[j][i])
bpy.ops.export_mesh.stl(filepath=bpy.path.abspath("//test.stl"), global_space=frame )

If this flattening is not performed, then an error is returned:

bpy.ops.export_mesh.stl(filepath=bpy.path.abspath("//test.stl"), global_space=obj.matrix_world.copy() )
...
Traceback (most recent call last):
  File "/home/jjasper/Desktop/test_export.blend/export by script", line 20, in <module>
  File "/home/jjasper/blender-git/build_linux/bin/3.0/scripts/modules/bpy/ops.py", line 132, in __call__
    ret = _op_call(self.idname_py(), None, kw)
ValueError: Converting py args to operator properties:  EXPORT_MESH_OT_stl.global_space, matrix assign array with 1 dimensions

This error is called in bpy_rna_array.c:387, in the function validate_array(). Assuming I'm not making a dumb mistake.. do you see this as a problem? If so, is it within the scope of this diff to address, or should it be a separate issue?

Python defined matrix properties are currently unsupported. I'll check on adding support for this.

If you want you could you get this working without the subtype="MATRIX" property part, since FloatVectorProperty 1d arrays work.
It will involve flatten / conversion back into a 4x4 mathutils matrix (while inconvenient it's straightforward enough).

io_mesh_stl/__init__.py
251–254

No need for a default. The property should only be used when it's set.

Campbell Barton (campbellbarton) requested changes to this revision.Jul 29 2021, 5:41 AM
This revision now requires changes to proceed.Jul 29 2021, 5:41 AM

Lines 252-255:

No need for a default. The property should only be used when it's set.

@Campbell Barton (campbellbarton) I haven't been able to figure out how to "only use the property when it is set" because I haven't been able to figure out whether or not the property is set when the operator is called (if no default is defined, and the property is not set, it becomes all zeros. But I assume it is bad practice to rely on checking against a default value not being set yourself).

My inquiries in blender.chat were also unsuccessful, Can you please help or point me to an example/documentation of what you're asking for? Thank you

Jay Jasper (Jay_J) edited the summary of this revision. (Show Details)

Removed defaulting global_space matrix to identity matrix per request. Instead relying on FloatVectorProperty behavior to initialize to all zeros to detect if the global_space argument has been provided.

Jay Jasper (Jay_J) marked an inline comment as done.Mar 18 2022, 5:37 AM

Removed default per request. Diff 49390. I haven't been able to figure out a proper way to detect if the argument was passed or not.

Finally figured out how to check if an argument was passed to the operator function correctly (without relying on default or magic numbers). Ready for review, please.

Use is_property_set method, use the term space instead of frame.

Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)