Start a new topic
Answered

How to Create Triangle Mesh Collision Geometry Through Scripting?

I'm trying to automatically generate a triangle mesh collision geometry using a python script.


This is doable in the editor by right-clicking a part associated with a graphics node and selecting "Create Collision Geometry -> Triangle Mesh" and I'd like to replicate this behavior through code.


I've managed to associate the part with the graphics node like so:

 

# Load files to create object definitions
mechanism = MechanismInterface(LoadFile('Test.vxmechanism'))
assembly = AssemblyInterface(LoadFile('Test_Assembly.vxassembly'))
part1 = PartInterface(LoadFile('Test_Assembly_Part1.vxpart'))
gallery = IExtensionInterface(LoadFile('Test_Gallery.vxgraphicgallery')).getExtension()

# Create instances of each object to work with
part1_instance = part1.instantiate()
assembly.addPart(part1_instance)
assembly_instance = assembly.instantiate()
mechanism.addAssembly(assembly_instance)
mechanism.addExtension(gallery)

skin = ConnectionContainerExtension.create()
mechanism.addExtension(skin.getExtension())
index = skin.createConnection(assembly_instance.getParts()[0].outputWorldTransform, \
                              gallery.findExtensionRecursivelyByName("LOD 1").getInput("Parent Transform"))
skin[index].valid() # Check to make sure the connection creates successfully

 This successfully attaches the part to the graphics node when the mechanism is serialized and then opened in the editor. I can create primitive geometries:


 

box = BoxInterface().create()
sphere = SphereInterface().create()
cylinder = CylinderInterface().create()
part1.addCollisionGeometry(box)
part2.addCollisionGeometry(sphere)
part3.addCollisionGeometry(cylinder)

But can't find a way to create a triangle mesh based on the graphics geometry. I can access the geometry, and can see that the total number of vertices and triangles are stored. I can't find how to access the list of triangles directly, and even if I could I'm not seeing how to pass that to a TriangleMeshUVGrid object to create the collision geometry I'm looking for.


Any advice on how to create a triangle mesh collision geometry based on an existing graphics geometry?


Best Answer

Hi Seth,


The functions used for creating collision geometries (CGs) based on graphics geometries were not exposed in our Python binding.   Some of those might be available in our C++ API.  Most of the time, content creation is done via the Vortex Editor, since it is easier to use. 


We would be curious in hearing more about your use case and what you are trying to achieve with the python script you are writing...


Regards,


Sylvain Giasson

Team Lead - Front End - Vortex Studio

CM Labs Simulations

www.cm-labs.com


Answer

Hi Seth,


The functions used for creating collision geometries (CGs) based on graphics geometries were not exposed in our Python binding.   Some of those might be available in our C++ API.  Most of the time, content creation is done via the Vortex Editor, since it is easier to use. 


We would be curious in hearing more about your use case and what you are trying to achieve with the python script you are writing...


Regards,


Sylvain Giasson

Team Lead - Front End - Vortex Studio

CM Labs Simulations

www.cm-labs.com

A lot of the vehicles I'm working with are similar enough to each other that making a mechanism involves using the same process for all of them. However, they're different enough that I can't just swap out the graphics gallery and call it a day. The biggest timesink for me is automating the connections between nodes in the editor - oftentimes the editor is laggy, or I make a mistake connecting outputs and inputs in the editor. I've made a basic mechanism template that handles most of the vehicle creation process, but there are some things that the template can't cover just with a file name change.


What I'm trying to do with the script is something like:

  1. Manually create a directory with only a graphics gallery
  2. Start the script with command line arguments to specify number of axles, presence of emergency lights, manual/automatic transmission, or whatever other differences may exist between similar vehicles
  3. The script automatically generates the parts, constraints, vehicle system, and entire control scheme based on presets I've already defined.

So far this is actually going pretty well - I've figured out how to accomplish all of these tasks except for the collision geometry. If there IS no way to accomplish this through scripting, then it's not a huge deal to do that one step manually. But if it is possible, I'd like to automate as much of the mechanism creation process as possible.

On the note of the API exposure - is this the difference between VxSim and pyvx? I can't find any documentation on pyvx and didn't even realize it existed until Daniel gave me an example that used it. My loose understanding is that pyvx can create Vortex objects without the standard Python API, but I don't fully understand how it works. 

As for using the Python API instead of the C++ API - if it's possible to do in the C++ API, I'll likely switch over to that. The only reason I'm working in python right now is because it's my language of choice, but if the C++ API has more functionality then I have no problem switching.

Apologies if this makes a double post - my previous comment seems to have been caught by the spam filter somehow.


Most of the vehicles I'm creating are similar to each other, with some broad-definition differences (e.g. emergency lights vs no emergency lights, manual vs automatic transmission). The only other differences are their general shape. I've made a template mechanism/assembly/parts that I've been using, and editing an exact instance of that template based on the characteristics of each vehicle. e.g. the template has a 3-axle automatic transmission vehicle, 2-axle automatic transmission vehicle, and 2-axle manual transmission vehicle connected and ready to go, but I delete the two vehicles I won't be using.

 

The problem with this template is that the connections to the graphics gallery do not carry over when the gallery is replaced. While the template cuts down on mechanism creation time by saving the part definitions, vehicle definition, and constraints, it does not save all of the connections, and some constraints need to be redefined since the graphics have moved considerably. The positions of parts will also be changing based solely on the graphics, e.g. the wipers aren't always in the same spot in worldspace when your vehicles vary in size.

 

This is what I'm trying to do with my script:

 

  1. Manually create a new directory, and put a graphics gallery into the directory 
  2. Run the script. The script will have some command line arguments to define things like transmission type, number of axles, presence of emergency lights, etc. The script will automatically generate a .vxmechanism, .vxassembly, and some number of .vxpart files based on the arguments. All the connections, constraints, parts, and vehicle logic will be handled automatically in the script. 

 

So far most of this is going well. I can automatically generate parts and position them based on the gallery, and I can automatically set a vehicle based on a loaded preset, connect the wheels and chassis, and everything's good to go. Right now I'm working on automatically setting up the constraints, but so far progress is good.

 

If it is impossible to generate the triangle mesh collision geometry automatically, then it's not the end of the world for me to do it manually - but I would like to automate anything I can. Right now I'm working with the Python API because Python is my language of choice. But if I need to switch to the C++ API to accomplish every goal, then that's what I'll do.

 

My previous question on this forum regarding collision geometry was solved by using the pyvx library. I have not been able to find any documentation on this library, but my understanding is that pyvx can create some objects in Vortex that go around the usual Python API through VxSim. I'm not totally sure how useful this would be, since I can't tell if a pyvx object can interact with VxSim objects. Is there any chance that there are more resources on this library so I can take a look at how to use it?

Hi Seth,

Thanks for sharing your needs and workflow with us, it is quite interesting.  I am glad to see that you were able to go a bit further.

About pyvx: Indeed we have two python bindings: VxSim and pyvx.   The VxSim is the more modern one and "pyvx" is the legacy one, to be deprecated at some point.  "pyvx" is built with the VxCore library, which is the low level API for the physics engine.  It interacts with the runtime structure of the physics library.  There is no specific documentation about it, but you can refer to the header files of the VxCore library and also rely on the native documentation feature of python using the "dir()" function...

Regards,

Sylvain Giasson

Team Lead - Front End - Vortex Studio

CM Labs Simulations

www.cm-labs.com




 

Hi Seth,


I read your last post and thought I'd pitch in to give you some more useful pointers.

So, if I understand correctly, the only part which is missing in your pipeline is the creation of collision geometries from meshes, right?

Since C++ is an option for you, I am listing here a bunch of useful functionalities in the Vortex Studio SDK for this purpose:


1) Creation of meshes from graphics objects:

See VxGraphics/NodeHelper.h for this. Specifically the functions initConvexMesh and initTriangleMeshData.

The first can be used to create a single convex mesh from the graphics node and the latter is useful to initialize the triangle mesh data object of a VxTriangleMeshBVTree, which is a generic triangle mesh geometry, which supports collision with all other geometry types, including other meshes and even the UV Grid mesh version (VxTriangleMeshUVGridwhich is optimized for representing terrains.


2) Convex decomposition:

If you want to create a convex mesh decomposition from the graphics node (multiple convex meshes which approximate the graphical mesh), you can use the following toolset (which uses the HACD and V-HACD algorithms that you can find on the web):


Vx/VxConvexDecomposition.h


The functions of interest for you are:


/// Convex decomposition using the HACD algorithm

///

static void computeHACD(VxTriangleMeshData* triangleMeshData, const ParametersHACD& parameters, VxArray<VxSmartPtr<VxConvexMesh> >& convexMeshes, Handler* handler = nullptr);


/// Convex decomposition using the V-HACD (Volumetric Hierarchical Approximate Convex Decomposition) algorithm

///

static bool computeVHACD(VxTriangleMeshData* triangleMeshData, const ParametersVHACD& parameters, VxArray<VxSmartPtr<VxConvexMesh> >& convexMeshes, Handler* handler = nullptr);


You can simply use the methods given under point (1) to initialize a triangle mesh data object from a generic graphics mesh, and then decompose it into a bunch of VxConvexMeshes, which will give you very stable and fast collision response.

To reduce the number of dynamics contacts produced with the convex meshes, I recommend you add them to a VxCompositeCollisionGeometry first before adding it to your vehicle rigid body (VxDynamics::Part or the underlying VxPart).


3) Fitting primitives to points clouds:

You can also fit a bunch of primitive geometries (VxBox, VxCylinder etc.) to triangle meshes by using the following function from VxCollisionGeometry:


/// Resizes the underlying geometry and sets new position and orientation such that the given set of

/// points is covered while minimizing the geometry volume.

///

/// @param[in] points Set of points

/// @param[in] lockedAxes No restriction on rotation=VxGeometry::kNoAxis. Rotation only around x-axis=VxGeometry::kXAxis, y-axis=VxGeometry::kYAxis or z-axis=VxGeometry::kZAxis. No rotation (fully locked)=VxGeometry::kAllAxes.

/// @param[in] isPositionLocked If @c isPositionLocked is set the position in the @c inOutTM is not modified and the fit is done

/// purely on size, modifying the orientation as permitted by @c lockedAxes.

///

void computeSmallestEnclosing(const VxArray<VxVector3>& points, VxGeometry::eSmallestEnclosingLockedAxes lockedAxes = VxGeometry::kNoAxis, bool isPositionLocked = false);


The input points can be taken from the vertices in the graphics mesh directly or from the triangle mesh data object created through the functions provided under point (1).

By choosing sets of points which represent logical components of your vehicle chassis (hood, rear etc.), you can get a quite accurate fit from primitives with this approach.


Primitives generally provide the most accurate and fastest collision response, closely followed by convex meshes and then triangle meshes.


Hope this helps.

If you have more questions, let me know.


Cheers,

Daniel


2 people like this
Login to post a comment