sofa-framework / sofa

Real-time multi-physics simulation with an emphasis on medical simulation.
https://www.sofa-framework.org
GNU Lesser General Public License v2.1
920 stars 311 forks source link

Wrong vertex normal orientation #2451

Open jducrocq007 opened 2 years ago

jducrocq007 commented 2 years ago

Problem

Description Exporting a regular grid of hexahedras as an OBJ file does not properly export the normals. As you can see in the attached images "sofaNormals.png" and "blenderNormals.png", the normals are not oriented the same inside the Sofa scene and on the OBJ exported. This is an issue when you want to compute light effect like refractions or reflections on the exported mesh.

sofaNormals

blenderNormals

Steps to reproduce

Expected behavior The normals should have had an orientation which is perpendicular to the local surface around each vertex (should be straight perpendicular to a planar surface around the center and around 45 degrees in the borders, since the vertices touch two different faces there).


Environment

Context

Command called (to copy in a .scn/xml file)


<?xml version="1.0" ?>

<Node name="root" dt="0.1" gravity="0 0 0">

    <VisualStyle displayFlags="showBehavior hideVisual hideCollision" />

    <EulerImplicit name="cg_odesolver" printLog="false" />
    <CGLinearSolver iterations="25" name="linear solver" tolerance="1.0e-9" threshold="1.0e-9" />

    <RequiredPlugin pluginName='SofaExporter'/> <!-- Needed to use components [MeshExporter, ]-->
    <RequiredPlugin pluginName='SofaGeneralSimpleFem'/> <!-- Needed to use components [HexahedralFEMForceField, ]-->
    <RequiredPlugin pluginName='SofaImplicitOdeSolver'/> <!-- Needed to use components [EulerImplicitSolver, ]-->
    <RequiredPlugin pluginName='SofaOpenglVisual'/> <!-- Needed to use components [OglModel, ]-->

    <!-- The object to export -->
    <Node name="MyRegularGrid">

        <MechanicalObject name="mo"/> 
        <UniformMass vertexMass="0.2" />
        <RegularGrid name="hexaGrid" nx="6" ny="6" nz="4" xmin="-10.0" xmax="10.0" ymin="-10.0" ymax="10.0" zmin="0" zmax="0.50"/>
        <HexahedronSetTopologyContainer name="Topo" src="@hexaGrid" />      
        <HexahedralFEMForceField name="FEM" youngModulus="1e13" poissonRatio="0.3" method="large" />

        <!-- Visual node to allow the exportation -->
        <Node name="VisualNode" >
            <OglModel name="Visual" color="green" />
            <IdentityMapping input="@.." output="@Visual" /> 
        </Node>

        <OBJExporter name="export_OBJ" filename="C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/regularGrid5x5"  exportAtBegin="true" exportEveryNumberOfSteps="0" />

    </Node>

</Node>

Env vars

  echo "SOFA_ROOT = C:\Users\jducr\Documents\Librairies\sofa\build\bin\Release"
  echo "PYTHONPATH = C:\Users\jducr\Documents\Librairies\Python\Python37"
  echo "python3 -V = Python 3.7.7"
The scene is working fine, just the normals are exported wrong.

Logs

Full output


[WARNING] [SceneCheckUsingAlias] This scene is using hard coded aliases. Aliases can be very confusing, use with caution.
  - EulerImplicitSolver: 1 created with alias "EulerImplicit"
  - RegularGridTopology: 1 created with alias "RegularGrid"
[INFO]    [SceneCheckerVisitor] Finished validating node "root".
[ERROR]   [MeshGmshLoader(export_filename)] File: 'C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/membrane_7x7_quads' not found.
[ERROR]   [MeshGmshLoader(export_filename)] Can't load file C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/membrane_7x7_quads
[INFO]    [SofaViewer] QtViewer::keyPressEvent, CONTROL pressed
[ERROR]   [MeshGmshLoader(export_filename)] File: 'C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/membrane_7x7_quads' not found.
[INFO]    [SceneCheckerVisitor] Validating node "root" with checks: [SceneCheckDuplicatedName, SceneCheckMissingRequiredPlugin, SceneCheckUsingAlias]
[WARNING] [SceneCheckMissingRequiredPlugin] This scene is using component defined in plugins but is not importing the required plugins.
  Your scene may not work on a sofa environment with different pre-loaded plugins.
  To fix your scene and remove this warning you just need to cut & paste the following lines at the begining of your scene (if it is a .scn):
  <RequiredPlugin pluginName='SofaExporter'/> <!-- Needed to use components [MeshExporter, ]-->
<RequiredPlugin pluginName='SofaGeneralSimpleFem'/> <!-- Needed to use components [HexahedralFEMForceField, ]-->

[WARNING] [SceneCheckUsingAlias] This scene is using hard coded aliases. Aliases can be very confusing, use with caution.
  - EulerImplicitSolver: 1 created with alias "EulerImplicit"
  - RegularGridTopology: 1 created with alias "RegularGrid"
[INFO]    [SceneCheckerVisitor] Finished validating node "root".
[ERROR]   [MeshGmshLoader(export_filename)] File: 'C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/membrane_7x7_quads' not found.
[ERROR]   [MeshGmshLoader(export_filename)] Can't load file C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/membrane_7x7_quads
[INFO]    [SofaViewer] QtViewer::keyPressEvent, CONTROL pressed
[ERROR]   [MeshGmshLoader(export_filename)] File: 'C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/membrane_7x7_quads' not found.
[INFO]    [SceneCheckerVisitor] Validating node "root" with checks: [SceneCheckDuplicatedName, SceneCheckMissingRequiredPlugin, SceneCheckUsingAlias]
[WARNING] [SceneCheckMissingRequiredPlugin] This scene is using component defined in plugins but is not importing the required plugins.
  Your scene may not work on a sofa environment with different pre-loaded plugins.
  To fix your scene and remove this warning you just need to cut & paste the following lines at the begining of your scene (if it is a .scn):
  <RequiredPlugin pluginName='SofaExporter'/> <!-- Needed to use components [MeshExporter, ]-->
<RequiredPlugin pluginName='SofaGeneralSimpleFem'/> <!-- Needed to use components [HexahedralFEMForceField, ]-->

[WARNING] [SceneCheckUsingAlias] This scene is using hard coded aliases. Aliases can be very confusing, use with caution.
  - EulerImplicitSolver: 1 created with alias "EulerImplicit"
  - RegularGridTopology: 1 created with alias "RegularGrid"
[INFO]    [SceneCheckerVisitor] Finished validating node "root".
[ERROR]   [MeshGmshLoader(export_filename)] File: 'C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/membrane_7x7_quads' not found.
[ERROR]   [MeshGmshLoader(export_filename)] Can't load file C:/Users/jducr/Documents/Developpement/Sofa_ws/scenes/exports/membrane_7x7_quads
[INFO]    [SceneCheckerVisitor] Validating node "root" with checks: [SceneCheckDuplicatedName, SceneCheckMissingRequiredPlugin, SceneCheckUsingAlias]
[WARNING] [SceneCheckUsingAlias] This scene is using hard coded aliases. Aliases can be very confusing, use with caution.
  - EulerImplicitSolver: 1 created with alias "EulerImplicit"
  - RegularGridTopology: 1 created with alias "RegularGrid"
[INFO]    [SceneCheckerVisitor] Finished validating node "root".

Content of build_dir/CMakeCache.txt

CMakeCache.txt

jducrocq007 commented 2 years ago

According to @damienmarchal , the issue comes from the fact that the faces normals in regularGridTopoly components are computed to be oriented sometimes inwards and sometimes outwards. Since the vertices normals consist in an interpolation of the faces normals around the specified vertex, the orientation of the vertex normals are wrong.