Exporting Models as GlTF meshes from Blender

This section discusses how to export scenes from Blender (2.8+) in glTF format appropriate for use by AssetManager.loadModel.

Background

glTF (GL Transmission Format) is a specification for transmitting 3D scenes between applications. The specification is owned by Khronos Group but is publicly available and can be used royalty free. It is growing in popularity as a robust and efficient transmission mechanism.

jME3 introduced a loader for glTF in 2017 (written by nehon) and it has since been included as a standard part of the jme3-plugins target. There are some limitations of the importer which can be avoided by following the guidelines below.

Ultimately all jME projects should use the .j3o format for storing assets. However during development, it’s required to export scenes from Blender in a format suitable for conversion (either through the SDK or directly through code).

Use of glTF (or another standard format) has a significant advantage as new versions of Blender with significant enhancements are released fairly regularly.

Blender 2.7 had a number of problems in exporting glTF; these notes refer exclusively to Blender 2.8+

Creating Models

Details of how to create models in Blender that are compatible with jME are given at Creating assets in Blender3D. Follow all details on that page for creating models before attempting an export.

Before exporting a model all transforms need to be applied. This performs the required transforms on the vertices in a mesh to reset the transforms on the object. To apply all transforms in Blender 2.8, select each object (in object mode, not edit mode) then choose from the Object menu Apply/All Transforms.

As always, see Best Practices for additional information.

Blender Buffer Clearing should be performed prior to exporting any model from Blender.

Animations

  1. Blender supports non-linear transitions using F-Curves. However the glTF importer only supports linear transitions. There are 2 ways to ensure all transitions are linear:

    1. In Blender 2.8, go to the graph editor, select all keys (menu select/all) and then change to linear interpolation (menu key/interpolation mode/linear).

    2. At export time, force the export to create interpolated keyframes using sampling. This can be done in Python using export_force_sampling=True or selecting Always Sample Animations in the Animation tab of the export function. By default a sample is created from each frame of the animation. This can be changed in Python using export_frame_step=n where n is number of frames between samples or changing the sampling rate in the Animation tab of the export function.

  2. Blender has a powerful tool to allow bones to be posed by just specifying the position of the final bone in a chain and allowing Blender to work out where to position attached bones. This tool is a bone constraint called IK (Inverse Kinematics) and it can save a lot of time in building animations. However jME does not support IK constraints so any use of IK needs to be "baked" before the export. To do this, select the appropriate bone, go to the bone contraints tab and apply the IK constraint. A useful workflow is to save the file, bake the constrain, export to glTF then revert to the saved file to restore the IK constraint.

  3. All actions in Blender will be added as animations to the Node corresponding to the armature. In addition, the action last tweaked within Blender will also be added as an animation to the object’s node. This is just an artifact of the organisation of actions within Blender and should be ignored within jME.

  4. glTF models loaded using jME 3.3 will create animations that use the new animation system introduced in jME 3.3.

    See https://hub.jmonkeyengine.org/t/monkanim-v2/39877 for more info about the new animation system.

Materials

All of the rules associated with defining materials in Blender suitable for use in jME apply when glTF is used as the import/export format.

  1. Blender supports lots of different types of shaders and complex materials with several different renderers. glTF supports a relatively basic set of PBR attributes. If the primary purpose of the materials is to produce glTF exported models use a simple Principled BSDF node in your materials with the following settings:

    1. Metalling and roughness values

    2. Base color

    3. Diffuse and Normal (bump) textures

Shape Keys

Shape keys in Blender are used to apply a deformation to a mesh without changing the underlying vertices. The glTF exporter ignores shape keys unless they are part of an animation. To include shape keys in the export, select the Shape Keys option in the Animation tab of the glTF export options.

Shape keys are supported as of jME version 3.3.0-beta2+. Use the PBRLighting.j3md material definition when doing so.

youtu.be/DZQ6HJgUheY
Figure 1. youtube

Export options

Blender 2.8 supports many options when exporting in glTF format. Most of the default options work fine.

You have 3 options of the format to export, . GLB: a single file in binary format (the default) . GLTF_EMBEDDED: a single file in JSON format . GLTF_SEPERATE: multiple files for separate objects, textures etc.

The GLB format is the most efficient so use it unless you need to debug the output or edit it prior to import for any reason.

The export can be performed manually (File/Export/GLTF 2.0) or via a Python script. If using a script to export, the following command will export the entire scene to the current directory in .glb format with recommended options.

bpy.ops.export_scene.gltf(filepath=filename, export_materials=False, export_force_sampling=True, check_existing=False)

Import structure

The structure of the nodes following import will roughly match their structure in Blender. Note the following exceptions: . There is no equivalent in glTF to Blender collections. These will not be represented in the imported structure. . If an object has no material, a default material will be created for it. . If an object has a single material, the corresponding node in the imported structure will have type Geometry with the object’s mesh and the associated material. . If an object has more than one material, the corresponding node will have type Node with 1 child per material. Each of these children will be a Geometry with the associated material and a mesh containing the vertices assigned to the material.

For example, if a blender scene has the following structure

Scene collection
    Collection A
        Tree (Object)
            Tree_Mesh (Mesh)
        Car (Object)
            Car_Mesh (Mesh)
                Body (Material)
        House (Object)
            House_Mesh (Mesh)
                Walls (Material)
                Roof (Material)
    Collection B
        Person_Armature (Armature)
            Root (Bone)
                Head (Bone)
            Animations
                Walk (Action)
                NLA Tracks
                    NLA Track
                        Run (Action)
            Person (Object)
                Animation
                    Walk (Action link)
                Person_Mesh

Then after export to glTF format and import to jME it will look like:

Scene (Node)
    Tree (Geometry)
        Default (Material)
    Car (Geometry)
        Body (Material)
    House (Node)
        House_1 (Geometry)
            Walls (Material)
        House_1 (Geometry)
            Roof (Material)
    Person_Armature (Node)
        Animations (AnimControl)
            Walk (Animation)
            Run (Animation)
        Person (Geometry)
            Animations (AnimControl)
                Walk (Animation)

For example, the animated person could be loaded with a custom material assigned as follows:

ModelKey key = new ModelKey("Models/model.glb");
Node scene = (Node)assetManager.loadModel(key);
Node person = scene.getChild("Person_Armature");
Geometry geometry = (Geometry)person.getChild("Person");
geometry.setMaterial(customMaterial);
root.attachChild(person);

And an animation for the model could be run as follows:

AnimControl animControl = person.getControl(AnimControl.class);
AnimChannel animChannel = animControl.createChannel();
animChannel.setAnim("Run");

If you use the jME3 SDK, you can explore the scene graph using the Scene Explorer.

See Traverse the SceneGraph for assistance in finding the AnimControl of your models.

See Animation in jME3 for further details on using animations in your code.

Additional Reading