Writing a mesh loader

If you want use a custom mesh format you can extend atoms with a new mesh loader. Atoms supports atoms mesh and alembic mesh formats (from version 2.0). To add a new mesh format you must create a new class definition that extend the Atoms::BaseMeshLoader, then you must register the new loader class inside an atoms plugin


Class definition

#include <Atoms/Globals.h>
#include <AtomsCore/Metadata/MapMetadata.h>
#include <Atoms/Loaders/BaseMeshLoader.h>

#define kFooMeshLoaderId 101

namespace Atoms
{
	class ATOMSPLUGIN_EXPORT FooMeshLoader : public BaseMeshLoader
	{
	public:
		//! Type string
		/*!
		\return Class type string
		*/
		std::string typeStr() const;

		//! Class static type string. This is also the file extension of your file format
		static std::string const staticTypeStr;

		//! Type id
		/*!
		\return Class type id
		*/
		unsigned int typeId() const;

		//! Class static type id
		static const unsigned int staticTypeId;

		//! Constructor
		FooMeshLoader();

		//! Destructor
		~FooMeshLoader();

		//! Creator function
		/*!
		\return Return a new AlembicMeshLoader object
		*/
		static AtomsPtr<BaseMeshLoader> creator();

		//! load
		/*!
		Load an atoms file
		*/
		AtomsPtr<AtomsCore::MapMetadata> load(const std::string &filePath, const std::string& filter = "*");
	};
}

namespace Atoms
{
std::string const FooMeshLoader::staticTypeStr = "foo"; // the file extension

std::string FooMeshLoader::typeStr() const
{
	return FooMeshLoader::staticTypeStr;
}

const unsigned int FooMeshLoader::staticTypeId = kFooMeshLoaderId;

unsigned int FooMeshLoader::typeId() const
{
	return FooMeshLoader::staticTypeId;
}

FooMeshLoader::FooMeshLoader() :
	BaseMeshLoader()
{
}

FooMeshLoader::~FooMeshLoader()
{
}

AtomsPtr<BaseMeshLoader> FooMeshLoader::creator()
{
	return std::dynamic_pointer_cast<BaseMeshLoader>(std::make_shared<FooMeshLoader>());
}

AtomsPtr<AtomsCore::MapMetadata> FooMeshLoader::load(const std::string &filePath, const std::string& filter = "*")
{
	AtomsPtr<AtomsCore::MapMetadata>  skinMeshMetadata(new AtomsCore::MapMetadata);
	std::string fullPath = AtomsUtils::solvePath(filePath);
	std::vector<std::string> filterVec;
	if ((filter != "*") || (filter != ""))
	{
		AtomsUtils::splitString(AtomsUtils::eraseFromString(filter, ' '), ',', filterVec);
	}

	//load your mesh file here and start to fill the mapmetadata
	for (const std::string& geoName: fooGeoFileList)
	{
		//Check if the current geo is passing the filter
		if ((filterVec.size() > 0) && (!AtomsUtils::filterNames(filterVec, geoName)))
			continue;
	}

	...
	return skinMeshMetadata;
}
}


Atoms calls the load function to read the new mesh format. This function must fill and return a MapMetadata with the data read from your mesh file.

This MapMetadata can contain multiple meshes and it must follow this structure:

MapMetadata
	"version":  IntMetadata(2)
	"children": MapMedata
              "fooNode1": MapMetadata
                          "geo": MeshMetadata
                          "cloth" BoolMeatadata // set to true if this is a cloth mesh
                          "material": MapMetadata
                                           "color": Vector3Metadata // Color used for preview without the textures by the skin mode (optional)
                                           "diffuseTexture": ImageMetadata // Texture used for preview by the skin mode (optional)
                          "attributes": MapMetadata //Custom data. This data is written on the mesh sent to the renderer. You can use these attributes to drive shader attributes from he mesh. The mesh attribute on the arnold/rman/vray mesh will use the atoms_ prefix. (optional)
                                           "atoms": MapMetadata
                                                       "foo_Attr1":...
                                                       "foo_Attr2":...
                                           "arnold": MapMetadata
                                                       "ai...":...
											"rman": MapMetadata
                                                       "...":...
											"vray": MapMetadata
                                                       "...":...
                                           ....
                        "primVars": MapMetadata:
                                           "myVar": MapMetadata
                                                       "interpolation": StringMetadata (constant/uniform/vertex/faceVarying).
                                                       "data: Metadata
                                           "arnold": MapMetadata
                                                       "ai...":...
                                           ....
                          "matrix": MatrixMetadata
                          "wolrdMatrix": MatrixMetadata
                          "translation": Vector3Metadata
                          "rotation": Vector3Metadata
						  "rotationOrder": IntMetadata
                          "scale": Vector3Metadata
						  "pivot": Vector3Metadata
                          "sets": StringArrayMetadata
                          "jointIndices": ArrayMetadata // skin joint ids per vertex, this must have the same length of the points array
								IntArrayMetadata, // array of joint (influence) indices for the current vertex
								IntArrayMetadata,
								...
                          "jointWeights": ArrayMetadata// skin joint weights per vertex, this must have the same length of the points array
								DoubleArrayMetadata(), // array of joint (influence) weight for the current vertex
								DoubleArrayMetadata(),
								...
                          "blendShapes": ArrayMetadata // Blend shapes data (optional)
									MapMetadata
										"id":IntMetadata // index of the current blend shape, this index is used at render/preview time to get the target weight from the agent metadata
										"name":StringMetadata // name of the target
										"P":Vector3ArrayMetadata
										"N":Vector3ArrayMetadata
									MapMetadata
										"id":IntMetadata
										"name":StringMetadata
										"P":Vector3ArrayMetadata
										"N":Vector3ArrayMetadata
									...
                          "children": MapMetadata
                                         "fooChildNode1": MapMetadata
                                                       "geo": MeshMetadata
                                                       ...
                                         "fooChildNode2": MapMetadata
                                                       "geo": MeshMetadata
                                                       ...



To register the new loader to atoms:

extern "C"
{
	ATOMSPLUGIN_EXPORT bool initializePlugin()
	{
		MeshLoaderFactory& factory = MeshLoaderFactory::instance();
		factory.registerMeshLoader(FooMeshLoader::staticTypeStr, &FooMeshLoader::creator);
	}
}


Compile the plugin

Windows:

In visual studio create a dll projects, add the atoms, tbb and openexr includes and add

BUILD_ATOMSPLUGIN,WIN,_CRT_SECURE_NO_WARNINGS,_CRT_NONSTDC_NO_DEPRECATE

to the preprocessor definitions..


Linux:

Compile as a shared object adding the atoms, tbb and opendexr includes and BUILD_ATOMSPLUGIN to the preprocessor definitions.


Use the plugin

Add to the ATOMS_PLUGINS_PATH environment variable the folder where the plugin is located.

Copyright © 2017, Toolchefs LTD.