Lovebirb.MonoGame.SkinnedMeshImporter 1.0.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package Lovebirb.MonoGame.SkinnedMeshImporter --version 1.0.2
NuGet\Install-Package Lovebirb.MonoGame.SkinnedMeshImporter -Version 1.0.2
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Lovebirb.MonoGame.SkinnedMeshImporter" Version="1.0.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Lovebirb.MonoGame.SkinnedMeshImporter --version 1.0.2
#r "nuget: Lovebirb.MonoGame.SkinnedMeshImporter, 1.0.2"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Lovebirb.MonoGame.SkinnedMeshImporter as a Cake Addin
#addin nuget:?package=Lovebirb.MonoGame.SkinnedMeshImporter&version=1.0.2

// Install Lovebirb.MonoGame.SkinnedMeshImporter as a Cake Tool
#tool nuget:?package=Lovebirb.MonoGame.SkinnedMeshImporter&version=1.0.2

MonoGame Skinned Mesh Importer

N|Solid

This is a custom importer, processor, reader, writer, and framework to handle skinned meshes within MonoGame. It uses MonoGame's content system to avoid needing to package Assimp with your game, as well as fitting into your pre-existing content methodology.

About

After looking through many projects that import animations into MonoGame, I decided that I would need to make my own. Many other projects are incredibly messy with code that is hard to read and even harder to maintain, and I have not yet found an importer that actually uses MonoGame's content pipeline at all.

This importer is written neatly using OOP principles, almost everything is commented, all important state is handled by the respective classes, and there is a simple interface in order to use its features. The system exists as a shared project including the data classes and structs (animations, bones, meshes, etc.), and classes to handle playing animations and rendering the skinned meshes.

The tool was tested with Blender 2.93.1 exporting to FBX files, more on that below.

Installation

This tool is available on NuGet here and can be installed in Visual Studio with the NuGet package manager.

Usage

Adding the Content Builder Reference

Once the package has been installed to the MonoGame project of your choice, the reference to the content builder has to be added via the Content Pipeline Tool.

  1. Open the content file for the project within the Content Pipeline tool.
  2. Select the main "Content" object within the tool.
  3. Find the "References" property in the window below and click on it, a window should open.
  4. Click the "Add" button at the top right of the window.
  5. Navigate to C:\Users{USERNAME}.nuget\packages and open the lovebirb.monogame.skinnedmeshimporter folder.
  6. Open the folder of the used version (e.g. 1.0.0), then the lib folder, finally the netstandard2.0 folder, and select the SkinnedMeshImporter.dll file.
  7. Click the "Ok" button on the window to close it.
  8. The content builder has now been referenced and skinned meshes can now be added as content.

Exporting

All instructions are written with Blender 2.93.1 in mind. Other tools have not been tested, however; they should work as this content builder uses Assimp, which is quite capable. If you do try this content builder with something other than Blender, it would be appreciated if you could get in contact.

  1. Open your Blender file with your rigged and animated model.
  2. Select the armature and mesh(es).
  3. Click on File>Export>FBX(.fbx).
  4. Choose a folder to export the file, obviously this is likely to be within your project's Content folder.
  5. Path mode does not matter as the importer does not load them, so path mode can be set to anything you want.
  6. Make sure "Limit to selected objects" is checked.
  7. Under "Transform", "Apply Scalings" should be set to "FBX All", "Forward" to "-Z Forward", "Up" to "Y Up", "Apply Unit" should be false, and "Use Space Transform" and "Apply Transform" should be true.
  8. Under "Armature", "Add Leaf Bones" should be false. This can be left true to include a bone at the end of any bone with no child, but has not been tested.
  9. Click Export FBX. The model is now ready to be imported.

Importing

  1. Within the Content Pipeline Tool with the content file for your project opened, add the model as you would add any other content with the tool.
  2. Click on the model within the content tool and change the "Importer" property to the "SkinnedMeshImporter - Liru3D" option, the processor should automatically change to match.
  3. Save the file. The model is now ready to be used in the project, which will be covered in the next section.

Loading

The model can now be loaded like any other content within MonoGame, using the Content.Load function. The type is SkinnedModel.

SkinnedModel characterModel = Content.Load<SkinnedModel>("Character");

This SkinnedModel instance includes the meshes, bones, and animations loaded from the file, but by itself does not do anything. The data is immutable, meaning that it will forever remain as it was loaded.

Note that textures are not loaded, which avoids the messy content problem of the default MonoGame model loader. Textures must be loaded separately and set on the effect.

Animation

The AnimationPlayer class handles playing animations for a SkinnedModel. It is created using a SkinnedModel instance.

AnimationPlayer animationPlayer = new AnimationPlayer(characterModel);

The player's current animation can be set to any animation, even those from other files. It looks for bones with the same names, so ensure the skeletons of the models are the same in layout.

animationPlayer.Animation = characterModel.Animations[0];

The player must be updated.

animationPlayer.Update(gameTime);

In order to make sure the system can work with custom effects and is not limited with anything built-in, the AnimationPlayer itself does not handle drawing. It does, however; work with MonoGame's SkinnedEffect.

SkinnedEffect effect = new SkinnedEffect(GraphicsDevice);

effect.Texture = ...
effect.View = ...
effect.Projection = ...
effect.World = ...

foreach (SkinnedMesh mesh in characterModel.Meshes)
{
	animationPlayer.SetEffectBones(effect);
	effect.CurrentTechnique.Passes[0].Apply();
	mesh.Draw();
}

Playback can be started and stopped with the IsPlaying property. Playback speed and looping can be changed with the PlaybackSpeed and IsLooping properties respectively.

animationPlayer.PlaybackSpeed = 2.0f;
animationPlayer.IsLooping = true;
animationPlayer.IsPlaying = true;

Playback can also be set to a specific time with the CurrentTime property, this works in seconds and ticks.

animationPlayer.CurrentTime = 1.0f;
animationPlayer.CurrentTick = 5;

Future Plans

I want to keep this project lightweight and simple to use. I'm not trying to compete with Unity or anything more capable, merely providing an option for devs to use skinned meshes without needing knowledge of asset importing and bone-space transforms.

This was mainly made as I needed animations for my project, Terror Cell. As I implement this into Terror Cell, some changes may be made and additions included. I eventually want to implement a nice UI to properly load and test animations, including a seek bar. A unique model with proper animations would also be nice at some point.

The main plan right now is to neaten and comment everything in the project and ensure it's all 100% readable and maintainable, then I will create some tests to ensure it's all bug free, then the previously mentioned UI. After that, if I have the time, I will possibly look into some more advanced features like blending and parameters.

Regardless of my future plans, the current version does what it's supposed to do.

Credits

SkinnedMeshLoader by Laura Jenkins (Liru)

  • Assimp and AssimpNet for removing large amounts of pain from asset importing.
  • AlienScribble for the FBXLoader project which I used extensively to test against.
  • Dillinger for the great markdown tool for this readme file.
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.4 170 5/24/2023
1.0.3 292 1/7/2023
1.0.2 358 10/4/2021
1.0.1 272 8/2/2021
1.0.0 333 7/26/2021

Fixed bug where setting the current tick of an animation would have no effect.
Made the model of an animation public so that it can be swapped out at runtime.