MagicaVoxel-Blender-Unity Workflow

Hi Trixie here….

We had a good break from the build cycle with the Text Adventure framework and since then have been making lots of fun headway on the main game in development Endless Elevator.

Endless Elevator is, as the name suggests, an endless runner style of game. It’s played in the vertical axis and follows the Good Cop as he scales the heights of an endless building shooting down the bad guys, climbing stairs, and catching elevators.

We have the main game functionality finished to a point so we started working on background objects and some cute little buddies for the Good Cop. It’s puppies…ain’t they cute!

This is not about the puppies though. This is about the workflow we have been using for creating assets using MagicaVoxel and making them game engine ready using Blender before importing them into Unity.

Lets start with MagicaVoxel. A 3D voxel editor that is free (no commercial license required) 8 bit and super awesome. Credits to the software are appreciated (e.g. “created by MagicaVoxel”) – like what I did there just like that! All the assets for the Endless Elevator have been made with MagicaVoxel. The walls, the floors, the furniture, and the characters.

First we model and then we paint in MagicaVoxel. For example this table lamp:

When we are done modelling and painting we export it as an .obj file that also produces a .png of the palette mesh mapping. It’s a bit like using the UV Unwrap in Blender but much harder to manually map or see.

Once we are done with MagicaVoxel if we want to optimise we import the .obj file into Blender. Blender is a terrific open source 3D modelling (and more) software. There is a trade-off here… we use Blender to lower the poly count on complex objects by using the decimate modifier. This modifier basically takes a parameter in your vertexes (like the angle between edges) and reduces the vertex count by simplifying the model. You see the problem with MagicaVoxel is that it created edges from a fixed point which can make lots of thin triangles.

Have a look at this model of the lamp imported into Blender:

You can see all the sharp angles of the triangles there. This is how MagicaVoxel works under the hood and it’s great for the internal workings of that program and is very efficient when working in that app but it sucks a bit for making complex models that you want to import into a game engine.

This is the Decimate modifier in Blender that we use to simplify this topology. We tell the modifier to take the Planar (faces) and simplify anything that has an angle under 25 degree.

We are left with something like this: (below)

This is much simpler and super easy for the game engine to understand and render.

The trade off here is that when you decimate all the vertices you lose your UV mapping for the paint work you might have done with MagicaVoxel. These are the limitations of working with awesome freeware. Sure they are awesome but if you shell out a few hundred (or less in some cases) for different Voxel modelling software you can get away with not having to work around these problems. But welcome to the world of no-budget game making. Hacking through the workarounds is part of the fun. Plus you actually learn a bit while you are working it out.

So in our game Endless Elevator we use a lot of small models (ie. not complex) and import them straight from MagicaVoxel and use their paint system and resulting exported image files for making the materials (albedo component). If we have more complex models that we want to simplify, like the walls and lifts in the surrounding building, then we import into Blender and do some optimising. Once the complex models have been optimised then we unmask them and paint the UV’s using GIMP. Next when they are imported into Unity we either add a material with the coloured UV mask we painted up or use Unity’s in built colour system for large areas.

There is another problem with using MagicaVoxel to make your game assets and that is on more complex models the “normal” of a face are often flipped the wrong way round. This one is kind of easy to spot and not that much fun to re-mediate. If you have a look at our character below you can see his shadow being projected on to the wall behind him.

Oops – he’s got big holes in him. You cannot see it on the model and it’s really only a problem if you are looking for it and using lots of hard lighting. In a 3D model each mesh forms a face and that face has two sides. In Unity’s default Shader only one face (the forward one) is rendered. So when MagicVoxel flips a few faces here and there (they are very small usually) you get these gaps that do not block the light in a shadow. It’s pretty hard to show in an image but what we have below is the model imported into Blender where we can expose the normals (the direction the face is facing!) and see the issue. In this image we have clipped the camera hard so that we can see into the cavity inside the model. Normals show up as light blue lines. You can see a few of them poking the wrong way into the center of the model instead of the outside. You can play around with the “flip normals” feature in Blender to fix these issues but it’s a lot of fiddling that frankly I have not had the patience or need to do yet!

So these are just a few of the issues and workarounds we use with this workflow – I hope you enjoy reading about it and if you have any questions feel free to comment 🙂

Trixie out.

Unity Hinge Joint

Hi Xander here…

For our game Endless Elevator, which is in development, we have a bad guy who is a knife thrower. I know nasty. In keeping with the blocky style of the characters in the game only his throwing arm moves and the rest of him is rigid. We decided to use the Unity inbuilt Hinge Joint and “spring” feature to simulate the throwing action. It turned out to be really easy to implement but hard to control perfectly. This is the story of how it all hangs together.

This guy below with the creepy eyes and beard is our knife throwing guy. You can see the top level empty Game Object called KnifeSpy_Package and two child objects (one for his body mesh the other for his arm which is separate). You can just make out the orange arrow of the Hinge Joint near his shoulder but more of that below.

This is his arm object. He’s holding a knife now… but soon we are going to teach him how to throw it (kinda).

You can see the Hinge Joint attached to the arm object here as a red arc around the Z axis. The arc of the Hinge Joint has been limited to just the angle that he needs to raise the arm and bring it back down in a throwing action.

Here is what the Hinge Joint looks like in the Editor. That Connected Body is the main figure of the character. The arm mesh that this script is attached to also has a Rigidbody component and must be set to “Use Gravity” for the Spring to work.

You can see where we set the limits for the arm axis in the bottom of the object there. We access the Use Motor boolean from our script to turn that feature on and off. When it’s on a spring winds up the arm to it’s firing position and when he throws that spring is released shooting his arm back down in a throwing arc.

This is what our script looks like in the editor:

The Target Angle is the height of the arm as it raises to throw. When the Player is in range and we are facing him if the arm has been raised above the target angle we can throw the knife. We can use this to tweak the throw. You can see in the example below our arm doesn’t really come up high enough so we can use this setting to fix what it looks like on the fly.

The ‘X’ is exposed in the editor to help with that process so that we can understand what’s going on with that setting without having to click around in the editor to see it against the arm transform.

The Knife Prefab is the knife mesh and the Knife Transform is an empty game object used to define the spot where we instantiate the Knife Prefab.

The Knife is instantiated with some Force and there are booleans to control if we can shoot and if the wait between shoots has completed.

This is what the script looks like as code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KnifeHinge : MonoBehaviour {

    private HingeJoint hingeKnife;
    public Vector3 targetAngle;
    public float x;    // Debug in Editor
    public GameObject knifePrefab;
    public GameObject knifeTransform;
    public float force;
    public bool canShoot;
    public bool waitDone;

    private Transform playerTransform;
    public Transform parentTransform;

    // Use this for initialization
    void Start () {
        hingeKnife = GetComponent<HingeJoint>();
        playerTransform = GameObject.FindWithTag("Player").transform;
    }
	
	// Update is called once per frame
	void Update () {

        if (Mathf.Abs(playerTransform.transform.position.y - (parentTransform.transform.position.y)) < 1)  // If the player is on the same level as you
        {
            if (Mathf.Abs(playerTransform.transform.position.x - parentTransform.transform.position.x) < 8)  // If he is within 16 units from you
            {
                var lookPos = playerTransform.position;
                var rotation = Quaternion.LookRotation(lookPos);
                parentTransform.transform.LookAt(lookPos);
                if (waitDone)
                {
                    canShoot = true; // Can shoot is only true if you are looking at the Player (on the same level and 16 units away)
                }

            }
        }

	}

    void FixedUpdate()
    {
        x = hingeKnife.transform.rotation.eulerAngles.x;   // this is for debugging the angle of the arm and hinge in the editor easily
        if (canShoot)
        {

            if (hingeKnife.transform.rotation.eulerAngles.x > targetAngle.x && hingeKnife.transform.rotation.eulerAngles.x < (targetAngle.x + 10f))  // this is set to 295 it goes up to 297 (If your arm is all the way up)
            {

                hingeKnife.useMotor = false;
                var theKnife = (GameObject)Instantiate(knifePrefab, knifeTransform.transform.position, knifeTransform.transform.rotation);
                theKnife.GetComponent<Rigidbody>().AddForce(-force, 0, 0, ForceMode.Impulse);
                Destroy(theKnife, 2.0f);
                canShoot = false;
                waitDone = false;
                StartCoroutine(WaitAround(2f));  // shoot every 2 seconds

            }

        }
    }

    private IEnumerator WaitAround(float waitTime)
    {
        yield return new WaitForSeconds(waitTime);
        waitDone = true;
        hingeKnife.useMotor = true;


    }
}

This is what the whole thing looks like put together:

As I mentioned above there is a bit of tweaking to get it to look right – but this post is about the process of putting everything together and how the components work to achieve the effect.

This is what it looks like after the tweaking:

I hope you found this interesting enough – if you did and want to read more about this stuff I did a post a few weeks back about how we do the guns in this game Endless Elevator:
http://www.zuluonezero.net/2019/03/15/unity-how-to-do-guns/

Enjoy.