Issue with collisions, possibly related to CGAL plugin and/or Tetra2TriangleTopologicalMapping #4346
-
I am building a simple simulation of a soft body and am stumped by an issue with collisions. I am a fine visual mesh, which I use in conjunction with the CGAL plugin to create a coarse tetrahedral simulation mesh. The FEM simulation on this mesh seems to work fine. Visual mesh : I then decided to implement collisions with a floor from STLIB. I wanted to use the coarse mesh for collision handling, so I used a topological mapping to populate a TriangleTopologyContainer with the border of the tetrahedral mesh. When I run the simulation, the collision mesh looks fine at first, but collisions are not detected on the outside. However, the topological mapping seems to leave behind isolated vertices inside the mesh. It appears that the collision pipeline only considers these isolated vertices, which makes for a rather unsightly result... From the side : To code the collision, I took inspiration from various examples and these topics : https://www.sofa-framework.org/community/forum/topic/how-to-extract-the-surface-of-a-volumeyric-mesh/ ; #4033 Obviously the most likely explanation is that I am doing something wrong. I do however get a bunch of warnings probably related : [WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 135 109 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 109 9 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 9 135 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 144 73 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 73 10 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 10 144 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 73 137 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 137 10 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 300 269 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 269 78 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 78 300 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 197 160 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 160 77 for: 0 points.
[WARNING] [TriangleSetTopologyContainer(Container)] EdgesAroundVertex creation failed, Edge buffer is not concistent with number of points: Edge: 77 197 for: 0 points. Any help would be appreciated ! Here is my code for this simulation : import Sofa
from stlib3.scene import ContactHeader
from stlib3.physics.rigid import Floor
# Units : mm and kg
def createScene(rootNode):
rootNode.findData('dt').value = 0.01
rootNode.findData('gravity').value = [0, 0, -9180] # gravity is disabled
rootNode.addObject('VisualStyle',
displayFlags='showCollision showVisualModels showForceFields showInteractionForceFields'
+' hideCollisionModels hideBoundingCollisionModels hideWireframe')
rootNode.bbox = "-50 -50 -50 50 50 50" # field of view of the viewer
# Required plugins
rootNode.addObject('RequiredPlugin', pluginName=[
"Sofa.Component.AnimationLoop", # Needed to use components FreeMotionAnimationLoop
"Sofa.Component.Constraint.Lagrangian.Correction", # Needed to use components LinearSolverConstraintCorrection
"Sofa.Component.Constraint.Lagrangian.Solver", # Needed to use components GenericConstraintSolver
"Sofa.Component.Constraint.Projective", # Needed to use components FixedConstraint
"Sofa.Component.Engine.Select", # Needed to use components BoxROI
"Sofa.Component.IO.Mesh", # Needed to use components MeshVTKLoader
"Sofa.Component.LinearSolver.Direct", # Needed to use components SparseLDLSolver
"Sofa.Component.LinearSolver.Iterative", # Needed to use components ShewchukPCGLinearSolver
"Sofa.Component.Mass", # Needed to use components UniformMass
"Sofa.Component.ODESolver.Backward", # Needed to use components EulerImplicitSolver
"Sofa.Component.SolidMechanics.FEM.Elastic", # Needed to use components TetrahedronFEMForceField
"Sofa.Component.Topology.Container.Constant", # Needed to use components MeshTopology
"Sofa.Component.Visual", # Needed to use components VisualStyle
"Sofa.Component.Mapping.Linear", # Needed to use components BarycentricMapping
"Sofa.Component.StateContainer", # Needed to use components MechanicalObject
"Sofa.Component.Setting", # Needed to use components BackgroundSetting
"Sofa.Component.Topology.Container.Dynamic", # Needed to use components TetrahedronSetGeometryAlgorithms,TetrahedronSetTopologyContainer
"Sofa.GL.Component.Rendering3D", # Needed to use components OglModel,OglSceneFrame
"CGALPlugin", # Needed to use MeshGenerationFromPolyhedron
"SoftRobots",
"SofaPython3"
])
rootNode.addObject('BackgroundSetting', color=[0, 0.168627, 0.211765, 1]) # set background color
rootNode.addObject('OglSceneFrame', style="Arrows", alignment="TopRight") # add a triedron to help with orientation
# setup the animation loop
rootNode.addObject('FreeMotionAnimationLoop')
rootNode.addObject('GenericConstraintSolver', maxIterations=500, tolerance=1e-8)
# add a collision pipeline
ContactHeader(rootNode, alarmDistance=1, contactDistance=.01)
# Add a floor
Floor(rootNode, rotation=[90, 0, 0], translation=[0,0,-10], isAStaticObject=True)
# create the larva object
larvaBody = rootNode.addChild('larvaBody')
# load the detailed mesh
larvaSTL = '/home/alexandre/workspace/larva_meshing/mesh_cuticle_simplified.stl'
larvaBody.addObject('MeshSTLLoader', name='larvaMesh', filename=larvaSTL)
# create the overall body mechanics
bodyMechanics = larvaBody.addChild('bodyMechanics')
# use CGAL to create a simplified tetrahedral mesh of the larva
bodyMechanics.addObject('MeshGenerationFromPolyhedron', name='gen', template='Vec3d', inputPoints='@../larvaMesh.position', inputTriangles='@../larvaMesh.triangles', drawTetras='0',
cellSize="10", facetAngle="30", facetSize="5", cellRatio="2", #Convergence problem if lower than 2
facetApproximation="1")
# Create the state from the coarse mesh
bodyMechanics.addObject('MechanicalObject', name="dofs", position="@gen.outputPoints")
bodyMechanics.addObject('TetrahedronSetTopologyContainer', name='topo', tetrahedra='@gen.outputTetras')
bodyMechanics.addObject('TetrahedronSetGeometryAlgorithms', template="Vec3d", name="GeomAlgo", drawTetrahedra="0", drawScaleTetrahedra="0.8")
# Set the mechanical parameters and force fields
bodyMechanics.addObject('UniformMass', totalMass=0.5) # add mass
bodyMechanics.addObject('TetrahedronFEMForceField', youngModulus=180, poissonRatio=0.45) # add elasticity
# Define resolution method
bodyMechanics.addObject('EulerImplicitSolver') # define numerical scheme
bodyMechanics.addObject('SparseLDLSolver', template="CompressedRowSparseMatrixMat3x3d") # define solve method
# Fix the tail of the larva, so that it is anchored and we can deform the larva by pulling on it
# bodyMechanics.addObject('BoxROI', name="boxROI", box=[55, -25, -10, 80, 15, 10], drawBoxes=True) # create an anchor or selection zone (red skeleton)
# bodyMechanics.addObject('FixedConstraint', indices="@boxROI.indices") # add the constraint
bodyMechanics.addObject('UncoupledConstraintCorrection') # add the constraint solver
# Set a visual model
visualModel = larvaBody.addChild('visualModel')
visualModel.addObject('OglModel', name='visualMesh', src='@../larvaMesh')
# Align the visual model on the coarse mechanical mesh
visualModel.addObject('BarycentricMapping', input='@../bodyMechanics/dofs', output='@visualMesh')
# Collision model
collision = bodyMechanics.addChild('larvaCollisionModel') # collision model
collision.addObject('TriangleSetTopologyContainer', name="Container")
collision.addObject('TriangleSetTopologyModifier')
collision.addObject('Tetra2TriangleTopologicalMapping', input="@../topo", output="@Container")
collision.addObject('MechanicalObject', name="tetras", template="Vec3", position="@../gen.outputPoints")
collision.addObject('TriangleCollisionModel', selfCollision=True) # 3 types of collision
collision.addObject('LineCollisionModel', selfCollision=True)
collision.addObject('PointCollisionModel', selfCollision=True)
collision.addObject('BarycentricMapping', input="@../dofs")
return rootNode |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 12 replies
-
I updated the collision model according to #4033 : collision = bodyMechanics.addChild('larvaCollisionModel') # collision model
collision.addObject('TriangleSetTopologyContainer', name="Container")#, position="@../topo.position") # uncomment to get a segfault
collision.addObject('TriangleSetTopologyModifier')
collision.addObject('Tetra2TriangleTopologicalMapping', input="@../topo", output="@Container")
collision.addObject('MechanicalObject', name="collisionDOFs")
collision.addObject('IdentityMapping', input="@../dofs", output="@collisionDOFs")
collision.addObject('TriangleCollisionModel', selfCollision=True) # 3 types of collision
collision.addObject('LineCollisionModel', selfCollision=True)
collision.addObject('PointCollisionModel', selfCollision=True) and suddenly the plot thickened, as I got a different buggy behavior : more vertices inside are now considered for collision. Also, initializing the position attribute of the TriangleSetTopologyContainer now seems crucial to avoid a segfault, and I do not get warnings from Tetra2TriangleTopologyContainer anymore. |
Beta Was this translation helpful? Give feedback.
-
Hi @aleblanc30 Thanks a lot for your question. In your case, just remove both lines: collision.addObject('MechanicalObject', name="collisionDOFs")
collision.addObject('IdentityMapping', input="@../dofs", output="@collisionDOFs") Hope this helps |
Beta Was this translation helpful? Give feedback.
-
Hi @hugtalbot, thank you for your availability. I followed your recommendation. The behavior is a bit better but I still have issues with collisions only being detected at interior points of the mesh. See the following screenshots : Bounding boxes and interaction forces : the forces are on the surface of the floor, inside the body. Collision model and interaction forces, viewed from inside the model : the interaction occurs at isolated points inside the collision model |
Beta Was this translation helpful? Give feedback.
-
Hi,
Hope it helps |
Beta Was this translation helpful? Give feedback.
-
Apparently the normals of my mesh are fine. However the normals of the Floor from STLIB are actually tangent to the surface. I'll look for a way to fix this. EDIT : I found the function updateNormals in MeshLoader, maybe that would do the trick ? I don't know if it is possible to have it called. |
Beta Was this translation helpful? Give feedback.
-
Hi @aleblanc30 I detected several issues in your scene:
Let me know if the example below is working for you 👇import Sofa
from stlib3.scene import ContactHeader
from stlib3.physics.rigid import Floor
# Units : mm and kg
def createScene(rootNode):
rootNode.findData('dt').value = 0.001
rootNode.findData('gravity').value = [0, 0, -9180] # gravity is disabled
rootNode.addObject('VisualStyle',
displayFlags='showCollision hideVisualModels hideForceFields hideInteractionForceFields'
+' hideCollisionModels hideBoundingCollisionModels showWireframe')
rootNode.bbox = "-50 -50 -50 50 50 50" # field of view of the viewer
# Required plugins
rootNode.addObject('RequiredPlugin', pluginName=[
"Sofa.Component.AnimationLoop", # Needed to use components FreeMotionAnimationLoop
"Sofa.Component.Constraint.Lagrangian.Correction", # Needed to use components LinearSolverConstraintCorrection
"Sofa.Component.Constraint.Lagrangian.Solver", # Needed to use components GenericConstraintSolver
"Sofa.Component.Constraint.Projective", # Needed to use components FixedConstraint
"Sofa.Component.Engine.Select", # Needed to use components BoxROI
"Sofa.Component.IO.Mesh", # Needed to use components MeshVTKLoader
"Sofa.Component.LinearSolver.Direct", # Needed to use components SparseLDLSolver
"Sofa.Component.LinearSolver.Iterative", # Needed to use components ShewchukPCGLinearSolver
"Sofa.Component.Mass", # Needed to use components UniformMass
"Sofa.Component.ODESolver.Backward", # Needed to use components EulerImplicitSolver
"Sofa.Component.SolidMechanics.FEM.Elastic", # Needed to use components TetrahedronFEMForceField
"Sofa.Component.Topology.Container.Constant", # Needed to use components MeshTopology
"Sofa.Component.Visual", # Needed to use components VisualStyle
"Sofa.Component.Mapping.Linear", # Needed to use components BarycentricMapping
"Sofa.Component.StateContainer", # Needed to use components MechanicalObject
"Sofa.Component.Setting", # Needed to use components BackgroundSetting
"Sofa.Component.Topology.Container.Dynamic", # Needed to use components TetrahedronSetGeometryAlgorithms,TetrahedronSetTopologyContainer
"Sofa.GL.Component.Rendering3D", # Needed to use components OglModel,OglSceneFrame
"CGALPlugin",
"Sofa.Component.Collision.Detection.Algorithm",
"Sofa.Component.Collision.Detection.Intersection",
"SofaPython3"
])
rootNode.addObject('BackgroundSetting', color=[0, 0.168627, 0.211765, 1]) # set background color
rootNode.addObject('OglSceneFrame', style="Arrows", alignment="TopRight") # add a triedron to help with orientation
# setup the animation loop
rootNode.addObject('FreeMotionAnimationLoop')
rootNode.addObject('GenericConstraintSolver', maxIterations=500, tolerance=1e-8)
# add a collision pipeline
rootNode.addObject('CollisionPipeline')
rootNode.addObject('BruteForceBroadPhase')
rootNode.addObject('BVHNarrowPhase')
rootNode.addObject('LocalMinDistance',
alarmDistance=0.5, contactDistance=0.1,
angleCone=0.5)
rootNode.addObject('CollisionResponse', response='FrictionContactConstraint')
# Add a floor
Floor(rootNode, rotation=[90, 0, 0], translation=[0,0,-10], isAStaticObject=True)
# create the larva object
larvaBody = rootNode.addChild('larvaBody')
# load the detailed mesh
larvaSTL = 'mesh_cuticle_simplified.stl'
larvaBody.addObject('MeshSTLLoader', name='larvaMesh', filename=larvaSTL)
# create the overall body mechanics
bodyMechanics = larvaBody.addChild('bodyMechanics')
# use CGAL to create a simplified tetrahedral mesh of the larva
bodyMechanics.addObject('MeshGenerationFromPolyhedron', name='gen', template='Vec3d', inputPoints='@../larvaMesh.position', inputTriangles='@../larvaMesh.triangles', drawTetras='0',
cellSize="10", facetAngle="30", facetSize="5", cellRatio="2", #Convergence problem if lower than 2
facetApproximation="1")
# Create the state from the coarse mesh
bodyMechanics.addObject('MechanicalObject', name="dofs", position="@gen.outputPoints")
bodyMechanics.addObject('TetrahedronSetTopologyContainer', name='topo', tetrahedra='@gen.outputTetras')
bodyMechanics.addObject('TetrahedronSetGeometryAlgorithms', template="Vec3d", name="GeomAlgo", drawTetrahedra="0", drawScaleTetrahedra="0.8")
# Set the mechanical parameters and force fields
bodyMechanics.addObject('UniformMass', totalMass=0.5) # add mass
bodyMechanics.addObject('TetrahedronFEMForceField', youngModulus=180, poissonRatio=0.45) # add elasticity
# Define resolution method
bodyMechanics.addObject('EulerImplicitSolver') # define numerical scheme
bodyMechanics.addObject('SparseLDLSolver', template="CompressedRowSparseMatrixMat3x3d") # define solve method
# Fix the tail of the larva, so that it is anchored and we can deform the larva by pulling on it
# bodyMechanics.addObject('BoxROI', name="boxROI", box=[55, -25, -10, 80, 15, 10], drawBoxes=True) # create an anchor or selection zone (red skeleton)
# bodyMechanics.addObject('FixedConstraint', indices="@boxROI.indices") # add the constraint
bodyMechanics.addObject('UncoupledConstraintCorrection') # add the constraint solver
# Set a visual model
visualModel = larvaBody.addChild('visualModel')
visualModel.addObject('OglModel', name='visualMesh', src='@../larvaMesh')
# Align the visual model on the coarse mechanical mesh
visualModel.addObject('BarycentricMapping', input='@../bodyMechanics/dofs', output='@visualMesh')
# Collision model
collision = bodyMechanics.addChild('larvaCollisionModel') # collision model
collision.addObject('TriangleSetTopologyContainer', name="Container")
collision.addObject('TriangleSetTopologyModifier')
collision.addObject('Tetra2TriangleTopologicalMapping', input="@../topo", output="@Container")
collision.addObject('TriangleCollisionModel', selfCollision=True) # 3 types of collision
collision.addObject('LineCollisionModel', selfCollision=True)
collision.addObject('PointCollisionModel', selfCollision=True)
return rootNode Cheers |
Beta Was this translation helpful? Give feedback.
Hi @aleblanc30
I detected several issues in your scene:
CollisionHeader()
prefab, based on a RuleBasedContactManager for the collision response is not appropriate. We should actually update this prefab.Let me know if the example below is working for you 👇