OBJParser - Quick Start
  1. 1. Assumptions
  2. 2. Parsing a File
  3. 3. Groups
  4. 4. Polygonal Data
    1. 4.1. OBJPoint
    2. 4.2. OBJLine
    3. 4.3. OBJFace
    4. 4.4. OBJVertexGroup
  5. 5. Vertex Data
  6. 6. Render States
  7. 7. Materials
  8. 8. Supported Statements
    1. 8.1. OBJ
    2. 8.2. MTL

Assumptions

All end-user interactions with the OBJParser revolve around two primary classes: OBJParser and OBJState.

The former is the class to invoke to perform the actual parse, while the latter stores the state of the parsed file. For the rest of this guide, the following assumptions will be made:

  • parser is an instance of OBJParser
  • state is an instance of OBJState

Parsing a File

To parse an OBJ file, all you need to do is create an instance of the OBJParser and then provide a file path:

1
2
3
4
5
6
7
8
9
10
11
OBJParser parser;

if(parser.parseOBJFile("test.obj") == OBJParser::Result::Success)
{
// Success
}
else
{
// Failed
std::cout << "Failed to parse with error: " << parser.getLastError() << std::endl;
}

Once parsed, the contents of the file are placed within an OBJState instance that belongs to the parser. This state can be retrieved via:

1
OBJState* state = parser.getOBJState();

This is a pointer to a member variable, not member pointer, of the parser. So as long as the parser is valid, the pointer to the state will be. But the parser will clear away the internal data of the state before starting each new parse.

The rest of this guide will detail how to access and interpret data in the state.

Groups

A standard OBJ file is typically split into multiple groups. Each group can represent a single side of an individual mesh, or a single mesh among hundreds in a complex scene.

Groups are identified by their unique names and they contain the polygonal structures that make up the model. A container of all parsed groups can be retrieved from the OBJState via:

1
2
std::vector<OBJGroup const*> groups;
state->getGroups(groups);

Polygonal Data

There are three different types of polygonal data that are stored inside of a group:

  • Points
  • Lines
  • Faces

These are represented by the OBJPoint, OBJLine, and OBJFace structures.

OBJPoint

Vector of OBJVertexGroup objects. Each vertex group represents a single, individual point.

OBJLine

Vector of OBJVertexGroup objects. Each vertex group represents an individual segment of a single line.

OBJFace

A collection of four OBJVertexGroup objects.

If all four vertex groups are in use, then the face represents a quad. If only three are in use, then the face represents a triangle.

Additionally maintains a reference to the render state that was active when the face was declared. This is an index that can be supplied to OBJState::getRenderState.

OBJVertexGroup

A vertex group is a structure of three integer indices. Each index references a polygonal vertex element (spatial, texture, or normal) which can be used to access a specific vertex in the data containers.

The OBJ file format specifies that all indices are 1-based and can additionally be negative. But as standard containers are 0-based and do not support negative values, these indices have been pre-transformed to work with them.

All unspecified indices are set to -1. This can be used to not only check if normals, for example, are used, but to also check if an OBJFace represents a quad or triangle:

1
2
3
4
5
6
7
8
if(face.group3.indexSpatial == -1)
{
// Fourth vertex is unspecified. Face is a triangle.
}
else
{
// Fourth vertex is specified. Face is a quad.
}

Vertex Data

There are four different types of vertex data that can be stored in an OBJ file:

  • Spatial
  • Texture
  • Normal
  • Parameter

The first three are used by both polygonal and free-form structures, while the last is free-form only. They can be retrieved via:

1
2
3
4
std::vector<OBJVector4> const* spatial = state->getSpatialData();
std::vector<OBJVector2> const* texture = state->getTextureData();
std::vector<OBJVector3> const* normals = state->getNormalData();
std::vector<OBJVector3> const* params = state->getParameterData();

These can then be referenced by the index data stored in points, lines, faces, and curves. For example:

1
2
3
4
5
6
7
8
9
10
11
auto spatial = state->getSpatialData();
OBJFace face = group.faces[0];

OBJVector4 vert0 = spatial->at(face.group0.indexSpatial);
OBJVector4 vert1 = spatial->at(face.group1.indexSpatial);
OBJVector4 vert2 = spatial->at(face.group2.indexSpatial);

std::cout << "Triangle Face"
<< "V0: (" << vert0.x << ", " << vert0.y << ", " << vert0.z << ")\n"
<< "V1: (" << vert1.x << ", " << vert1.y << ", " << vert1.z << ")\n"
<< "V2: (" << vert2.x << ", " << vert2.y << ", " << vert2.z << ")" << std::endl;

Render States

At any time during the parsing of an OBJ file, the render state of that model or scene may change. The most common of these state changes in modern applications is the material, but there are numerous other render state attributes.

These states are most important when rendering faces, which is why each face maintains an index to the specific state that was active.

As an example, we can retrieve the material that was active when a face was created by:

1
2
3
4
5
OBJFace face = ...;

OBJRenderState renderState = state->getRenderState(face.renderState);

std::cout << "Active Material: " << renderState.material << std::endl;

Materials

Materials are parsed from .mtl files that are referenced in OBJ files via the mtllib statement. Each material file (also called libraries) can contain an indefinite number of individual materials.

When parsed, the materials are stored in an internal map within the state in the form of OBJMaterial objects. They may be retrieved via:

1
2
std::vector<OBJMaterial const*> materials;
state->getMaterials(materials);

Each material can have a multitude of elements, but the most important (and commonly used) are the reflectivity values and the texture maps.

An example of fetching data from a material:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
auto material = materials->at(0);

const std::string name = material->getName();
const std::string diffTexturePath = material->getDiffuseTexture().getPath();

const OBJMaterialProperty diffProp = material->getDiffuseReflectivity();

std::cout << "Diffuse Reflectivity Property: \n";

switch(diffProp.type)
{
case OBJMaterialPropertyType::RGB:
std::cout << "RGB (" << diffProp.r << ", " << diffProp.g << ", " << diffProp.b << ")";
break;

case OBJMaterialPropertyType::XYZ:
std::cout << "XYZ (" << diffProp.x << ", " << diffProp.y << ", " << diffProp.z << ")";
break;

case OBJMaterialPropertyType::RFL:
std::cout << "RFL: '" << diffProp.rfl.path << "'";
break;

default:
break;
}

std::cout << std::endl;

Supported Statements

List of all statements supported by the OBJParser for both OBJ and MTL formats. Note all statements are case-sensitive.

See the following links for more detailed explanations:

http://paulbourke.net/dataformats/obj/
http://paulbourke.net/dataformats/mtl/

OBJ

Statement Official Brief
v Vertex spatial data
vt Vertex texture data
vn Vertex normal data
vp Vertex parameter data
cstype Free-form type
deg Free-form degree
bmat Free-form basis matrix
step Free-form step size
p Polygonal points
l Polygonal line
f Polygonal face (quad/tri)
curv Free-form curve
curv2 Free-form 2D curve
surf Free-form surface
parm Free-form parameter
trim Free-form trim curve
hole Free-form hole curve
scrv Free-form special curve
sp Free-form special point
end Free-form statement end
con Free-form surface connection
g Group state set
s Smoothing group state set
mg Merging group state set
o Object name
bevel Sets bevel interpolation
c_interp Sets color interpolation
d_interp Sets dissolve interpolation
lod Sets level-of-detail
usemtl Sets active material
mtllib Sets material library path
shadow_obj Sets shadow object
trace_obj Sets tracer object
ctech Curve subdivision technique
stech Surface subdivision technique

MTL

Statement Official Brief
newmtl Starts new material definition
Ka Ambient reflectivity
Kd Diffuse reflectivity
Ks Specular reflectivity
Ke Emissive reflectivity
Tf Transmission filter
d Dissolve
Tr Transparency (dissolve inverse)
illum Illumination
Ns Specular Exponent
sharpness Sharpness
Ni Optical density
map_Ka Ambient texture
map_Kd Diffuse texture
map_ks Specular texture
map_Ns Specular exponent texture
map_Ke Emissive texture
map_d Dissolve texture
decal Decal texture
disp Displacement Texture
bump Bump texture
map_bump Bump texture
map_aat Anti-aliasing texture
refl Reflection map