WebGL: Loading OBJ
Overview: Wavefront OBJ
OBJ is one of industry-standard 3D geometry formats, which is originally developed by Wavefront Technologies. OBJ file format stores 3D geometric data in ASCII text. OBJ format consists of 2 major sections. The first section is to define vertext attributes such as vertex positions (v), normals (vn) and texture coordinates (vt). The second part is the list of polygons (f) referencing the indices of the previous vertex attribute arrays.
OBJ also supports to partition the entire 3D model into multiple group. Each group can have separate material; color and texture map. These material definitions are stored in a separate file; .MTL.
This page shows how to parse the OBJ file and to render the 3D geometry data in WebGL. The comprehensive specification and documentation can be found at Paul Bourke's web page.
Loading OBJ File
In OBJ format, a list of unique vertex attributes is defined with specific keywords; v for positions, vn for normals and vt for texture coordinates.
# vertex position
v 0 1 2
# vertex normal
vn 0 0 1
# vertex tex coord
vt 0 1
After the definition of the list of vertex attributes, it defines a list of faces beginning with f keyword by indexing the previously defined vertex attributes. The vertex normal and texture coordinates are optional to define a face. However, the index of vertex positions are mandatory to define a face. All index values are 1-based. The face can be a triangle or polygon. If a face constructed by more than 3 vertices, it must be triangulated in WebGL.
# 4 different cases of face definitions
f 1 2 3 # with v only
f 1/1 2/2 3/3 # with v and vt
f 1//1 2//2 3//3 # with v and vn
f 1/1/1 2/2/2 3/3/3 # with v, vt and vn
...
ObjModel.js is a JavaScript class to parse an OBJ file, and to pass the vertex data to VBOs in WebGL. The core interfaces of ObjModel class are;
ObjModel | |
---|---|
Interface | Description |
read(url) | Parse OBJ from URL, and return a Promise object |
vertices | Float32Array to hold vertex positions |
normals | Float32Array to hold vertex normals |
texCoords | Float32Array to hold texture coordinates |
indices | Unit16Array or Unit32Array to hold indices |
A typical usage of ObjModel class follows;
// global object
gl = {};
...
// load OBJ file
gl.obj = new ObjModel();
gl.obj.read("debugger_50k.obj").then(obj =>
{
// loaded OBJ successfully
initVBO(obj); // copy vertex data to VBO
log(obj); // print OBJ info
});
function initVBO(obj)
{
gl.vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, gl.vbo);
// total # of bytes
let dataSize = obj.vertices.byteLength + obj.normals.byteLength;
gl.bufferData(gl.ARRAY_BUFFER, dataSize, gl.STATIC_DRAW);
// copy vertices
gl.bufferSubData(gl.ARRAY_BUFFER, 0, obj.vertices);
// copy normals
gl.bufferSubData(gl.ARRAY_BUFFER, obj.vertices.byteLength, obj.normals);
gl.ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.ibo);
// copy indices
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, obj.indices, gl.STATIC_DRAW);
}
...
// draw VBO
gl.bindBuffer(gl.ARRAY_BUFFER, gl.vbo);
gl.vertexAttribPointer(program.attribute.position, 3, gl.FLOAT, false, 0, 0);
gl.vertexAttribPointer(program.attribute.normal, 3, gl.FLOAT, false, 0, gl.obj.normals.byteLength);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.ibo);
gl.drawElements(gl.TRIANGLES, gl.obj.indices.length, gl.obj.indexType, 0);
...
There is a C++ version of ObjModel class and ObjViewer application using OpenGL for Windows and macOS. You can download the source codes and binaries from the following link.
ObjViewer.zip
ObjViewer_mac.zip


Example
This example is parsing and rendering an OBJ model with a default texture map if the OBJ file specifies texture coordinates. You can upload your own OBJ file or choose from the sample OBJ files.
Fullscreen Demo: test_obj.html
GitHub Repo: test_obj.html