diff --git a/common/jobs/job_export_pcb_3d.h b/common/jobs/job_export_pcb_3d.h
index f70deb4eb1..b94aa579ed 100644
--- a/common/jobs/job_export_pcb_3d.h
+++ b/common/jobs/job_export_pcb_3d.h
@@ -32,6 +32,7 @@ public:
             m_overwrite( false ),
             m_useGridOrigin( false ),
             m_useDrillOrigin( false ),
+            m_hasUserOrigin( false ),
             m_boardOnly( false ),
             m_includeUnspecified( false ),
             m_includeDNP( false ),
@@ -44,7 +45,10 @@ public:
             m_BoardOutlinesChainingEpsilon( 0.01 ),     // 0.01 mm is a good value
             m_exportTracks( false ),     // Extremely time consuming if true
             m_exportZones( false ),      // Extremely time consuming if true
-            m_format( JOB_EXPORT_PCB_3D::FORMAT::UNKNOWN )
+            m_format( JOB_EXPORT_PCB_3D::FORMAT::UNKNOWN ),
+            m_vrmlUnits( JOB_EXPORT_PCB_3D::VRML_UNITS::METERS ),
+            m_vrmlModelDir( wxEmptyString ),
+            m_vrmlRelativePaths( false )
     {
     }
 
@@ -52,12 +56,22 @@ public:
     {
         UNKNOWN, // defefer to arg
         STEP,
-        GLB
+        GLB,
+        VRML
+    };
+
+    enum class VRML_UNITS
+    {
+        INCHES,
+        MILLIMETERS,
+        METERS,
+        TENTHS // inches
     };
 
     bool                      m_overwrite;
     bool                      m_useGridOrigin;
     bool                      m_useDrillOrigin;
+    bool                      m_hasUserOrigin;
     bool                      m_boardOnly;
     bool                      m_includeUnspecified;
     bool                      m_includeDNP;
@@ -70,6 +84,10 @@ public:
     bool                      m_exportTracks;
     bool                      m_exportZones;
     JOB_EXPORT_PCB_3D::FORMAT m_format;
+
+    VRML_UNITS m_vrmlUnits;
+    wxString   m_vrmlModelDir;
+    bool       m_vrmlRelativePaths;
 };
 
 #endif
diff --git a/kicad/cli/command_pcb_export_3d.cpp b/kicad/cli/command_pcb_export_3d.cpp
index 693613006f..b91d81b676 100644
--- a/kicad/cli/command_pcb_export_3d.cpp
+++ b/kicad/cli/command_pcb_export_3d.cpp
@@ -41,6 +41,9 @@
 #define ARG_INCLUDE_TRACKS "--include-tracks"
 #define ARG_INCLUDE_ZONES "--include-zones"
 #define ARG_FORMAT "--format"
+#define ARG_VRML_UNITS "--units"
+#define ARG_VRML_MODELS_DIR "--models-dir"
+#define ARG_VRML_MODELS_RELATIVE "--models-relative"
 
 #define REGEX_QUANTITY "([\\s]*[+-]?[\\d]*[.]?[\\d]*)"
 #define REGEX_DELIMITER "(?:[\\s]*x)"
@@ -58,59 +61,85 @@ CLI::PCB_EXPORT_3D_COMMAND::PCB_EXPORT_3D_COMMAND( const std::string&   aName,
                 .help( UTF8STDSTR( _( "Output file format, options: step, glb (binary glTF)" ) ) );
     }
 
-    m_argParser.add_argument( ARG_DRILL_ORIGIN )
-            .help( UTF8STDSTR( _( "Use Drill Origin for output origin" ) ) )
-            .implicit_value( true )
-            .default_value( false );
-
-    m_argParser.add_argument( ARG_GRID_ORIGIN )
-            .help( UTF8STDSTR( _( "Use Grid Origin for output origin" ) ) )
-            .implicit_value( true )
-            .default_value( false );
-
-    m_argParser.add_argument( ARG_NO_UNSPECIFIED )
-            .help( UTF8STDSTR( _( "Exclude 3D models for components with 'Unspecified' footprint type" ) ) )
-            .implicit_value( true )
-            .default_value( false );
-
-    m_argParser.add_argument( ARG_NO_DNP )
-            .help( UTF8STDSTR( _( "Exclude 3D models for components with 'Do not populate' attribute" ) ) )
-            .implicit_value( true )
-            .default_value( false );
-
-    m_argParser.add_argument( "--subst-models" )
-            .help( UTF8STDSTR( _( "Substitute STEP or IGS models with the same name in place of VRML models" ) ) )
-            .implicit_value( true )
-            .default_value( false );
-
     m_argParser.add_argument( ARG_FORCE, "-f" )
             .help( UTF8STDSTR( _( "Overwrite output file" ) ) )
             .implicit_value( true )
             .default_value( false );
 
-    m_argParser.add_argument( ARG_BOARD_ONLY )
-            .help( UTF8STDSTR( _( "Only generate a board with no components" ) ) )
-            .implicit_value( true )
-            .default_value( false );
+    if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP || m_format == JOB_EXPORT_PCB_3D::FORMAT::GLB )
+    {
+        m_argParser.add_argument( ARG_GRID_ORIGIN )
+                .help( UTF8STDSTR( _( "Use Grid Origin for output origin" ) ) )
+                .implicit_value( true )
+                .default_value( false );
 
-    m_argParser.add_argument( ARG_INCLUDE_TRACKS )
-            .help( UTF8STDSTR( _( "Export tracks (extremely time consuming)" ) ) )
-            .implicit_value( true )
-            .default_value( false );
+        m_argParser.add_argument( ARG_DRILL_ORIGIN )
+                .help( UTF8STDSTR( _( "Use Drill Origin for output origin" ) ) )
+                .implicit_value( true )
+                .default_value( false );
 
-    m_argParser.add_argument( ARG_INCLUDE_ZONES )
-            .help( UTF8STDSTR( _( "Export zones (extremely time consuming)" ) ) )
-            .implicit_value( true )
-            .default_value( false );
+        m_argParser.add_argument( ARG_NO_UNSPECIFIED )
+                .help( UTF8STDSTR( _(
+                        "Exclude 3D models for components with 'Unspecified' footprint type" ) ) )
+                .implicit_value( true )
+                .default_value( false );
 
-    m_argParser.add_argument( ARG_MIN_DISTANCE )
-            .default_value( std::string( "0.01mm" ) )
-            .help( UTF8STDSTR( _( "Minimum distance between points to treat them as separate ones" ) ) );
+        m_argParser.add_argument( ARG_NO_DNP )
+                .help( UTF8STDSTR(
+                        _( "Exclude 3D models for components with 'Do not populate' attribute" ) ) )
+                .implicit_value( true )
+                .default_value( false );
+
+        m_argParser.add_argument( "--subst-models" )
+                .help( UTF8STDSTR( _( "Substitute STEP or IGS models with the same name in place "
+                                      "of VRML models" ) ) )
+                .implicit_value( true )
+                .default_value( false );
+
+        m_argParser.add_argument( ARG_BOARD_ONLY )
+                .help( UTF8STDSTR( _( "Only generate a board with no components" ) ) )
+                .implicit_value( true )
+                .default_value( false );
+
+        m_argParser.add_argument( ARG_INCLUDE_TRACKS )
+                .help( UTF8STDSTR( _( "Export tracks (extremely time consuming)" ) ) )
+                .implicit_value( true )
+                .default_value( false );
+
+        m_argParser.add_argument( ARG_INCLUDE_ZONES )
+                .help( UTF8STDSTR( _( "Export zones (extremely time consuming)" ) ) )
+                .implicit_value( true )
+                .default_value( false );
+
+        m_argParser.add_argument( ARG_MIN_DISTANCE )
+                .default_value( std::string( "0.01mm" ) )
+                .help( UTF8STDSTR(
+                        _( "Minimum distance between points to treat them as separate ones" ) ) );
+    }
 
     m_argParser.add_argument( ARG_USER_ORIGIN )
             .default_value( std::string() )
             .help( UTF8STDSTR( _( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default unit mm)" ) ) );
 
+    if( m_format == JOB_EXPORT_PCB_3D::FORMAT::VRML )
+    {
+        m_argParser.add_argument( ARG_VRML_UNITS )
+                .default_value( std::string( "in" ) )
+                .help( UTF8STDSTR(
+                        _( "Output units; ascii or csv format only; valid options: mm, m, in, tenths" ) ) );
+
+        m_argParser.add_argument( ARG_VRML_MODELS_DIR )
+                .default_value( std::string( "" ) )
+                .help( UTF8STDSTR(
+                        _( "Name of folder to create and store 3d models in, if not specified or "
+                           "empty, the models will be embedded in main exported vrml file" ) ) );
+
+        m_argParser.add_argument( ARG_VRML_MODELS_RELATIVE )
+                .help( UTF8STDSTR( _( "Used with --models-dir to output relative paths in the resulting file" ) ) )
+                .implicit_value( true )
+                .default_value( false );
+    }
+
     m_argParser.add_argument( "-o", ARG_OUTPUT )
             .default_value( std::string() )
             .help( UTF8STDSTR( _( "Output file name" ) ) );
@@ -122,17 +151,21 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway )
 {
     std::unique_ptr<JOB_EXPORT_PCB_3D> step( new JOB_EXPORT_PCB_3D( true ) );
 
-    step->m_useDrillOrigin = m_argParser.get<bool>( ARG_DRILL_ORIGIN );
-    step->m_useGridOrigin = m_argParser.get<bool>( ARG_GRID_ORIGIN );
-    step->m_includeUnspecified = !m_argParser.get<bool>( ARG_NO_UNSPECIFIED );
-    step->m_includeDNP = !m_argParser.get<bool>( ARG_NO_DNP );
-    step->m_substModels = m_argParser.get<bool>( ARG_SUBST_MODELS );
+    if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP || m_format == JOB_EXPORT_PCB_3D::FORMAT::GLB )
+    {
+        step->m_useDrillOrigin = m_argParser.get<bool>( ARG_DRILL_ORIGIN );
+        step->m_useGridOrigin = m_argParser.get<bool>( ARG_GRID_ORIGIN );
+        step->m_includeUnspecified = !m_argParser.get<bool>( ARG_NO_UNSPECIFIED );
+        step->m_includeDNP = !m_argParser.get<bool>( ARG_NO_DNP );
+        step->m_substModels = m_argParser.get<bool>( ARG_SUBST_MODELS );
+        step->m_exportTracks = m_argParser.get<bool>( ARG_INCLUDE_TRACKS );
+        step->m_exportZones = m_argParser.get<bool>( ARG_INCLUDE_ZONES );
+        step->m_boardOnly = m_argParser.get<bool>( ARG_BOARD_ONLY );
+    }
+
     step->m_overwrite = m_argParser.get<bool>( ARG_FORCE );
     step->m_filename = FROM_UTF8( m_argParser.get<std::string>( ARG_INPUT ).c_str() );
     step->m_outputFile = FROM_UTF8( m_argParser.get<std::string>( ARG_OUTPUT ).c_str() );
-    step->m_boardOnly = m_argParser.get<bool>( ARG_BOARD_ONLY );
-    step->m_exportTracks = m_argParser.get<bool>( ARG_INCLUDE_TRACKS );
-    step->m_exportZones = m_argParser.get<bool>( ARG_INCLUDE_ZONES );
     step->m_format = m_format;
 
     if( step->m_format == JOB_EXPORT_PCB_3D::FORMAT::UNKNOWN )
@@ -150,6 +183,29 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway )
         }
     }
 
+    if( step->m_format == JOB_EXPORT_PCB_3D::FORMAT::VRML )
+    {
+        wxString units = FROM_UTF8( m_argParser.get<std::string>( ARG_VRML_UNITS ).c_str() );
+
+        if( units == wxS( "in" ) )
+            step->m_vrmlUnits = JOB_EXPORT_PCB_3D::VRML_UNITS::INCHES;
+        else if( units == wxS( "mm" ) )
+            step->m_vrmlUnits = JOB_EXPORT_PCB_3D::VRML_UNITS::MILLIMETERS;
+        else if( units == wxS( "m" ) )
+            step->m_vrmlUnits = JOB_EXPORT_PCB_3D::VRML_UNITS::METERS;
+        else if( units == wxS( "tenths" ) )
+            step->m_vrmlUnits = JOB_EXPORT_PCB_3D::VRML_UNITS::TENTHS;
+        else
+        {
+            wxFprintf( stderr, _( "Invalid units specified\n" ) );
+            return EXIT_CODES::ERR_ARGS;
+        }
+
+        step->m_vrmlModelDir = FROM_UTF8( m_argParser.get<std::string>( ARG_VRML_MODELS_DIR ).c_str() );
+
+        step->m_vrmlRelativePaths = m_argParser.get<bool>( ARG_VRML_MODELS_RELATIVE );
+    }
+
     wxString userOrigin = FROM_UTF8( m_argParser.get<std::string>( ARG_USER_ORIGIN ).c_str() );
 
     LOCALE_IO dummy;    // Switch to "C" locale
@@ -192,31 +248,36 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway )
                 return CLI::EXIT_CODES::ERR_ARGS;
             }
         }
+
+        step->m_hasUserOrigin = true;
     }
 
-    wxString minDistance = FROM_UTF8( m_argParser.get<std::string>( ARG_MIN_DISTANCE ).c_str() );
-
-    if( !minDistance.IsEmpty() )
+    if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP || m_format == JOB_EXPORT_PCB_3D::FORMAT::GLB )
     {
-        std::regex  re_pattern( REGEX_QUANTITY REGEX_UNIT,
-                                std::regex_constants::icase );
-        std::smatch sm;
-        std::string str( minDistance.ToUTF8() );
-        std::regex_search( str, sm, re_pattern );
-        step->m_BoardOutlinesChainingEpsilon = atof( sm.str( 1 ).c_str() );
+        wxString minDistance =
+                FROM_UTF8( m_argParser.get<std::string>( ARG_MIN_DISTANCE ).c_str() );
 
-        std::string tunit( sm[2] );
-
-        if( tunit.size() > 0 ) // No unit accepted ( default = mm )
+        if( !minDistance.IsEmpty() )
         {
-            if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) )
+            std::regex  re_pattern( REGEX_QUANTITY REGEX_UNIT, std::regex_constants::icase );
+            std::smatch sm;
+            std::string str( minDistance.ToUTF8() );
+            std::regex_search( str, sm, re_pattern );
+            step->m_BoardOutlinesChainingEpsilon = atof( sm.str( 1 ).c_str() );
+
+            std::string tunit( sm[2] );
+
+            if( tunit.size() > 0 ) // No unit accepted ( default = mm )
             {
-                step->m_BoardOutlinesChainingEpsilon *= 25.4;
-            }
-            else if( tunit.compare( "mm" ) )
-            {
-                std::cout << m_argParser;
-                return CLI::EXIT_CODES::ERR_ARGS;
+                if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) )
+                {
+                    step->m_BoardOutlinesChainingEpsilon *= 25.4;
+                }
+                else if( tunit.compare( "mm" ) )
+                {
+                    std::cout << m_argParser;
+                    return CLI::EXIT_CODES::ERR_ARGS;
+                }
             }
         }
     }
diff --git a/kicad/kicad_cli.cpp b/kicad/kicad_cli.cpp
index fef598aa67..f8f4fff4eb 100644
--- a/kicad/kicad_cli.cpp
+++ b/kicad/kicad_cli.cpp
@@ -132,6 +132,7 @@ static CLI::PCB_EXPORT_DRILL_COMMAND     exportPcbDrillCmd{};
 static CLI::PCB_EXPORT_DXF_COMMAND       exportPcbDxfCmd{};
 static CLI::PCB_EXPORT_3D_COMMAND        exportPcbGlbCmd{ "glb", JOB_EXPORT_PCB_3D::FORMAT::GLB };
 static CLI::PCB_EXPORT_3D_COMMAND        exportPcbStepCmd{ "step", JOB_EXPORT_PCB_3D::FORMAT::STEP };
+static CLI::PCB_EXPORT_3D_COMMAND        exportPcbVrmlCmd{ "vrml", JOB_EXPORT_PCB_3D::FORMAT::VRML };
 static CLI::PCB_EXPORT_SVG_COMMAND       exportPcbSvgCmd{};
 static CLI::PCB_EXPORT_PDF_COMMAND       exportPcbPdfCmd{};
 static CLI::PCB_EXPORT_POS_COMMAND       exportPcbPosCmd{};
@@ -192,7 +193,8 @@ static std::vector<COMMAND_ENTRY> commandStack = {
                     &exportPcbPdfCmd,
                     &exportPcbPosCmd,
                     &exportPcbStepCmd,
-                    &exportPcbSvgCmd
+                    &exportPcbSvgCmd,
+                    &exportPcbVrmlCmd
                 }
             }
         }
diff --git a/pcbnew/dialogs/dialog_export_vrml.cpp b/pcbnew/dialogs/dialog_export_vrml.cpp
index 54bd605c59..8a687053cf 100644
--- a/pcbnew/dialogs/dialog_export_vrml.cpp
+++ b/pcbnew/dialogs/dialog_export_vrml.cpp
@@ -231,9 +231,9 @@ void PCB_EDIT_FRAME::OnExportVRML( wxCommandEvent& event )
     {
         // Origin = board center:
         BOARD* pcb = GetBoard();
-        VECTOR2I center = pcb->GetBoundingBox().GetCenter();
-        aXRef = pcbIUScale.IUTomm( center.x );
-        aYRef = pcbIUScale.IUTomm( center.y );
+        BOX2I  bbox = pcb->ComputeBoundingBox( true );
+        aXRef = pcbIUScale.IUTomm( bbox.GetCenter().x );
+        aYRef = pcbIUScale.IUTomm( bbox.GetCenter().y );
     }
 
     double scale = scaleList[dlg.GetUnits()];     // final scale export
diff --git a/pcbnew/exporters/exporter_vrml.cpp b/pcbnew/exporters/exporter_vrml.cpp
index e11bba99bd..503f5bee78 100644
--- a/pcbnew/exporters/exporter_vrml.cpp
+++ b/pcbnew/exporters/exporter_vrml.cpp
@@ -1025,7 +1025,6 @@ void EXPORTER_PCB_VRML::ExportVrmlFootprint( FOOTPRINT* aFootprint, std::ostream
     auto sM = aFootprint->Models().begin();
     auto eM = aFootprint->Models().end();
 
-    wxFileName subdir( m_Subdir3DFpModels, wxT( "" ) );
 
     while( sM != eM )
     {
@@ -1245,7 +1244,11 @@ bool EXPORTER_PCB_VRML::ExportVRML_File( PROJECT* aProject, wxString *aMessages,
 
     SetScale( aMMtoWRMLunit );
     m_UseInlineModelsInBrdfile = aExport3DFiles;
-    m_Subdir3DFpModels = a3D_Subdir;
+
+    wxFileName subdir( a3D_Subdir, wxT( "" ) );
+    // convert the subdir path to a absolute full one with the output file as the cwd
+    m_Subdir3DFpModels = subdir.GetAbsolutePath( wxFileName( aFullFileName ).GetPath() );
+
     m_UseRelPathIn3DModelFilename = aUseRelativePaths;
     m_Cache3Dmodels = aProject->Get3DCacheManager();
 
@@ -1329,11 +1332,9 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
 void EXPORTER_PCB_VRML::ExportFp3DModelsAsLinkedFile( const wxString& aFullFileName )
 {
     // check if the 3D Subdir exists - create if not
-    wxFileName subdir( m_Subdir3DFpModels, wxT( "" ) );
-
-    if( ! subdir.DirExists() )
+    if( !wxDir::Exists( m_Subdir3DFpModels ) )
     {
-        if( !wxDir::Make( subdir.GetFullPath() ) )
+        if( !wxDir::Make( m_Subdir3DFpModels ) )
             throw( std::runtime_error( "Could not create 3D model subdirectory" ) );
     }
 
diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp
index 6a6ad4dad8..b403f1227e 100644
--- a/pcbnew/pcbnew_jobs_handler.cpp
+++ b/pcbnew/pcbnew_jobs_handler.cpp
@@ -59,6 +59,7 @@
 #include <plugins/kicad/pcb_plugin.h>
 #include <reporter.h>
 #include <wildcards_and_files_ext.h>
+#include <export_vrml.h>
 
 #include "pcbnew_scripting_helpers.h"
 
@@ -96,36 +97,79 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob )
 
     BOARD* brd = LoadBoard( aStepJob->m_filename );
 
-    EXPORTER_STEP_PARAMS params;
-    params.m_exportTracks = aStepJob->m_exportTracks;
-    params.m_exportZones = aStepJob->m_exportZones;
-    params.m_includeUnspecified = aStepJob->m_includeUnspecified;
-    params.m_includeDNP = aStepJob->m_includeDNP;
-    params.m_BoardOutlinesChainingEpsilon = aStepJob->m_BoardOutlinesChainingEpsilon;
-    params.m_overwrite = aStepJob->m_overwrite;
-    params.m_substModels = aStepJob->m_substModels;
-    params.m_origin = VECTOR2D( aStepJob->m_xOrigin, aStepJob->m_yOrigin );
-    params.m_useDrillOrigin = aStepJob->m_useDrillOrigin;
-    params.m_useGridOrigin = aStepJob->m_useGridOrigin;
-    params.m_boardOnly = aStepJob->m_boardOnly;
-
-    switch( aStepJob->m_format )
+    if( aStepJob->m_format == JOB_EXPORT_PCB_3D::FORMAT::VRML )
     {
-    case JOB_EXPORT_PCB_3D::FORMAT::STEP:
-        params.m_format = EXPORTER_STEP_PARAMS::FORMAT::STEP;
-        break;
-    case JOB_EXPORT_PCB_3D::FORMAT::GLB:
-        params.m_format = EXPORTER_STEP_PARAMS::FORMAT::GLB;
-        break;
-    default: return CLI::EXIT_CODES::ERR_UNKNOWN; // should have gotten here
+        double scale = 0.0;
+        switch ( aStepJob->m_vrmlUnits )
+        {
+        case JOB_EXPORT_PCB_3D::VRML_UNITS::MILLIMETERS: scale = 1.0; break;
+        case JOB_EXPORT_PCB_3D::VRML_UNITS::METERS: scale = 0.001; break;
+        case JOB_EXPORT_PCB_3D::VRML_UNITS::TENTHS: scale = 10.0 / 25.4; break;
+        case JOB_EXPORT_PCB_3D::VRML_UNITS::INCHES: scale = 1.0 / 25.4; break;
+        }
+
+        EXPORTER_VRML vrmlExporter( brd );
+        wxString      messages;
+
+        double originX = pcbIUScale.IUTomm( aStepJob->m_xOrigin );
+        double originY = pcbIUScale.IUTomm( aStepJob->m_yOrigin );
+
+        if( !aStepJob->m_hasUserOrigin )
+        {
+            BOX2I bbox = brd->ComputeBoundingBox( true );
+            originX = pcbIUScale.IUTomm( bbox.GetCenter().x );
+            originY = pcbIUScale.IUTomm( bbox.GetCenter().y );
+        }
+
+        bool success = vrmlExporter.ExportVRML_File(
+                brd->GetProject(), &messages, aStepJob->m_outputFile, scale,
+                !aStepJob->m_vrmlModelDir.IsEmpty(), aStepJob->m_vrmlRelativePaths,
+                aStepJob->m_vrmlModelDir, originX, originY );
+
+        if ( success )
+        {
+            m_reporter->Report( wxString::Format( _( "Successfully exported VRML to %s" ), aStepJob->m_outputFile ),
+                                RPT_SEVERITY_INFO );
+        }
+        else
+        {
+            m_reporter->Report( _( "Error exporting VRML" ), RPT_SEVERITY_ERROR );
+            return CLI::EXIT_CODES::ERR_UNKNOWN;
+        }
     }
-
-    EXPORTER_STEP stepExporter( brd, params );
-    stepExporter.m_outputFile = aStepJob->m_outputFile;
-
-    if( !stepExporter.Export() )
+    else
     {
-        return CLI::EXIT_CODES::ERR_UNKNOWN;
+        EXPORTER_STEP_PARAMS params;
+        params.m_exportTracks = aStepJob->m_exportTracks;
+        params.m_exportZones = aStepJob->m_exportZones;
+        params.m_includeUnspecified = aStepJob->m_includeUnspecified;
+        params.m_includeDNP = aStepJob->m_includeDNP;
+        params.m_BoardOutlinesChainingEpsilon = aStepJob->m_BoardOutlinesChainingEpsilon;
+        params.m_overwrite = aStepJob->m_overwrite;
+        params.m_substModels = aStepJob->m_substModels;
+        params.m_origin = VECTOR2D( aStepJob->m_xOrigin, aStepJob->m_yOrigin );
+        params.m_useDrillOrigin = aStepJob->m_useDrillOrigin;
+        params.m_useGridOrigin = aStepJob->m_useGridOrigin;
+        params.m_boardOnly = aStepJob->m_boardOnly;
+
+        switch( aStepJob->m_format )
+        {
+        case JOB_EXPORT_PCB_3D::FORMAT::STEP:
+            params.m_format = EXPORTER_STEP_PARAMS::FORMAT::STEP;
+            break;
+        case JOB_EXPORT_PCB_3D::FORMAT::GLB:
+            params.m_format = EXPORTER_STEP_PARAMS::FORMAT::GLB;
+            break;
+        default: return CLI::EXIT_CODES::ERR_UNKNOWN; // should have gotten here
+        }
+
+        EXPORTER_STEP stepExporter( brd, params );
+        stepExporter.m_outputFile = aStepJob->m_outputFile;
+
+        if( !stepExporter.Export() )
+        {
+            return CLI::EXIT_CODES::ERR_UNKNOWN;
+        }
     }
 
     return CLI::EXIT_CODES::OK;