5.10 - Converting OBJ Model Data to Buffer Objects¶
Building complex models for WebGL programs should be done using modeling tools such as Blender. However, getting a model from Blender into a WebGL application is non-trivial. You can use the JavaScript class described below to convert an OBJ model file into WebGL arrays suitable for GPU buffer objects.
You have two fundamental choices when you organize the data of a model for rendering.
- Optimize for speed.
- How:
- Minimize the number of WebGL Javascript commands issued to render a model.
- Minimize context switching as you render a scene.
- Render an entire model (or multiple models) using one call
to
gl.drawArrays()
.
- Implications:
- Everything is rendered using
gl.TRIANGLE
mode. - All data a shader program needs is in buffer objects organized by vertices.
- A single shader program is used to render an entire model (or scene).
- Model data will be duplicated for individual vertices resulting in
very large buffer objects.
- Everything is rendered using
- How:
- Minimize memory usage.
- How:
- Use
gl.TRIANGLE_FAN
and/orgl.TRIANGLE_STRIP
as often as possible to render collections of triangles. - Use
uniform
variables in your vertex shader programs for values that are constant for multiple triangles.
- Use
- Implications:
- Many calls to WebGL Javascript commands.
- Many calls to
gl.drawArrays()
. - Many context switches.
- Rendering will be slower.
- How:
It is impossible to organize model data to get fast rendering and efficient memory usage at the same time. You have to make trade-offs based on the application you are creating.
Function createModelsFromOBJ()¶
The JavaScript file learn_webgl_obj_to_arrays.js
contains class
definitions and global functions that will convert a model defined in an
*.obj
data file into a set of 1D arrays suitable for buffer objects.
The function createModelsFromOBJ
, (see function prototype below), receives
the text description of one or more models, along with a set of material
property definitions, and returns a set of ModelArrays
objects.
/**
* Given an OBJ text model description, convert the data into 1D arrays
* that can be rendered in WebGL.
* @param model_description String Contains the model data.
* @param materials_dictionary Dictionary of material objects.
* @param out An object that knows where to display output messages
* @return Object A set of ModelArray objects accessible by name or index.
*/
function createModelsFromOBJ(model_description, materials_dictionary, out) {
The arrays in an ModelArrays
object are optimizes for fast rendering, not
efficient memory usage. The buffers are organized around gl.drawArrays()
rendering modes.
- A
ModelArrays
object contains 3 sub-objects:- Points object, which can be rendered using
gl.POINTS
mode.vertices
1D array:[x1,y1,z1, x2,y2,z2, ...]
colors
1D array:[r1,g1,b1, r2,g2,b2, ...]
- Material properties for all points.
- Lines object, which can be rendered using
gl.LINES
mode.vertices
1D array:[x1,y1,z1, x2,y2,z2, ...]
colors
1D array:[r1,g1,b1, r2,g2,b2, ...]
textures
1D array:[t1, t2, t3, ...]
- Material properties for all lines.
- Triangle object, which can be rendered using
gl.TRIANGLES
mode.vertices
1D array:[x1,y1,z1, x2,y2,z2, ...]
colors
1D array:[r1,g1,b1, r2,g2,b2, ...]
flat_normals
vector 1D array:[dx1,dy1,dz1, dx2,dy2,dz2, ...]
smooth_normals
vector 1D array:[dx1,dy1,dz1, dx2,dy2,dz2, ...]
textures
1D array:[s1,t1, s2,t2, ...]
- Material properties for all triangles.
- Points object, which can be rendered using
Note the following about arrays in a ModelArrays
object:
- If the OBJ file contains normal vectors, the vectors from the file are used.
- If the OBJ file contains no normal vector information:
- If a face is marked as “smooth” by a ‘
s on
‘ line in the data file, then the normal vector for a vertex is calculated as an average of the normal vectors of the triangles that uses that vertex. - If a face is marked as “flat” by a ‘
s off
‘ line in the data file, then the normal vector for a vertex is the face’s normal vector.
- If a face is marked as “smooth” by a ‘
- If the file contains no texture coordinates, the texture coordinates array will be empty.
- The color of a vertex is the
Kd
value of the active material property, which comes from a *.mtl file. TheKd
value is the diffuse color of the material’s properties. It is assumed for this implementation that all of the elements in a model will use the same ambient, specular, specular highlight, and other material properties. If you use these properties in your shader programs they can be set asuniform
values in your shaders. (If any of the material properties change from vertex to vertex, and you want to use them asattributes
in your shader program, you would need to modify the code in theObjToArrays
class to create an appropriate 1D array for the values.)
OBJ Model Data Demo¶
The code in Learn_webgl_matrix.js
can be studied in the following demo.
You don’t need to fully understand the code, but you should get an overall idea of
what the code is accomplishing. You send the text from an .obj
file
which contains the description of one or more models, and it returns
you an array of ModelArray
objects. Each ModelArray
object
contains a set of 1D arrays containing the model data organized by vertices.
These arrays are ready to be put into GPU buffer objects and then linked
to shader program variables.
Render various models using various shader programs.
Note: It may take several seconds for the large Dragon model to load.
Flat shaded - use lighting calculations with one normal vector per triangle.
Smooth shaded - use lighting calculations with one normal vector per vertex.
Wireframe - only draw the triangle edges.
Animate
Sphere: 134 vertices, 264 triangles
Dragon: 418,336 vertices, 836,672 triangles
The object returned by the createModelsFromOBJ
function
contains one or more models. The models can be accessed “by name” or by
array indexes. To access the models as an array:
// Create ModelArrays objects from the obj data
models = createModelsFromOBJ(obj_text, obj_materials, out);
// Access the models by array index
for (j = 0; j < models.number_models; j += 1) {
one_model = models[j];
// Do something with one_model
}
If you know the exact name of your models, you can access them using those
names. The “name” of a model comes from the name you assigned
a set of geometry in Blender. The object return by the createModelsFromOBJ
function
has properties using those names. Suppose you named your models “Bear”, “Monkey”,
and “Goat”. You can access the individual models using those names like this:
// Create ModelArrays objects from the obj data
models = createModelsFromOBJ(obj_text, obj_materials, out);
models.Bear
models.Monkey
models.Goat
Conclusion¶
This concludes the lessons on rendering. We will discuss shader programs again in sections 9, 10, & 11 because all surface materials and lighting effects are done in shader programs.