Lua logo

Preface

This is the reference manual of MoonAssimp, which is a Lua binding library for the Open Asset Import Library (Assimp). [1]

It is assumed that the reader is familiar with both Assimp and the Lua programming language.

For convenience of reference, this document contains external (deep) links to the Lua Reference Manual and to the Assimp Documentation.

Getting and installing

For installation intructions, refer to the README file in the MoonAssimp official repository on GitHub.

Module organization

The MoonAssimp module is loaded using Lua’s require() and returns a table containing the functions it provides (as usual with Lua modules). This manual assumes that such table is named ai, i.e. that it is loaded with:

 ai = require("moonassimp")

but nothing forbids the use of a different name.

Examples

A few examples can be found in the examples/ directory of the release package.

License

MoonAssimp is released under the MIT/X11 license (same as Lua, and with the same only requirement to give proper credits to the original author). The copyright notice is in the LICENSE file in the base directory of the official repository on GitHub.

Usage

MoonAssimp presents an object-oriented interface but it actually binds to the Assimp C API, so loading a scene with MoonAssimp in Lua is very similar to loading a scene with Assimp in C. For example, to load a scene from a 3D model file named 'mymodel.obj', one could do the following:

ai = require("moonassimp")

scene, errmsg = ai.import_file("mymodel.obj", -- post-processing flags:
                               "triangulate", "join identical vertices", "sort by p type")
assert(scene, errmsg) -- check that nothing went wrong

If the file is loaded with success then ai.import_file( ) returns a scene object. The contents of the scene can then be retrieved with the object’s methods and with those of the objects it contains.

At exit, the scene object is garbage collected together with the contained objects, so the ai.release_import( ) function need not be called, unless one wants to release memory when the scene is no more needed and the application is not exiting.

Objects' methods are described in the 'Methods' section, while herafter are described the general functions provided in the ai table for importing models, logging, etc. These are bindings to functions of the Assimp C API (defined in cimport.h), and usually preserve their semantics. Not all Assimp functions are used or exposed by MoonAssimp.

Note
In this document the terms float and integer are used to denote Lua values of type number that are, respectively, floating-point numbers or integers.

Scene import functions

  • scene = ai.import_file(filename, postprocessflags)
    Loads the model file from filename (a string) and returns a scene object. On error, it returns nil and an error message.

  • scene = ai.import_file_from_memory(data, postprocessflags [, hint])
    Loads the model file from the data binary string and returns a scene object. The optional hint parameter (a string) can be used to suggest Assimp the model file format. On error, it returns nil and an error message.

  • scene = ai.apply_post_processing(scene, postprocessflags)
    Applies the specified post-processing to the passed scene and returns a new scene object. On error, it returns _nil and an error message.

  • mem = ai.get_memory_requirements(scene)
    Returns a table with the memory requirements of the scene object. The mem table contains the following fields: mem.total, mem.nodes, mem.meshes, mem.materials, mem.cameras, mem.lights, and mem.animations. The value of each field is an integer indicating the memory (in bytes) used by the various items contained in the scene.

  • ai.release_import(scene)
    This also invalidates all the references to imported objects.

Querying for supported formats

  • boolean = ai.is_extension_supported(ext)
    Returns true if the format with the given extension is supported by Assimp, false otherwise (ext must be a string with the extension and a leading dot, e.g. '.3ds').

  • string = ai.get_extension_list( )
    Returns a string indicating all the supported extensions (the string can be easily converted to a table of extensions with the code snippet below).

-- How to convert the extension list string to an array of extensions:
s = ai.get_extension_list()
-- s = "*.3d;*.3ds;*.ac; ..."
t = {}
for v in string.gmatch(s, "%*%.(%w+);") do t[#t+1] = v end
-- t = { "3d", "3ds", "ac", ... }

Logging facilities

  • ai.enable_verbose_logging(boolean)
    Enables or disables verbose logging.

  • ai.attach_log_stream(logstream [, arg])
    Attaches a log stream. If logstream is 'file', then the arg parameter must be a filename. If logstream is 'user', then the arg parameter must be a function, that will be executed as func(message) for every message (string) to be logged. If logstream is 'stdout' or 'stderr', the arg parameter is ignored.

  • ai.detach_log_stream(logstream)
    Detaches a log stream.

  • ai.detach_all_log_streams( )
    Detaches all log streams.

  • ai.trace_objects(boolean)
    Enable/disable tracing on stdout of objects creation and deletion (default=disabled).

Objects

The following tree shows the MoonAssimp (Assimp) objects and their relationships.

scene (aiScene)
├─ node (aiNode): root node
│   ├─ {mesh} (aiMesh): subset of the scene’s {mesh} list
│   └─ {node} (aiNode): children nodes
│       ├─ {mesh}
│       └─ {node}
│           └─ …​
├─ {mesh} (aiMesh)
│   ├─ material (aiMaterial): element of the scene’s {material} list
│   ├─ {face} (aiFace)
│   ├─ {bone} (aiBone)
│   └─ {animmesh} (aiAnimMesh)
├─ {material} (aiMaterial)
├─ {light} (aiLight)
├─ {texture} (aiTexture)
├─ {camera} (aiCamera)
└─ {animation} (aiAnimation)
    ├─ {nodeanim} (aiNodeAnim)
    └─ {meshanim} (aiMeshAnim)

Methods

scene

Rfr: aiScene.

  • boolean = scene:has_animations( )
    boolean = scene:has_cameras( )
    boolean = scene:has_lights( )
    boolean = scene:has_materials( )
    boolean = scene:has_meshes( )
    boolean = scene:has_textures( )
    Return true if scene contains one or more objects of the given type, false otherwise.

  • sceneflags = scene:flags( )
    Returns the scene's flags.

  • n = scene:num_animations( )
    n = scene:num_cameras( )
    n = scene:num_lights( )
    n = scene:num_materials( )
    n = scene:num_meshes( )
    n = scene:num_textures( )
    Return the number of objects of the given type that are contained in scene.

  • node = scene:root_node( )
    Returns the root node of the scene.

  • animation = scene:animation(i)
    camera = scene:camera(i)
    light = scene:light(i)
    material = scene:material(i)
    mesh = scene:mesh(i)
    texture = scene:texture(i)
    Each of these methods the i-th object of the given type (i = 1 .. num_xxx( )).

  • {animation} = scene:animations( )
    {camera} = scene:cameras( )
    {light} = scene:lights( )
    {material} = scene:materials( )
    {mesh} = scene:meshes( )
    {texture} = scene:textures( )
    Each of these methods returns a table with the objects of the given type that are contained in scene.

node

Rfr: aiNode.

  • name = node:name( )

  • n = node:num_children( )
    n = node:num_meshes( )

  • node = node:child(i)
    Returns the i-th child node of this node (i = 1 .. num_children( )).

  • {node} = node:children( )
    Returns a table containing the children of this node.

  • mesh = node:mesh(i)
    Returns the node’s i-th mesh (i = 1 .. num_meshes( )).

  • {mesh} = node:meshes( )
    Returns a table containing this node’s meshes.
    Note that this is a subset of the scene's meshes list.

  • node = node:parent( )
    Returns the parent node for this node, or nil if this node is the root.

  • a11, a12, …​, a44 = node:transformation( )
    Returns the elements of the transformation matrix, in row-major order.

mesh

Rfr: aiMesh.

  • name = mesh:name( )

  • primtypes = mesh:primitive_types( )

  • boolean = mesh:has_positions( )
    boolean = mesh:has_normals( )
    boolean = mesh:has_tangents( )
    boolean = mesh:has_faces( )
    boolean = mesh:has_bones( )
    boolean = mesh:has_anim_meshes( )
    boolean = mesh:has_colors(channel)
    boolean = mesh:has_texture_coords(channel)

  • n = mesh:num_vertices( )
    n = mesh:num_faces( )
    n = mesh:num_bones( )
    n = mesh:num_anim_meshes( )
    n = mesh:num_color_channels( )
    n = mesh:num_texture_coords_channels( )

  • n = mesh:num_texture_coords_components(channel)

  • x, y, z = mesh:position(i)
    x, y, z = mesh:normal(i)
    x, y, z = mesh:tangent(i)
    x, y, z = mesh:bitangent(i)
    Return the components of the affected 3D vector for the vertex indexed by i, where i = 1 .. num_vertices( ).

  • r, g, b, a = mesh:color(channel, i)
    Returns the channel color components for the vertex indexed by i, where channel = 1 .. num_color_channels( ) and i = 1 .. num_vertices( ).

  • u, v, w = mesh:texture_coords(channel, i)
    Returns the channel texture components for the vertex indexed by i, where channel = 1 .. num_texture_coords_channels and i = 1 .. num_vertices( ). Only num_texture_coords_components(channel) are returned.

  • material = mesh:material( )
    Returns the mesh’s material.

  • face = mesh:face(i)
    Returns the i-th face of the mesh, where i = 1 .. num_faces( ).

  • bone = mesh:bone(i)
    Returns the i-th bone of the mesh, where i = 1 .. num_bones( ).

  • animmesh = mesh:anim_mesh(i)
    Returns the i-th anim mesh of the mesh, where i = 1 .. num_anim_mesh( ).

  • {face} = mesh:faces( )
    {bone} = mesh:bones( )
    {animmesh} = mesh:anim_meshes( )
    Return the list of the faces, bones, or anim meshes for this mesh.


The following functions provide a more compact way to retrieve the mesh’s vertex attributes and face indices.

  • positions = mesh:all_positions( )
    normals = mesh:all_normals( )
    tangents = mesh:all_tangents( )
    bitangents = mesh:all_bitangents( )
    Each of these functions returns nil if the mesh does not have the requested vertex attribute (position, normal, tangent, or bitangent), otherwise it returns a table of num_vertices 3D vectors (arrays of 3 floats).

  • coords = mesh:all_texture_coords( )
    Returns a table of num_texture_coords_channels tables, each containing num_vertices texture coordinates.
    More precisely, coords[i] is a table containing all the texture coordinates in the i-th channel, so that coords[i][k] are the texture coordinates for the k-th vertex in that channel. Texture coordinates are represented as 1D, 2D or 3D vectors, i.e. arrays of 1, 2, or 3 floats.
    If the mesh has no textures coordinates channels, then an empty table is returned.

  • colors = mesh:all_colors( )
    Returns a table of num_color_channels tables, each containing num_vertices colors.
    More precisely, colors[i] is a table containing all the colors in the i-th channel, so that colors[i][k] is the color for the k-th vertex in that channel. Colors are represented a arrays of 4 floats (normalized RGBA components).
    If the mesh has no colors channels, then an empty table is returned.

  • indices = mesh:all_indices([zerobased=false])
    Returns a table of num_faces tables of integer indices, identifying the vertices that compose each face.
    If the optional zerobased parameter (a boolean) is true, then the returned indices are 0-based (0,..,num_vertices-1), otherwise they are 1-based (1,..,num_vertices).

face

Rfr: aiFace.

  • N = face:num_indices( )

  • i1, …​, iN = face:indices( )
    i1-1, …​, iN-1 = face:zero_based_indices( )
    Return the indices, in the mesh's list of vertices, of the vertices that compose the face.
    The first function returns 1-based indices (table indices), while the second one returns 0-based indices (as expected by graphics APIs).

material

Rfr: aiMaterial.

Note
All these functions return nil if the given property is not defined for the material.
  • name = material:name( )

  • boolean = material:twosided( )

  • shadingmode = material:shading( )

  • boolean = material:wireframe( )

  • blendmode = material:blend( )

  • float = material:opacity( )
    float = material:bumpscaling( )
    float = material:shininess( )
    float = material:shinpercent( )
    float = material:reflectivity( )
    float = material:refraction( )

  • r, g, b, a = material:color_ambient( )
    r, g, b, a = material:color_diffuse( )
    r, g, b, a = material:color_emissive( )
    r, g, b, a = material:color_reflective( )
    r, g, b, a = material:color_specular( )
    r, g, b, a = material:color_transparent( )

  • string = material:global_bg_image( )


  • n = material:texture_count(texturetype)
    Returns the number of textures of the given type.

The following methods refer to the i-th texture of the given texture type, where i must be in the range 1 .. texture_count( ).


The following functions provide a more compact way to retrieve the material textures.

  • counts =material:all_texture_counts( )
    Returns a table with the counts for all texturetypes (e.g. counts.diffuse = 2 if there are 2 'diffuse' textures).

  • textures =material:all_textures([texturetype])
    Returns a table with the properties of all the material textures.
    If the optional texturetype parameter is given, only the textures of that type are listed.
    Each entry of the table describes a texture, and has the following format (optional fields have a nil value when not defined for the texture):
    textures[i] = {
    type: texturetype,
    flags: textureflags,
    path: string,
    channel: integer (1-based, opt.),
    op: textureop (opt.),
    mapping: texturemapping (opt.),
    blend: float (opt.),
    mapmode_u: texturemapmode (opt.),
    mapmode_v: texturemapmode (opt.),
    axis: {float, float, float} (opt.),
    translation: {float, float} (opt.),
    scaling: {float, float} (opt.),
    rotation: float (radians, opt.),
    }.

texture

Rfr: aiTexture.

Note
This object represents a texture that is embedded in the model file, since some file formats do this (see details). More often, textures are instead contained in external files and associated with materials.
  • boolean = texture:is_compressed( )
    Returns true if the texture data is in a compressed format, false otherwise.

  • fmt = texture:format_hint( )
    Returns the format hint as a string, or nil if the texture data is not in a compressed format.

  • w = texture:width( )
    h = texture:height( )

  • n = texture:size( )
    Returns the size in byte of the texture data, or nil if the texture data is not in a compressed format.

  • data = texture:data( )
    Returns the texture data as a binary string, or nil if the texture data is not in a compressed format.

  • r, g, b, a = texture:texel(u, v)
    Returns the RGBA components (normalized float values) of the texel with texture coordinates (u, v), or nil if the texture is in a compressed format. The coordinates u and v must be in the ranges 1 .. width( ) and 1 .. height( ), respectively. The values are returned as normalized floating points.

  • t = texture:texels( )
    Returns all the texels in a (table) matrix t, where t[u][v] = { r, g, b, a } are the RGBA components (normalized float values) of the texel with texture coordinates (u, v).

  • r, g, b, a = texture:btexel(u, v)
    t = texture:btexels( )
    Same as texel( ) and texels( ), but the RGBA components are returned as 8 bit values (0..255).

light

Rfr: aiLight.

  • name = light:name( )

  • lightsourcetype = light:source_type( )

  • float = light:attenuation_constant( )
    float = light:attenuation_linear( )
    float = light:attenuation_quadratic( )
    float = light:angle_inner_cone( )
    float = light:angle_outer_cone( )

  • x, y, z = light:position( )
    x, y, z = light:direction( )

  • r, g, b = light:color_diffuse( )
    r, g, b = light:color_specular( )
    r, g, b = light:color_ambient( )

camera

Rfr: aiCamera.

  • name = camera:name( )

  • float = camera:aspect( )
    float = camera:clip_plane_near( )
    float = camera:clip_plane_far( )
    float = camera:horizontal_fov( )

  • x, y, z = camera:position( )
    x, y, z = camera:up( )
    x, y, z = camera:look_at( )

animation

Rfr: aiAnimation.

  • name = animation:name( )

  • duration = animation:duration( )

  • ticks = animation:ticks_per_second( )

  • n = animation:num_node_anims( )
    n = animation:num_mesh_anims( )

  • nodeanim = animation:node_anim(name)
    Returns the node anim for the given node name, or nil if not found.

  • {nodeanim} = animation:node_anims( )
    Returns the list of node anims.

  • {meshanim} = animation:mesh_anims([name])
    Returns the list of mesh anims.
    If the optional name parameter (a string) is passed, only meshanims with such name are added to the list.

nodeanim

Rfr: aiNodeAnim.

  • name = nodeanim:node_name( )

  • n = nodeanim:num_position_keys( )
    n = nodeanim:num_rotation_keys( )
    n = nodeanim:num_scaling_keys( )

  • {key} = nodeanim:position_keys( )
    Returns the list of position keys. Each entry of the list is a table with the following fields:
    key.time: a float denoting time, and
    key.value: an array of 3 floats representing the position vector.

  • {key} = nodeanim:rotation_keys( )
    Returns the list of rotation keys. Each entry of the list is a table with the following fields:
    key.time: a float denoting time, and
    key.value: an array of 4 floats representing the rotation quaternion.

  • {key} = nodeanim:scaling_keys( )
    Returns the list of scaling keys. Each entry of the list is a table with the following fields:
    key.time: a float denoting time, and
    key.value: an array of 3 floats representing the scaling factors.

  • animbehaviour = nodeanim:pre_state( )
    animbehaviour = nodeanim:post_state( )

animmesh

Rfr: aiAnimMesh.

  • mesh = animmesh:mesh( )
    The mesh it belongs to (and is a replacement for).

  • animmesh:has_positions( )
    animmesh:has_normals( )
    animmesh:has_tangents( )
    animmesh:has_colors(channel)
    animmesh:has_texture_coords(channel)
    animmesh:position(i)
    animmesh:normal(i)
    animmesh:tangent(i)
    animmesh:bitangent(i)
    animmesh:color(channel, i)
    animmesh:texture_coords(channel, i)
    Replacements for mesh methods.

bone

Rfr: aiBone.

  • name = bone:name( )

  • n = bone:num_weights( )

  • t = bone:weights( )
    Returns a table t, where t[i] is the weight of the i-th vertex (its 1-based index in the mesh's list of vertices), or nil if the vertex is not part of the bone.
    (Note that the returned table is likely to contain holes, so do not iterate with ipairs().)

  • t = bone:ordered_weights( )
    Returns an array t of num_weights( ) tables, each having two elements: t[i].vertex and t[i].weight, denoting respectively the 1-based index of a vertex and its weight. The vertices are in the same order as in the underlying aiBone structure

  • a11, a12, …​, a44 = bone:offset_matrix( )
    Returns the elements of the offset matrix, in row-major order.

meshanim

Rfr: aiMeshAnim.

  • name = meshanim:mesh_name( )

  • n = meshanim:num_keys( )

  • {key} = meshanim:keys( )
    Returns the list of keys (or, more precisely, of key frames). Each entry of the list is a table having the following fields:
    key.time: a float denoting time, and
    key.value: an index into the mesh's list of anim meshes.

Note
(In my understanding) the mesh_name should allow to identify one or more meshes to be animated with this set of keys. Each of these meshes should then have, in its own list of anim meshes, the data for its animation at the indices contained in the keys returned by meshanim:keys( ).

Enumerations and bitfields

An enumeration is a string (a literal) from a well defined set of values.

A bitfield, when used as a function argument it may be passed either as an integer code, or as a sequence of strings from a well defined set of values. When it is not the last argument of the function, it may be passed only as an integer code. Functions returning a bitfield return the integer code only (utilities are provided to encode/decode bitfields, if needed).

  • animbehaviour: enumeration.
    Values: 'default', 'constant', 'linear', 'repeat'.

  • blendmode: enumeration.
    Values: 'default', 'additive'.

  • lightsourcetype: enumeration.
    Values: 'wrap', 'clamp', 'decal', 'mirror'.

  • logstream: enumeration.
    Values: 'file', 'stdout', 'stderr', 'user'.

  • postprocessflags: bitfield.
    Code: a combination of ai.Process_Xxx values (corresponding to aiProcess_Xxx values in Assimp).
    Strings: 'none', 'calc tangent space', 'join identical vertices', 'make left handed', 'triangulate', 'remove component', 'gen normals', 'gen smooth normals', 'split large meshes', 'pre transform vertices', 'limit bone weights', 'validate data structure', 'improve cache locality', 'remove redundant materials', 'fix infacing normals', 'sort by p type', 'find degenerates', 'find invalid data', 'gen uv coords', 'transform uv coords', 'find instances', 'optimize meshes', 'optimize graph', 'flip uvs', 'flip winding order', 'split by bone count', 'debone'.

  • primtypes: bitfield.
    Code: a combination of ai.PrimitiveType_Xxx values (corresponding to aiPrimitiveType_Xxx values in Assimp).
    Strings: 'point', 'line', 'triangle', 'polygon'.

  • sceneflags: bitfield.
    Code: a combination of ai.SCENE_FLAGS_XXX values (corresponding to AI_SCENE_FLAGS_XXX defines in Assimp).
    Strings: 'incomplete', 'validated', 'validation warning', 'non verbose format', 'terrain'.

  • shadingmode: enumeration.
    Values: 'flat', 'gouraud', 'phong', 'blinn', 'toon', 'oren nayar', 'minnaert', 'cook torrance', 'no shading', 'fresnel'.

  • textureflags: bitfield.
    Code: a combination of ai.TextureFlags_Xxx values (corresponding to aiTextureFlags_Xxx values in Assimp).
    Strings: 'invert', 'use alpha', 'ignore alpha'.

  • texturemapmode: enumeration.
    Values:'undefined', 'directional', 'point', 'spot'.

  • texturemapping: enumeration.
    Values: 'uv', 'sphere', 'cylinder', 'box', 'plane', 'other'.

  • textureop: enumeration.
    Values: 'multiply', 'add', 'subtract', 'divide', 'smooth add', 'signed add'.

  • texturetype: enumeration.
    Values: 'diffuse', 'specular', 'ambient', 'emissive', 'height', 'normals', 'shininess', 'opacity', 'displacement', 'lightmap', 'reflection', 'unknown'.

Additional utilities

  • s1, s2, …​ = ai.postprocessflags(code)
    Converts a postprocessflags bitfield from an integer code to a sequence of strings.

  • code = ai.postprocessflags(s1, s2, …​)
    Converts a postprocessflags bitfield from a sequence of strings to an integer code.

  • s1, s2, …​ = ai.primtypes(code)
    Converts a primtypes bitfield from an integer code to a sequence of strings.

  • code = ai.primtypes(s1, s2, …​)
    Converts a primtypes bitfield from a sequence of strings to an integer code.

  • s1, s2, …​ = ai.sceneflags(code)
    Converts a sceneflags bitfield from an integer code to a sequence of strings.

  • code = ai.sceneflags(s1, s2, …​)
    Converts a sceneflags bitfield from a sequence of strings to an integer code.

  • s1, s2, …​ = ai.textureflags(code)
    Converts a textureflags bitfield from an integer code to a sequence of strings.

  • code = ai.textureflags(s1, s2, …​)
    Converts a textureflags bitfield from a sequence of strings to an integer code.


1. This manual is written in AsciiDoc, rendered with AsciiDoctor and a CSS from the AsciiDoctor Stylesheet Factory. The PDF version is produced with AsciiDoctor-Pdf.