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

STL support #19408

Open
SeanCurtis-TRI opened this issue May 15, 2023 · 8 comments
Open

STL support #19408

SeanCurtis-TRI opened this issue May 15, 2023 · 8 comments
Assignees
Labels
component: geometry general Geometry infrastructure or topics that defy categorization into other geometry components type: feature request

Comments

@SeanCurtis-TRI
Copy link
Contributor

What happened?

In a recent slack coversation a user tried instantiating a model using STL files. They went through the following unhelpful process.

  1. Simply reference the STL and receive the following errror:
    • RuntimeError: ProximityEngine: expect an Obj file for non-hydroelastics but get .stl file /workspaces/bdai/ws/install/spot_description/share/spot_description/meshes/base/collision/body_collision.stl) instead.
  2. Try adding the tag <drake:compliant_hydroelastic>
    • RuntimeError: A mesh must contain at least one tetrahedron
  3. Try switching to <drake:rigid_hydroelastic>:
    • RuntimeError: hydroelastic::MakeRigidRepresentation(): unsupported mesh file: /workspaces/bdai/ws/install/spot_description/share/spot_description/meshes/base/collision/body_collision.stl

The real problem is:

  1. Drake doesn't consume STL files. Period. And, more generally, supports a limited domain of mesh files.
  2. Users should be given direct feedback on this subject with clear directions on guidance for converting.

Proposal:

  1. SceneGraph should take responsibility for assessing Mesh types upon registration.
    • If it's an unsupported type, SceneGraph should make that clear and direct the user to a drake webpage discussing how to get supported geometry.
    • For the legacy behavior of, "you've specified an STL but have an identically named OBJ next to it", we should emit a warning right then (that we are swapping the STL for the OBJ) and then swap it internally so no downstream geometry consumers have to worry about it.

Some nuances:

  1. We support more than OBJ. We also support VTK, but for limited purposes (e.g., proximity with compliant hydorelastic.). The principle of "the mesh may depend on the application" is a principle that will grow (e.g., gltf for perception roles). So, we may need to defer some of the final validation until we see what role is applied. But this would still lie within SceneGraph's purview (see AssignRole()).
  2. This lies outside the domain of parsing (which would be a natural home). Do we want this validation to be in stand-alone functions that parsing and SceneGraph can use?
  3. The page to which we refer the reader may not yet exist and may need to be created.

Version

No response

What operating system are you using?

No response

What installation option are you using?

No response

Relevant log output

No response

@SeanCurtis-TRI SeanCurtis-TRI added type: bug component: geometry general Geometry infrastructure or topics that defy categorization into other geometry components labels May 15, 2023
@jwnimmer-tri
Copy link
Collaborator

See also #19055.

@markisus
Copy link

markisus commented Jul 6, 2023

Just got bit by this. Until the issue is resolved, do you have a recommended workflow for doing the conversion? I see there is the stl2obj

drake_cc_binary(
tool. Is this tool available if I installed the python version of drake using pip?

@markisus
Copy link

markisus commented Jul 6, 2023

I found your converter script using trimesh and adapted it to work for stl as well. Converting all stls and daes to obj fixed the error for me.

import argparse            
import pathlib
from trimesh import load_mesh
from trimesh.exchange.obj import export_obj

def convert(root, extension):
    for mesh_file in pathlib.Path(root).glob(f'*/**/*.{extension}'):
        print(f"Converting {mesh_file}")
        mesh = load_mesh(mesh_file)
        obj, data = export_obj(
                    mesh, return_texture=True, mtl_name=mesh_file.with_suffix('.mtl'))
        obj_file = mesh_file.with_suffix('.obj')
        with open(obj_file, "w") as f:
            f.write(obj)
            print(f"Wrote {obj_file}")
        # save the MTL and images                                
        for k, v in data.items():
            with open(k, 'wb') as f:
                f.write(v)
                print(f"Wrote {k}")

parser = argparse.ArgumentParser("Convert meshes to obj")
parser.add_argument("root", type=str, help="The root directory to glob for stl files")
parser.add_argument("--extension", type=str, default="stl", help="The type of mesh to convert. You may specify dae. Other extensions may work as well.")

args = parser.parse_args()

convert(args.root, extension=args.extension)

There is a bug in the current version of Trimesh that I had to resolve locally to fix meshes that had no associated materials. See mikedh/trimesh#1970

@jwnimmer-tri
Copy link
Collaborator

FYI I think the points above about giving good, early feedback in case of file type problems are right on point.

However, for the particular case of STL files, now that we have VTK packaged well I think it would be a good idea to add direct support for STL files. Possibly that rebalances the priorities here somewhat.

@jwnimmer-tri jwnimmer-tri changed the title Unhelpful feedback when passing an STL file STL support Jul 9, 2024
@jwnimmer-tri
Copy link
Collaborator

Given my prior comment, I'm repurposing this issue:

The new call to action is either:

(1) When given an STL mesh, throw an error with a hyperlink to a troubleshooting guide that convincingly explains how to convert the model file to use a different supported file format -- either OBJ or glTF. Our MuJoCo parser has an epsilon version of this, but we need it for SDFormat / URDF parsers as well, and we still need a guide document for how to convert.

(2) Actually parse and support the STL meshes, for all geometry endpoints. (This means Meshcat, Meldis, all RenderEngines, implicit inertia calculations, etc.)

Obviously (2) is better if we can swing it. I anticipate it will not be that difficult.

@RussTedrake
Copy link
Contributor

I also like the idea of a single prepare_model_for_drake.py. #19109 (comment)

@RussTedrake
Copy link
Contributor

Note: I believe that this could become much easier to support once the in-memory mesh PR train lands.

@jwnimmer-tri
Copy link
Collaborator

jwnimmer-tri commented Sep 22, 2024

I anticipate that the geometry endpoints for all illustration (meshcat, meldis), all proximity, and most rendering (render engine vtk, render engine gltf client) would consume STL natively, without OBJ as an intermediary.

I am not sure exactly what the plan would be for render engine gl. The question there would be if we want to eschew vtk entirely from its dependency tree, in which case we'd need to find a standalone STL parser instead of using VTK conversion. Since the MbP would already pull in VTK to read the STL files for the proximity engine, probably using the VTK STL reader for render engine gl will be fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: geometry general Geometry infrastructure or topics that defy categorization into other geometry components type: feature request
Projects
Status: Todo
Development

No branches or pull requests

5 participants