Tiny script to export a blender object to a OBJ like of file. This format is very simple to parse. I use this sometimes when working on small simulations where I want to have a 3D model.
import bpy
import math
import mathutils
from mathutils import Vector, Matrix
o = bpy.context.active_object
print("="*40)
output = []
mat_x90 = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
conv_mat = o.matrix_world
def add_vert(face_index, n):
v = o.data.vertices[face_index].co
v = conv_mat * v
v = mat_x90 * v
output.append("v %f %f %f %f %f %f" % (v.x, v.y, v.z, n.x, n.y, n.z))
def add_face(face, norm):
if len(face) == 4:
add_vert(face[0], norm)
add_vert(face[1], norm)
add_vert(face[2], norm)
add_vert(face[0], norm)
add_vert(face[2], norm)
add_vert(face[3], norm)
elif len(face) == 3:
add_vert(face[0], norm)
add_vert(face[1], norm)
add_vert(face[2], norm)
for face in o.data.polygons:
verts = face.vertices[:]
n = face.normal
add_face(verts, n)
out_str = "\n".join(map(str, output))
Another example which lets the user select the destination path of the exported file:
import bpy
import math
import mathutils
from mathutils import Vector, Matrix
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator
# Get the active object, create rotation matrix for Blender > GL, coordinate system
o = bpy.context.active_object
print("="*40)
output = []
mat_x90 = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
conv_mat = o.matrix_world
# Collect all vertices / normals
def add_vert(face_index, n):
v = o.data.vertices[face_index].co
v = conv_mat * v
v = mat_x90 * v
output.append("v %f %f %f %f %f %f" % (v.x, v.y, v.z, n.x, n.y, n.z))
# Export the given face
def add_face(face, norm):
if len(face) == 4:
add_vert(face[0], norm)
add_vert(face[1], norm)
add_vert(face[2], norm)
add_vert(face[0], norm)
add_vert(face[2], norm)
add_vert(face[3], norm)
elif len(face) == 3:
add_vert(face[0], norm)
add_vert(face[1], norm)
add_vert(face[2], norm)
# Called when user selected a file, saved the file
def write_some_data(context, filepath):
for face in o.data.polygons:
verts = face.vertices[:]
n = face.normal
add_face(verts, n)
out_str = "\n".join(map(str, output))
f = open(filepath, 'w', encoding='utf-8')
f.write(out_str)
f.close()
return {'FINISHED'}
# This snippet is necessary to popup the file save window.
# Also adds this operator to the 'space bar menu'
class ExportSomeData(Operator, ExportHelper):
bl_idname = "export_simple_obj.exp"
bl_label = "Export Simple Object (ROXLU)"
filename_ext = ".txt"
filter_glob = StringProperty(
default="*.txt",
options={'HIDDEN'},
)
def execute(self, context):
return write_some_data(context, self.filepath)
def menu_func_export(self, context):
self.layout.operator(ExportSomeData.bl_idname, text="Simple Roxlu exporter")
def register():
bpy.utils.register_class(ExportSomeData)
bpy.types.INFO_MT_file_export.append(menu_func_export)
def unregister():
bpy.utils.unregister_class(ExportSomeData)
bpy.types.INFO_MT_file_export.remove(menu_func_export)
if __name__ == "__main__":
register()
bpy.ops.export_simple_obj.exp('INVOKE_DEFAULT')
Recently I've doing a lot of openGL and had some time to read up on the specs regarding VBOs and VAOs. Reading the openGL specs is something one needs to get into as it takes some level of understanding to filter out the necessary parts. In this post I want to share some of my understanding of how Vertex Array Objects, Vertex Buffers and Shaders can work nicely together with each other.

First I'll show you a basic example of how VBOs, VAOs and shaders are used together. This examples uses openFrameworks and my camera class from my library. It shows the testApp.h and testApp.cpp. I'm importing the vertices from an .obj file.
#pragma once
#include "ofMain.h"
#include
// Vertex and fragment shader sources
static const char* VS = "" \
"uniform mat4 u_projection_matrix;" \
"uniform mat4 u_view_matrix;" \
"attribute vec4 a_position;" \
"attribute vec2 a_tex; " \
"attribute vec3 a_normal; " \
" " \
"void main() { " \
" gl_Position = u_projection_matrix * u_view_matrix * a_position; " \
"}" \
"";
static const char* FS = "" \
"void main() { \n" \
" gl_FragColor.rgba = vec4(1.0,0.5,1.0,0.5); " \
"}" \
"";
// In this example, We only use the vertex position
struct MyVertex {
MyVertex(float x, float y, float z) {
position[0] = x;
position[1] = y;
position[2] = z;
memset(tex, 0, 2 * sizeof(float));
memset(normal, 0, 3 * sizeof(float));
}
float position[3];
float tex[2];
float normal[3];
};
class testApp : public ofBaseApp{
public:
Camera cam;
GLuint vao;
GLuint vbo;
GLuint vert_shader;
GLuint frag_shader;
GLuint prog;
int vertex_count;
};
Above I defined a MyVertex structure to which I refer in the text below. Note that I'm only using the positions in my code to keep it simple.
In the code below, I'm using a custom Camera class to get the projection and view matrices. I'm also reading a OBJ file that exported from Blender.
// testApp.cpp
#include "testApp.h"
//--------------------------------------------------------------
void testApp::setup(){
ofBackground(33);
cam.perspective(60.0f, 4.0/3.0f, 0.1, 10.0f);
cam.setPosition(0.0f, 0.0f, 2.5f);
// Step 1: create shaders
// ----------------------
vert_shader = glCreateShader(GL_VERTEX_SHADER);
frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vert_shader, 1, &VS, NULL);
glShaderSource(frag_shader, 1, &FS, NULL);
glCompileShader(vert_shader);
glCompileShader(frag_shader);
prog = glCreateProgram();
glAttachShader(prog, vert_shader);
glAttachShader(prog, frag_shader);
glBindAttribLocation(prog, 0, "a_position");
glBindAttribLocation(prog, 1, "a_tex");
glBindAttribLocation(prog, 2, "a_normal");
glLinkProgram(prog);
glUseProgram(prog);
// Camera + Projection matrices
GLint projection_id = glGetUniformLocation(prog, "u_projection_matrix");
GLint cam_id = glGetUniformLocation(prog, "u_view_matrix");
glUniformMatrix4fv(projection_id, 1, false, cam.pm().getPtr());
glUniformMatrix4fv(cam_id, 1, false, cam.vm().getPtr());
// Step 2: Create the vertices buffer (on cpu).
// We read the vertices from a .obj file.
std::vector vertices;
std::ifstream ifs;
ifs.open(ofToDataPath("suzanne.obj").c_str(), std::fstream::in);
if(!ifs.is_open()) {
::exit(1);
}
std::string line;
while(ifs >> line) {
if(line.size() == 1 && line[0] == 'v') {
float x,y,z = 0.0f;
ifs >> x >> y >> z;
MyVertex vertex(x,y,z);;
vertices.push_back(vertex);
}
}
vertex_count = vertices.size();
// Step 3: Pass the vertices to openGL and create VBO
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(
GL_ARRAY_BUFFER
,sizeof(MyVertex) * vertices.size()
,vertices[0].position
,GL_STATIC_DRAW
);
// Step 3: Create VAO which keeps track of the attribute info
glGenVertexArraysAPPLE(1, &vao); // apple specific here
glBindVertexArrayAPPLE(vao);
// Step 4: Create a VAO and set the attribute data
glEnableVertexAttribArray(0); // a_position
glEnableVertexAttribArray(1); // a_tex
glEnableVertexAttribArray(2); // a_normal
// IMPORTANT: we're "binding" our VBO again.. this triggers the currently bound
// VAO to use this VBO for the next function calls which influence the attribute
// state. The state is set by calling glVertexAttribPointer.
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE
,sizeof(MyVertex), (GLvoid*)offsetof(MyVertex, position));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE
,sizeof(MyVertex), (GLvoid*)offsetof(MyVertex, tex));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE
,sizeof(MyVertex), (GLvoid*)offsetof(MyVertex, normal));
ofEnableAlphaBlending();
}
//--------------------------------------------------------------
void testApp::draw(){
glBindVertexArrayAPPLE(vao);
glUseProgram(prog);
glDrawArrays(GL_POINTS, 0, vertex_count);
}
VBO
Think of a VBO just as an buffer into which you can store bytes. Most ofter these bytes will be information about your 3D model, namely the vertex positions, texture coordinates, colors, normals etc. But with modern openGL, you're not limited to these attributes. You can add any attribute you like.
Whenever you have any of this kind of data, you can use a VBO. Using an VBO is an efficient way to your 3D model data. When you want to create a new VBO you have to ask openGL to create one for you. Creating a VBO follows the same approach as with many other openGL "creation" functions. First you call a "glGen*" then you call "glBind*". So in this case:
glGenBuffers(1, &my_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
As you can see I'm binding the VBO as an GL_ARRAY_BUFFER. So, we could use the name "Array Buffer" instead of VBO. If you want to relate this to your favorite programming language one might say this is a bit similar to:
var array = new Array()
Okay, so now we have a buffer into which we can store some data. As I said above, you probably want to store vertex attributes for your 3D model in a this VBO. But what do I meean with "vertex attributes"? Well good question :-). A vertex is not just a position of a 3D model, although the term vertex is often used as a 3D/2D point. A better mental model of a vertex is a group of data which is related to a point in space. Of course this means that you need an actual 2D or 3D point. A good way to explain this, is by creating a vertex structure (C++)
struct MyVertex {
float position[3];
float uv[2];
float normal[3]
};
This would be a typical definition of a vertex with 3 attributes: position, uv and normal. The great thing with using the correct way of openGL, is that you can use any attribute you like. To continue, your 3D model will contain many of these vertices. A basic solution to store these vertices is using a std::vector variable. Once you've filled the vector with all vertices that make up your model you need hand over all the vertices to openGL. For this you use glBufferData:
glBufferData(
GL_ARRAY_BUFFER
,sizeof(MyVertex) * vertices.size()
,vertices[0].position
,GL_STATIC_DRAW
)
Once you've called glBufferData() the VBO that you've bound previously with glBindBuffer() will contain the all of the vertices from the "std::vector vertices" (I did not add code which filled this vertices vector.)
To summarize, when I think of a VBO I think about these three functions (there is a bit more into it, but this will do fine):
glGenBuffer(...)
glBindBuffer(...)
glBufferData(...)
How simple is that, right? Now, lets say we have a VBO which contains all the vertices for our 3D model. What do we need more to render this? OpenGL can't do anything with a buffer alone; for openGL, the buffer is just a bunch of bytes. Next step is telling openGL how the data is structured. Before you can tell openGL how it's structured you need to know that a std::vector is just a flat array in memory. So it's a continuous stream of bytes with position, uv, normal, position, uv, normal, position, uv, normal etc.. etc.. To explain this I can start with how shaders and vertex attributes are tight together or how a VAO is related to this. I'll start with the shader part.
SHADER
I'm not going to dive into the workings of a shader, I'll only explain some of the details you need to understand VBO + VAOs. A shader is a tiny program that's executed for each of the vertices and fragments. The first kind of shader is called a Vertex-Shader and as you might guessed is executed for each vertex. The other one is a Fragment Shader, which I won't describe further. So a vertex shader is excuted for each vertex. As I explained above I see a vertex as a group of attributes related to a point. To use these attributes in a shader, you need to tell the shader what kind of attributes you want to work with. One of the ways to tell this, is to add the attributes in the source like this:
attribute vec4 a_position;
attribute vec2 a_tex;
attribute vec3 a_normal;
void main() {
// some shader code.
}
In the example bove I created a vertex shader which can with with all of the attributes I defined in my MyVertex structure. Note: I'm using a vec4 for a_position but I defined a float[3] for position in MyVertex. openGL will set the fourth value of a_position to 1.0. The reason I'm using a vec4 is because I will multiply this a_position by a matrix 4x4.
Ok, awesome, we now have a VBO and a vertex shader. As you might have guessed we still need to tell openGL how the we want to use the VBO and how it's data is organized in memory and how this data is related to attributes. This is probably the most confusion part of Vertex Array Objects (VAOs).
VAO
Ok this is the toughest part of this article and I've been told many different things on the workings of this and I've to use the right words/names to explain this. To be clear, I want to describe my mental model of VAOs. The next paragraphs are not yet completely about VAOs but I think it's good to describe these functions here anyway.
It's good to keep in mind, that openGL still needs to find a way to use the bytes in the VBO for the correct attributes in the shader. For example, we don't want that openGL uses MyVertex.normal for the a_position attribute.
We can tell this by making connections between the attributes in the shader and the data in the VBO. When we look at the MyVertex struct, and lets say we look into the memory it will look something like:
- 12 bytes for the position
- 8 bytes for the uv
- 12 bytes for the normal
Note that a float takes 4 bytes. When the vertex-shader works with one vertex at a time, we can tell opengl "hey! for a_position, use the first 12 bytes, for the a_tex, the next8 and for a_normal, use the last 12 bytes". We can tell this by using glVertexAttribPointer().
In 99% of the cases when you're working with VBOs + VAOs and you get an memory access error, it's because you've used wrong values for glVertexAttribPointer. Lets say the a_position from my shader is stored at a index with the number 0, a_tex at 1, and a_normal at 2. Now we have enough information to tell openGL how to connect the dots. In the following code snippet, we are going to tell that the a_norma is related to MyVertex.normal, that the values are floats, they don't need to be normalized and that you can find them at an offset of 20 bytes (see offsetof).
glVertexAttribPointer(
2
,3
,GL_FLOAT
,GL_FALSE
,sizeof(MyVertex)
,(GLvoid*)offsetof(MyVertex, normal)
);
After calling glVertexAttribPointer() the result is that openGL knows something about an attribute, the size, the type, the stride, etc. To make this a bit more clear, lets say that openGL has a structure like this:
struct VertexAttribPointerInfo {
int attribute_index;
int number_of_elements;
DataType type; // e.g. FLOAT
bool must_normalize;
int stride;
int offset;
int vbo;
bool enabled;
}
So for each of the attributes openGL creates a new VertexAtribPointerInfo instance, sets the correct info and keeps track of these settings in a general array of VertexAttribPointerInfo. (keep in mind, that this is a mental model; how openGL manages the data it totally up to the way the driver is implemented.) One thing to pay attention to, is the "int vbo" in VertexAttribPointer. Each time you call glVertexAttribPointer() you must be sure a VBO is bound. This means that you can bind another VBO per attribute. This could make sense when you e.g. have tons of attributes, but only one attribute changes everytime. Then you want to create a separate VBO and update only this data everytime it changes.
Lets recap a bit. We now have a way to tell openGL how to relate a VBO, to attributes. I've left a couple of pieces from this puzzle though. Importantly I didn't tell you that you first need to enable a vertex attribute if you want to use it. You can do this by calling glEnableVertexAttribArray(). By calling glEnableVertexAttribArray(), you're setting the VertexAttribPointerInfo.enabled to true. This operation works on the general VertexArribPointerInfo array of opengl or on the currently bound VAO (note, I made this VertexAttribPointerInfo array up to give a modal of what's going on).
Because we have 3 vertex attributes: position, tex, normal, we need to enable all three of them. You can use more then 3 vertex attribute index numbers. You could for example use indices 2,3,4. But lets say we want to use 0,1,2, then we call:
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
OpenGL would do something like this, where vao is the currently bound VAO or the generic vertex attribute array.
VertexAttribPointerInfo vao[8];
vao[0].enabled = true;
vao[1].enabled = true;
vao[2].enabled = true;
Ok there is one last thing to do before I can explain more about what a VAO is. We did not yet tell openGL what the vertex attributes actually are. Yes, we did use the indices 0,1,2, but openGL has no way of knowing that these indices related to the variables in our shader (a_position, a_tex and a_normal). We use glBindAttribLocation() for this. This involves a bit of info I don't want to add here, but assume we have a program object then we can bind the attributes to the correct indices like this:
glBindBuffer(GL_ARRAY_BUFFER, my_vbo);
glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "a_tex");
glBindAttribLocation(program, 2, "a_normal");
In newer versions of openGL you can specify the location in the shader, but for this article this is a good solution too, which will also work with older versions the 3. Note that I'm explicitly binding the VBO again (with glBindBuffer(GL_ARRAY_BUFFER, my_vbo)). It depends a bit on how you structure you code, but you need to make sure that you bind the VBO after binding the VAO. When a VAO is bound and you call glBindBuffer, it's notifies the VAO that you want to work with this VBO.
I hope this article gives you a basic understanding of how VBOs and VAOs work. If you have any comments please contact me.

The band perfume released files that contain skeleton animations that I used to create ribbons. I exported the vertices and faces I generated (based on the skeleton information), to simple text file which I then imported into blender. The script below is what I used to create a new object from these vertices and faces.

import bpy
from pprint import pprint
file = open("file_with_points.pts")
vertices = []
texcoords = []
faces = []
faces_raw = []
vertices_raw = []
part = 0
for line in file:
line = line.strip()
# Parsing Vertices or Faces
if line == "V":
part = 1
continue
elif line == "F":
part = 2
continue
if part == 1:
x,y,z,u,v = [float(bit.strip()) for bit in line.split(',')]
vertices_raw.append(x)
vertices_raw.append(y)
vertices_raw.append(z)
texcoords.append([u,v])
vertices.append([x,y,z])
elif part == 2:
a,b,c,d = [int(bit.strip()) for bit in line.split(',')]
#a,b,c = [int(bit.strip()) for bit in line.split(',')]
faces.append([a,b,c])
faces_raw.append(a)
faces_raw.append(b)
faces_raw.append(c)
faces_raw.append(d)
print("Vertices: ", len(vertices))
print("Vertices RAW: ", len(vertices_raw))
print("Faces: ", len(faces))
print("Faces RAW: ", len(faces_raw))
m = bpy.data.meshes.new("mesh_test")
# Number of vertices where one XYZ is one vertex
m.vertices.add(len(vertices_raw)/3)
m.vertices.foreach_set("co", vertices_raw)
# number of quads
m.tessfaces.add(len(faces_raw)/4)
# sets: m.tessfaces.vertices_raw[0] ..., [1]...
m.tessfaces.foreach_set("vertices_raw", faces_raw)
uv = m.tessface_uv_textures.new("uvtexture")
for face in m.tessfaces:
print(face.index)
texcoord_index = face.index * 2
print("texcoord start: ", texcoord_index, len(vertices))
uv.data[face.index].uv1 = texcoords[texcoord_index]
uv.data[face.index].uv2 = texcoords[texcoord_index+2]
uv.data[face.index].uv3 = texcoords[texcoord_index+1]
uv.data[face.index].uv4 = texcoords[texcoord_index+3]
#uv.data[face.index].uv1 = texcoords[face.index][0]
#uv.data[face.index].uv2 = texcoords[face.index][1]
#m.from_pydata(vertices, [], faces)
m.update()
ob = bpy.data.objects.new("mesh_obj", m)
ob.location = (0,0,0)
bpy.context.scene.objects.link(ob)

The file which I imported into blender had a very basic format. I started with all vertices, followed by the faces. This is a snippet from such a file.
V
65.6948, 88.589, -144.407,0, 0
38.6111, 75.6872, -144.528,0, 1
65.8619, 88.2368, -144.236,0.000581734, 0
38.6347, 75.6405, -144.365,0.000581734, 1
66.0792, 87.7644, -143.993,0.00116347, 0
F
0,2,3,1
2,4,5,3
4,6,7,5
6,8,9,7
8,10,11,9
10,12,13,11
