Logo 3.5Cats_AndHalfAFish


Small steps.

March 18, 2019 Bethee, MagicaVoxel, Blender, Godot
A simple idle/walk cycle with turning on key press (Godot).

Disclaimer : I don't claim to know what I'm doing ; I'm discovering things as I go.

I'm using MagicaVoxel 0.99.3, Blender 2.76, and Godot 3.0.6.

The purpose is to get a simple 3d animation working in Godot (no skeleton animation).

MagicaVoxel models for 'idle' and 'walking'.
Idle / walking cycle models in MagicaVoxel.

In MagicaVoxel, I created a model of Bethee for every frame of the walk cycle, with the 'idle' model as a starting point.
Next, I exported all models as separate .obj files, and imported them by one into Blender.

MagicaVoxel models for 'idle' and 'walking' in Blender.
Idle / walking cycle models in Blender.

With each model, I removed the duplicate vertices and set the origin to the bottom of the mesh (center). Cleaning up a MagicaVoxel model in Blender gives you at least 2 advantages : you can reduce the number of vertices (for this simple mesh, I went from about 1350 verts to about 420 verts), and you can set a convenient origin.
The 7 meshes were then copied into a second layer and positioned at (0,0,0) for exporting as .obj files (= 7 .obj files).

Exporting the Blender models for 'standing' and 'walking'.
Cleaning up of the MagicaVoxel models in Blender + exporting to .obj.

In the next step, the 7 Blender .obj files as well as the MagicaVoxel .mtl and .png files were copied into the resource folder of a Godot project. I want to use these models to create a simple idle / walk animation in Godot.
In 2d, you can create an animation using the AnimatedSprite node to swap out sprites at runtime. I don't think there's a way to do something similar in 3d (swap out models at runtime), so I'll have to create the animation in code.
Edit : I was wrong ! You can use the AnimationPlayer node in 3d to swap out meshes (see my post 'Animations in 3d.') !

Scene setup in Godot.
Test scene setup in Godot.

This is the scene setup : a Spatial root node, a light and a camera, and another Spatial node (Bethee_Root) with a MeshInstance. I've also added a temporary MeshInstance Primitive (Camera_Mark) at (0,0,0) so I know where to point the camera at.

The MeshInstance 'mesh' and 'material_override' properties will be used to select a material and a mesh from code.
The mesh property of the MeshInstance will receive an .obj file so it can create the model mesh. The material_override needs a material, so we'll need to create one.

Creating a material resource.

Click the 'Create a new resource in memory' btn (top left in inspector) and choose 'SpatialMaterial'. Drag the MagicaVoxel .png file (palette colors) into the texture slot of the albedo property. Save the material as a .tres (text format) or .res (binary format).

As for the code (script on Bethee_Root node) ... The idea is to load the meshes (.obj) into an array and cycle through the array in the _process(delta) function.

Animation code (1/2).
Preloading the material and meshes.

A simplified script is used to test my setup : pressing the right arrow key should make Bethee walk in place. Releasing the arrow key should show the default 'idle' mesh.

Animation code (2/2).
Simplified animation code.

And the result :

Hurray !

Now for the hard part : rotating the mesh CCW or CW when the left or right arrow key is pressed ...

The Godot documentation tells us we should avoid using the Spatial node's rotation property (Euler angles). Instead, we should the transform (rotation relative to parent node) and global_transform (rotation relative to world) properties.
Let's see if we can understand how this works ...

Understanding transform and rotation (1/2).
Understanding transform and rotation (1/2).

The Model node has 3 'arms' that point in the direction of the positive X, Y, and Z world axes. It is positioned at (0,0,0). The Euler rotation is (0,0,0) degrees (= no rotation).
If we take a look at the transform panel, we find the following properties : transform, translation, rotation (degrees), and scale. All of these properties are 'local', meaning : relative to the parent node (Spatial).

'Transform' looks quite complicated, with a lot of numbers. It is in fact a matrix, and it contains all the information from the other 3 properties. Rotation and scale together are called the 'transform basis', translation is called the 'transform origin'.

Understanding transform and rotation (2/2).
Understanding transform and rotation (2/2).

If we rotate the Model node 90 degrees around the Y-axis, we see the local X and Z axis now pointing in new directions. As expected, this is reflected in the transform property.

Two things should be kept in mind, when using transforms :

  • 'Basis exposes its axis vectors transposed.' This is explained here.
    Summarized, 'transform.basis' is a 3x3 matrix. If we print it, it shows us (row1), (row2), (row3).
    'Transform.basis.x' is (col1) of the 3x3 matrix, 'transform.basis.y' = (col2), and 'transform.basis.z' = (col3).
  • 'Precision Errors.' This is explained in the Godot 3d tutorial.
    Basically, transforms will result in a loss of precision due to floating-point errors. Crazy things will happen if you don't take certain precautions.

The Godot documentation shows us how to rotate a mesh using the transform.basis property. For our convenience, there's also a shorter way to write the code, using rotate_xyz().

Rotating a model when a key is pressed (1/2). Rotating a model when a key is pressed (2/2).

The result, when I press the left / right / up keys :

Mission accomplished ! =)

In the next blog post, I'll try to set up a camera-follow.

Personal note : I have decided to be more transparent about what it is like for me, to be a creative person with an aging autistic brain.
It took me 3 weeks to write these 3 posts. I think that's a ridiculously long time. But there you have it.
Some days, my mind and body just don't work, and I feel exhausted. It's terribly discouraging, but I do my best not to give in to my frustration. =)