diff --git a/pcbnew/dialogs/dialog_export_step.cpp b/pcbnew/dialogs/dialog_export_step.cpp
index a7a8551314..4b7bf7f168 100644
--- a/pcbnew/dialogs/dialog_export_step.cpp
+++ b/pcbnew/dialogs/dialog_export_step.cpp
@@ -127,6 +127,9 @@ protected:
         return m_cbOverwriteFile->GetValue();
     }
 
+    // Called to update filename extension after the output file format is changed
+    void OnFmtChoiceOptionChanged();
+
 private:
     enum class COMPONENT_MODE
     {
@@ -161,8 +164,8 @@ private:
 };
 
 
-int  DIALOG_EXPORT_STEP::m_toleranceLastChoice = -1;     // Use default
-int  DIALOG_EXPORT_STEP::m_formatLastChoice = -1;    // Use default
+int  DIALOG_EXPORT_STEP::m_toleranceLastChoice = -1;    // Use default
+int  DIALOG_EXPORT_STEP::m_formatLastChoice = -1;       // Use default
 bool DIALOG_EXPORT_STEP::m_optimizeStep = true;
 bool DIALOG_EXPORT_STEP::m_exportBoardBody = true;
 bool DIALOG_EXPORT_STEP::m_exportComponents = true;
@@ -302,6 +305,10 @@ DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString&
 
     if( m_formatLastChoice >= 0 )
         m_choiceFormat->SetSelection( m_formatLastChoice );
+    else
+        // ensure the selected fmt and the output file ext are synchronized the first time
+        // the dialog is opened
+        OnFmtChoiceOptionChanged();
 
     // Now all widgets have the size fixed, call FinishDialogSettings
     finishDialogSettings();
@@ -474,6 +481,12 @@ void DIALOG_EXPORT_STEP::onBrowseClicked( wxCommandEvent& aEvent )
 
 
 void DIALOG_EXPORT_STEP::onFormatChoice( wxCommandEvent& event )
+{
+    OnFmtChoiceOptionChanged();
+}
+
+
+void DIALOG_EXPORT_STEP::OnFmtChoiceOptionChanged()
 {
     wxString newExt = c_formatCommand[m_choiceFormat->GetSelection()];
     wxString path = m_outputFileName->GetValue();
diff --git a/pcbnew/exporters/step/exporter_step.cpp b/pcbnew/exporters/step/exporter_step.cpp
index b69304decb..4443ba22ce 100644
--- a/pcbnew/exporters/step/exporter_step.cpp
+++ b/pcbnew/exporters/step/exporter_step.cpp
@@ -514,6 +514,35 @@ bool EXPORTER_STEP::buildGraphic3DShape( BOARD_ITEM* aItem, VECTOR2D aOrigin )
 }
 
 
+void EXPORTER_STEP::initOutputVariant()
+{
+    // Specialize the STEP_PCB_MODEL generator for specific output format
+    // it can have some minor actions for the generator
+    switch( m_params.m_Format )
+    {
+        case EXPORTER_STEP_PARAMS::FORMAT::STEP:
+            m_pcbModel->SpecializeVariant( OUTPUT_FORMAT::FMT_OUT_STEP );
+            break;
+
+        case EXPORTER_STEP_PARAMS::FORMAT::BREP:
+            m_pcbModel->SpecializeVariant( OUTPUT_FORMAT::FMT_OUT_BREP );
+            break;
+
+        case EXPORTER_STEP_PARAMS::FORMAT::XAO:
+            m_pcbModel->SpecializeVariant( OUTPUT_FORMAT::FMT_OUT_XAO );
+            break;
+
+        case EXPORTER_STEP_PARAMS::FORMAT::GLB:
+            m_pcbModel->SpecializeVariant( OUTPUT_FORMAT::FMT_OUT_GLTF );
+            break;
+
+        default:
+            m_pcbModel->SpecializeVariant( OUTPUT_FORMAT::FMT_OUT_UNKNOWN );
+            break;
+    }
+}
+
+
 bool EXPORTER_STEP::buildBoard3DShapes()
 {
     if( m_pcbModel )
@@ -541,6 +570,8 @@ bool EXPORTER_STEP::buildBoard3DShapes()
 
     m_pcbModel = std::make_unique<STEP_PCB_MODEL>( m_pcbBaseName );
 
+    initOutputVariant();
+
     m_pcbModel->SetCopperColor( m_copperColor.r, m_copperColor.g, m_copperColor.b );
     m_pcbModel->SetPadColor( m_padColor.r, m_padColor.g, m_padColor.b );
 
diff --git a/pcbnew/exporters/step/exporter_step.h b/pcbnew/exporters/step/exporter_step.h
index 3989225e0d..773632f9a2 100644
--- a/pcbnew/exporters/step/exporter_step.h
+++ b/pcbnew/exporters/step/exporter_step.h
@@ -62,6 +62,7 @@ private:
     bool buildTrack3DShape( PCB_TRACK* aTrack, VECTOR2D aOrigin );
     void buildZones3DShape( VECTOR2D aOrigin );
     bool buildGraphic3DShape( BOARD_ITEM* aItem, VECTOR2D aOrigin );
+    void initOutputVariant();
 
     EXPORTER_STEP_PARAMS m_params;
     std::unique_ptr<FILENAME_RESOLVER> m_resolver;
diff --git a/pcbnew/exporters/step/step_pcb_model.cpp b/pcbnew/exporters/step/step_pcb_model.cpp
index 51db2ebde9..07768ee4c2 100644
--- a/pcbnew/exporters/step/step_pcb_model.cpp
+++ b/pcbnew/exporters/step/step_pcb_model.cpp
@@ -179,30 +179,51 @@ MODEL3D_FORMAT_TYPE fileType( const char* aFileName )
         return FMT_NONE;
 
     char iline[82];
-    memset( iline, 0, 82 );
-    ifile.getline( iline, 82 );
+    MODEL3D_FORMAT_TYPE format_type = FMT_NONE;
+
+    // The expected header should be the first line.
+    // However some files can have a comment at the beginning of the file
+    // So read up to max_line_count lines to try to find the actual header
+    const int max_line_count = 3;
+
+    for( int ii = 0; ii < max_line_count; ii++ )
+    {
+        memset( iline, 0, 82 );
+        ifile.getline( iline, 82 );
+
+        iline[81] = 0;  // ensure NULL termination when string is too long
+
+        // check for STEP in Part 21 format
+        // (this can give false positives since Part 21 is not exclusively STEP)
+        if( !strncmp( iline, "ISO-10303-21;", 13 ) )
+        {
+            format_type = FMT_STEP;
+            break;
+        }
+
+        std::string fstr = iline;
+
+        // check for STEP in XML format
+        // (this can give both false positive and false negatives)
+        if( fstr.find( "urn:oid:1.0.10303." ) != std::string::npos )
+        {
+            format_type = FMT_STEP;
+            break;
+        }
+
+        // Note: this is a very simple test which can yield false positives; the only
+        // sure method for determining if a file *not* an IGES model is to attempt
+        // to load it.
+        if( iline[72] == 'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
+        {
+            format_type = FMT_IGES;
+            break;
+        }
+    }
+
     CLOSE_STREAM( ifile );
-    iline[81] = 0;  // ensure NULL termination when string is too long
 
-    // check for STEP in Part 21 format
-    // (this can give false positives since Part 21 is not exclusively STEP)
-    if( !strncmp( iline, "ISO-10303-21;", 13 ) )
-        return FMT_STEP;
-
-    std::string fstr = iline;
-
-    // check for STEP in XML format
-    // (this can give both false positive and false negatives)
-    if( fstr.find( "urn:oid:1.0.10303." ) != std::string::npos )
-        return FMT_STEP;
-
-    // Note: this is a very simple test which can yield false positives; the only
-    // sure method for determining if a file *not* an IGES model is to attempt
-    // to load it.
-    if( iline[72] == 'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
-        return FMT_IGES;
-
-    return FMT_NONE;
+    return format_type;
 }
 
 
@@ -743,6 +764,7 @@ STEP_PCB_MODEL::STEP_PCB_MODEL( const wxString& aPcbName )
     m_pcbName = aPcbName;
     m_maxError = pcbIUScale.mmToIU( ARC_TO_SEGMENT_MAX_ERROR_MM );
     m_fuseShapes = false;
+    m_outFmt = OUTPUT_FORMAT::FMT_OUT_UNKNOWN;
 }
 
 
@@ -2091,6 +2113,8 @@ bool STEP_PCB_MODEL::WriteIGES( const wxString& aFileName )
         return false;
     }
 
+    m_outFmt = OUTPUT_FORMAT::FMT_OUT_IGES;
+
     wxFileName fn( aFileName );
     IGESControl_Controller::Init();
     IGESCAFControl_Writer writer;
@@ -2123,6 +2147,8 @@ bool STEP_PCB_MODEL::WriteSTEP( const wxString& aFileName, bool aOptimize )
         return false;
     }
 
+    m_outFmt = OUTPUT_FORMAT::FMT_OUT_STEP;
+
     wxFileName fn( aFileName );
 
     STEPCAFControl_Writer writer;
@@ -2202,6 +2228,8 @@ bool STEP_PCB_MODEL::WriteBREP( const wxString& aFileName )
         return false;
     }
 
+    m_outFmt = OUTPUT_FORMAT::FMT_OUT_BREP;
+
     // s_assy = shape tool for the source
     Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
 
@@ -2236,6 +2264,8 @@ bool STEP_PCB_MODEL::WriteXAO( const wxString& aFileName )
         return false;
     }
 
+    m_outFmt = OUTPUT_FORMAT::FMT_OUT_XAO;
+
     // s_assy = shape tool for the source
     Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
 
@@ -2562,19 +2592,22 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a
 
             // VRML models only work when exporting to glTF
             // Also OCCT < 7.9.0 fail to load most VRML 2.0 models because of Switch nodes
-            if( readVRML( doc, aFileNameUTF8.c_str() ) )
+            if( m_outFmt == OUTPUT_FORMAT::FMT_OUT_GLTF )
             {
-                Handle( XCAFDoc_ShapeTool ) shapeTool =
-                        XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
+                if( readVRML( doc, aFileNameUTF8.c_str() ) )
+                {
+                    Handle( XCAFDoc_ShapeTool ) shapeTool =
+                            XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
 
-                prefixNames( shapeTool->Label(),
-                             TCollection_ExtendedString( baseName.c_str().AsChar() ) );
-            }
-            else
-            {
-                ReportMessage( wxString::Format( wxT( "readVRML() failed on filename '%s'.\n" ),
-                                                 fileName ) );
-                return false;
+                    prefixNames( shapeTool->Label(),
+                                 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
+                }
+                else
+                {
+                    ReportMessage( wxString::Format( wxT( "readVRML() failed on filename '%s'.\n" ),
+                                                     fileName ) );
+                    return false;
+                }
             }
         }
         else // Substitution is not allowed
@@ -2590,6 +2623,8 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a
         // TODO: implement IDF and EMN converters
 
     default:
+        ReportMessage( wxString::Format( wxT( "Cannot identify actual file type for '%s'.\n" ),
+                                         fileName ) );
         return false;
     }
 
@@ -2844,6 +2879,8 @@ bool STEP_PCB_MODEL::WriteGLTF( const wxString& aFileName )
         return false;
     }
 
+    m_outFmt = OUTPUT_FORMAT::FMT_OUT_GLTF;
+
     TDF_LabelSequence freeShapes;
     m_assy->GetFreeShapes( freeShapes );
 
diff --git a/pcbnew/exporters/step/step_pcb_model.h b/pcbnew/exporters/step/step_pcb_model.h
index 7941ec1c60..e888f33522 100644
--- a/pcbnew/exporters/step/step_pcb_model.h
+++ b/pcbnew/exporters/step/step_pcb_model.h
@@ -75,12 +75,25 @@ typedef std::map< std::string, TDF_Label > MODEL_MAP;
 
 extern void ReportMessage( const wxString& aMessage );
 
+enum class OUTPUT_FORMAT
+{
+    FMT_OUT_UNKNOWN = 0,
+    FMT_OUT_STEP,
+    FMT_OUT_IGES,
+    FMT_OUT_BREP,
+    FMT_OUT_XAO,
+    FMT_OUT_GLTF
+};
+
 class STEP_PCB_MODEL
 {
 public:
     STEP_PCB_MODEL( const wxString& aPcbName );
     virtual ~STEP_PCB_MODEL();
 
+    // Update m_outFmt to aVariant, giving the output format variant
+    void SpecializeVariant( OUTPUT_FORMAT aVariant ) { m_outFmt = aVariant; }
+
     // add a pad shape (must be in final position)
     bool AddPadShape( const PAD* aPad, const VECTOR2D& aOrigin, bool aVia );
 
@@ -255,9 +268,12 @@ private:
     std::map<wxString, std::pair<gp_Pnt, TopoDS_Shape>> m_pad_points;
 
     /// Name of the PCB, which will most likely be the file name of the path.
-    wxString                        m_pcbName;
+    wxString m_pcbName;
 
-    int                             m_maxError;
+    int      m_maxError;
+
+    /// The current output format for created file
+    OUTPUT_FORMAT m_outFmt;
 };
 
 #endif // OCE_VIS_OCE_UTILS_H
diff --git a/plugins/3d/oce/loadmodel.cpp b/plugins/3d/oce/loadmodel.cpp
index 5aba51c75b..41687cb77f 100644
--- a/plugins/3d/oce/loadmodel.cpp
+++ b/plugins/3d/oce/loadmodel.cpp
@@ -296,27 +296,39 @@ FormatType fileType( const char* aFileName )
     }
 
     char iline[82];
-    memset( iline, 0, 82 );
-    ifile.Read( iline, 82 );
-    iline[81] = 0;  // ensure NULL termination when string is too long
 
-    // check for STEP in Part 21 format
-    // (this can give false positives since Part 21 is not exclusively STEP)
-    if( !strncmp( iline, "ISO-10303-21;", 13 ) )
-        return FMT_STEP;
+    // The expected header should be the first line.
+    // However some files can have a comment at the beginning of the file
+    // So read up to max_line_count lines to try to find the actual header
+    const int max_line_count = 3;
 
-    std::string fstr = iline;
+    for( int ii = 0; ii < max_line_count; ii++ )
+    {
+        memset( iline, 0, 82 );
+        ifile.Read( iline, 82 );
+        iline[81] = 0;  // ensure NULL termination when string is too long
 
-    // check for STEP in XML format
-    // (this can give both false positive and false negatives)
-    if( fstr.find( "urn:oid:1.0.10303." ) != std::string::npos )
-        return FMT_STEP;
+        // check for STEP in Part 21 format
+        // (this can give false positives since Part 21 is not exclusively STEP)
+        if( !strncmp( iline, "ISO-10303-21;", 13 ) )
+        {
+            return FMT_STEP;
+            break;
+        }
 
-    // Note: this is a very simple test which can yield false positives; the only
-    // sure method for determining if a file *not* an IGES model is to attempt
-    // to load it.
-    if( iline[72] == 'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
-        return FMT_IGES;
+        std::string fstr = iline;
+
+        // check for STEP in XML format
+        // (this can give both false positive and false negatives)
+        if( fstr.find( "urn:oid:1.0.10303." ) != std::string::npos )
+            return FMT_STEP;
+
+        // Note: this is a very simple test which can yield false positives; the only
+        // sure method for determining if a file *not* an IGES model is to attempt
+        // to load it.
+        if( iline[72] == 'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
+            return FMT_IGES;
+    }
 
     return FMT_NONE;
 }