Skip to content

Commit

Permalink
Add support for 3MF format (#1138)
Browse files Browse the repository at this point in the history
  • Loading branch information
Meakk authored Jan 8, 2024
1 parent eaee80f commit 519edac
Show file tree
Hide file tree
Showing 16 changed files with 73 additions and 25 deletions.
3 changes: 2 additions & 1 deletion .github/actions/assimp-install-dep/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ runs:
uses: actions/cache@v3
with:
path: dependencies/assimp_install
key: assimp-v5.3.1-${{runner.os}}-${{inputs.cpu}}-1
key: assimp-v5.3.1-${{runner.os}}-${{inputs.cpu}}-2

- name: Checkout ASSIMP
if: steps.cache-assimp.outputs.cache-hit != 'true'
Expand All @@ -41,6 +41,7 @@ runs:
cmake ../assimp
-DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=OFF
-DASSIMP_BUILD_ASSIMP_TOOLS=OFF
-DASSIMP_BUILD_3MF_IMPORTER=ON
-DASSIMP_BUILD_COLLADA_IMPORTER=ON
-DASSIMP_BUILD_DXF_IMPORTER=ON
-DASSIMP_BUILD_FBX_IMPORTER=ON
Expand Down
1 change: 1 addition & 0 deletions application/testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ endif()

if(F3D_PLUGIN_BUILD_ASSIMP)
f3d_test(NAME TestOFF DATA teapot.off ARGS --up=+Z --load-plugins=assimp)
f3d_test(NAME Test3MF DATA cube_gears.3mf ARGS --load-plugins=assimp DEFAULT_LIGHTS) # Using default lights because of ResetCamera
f3d_test(NAME TestDXF DATA PinkEggFromLW.dxf ARGS --bg-color=1,1,1 -p --load-plugins=assimp DEFAULT_LIGHTS) # Using default lights because of ResetCamera
f3d_test(NAME TestFBX DATA phong_cube.fbx ARGS --load-plugins=assimp DEFAULT_LIGHTS) # Using default lights because of ResetCamera
f3d_test(NAME TestFBX16bits DATA 16bit.fbx ARGS --load-plugins=assimp THRESHOLD 70 DEFAULT_LIGHTS) # Using default lights because of ResetCamera
Expand Down
2 changes: 1 addition & 1 deletion doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ For F3D users:
- Reading EXR files is now multi-threaded and much faster.
- Translucency support is now enabled by default.
- A small margin is added between the model and the grid to avoid potential z-fighting.
- Add X files support (part of `assimp` plugin)
- Add 3MF and X files support (part of `assimp` plugin)
- Fix potential crashes when reading `assimp` plugin file format

For libf3d users:
Expand Down
2 changes: 1 addition & 1 deletion doc/dev/BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Some modules, plugins and bindings depending on external libraries can be option
* `F3D_MODULE_EXR`: Support for OpenEXR images. Requires `OpenEXR`. Disabled by default.
* `F3D_PLUGIN_BUILD_EXODUS`: Support for ExodusII (.ex2) file format. Requires that VTK has been built with `IOExodus` module (and `hdf5`). Enabled by default.
* `F3D_PLUGIN_BUILD_OCCT`: Support for STEP, IGES and BREP file formats. Requires `OpenCASCADE`. Disabled by default.
* `F3D_PLUGIN_BUILD_ASSIMP`: Support for FBX, DAE, OFF, DXF and X file formats. Requires `Assimp`. Disabled by default.
* `F3D_PLUGIN_BUILD_ASSIMP`: Support for FBX, DAE, OFF, DXF, X and 3MF file formats. Requires `Assimp`. Disabled by default.
* `F3D_PLUGIN_BUILD_ALEMBIC`: Support for ABC file format. Requires `Alembic`. Disabled by default.
* `F3D_PLUGIN_BUILD_DRACO`: Support for DRC file format. Requires `Draco`. Disabled by default.
* `F3D_PLUGIN_BUILD_USD`: Support for USD file format. Requires `OpenUSD`. Disabled by default.
Expand Down
4 changes: 3 additions & 1 deletion doc/user/LIMITATIONS_AND_TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ Here is a non exhaustive list of F3D limitations:
* The `--camera-zoom-factor` option require VTK >= 9.3.0

## Assimp
FBX, DAE, OFF, DXF and X file formats rely on [Assimp](https://github.com/assimp/assimp) library. It comes with some known limitations:
FBX, DAE, OFF, DXF, X and 3MF file formats rely on [Assimp](https://github.com/assimp/assimp) library. It comes with some known limitations:
- PBR materials are not supported for FBX file format.
- Complex animations are not working very well with Assimp 5.1, it's recommended to use Assimp 5.0 for this use case.
- Only one animation can be shown at a time, showing all animations is not supported yet.
- Some files can be empty, crash, or show artifacts.
- DXF support is very limited: only files with polylines and 3D faces are displayed.
- 3MF files may crash at exit (issue in Assimp: https://github.com/assimp/assimp/issues/5328)
- Only support RBGA 8-bits embedded textures

## Alembic
ABC file formats rely on [Alembic](https://github.com/alembic/alembic) library. It comes with some known limitations:
Expand Down
5 changes: 3 additions & 2 deletions doc/user/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ Here is the list of supported file formats:
* **.off** : Object File Format (full scene)
* **.dxf** : Drawing Exchange Format (full scene)
* **.x** : DirectX Format (full scene)
* **.3mf** : 3D Manufacturing Format (full scene)

## Scene construction

The **full scene** formats (.gltf/.glb, .3ds, .wrl, .obj, .fbx, .dae, .off) contain not only *geometry*,
The **full scene** formats (.gltf/.glb, .3ds, .wrl, .obj, .fbx, .dae, .off, .x, .3mf) contain not only *geometry*,
but also some scene information like *lights*, *cameras*, *actors* in the scene, as well as *texture* properties.
By default, all this information will be loaded from the file and displayed. Use the `--geometry-only` [options](OPTIONS.md)
to modify this behavior. For file formats that do not support it, **a default scene** is created.
Expand All @@ -58,7 +59,7 @@ In this case, in order to open a file that requires a plugin, you will have to m
Here is the list of plugins provided officially by F3D:

- **alembic**: ABC support
- **assimp**: FBX, DAE, OFF, DXF and X support
- **assimp**: FBX, DAE, OFF, DXF, X and 3MF support
- **draco**: DRC support
- **exodus**: EX2 support
- **occt**: STEP and IGES support
Expand Down
2 changes: 1 addition & 1 deletion plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
option(F3D_PLUGIN_BUILD_ALEMBIC "Alembic plugin (ABC files)" OFF)
option(F3D_PLUGIN_BUILD_ASSIMP "Assimp plugin (FBX, OFF, DAE, DXF and X files)" OFF)
option(F3D_PLUGIN_BUILD_ASSIMP "Assimp plugin (FBX, OFF, DAE, DXF, X and 3MF files)" OFF)
option(F3D_PLUGIN_BUILD_DRACO "Draco plugin (DRC files)" OFF)
option(F3D_PLUGIN_BUILD_EXODUS "ExodusII plugin (EX2 files)" ON)
option(F3D_PLUGIN_BUILD_OCCT "OpenCASCADE plugin (STEP and IGES files)" OFF)
Expand Down
8 changes: 8 additions & 0 deletions plugins/assimp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ f3d_plugin_declare_reader(
FORMAT_DESCRIPTION "DirectX File Format"
)

f3d_plugin_declare_reader(
NAME 3MF
EXTENSIONS 3mf
MIMETYPES model/3mf
VTK_IMPORTER vtkF3DAssimpImporter
FORMAT_DESCRIPTION "3D Manufacturing Format"
)

set(rpaths "")
get_target_property(target_type assimp::assimp TYPE)
if (target_type STREQUAL SHARED_LIBRARY)
Expand Down
4 changes: 2 additions & 2 deletions plugins/assimp/configs/config.d/10_assimp.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
".*(fbx|dae|off|dxf|x)":
".*(fbx|dae|off|dxf|x|3mf)":
{
"load-plugins": "assimp"
},
".*(off)":
".*(off|3mf)":
{
"up": "+Z",
"camera-direction": "-1,1,-0.5"
Expand Down
4 changes: 2 additions & 2 deletions plugins/assimp/configs/thumbnail.d/10_assimp.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
".*(fbx|dae|off|dxf|x)":
".*(fbx|dae|off|dxf|x|3mf)":
{
"load-plugins": "assimp"
},
".*(off)":
".*(off|3mf)":
{
"up": "+Z",
"camera-direction": "-1,1,-0.5"
Expand Down
41 changes: 28 additions & 13 deletions plugins/assimp/module/vtkF3DAssimpImporter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <assimp/scene.h>

#include <memory>
#include <regex>

vtkStandardNewMacro(vtkF3DAssimpImporter);

Expand Down Expand Up @@ -170,9 +171,14 @@ class vtkF3DAssimpImporter::vtkInternals
if (path[0] == '*')
{
int texIndex = std::atoi(path + 1);
vTexture = this->EmbeddedTextures[texIndex];

if (texIndex >= 0 && texIndex < static_cast<int>(this->EmbeddedTextures.size()))
{
vTexture = this->EmbeddedTextures[texIndex];
}
}
else

if (!vTexture)
{
// sometimes, embedded textures are indexed by filename
const aiTexture* aTexture = this->Scene->GetEmbeddedTexture(path);
Expand Down Expand Up @@ -257,15 +263,24 @@ class vtkF3DAssimpImporter::vtkInternals
}
else
{
vtkNew<vtkImageData> img;
img->SetDimensions(aTexture->mWidth, aTexture->mHeight, 1);
img->AllocateScalars(VTK_UNSIGNED_CHAR, 4);
// Sometimes Assimp returns corrupted textures (encountered with 3MF)
// Let's validate it before trying to read it
// See https://github.com/assimp/assimp/issues/5328
std::regex validRegexp("[rgba]{4}[0-9]{4}");

if (std::regex_match(aTexture->achFormatHint, validRegexp))
{
// only "rgba8888" is supported for now
vtkNew<vtkImageData> img;
img->SetDimensions(aTexture->mWidth, aTexture->mHeight, 1);
img->AllocateScalars(VTK_UNSIGNED_CHAR, 4);

unsigned char* imageBuffer = reinterpret_cast<unsigned char*>(img->GetScalarPointer());
std::copy(imageBuffer, imageBuffer + 4 * aTexture->mWidth * aTexture->mHeight,
reinterpret_cast<unsigned char*>(aTexture->pcData));
unsigned char* imageBuffer = reinterpret_cast<unsigned char*>(img->GetScalarPointer());
std::copy(imageBuffer, imageBuffer + 4 * aTexture->mWidth * aTexture->mHeight,
reinterpret_cast<unsigned char*>(aTexture->pcData));

vTexture->SetInputData(img);
vTexture->SetInputData(img);
}
}

return vTexture;
Expand Down Expand Up @@ -331,7 +346,7 @@ class vtkF3DAssimpImporter::vtkInternals
aiString texDiffuse;
if (material->GetTexture(aiTextureType_DIFFUSE, 0, &texDiffuse) == aiReturn_SUCCESS)
{
vtkSmartPointer<vtkTexture> tex = this->CreateTexture(texDiffuse.data);
vtkSmartPointer<vtkTexture> tex = this->CreateTexture(texDiffuse.C_Str());
if (tex)
{
property->SetTexture("diffuseTex", tex);
Expand All @@ -341,7 +356,7 @@ class vtkF3DAssimpImporter::vtkInternals
aiString texNormal;
if (material->GetTexture(aiTextureType_NORMALS, 0, &texNormal) == aiReturn_SUCCESS)
{
vtkSmartPointer<vtkTexture> tex = this->CreateTexture(texNormal.data);
vtkSmartPointer<vtkTexture> tex = this->CreateTexture(texNormal.C_Str());
if (tex)
{
property->SetTexture("normalTex", tex);
Expand All @@ -351,7 +366,7 @@ class vtkF3DAssimpImporter::vtkInternals
aiString texAlbedo;
if (material->GetTexture(aiTextureType_BASE_COLOR, 0, &texAlbedo) == aiReturn_SUCCESS)
{
vtkSmartPointer<vtkTexture> tex = this->CreateTexture(texAlbedo.data, true);
vtkSmartPointer<vtkTexture> tex = this->CreateTexture(texAlbedo.C_Str(), true);
if (tex)
{
property->SetTexture("albedoTex", tex);
Expand All @@ -361,7 +376,7 @@ class vtkF3DAssimpImporter::vtkInternals
aiString texEmissive;
if (material->GetTexture(aiTextureType_EMISSIVE, 0, &texEmissive) == aiReturn_SUCCESS)
{
vtkSmartPointer<vtkTexture> tex = this->CreateTexture(texEmissive.data, true);
vtkSmartPointer<vtkTexture> tex = this->CreateTexture(texEmissive.C_Str(), true);
if (tex)
{
property->SetTexture("emissiveTex", tex);
Expand Down
2 changes: 1 addition & 1 deletion plugins/assimp/module/vtkF3DAssimpImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* The list of supported file format is available here:
* https://github.com/assimp/assimp/blob/master/doc/Fileformats.md
*
* The following formats have been tested and are supported by f3d: FBX, DAE, OFF, DXF, X
* The following formats have been tested and are supported by f3d: FBX, DAE, OFF, DXF, X, 3MF
*/

#ifndef vtkF3DAssimpImporter_h
Expand Down
13 changes: 13 additions & 0 deletions resources/BundleInfo.plist.in
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,19 @@
<string>x</string>
</array>
</dict>
<!-- 3MF -->
<dict>
<key>CFBundleTypeName</key>
<string>3D Manufacturing Format</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSIsAppleDefaultForType</key>
<true/>
<key>CFBundleTypeExtensions</key>
<array>
<string>3mf</string>
</array>
</dict>
<!-- OFF -->
<dict>
<key>CFBundleTypeName</key>
Expand Down
3 changes: 3 additions & 0 deletions testing/baselines/Test3MF.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions testing/data/DATA_LICENSES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- animatedWorld.fbx: VTK Data: BSD-3-Clause
- animation_with_skeleton.fbx: assimp test models: BSD-3-Clause
- anim_test.x: assimp test models: BSD-3-Clause
- cube_gears.3mf: 3MF consortium samples: BSD-2-Clause
- beach.nrrd: VTK Data: BSD-3-Clause
- bluntfin.vts: VTK Data: BSD-3-Clause
- bot2.wrl: VTK Data: BSD-3-Clause
Expand Down
3 changes: 3 additions & 0 deletions testing/data/cube_gears.3mf
Git LFS file not shown

0 comments on commit 519edac

Please sign in to comment.