Skip to content

NML format

Jaak Laineste edited this page Nov 30, 2017 · 1 revision

About

NML format is a proprietary format used by CARTO (and formerly Nutiteq) for 3D mesh-based models. The model is defined as a Google protobuf message. Models are typically converted from Collada (DAE) files, though other input formats are also possible. NML is designed to be easily readable on Mobile devices and to provide relatively compact binary sizes.

Protobuf structure

Models and mesh instances

Each NML model contains at least one 'Model' instances which is defined as follows:

message Model {
	required string id = 1;
	repeated MeshInstance mesh_instances = 2;
	repeated Mesh meshes = 3;
	repeated Texture textures = 4;
	required Bounds3 bounds = 5;
	required int32 mesh_footprint = 6;
	required int32 texture_footprint = 7;
}

Here 'mesh_footprint' and 'texture_footprint' contain approximate geometry and texture footprints when the model is loaded. Note that meshes are instanced:

message MeshInstance {
	required string mesh_id = 1;
	repeated Material materials = 2;
	optional Matrix4 transform = 3;
}

Here 'mesh_id' refers to the actual meshes defined in Model. Mesh appearance is defined using a list of materials.

Materials

message Material {
	enum Type {
		CONSTANT = 1;
		PREBAKED = 2;
		LAMBERT = 3;
		PHONG = 4;
		BLINN = 5;
	}
	enum Culling {
		NONE = 1;
		FRONT = 2;
		BACK = 3;
	}
	enum OpaqueMode {
		OPAQUE = 0;
		TRANSPARENT_RGB = 1;
		TRANSPARENT_ALPHA = 2;
	}
	required string id = 1;
	required Type type = 2;
	required Culling culling = 3;
	optional ColorOrTexture emission = 4;
	optional ColorOrTexture ambient = 5;
	optional ColorOrTexture diffuse = 6;
	optional OpaqueMode opaque_mode = 7;
	optional float transparency = 8;
	optional ColorOrTexture transparent = 9;
	optional float shininess = 10;
	optional ColorOrTexture specular = 11;
}

The material definition follows closely Collada Standard material profile. All common material types are supported and most material attributes can be either constant colors or textures:

message ColorOrTexture {
	enum Type {
		COLOR = 1;
		TEXTURE = 2;
	}
	required Type type = 1;
	optional ColorRGBA color = 2;
	optional string texture_id = 3;
}

Here 'texture_id' refers to the textures defined in Model.

Meshes and submeshes

Each mesh is defined as a list of submeshes:

message Mesh {
	required string id = 1;
	required Bounds3 bounds = 2;
	repeated Submesh submeshes = 3;
}

message Submesh {
	enum Type {
		POINTS = 1;
		LINES = 2;
		LINE_STRIPS = 3;
		TRIANGLES = 4;
		TRIANGLE_STRIPS = 5;
		TRIANGLE_FANS = 6;
	}
	required Type type = 1;
	required string material_id = 2;
	repeated int32 vertex_counts = 3;
	required bytes positions = 4;
	optional bytes normals = 5;
	optional bytes uvs = 6;
	optional bytes colors = 7;
	repeated int64 vertex_ids = 8;
}

Here 'material_id' is a reference to MeshInstance material table. For POINTS, LINES, TRIANGLES, 'vertex_counts' contains 1 element - the number of vertices. For strips/fans, this contains number of elements for each strip/fan before restarting. 'positions' is defined as xyz*vertices*float (encoded as little-endian IEE754). 'normals' is defined as xyz*vertices*float (encoded as little-endian IEE754). 'uvs' (texture coordinates) is defined as uv*vertices*float (encoded as little-endian IEE754). Optional vertex colors 'colors' are encoded as rgba*vertices*byte.

'vertex_ids' are used to identify vertices (or triangles). Each vertex can be tagged with a 32-bit integer and the list is encoded as follows: count (upper 32 bits) + id (lower 32 bits). For example, if vertex_ids == [3 << 32 | 1, 1 << 32 | 0], then ids of vertices are [1, 1, 1, 0].

Textures and samplers

NML support different texture formats including mobile-specific compressed formats:

message Texture {
	enum Format {
		JPEG = -2;
		PNG = -1;
		LUMINANCE8 = 1;
		RGB8 = 2;
		RGBA8 = 3;
		ETC1 = 4;
		PVRTC = 5;
		DXTC = 6;
	}
	required string id = 1;
	required Format format = 2;
	required int32 width = 3;
	required int32 height = 4;
	required Sampler sampler = 5;
	repeated bytes mipmaps = 6;
}

ETC1 textures include 16-byte PKM header. PVRTC textures contain 52-byte PVRTCv3 header. DXTC textures contain 12-byte (format,width,height) header. Mipmaps are encoded sequentally starting from highest resolution to the lowest, encoding depends on format.

NML supports standard sampler attributes:

message Sampler {
	enum Filter {
		NEAREST = 1;
		BILINEAR = 2;
		TRILINEAR = 3;
	}
	enum WrapMode {
		CLAMP = 1;
		REPEAT = 2;
		MIRROR = 3;
	}
	optional Filter filter = 1;
	optional WrapMode wrap_s = 2;
	optional WrapMode wrap_t = 3;
}

Remaining structures

message Vector3 {
	required float x = 1;
	required float y = 2;
	required float z = 3;
}

message ColorRGBA {
	required float r = 1;
	required float g = 2;
	required float b = 3;
	required float a = 4;
}

message Bounds3 {
	required Vector3 min = 1;
	required Vector3 max = 2;
}

message Matrix4 {
	required float m00 = 1; // row 1, col 1
	required float m01 = 2; // row 2, col 1
	required float m02 = 3; // ...
	required float m03 = 4;
	required float m10 = 5;
	required float m11 = 6;
	required float m12 = 7;
	required float m13 = 8;
	required float m20 = 9;
	required float m21 = 10;
	required float m22 = 11;
	required float m23 = 12;
	required float m30 = 13;
	required float m31 = 14;
	required float m32 = 15;
	required float m33 = 16;
}