Browse Source

ObjImporter: option to skip index array merging on import.

Because MeshTools::removeDuplicates() uses a STL hashmap, it's quite
bad. So bad that on the Rungholt scene it takes 4 seconds out of 7.3 for
the whole import process.
master
Vladimír Vondruš 4 years ago
parent
commit
fefb86365a
  1. 3
      doc/changelog.dox
  2. 7
      src/MagnumPlugins/ObjImporter/ObjImporter.conf
  3. 24
      src/MagnumPlugins/ObjImporter/ObjImporter.cpp
  4. 20
      src/MagnumPlugins/ObjImporter/ObjImporter.h
  5. 52
      src/MagnumPlugins/ObjImporter/Test/ObjImporterTest.cpp

3
doc/changelog.dox

@ -1097,7 +1097,8 @@ See also:
consistent with @ref Trade::SceneData::findFieldId().
- Added @ref Trade::MeshData::attributeId() that returns ID of an attribute
in a set of attributes of the same name
- @relativeref{Trade,ObjImporter} now supports quads and negative indices
- @relativeref{Trade,ObjImporter} now supports quads and negative indices and
is able to optionally skip index array merging on import
- Added @ref Trade::TextureType::Texture1DArray,
@relativeref{Trade::TextureType,Texture2DArray} and
@relativeref{Trade::TextureType,CubeMapArray} in order to be able to

7
src/MagnumPlugins/ObjImporter/ObjImporter.conf

@ -0,0 +1,7 @@
# [configuration_]
[configuration]
# Merge the per-attribute index arrays into a single index buffer. If disabled,
# the resulting mesh will be non-indexed, with vertex data duplicated according
# to per-attribute index arrays.
mergeIndexArrays=true
# [configuration_]

24
src/MagnumPlugins/ObjImporter/ObjImporter.cpp

@ -34,6 +34,7 @@
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/StringStlHash.h>
#include <Corrade/Utility/Algorithms.h>
#include <Corrade/Utility/ConfigurationGroup.h>
#include "Magnum/Mesh.h"
#include "Magnum/MeshTools/RemoveDuplicates.h"
@ -558,13 +559,21 @@ Containers::Optional<MeshData> ObjImporter::doMesh(const UnsignedInt id, Unsigne
return Containers::NullOpt;
}
/* Merge index arrays. If any of the attributes was not there, the whole
index array has zeros, not affecting the uniqueness in any way. */
Containers::Array<char> indexData{NoInit, indices.size()*sizeof(UnsignedInt)};
/* Merge index arrays, unless disabled. If any of the attributes was not
there, the whole index array has zeros, not affecting the uniqueness in
any way. */
Containers::Array<char> indexData;
std::size_t vertexCount;
if(configuration().value<bool>("mergeIndexArrays")) {
indexData = Containers::Array<char>{NoInit, indices.size()*sizeof(UnsignedInt)};
const auto indexDataI = Containers::arrayCast<UnsignedInt>(indexData);
const std::size_t vertexCount = MeshTools::removeDuplicatesInPlaceInto(
vertexCount = MeshTools::removeDuplicatesInPlaceInto(
Containers::arrayCast<2, char>(arrayView(indices)), indexDataI);
/* If merging was disabled, this behaves like if all index tuples were
unique. No other change needed. */
} else vertexCount = indices.size();
/* Allocate attribute and vertex data */
std::size_t attributeCount = 1;
UnsignedInt stride = sizeof(Vector3);
@ -609,8 +618,13 @@ Containers::Optional<MeshData> ObjImporter::doMesh(const UnsignedInt id, Unsigne
}
CORRADE_INTERNAL_ASSERT(offset == stride && attributeIndex == attributeCount);
/* If mergeIndexArrays was disabled, indexData is nullptr and the mesh is
not indexed */
const auto meshIndices = indexData ?
Trade::MeshIndexData{MeshIndexType::UnsignedInt, indexData} :
Trade::MeshIndexData{};
return MeshData{*primitive,
Utility::move(indexData), Trade::MeshIndexData{indexDataI},
Utility::move(indexData), meshIndices,
Utility::move(vertexData), Utility::move(attributeData)};
}

20
src/MagnumPlugins/ObjImporter/ObjImporter.h

@ -101,9 +101,13 @@ information.
@section Trade-ObjImporter-behavior Behavior and limitations
Meshes are imported as @ref MeshPrimitive::Triangles with
@ref MeshIndexType::UnsignedInt indices, interleaved @ref VertexFormat::Vector3
positions with optional @ref VertexFormat::Vector3 normals and
@ref VertexFormat::Vector2 texture coordinates, if present in the source file.
@ref VertexFormat::Vector3 positions interleaved with optional
@ref VertexFormat::Vector3 normals and @ref VertexFormat::Vector2 texture
coordinates, if present in the source file. By default the per-attribute index
arrays are merged into a single @ref MeshIndexType::UnsignedInt index buffer.
If you disable the @cb{.ini} mergeIndexArrays @ce @ref Trade-ObjImporter-configuration "configuration option",
the resulting mesh will be nonindexed, with the vertex data duplicated
according to per-attribute index arrays.
Negative indices (where @cpp -1 @ce is the last position / texture coordinate
/ normal known at given point in the file, @cpp -2 @ce is the second-to-last,
@ -112,6 +116,16 @@ supported. Quads are converted to two triangles, higher-order polygons are not
supported.
Material properties are currently not supported.
@section Trade-ObjImporter-configuration Plugin-specific configuration
It's possible to tune various import options through @ref configuration(). See
below for all options and their default values:
@snippet MagnumPlugins/ObjImporter/ObjImporter.conf configuration_
See @ref plugins-configuration for more information and an example showing how
to edit the configuration values.
*/
class MAGNUM_OBJIMPORTER_EXPORT ObjImporter: public AbstractImporter {
public:

52
src/MagnumPlugins/ObjImporter/Test/ObjImporterTest.cpp

@ -28,6 +28,7 @@
#include <Corrade/Containers/String.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/ConfigurationGroup.h>
#include <Corrade/Utility/Format.h>
#include <Corrade/Utility/Path.h>
@ -56,6 +57,7 @@ struct ObjImporterTest: TestSuite::Tester {
void meshNormals();
void meshTextureCoordinatesNormals();
void meshNoMergeIndexArrays();
void meshNegativeIndices();
void meshQuads();
@ -199,6 +201,7 @@ ObjImporterTest::ObjImporterTest() {
&ObjImporterTest::meshNormals,
&ObjImporterTest::meshTextureCoordinatesNormals,
&ObjImporterTest::meshNoMergeIndexArrays,
&ObjImporterTest::meshNegativeIndices,
&ObjImporterTest::meshQuads,
@ -455,6 +458,55 @@ void ObjImporterTest::meshTextureCoordinatesNormals() {
TestSuite::Compare::Container);
}
void ObjImporterTest::meshNoMergeIndexArrays() {
Containers::Pointer<AbstractImporter> importer = _manager.instantiate("ObjImporter");
importer->configuration().setValue("mergeIndexArrays", false);
CORRADE_VERIFY(importer->openFile(Utility::Path::join(OBJIMPORTER_TEST_DIR, "mesh-texture-coordinates-normals.obj")));
CORRADE_COMPARE(importer->meshCount(), 1);
/* Same as meshTextureCoordinatesNormals() but with the index array used
to duplicate the vertex data */
const Containers::Optional<MeshData> data = importer->mesh(0);
CORRADE_VERIFY(data);
CORRADE_VERIFY(!data->isIndexed());
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Lines);
CORRADE_COMPARE(data->attributeCount(), 3);
CORRADE_COMPARE_AS(data->attribute<Vector3>(MeshAttribute::Position),
Containers::arrayView<Vector3>({
{0.5f, 2.0f, 3.0f},
{0.0f, 1.5f, 1.0f},
{0.5f, 2.0f, 3.0f},
{0.0f, 1.5f, 1.0f},
{0.0f, 1.5f, 1.0f},
{0.5f, 2.0f, 3.0f},
{0.0f, 1.5f, 1.0f},
{0.5f, 2.0f, 3.0f},
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(data->attribute<Vector2>(MeshAttribute::TextureCoordinates),
Containers::arrayView<Vector2>({
{1.0f, 0.5f},
{1.0f, 0.5f},
{0.5f, 1.0f},
{0.5f, 1.0f},
{1.0f, 0.5f},
{1.0f, 0.5f},
{0.5f, 1.0f},
{0.5f, 1.0f},
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(data->attribute<Vector3>(MeshAttribute::Normal),
Containers::arrayView<Vector3>({
{1.0f, 0.5f, 3.5f},
{0.5f, 1.0f, 0.5f},
{0.5f, 1.0f, 0.5f},
{1.0f, 0.5f, 3.5f},
{0.5f, 1.0f, 0.5f},
{1.0f, 0.5f, 3.5f},
{0.5f, 1.0f, 0.5f},
{0.5f, 1.0f, 0.5f},
}), TestSuite::Compare::Container);
}
void ObjImporterTest::meshNegativeIndices() {
Containers::Pointer<AbstractImporter> importer = _manager.instantiate("ObjImporter");
CORRADE_VERIFY(importer->openFile(Utility::Path::join(OBJIMPORTER_TEST_DIR, "mesh-negative-indices.obj")));

Loading…
Cancel
Save