Export blender object to simple file format
Update 2015:
The following script generates a C/C++ header that you can include in your project. By default we will include the glad.h (see the glad repository on github) header to make sure we have the openGL defines/functions.
""" Exports the selected object in blender to class with the same name as the selected object. We create a vao and vbo the first time the draw function is called. To use this script: - Copy and paste the contents in to a new blender script - Execute/Run the script with the select object. - Save the header file. """ import bpy import math import mathutils import os import bmesh from mathutils import Vector, Matrix from bpy_extras.io_utils import ExportHelper from bpy.props import StringProperty, BoolProperty, EnumProperty from bpy.types import Operator o = bpy.context.active_object print("="*40) output = [] mat_x90 = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X') conv_mat = o.matrix_world # Build the output list. # -------------------------------------------------- def add_vertex(v, n): v = conv_mat * v v = mat_x90 * v output.append(v.x) output.append(v.y) output.append(v.z) output.append(n.x) output.append(n.y) output.append(n.z) bm = bmesh.new() bm.from_mesh(o.data) bmesh.ops.triangulate(bm, faces=bm.faces) for face in bm.faces: for v in face.verts: add_vertex(v.co, face.normal) bm.free() del bm # -------------------------------------------------- def create_opengl_header(context, filepath): out_floats = [ '%.3f' % elem for elem in output ] out_floats_str = "float vertices[] = {" +",".join(out_floats) +"};" out_header = ("" "#ifndef " +o.name.upper() +"_H\n" "#define " +o.name.upper() +"_H\n" "\n" "#include <glad/glad.h>\n" "\n" "class " +o.name +" {\n" " public: \n" " void draw();\n" "};" "\n" "\n" "/* --------------------------------------------------------------- */\n" "\n" "inline void " +o.name +"::draw() {\n" "\n" " static GLuint vao = 0;\n" " static GLuint vbo = 0;\n" "\n" " int nvertices = " +str(len(output)) +";\n" " " +out_floats_str +"\n" "\n" " if (0 == vao) {\n" " glGenVertexArrays(1, &vao);\n" " glBindVertexArray(vao);\n" " glGenBuffers(1, &vbo);\n" " glBindBuffer(GL_ARRAY_BUFFER, vbo);\n" " glBufferData(GL_ARRAY_BUFFER, nvertices * sizeof(float), vertices, GL_STATIC_DRAW);\n" " glEnableVertexAttribArray(0); /* positions */\n" " glEnableVertexAttribArray(1); /* normals */\n" " glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (GLvoid*)0);\n" " glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (GLvoid*)12);\n" " }\n" "\n" " glBindVertexArray(vao);\n" " glDrawArrays(GL_TRIANGLES, 0, " +str(len(output)) +");\n" "}\n" "\n" "#endif\n" "") f = open(filepath, 'w', encoding='utf-8') f.write(out_header) 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_opengl_header.exp" bl_label = "Export OpenGL Header(ROXLU)" filename_ext = ".h" filter_glob = StringProperty( default="*.h", options={'HIDDEN'}, ) def invoke(self, context, event): self.filepath = o.name +".h" context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} def execute(self, context): return create_opengl_header(context, self.filepath) def menu_func_export(self, context): self.layout.operator(ExportSomeData.bl_idname, text="Export OpenGL Header") 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_opengl_header.exp('INVOKE_DEFAULT')
Scripts from 2012, 2013, 2014:
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')
We transform from the default Blender orientation to the default openGL orientation (z pointing into the screen).
""" Exports the selected object in blender to an float array with vertices and normals. We do not use vertex indices but rather duplicate each triangle. """ 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.x) output.append(v.y) output.append(v.z) output.append(n.x) output.append(n.y) output.append(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 = "int nvertices = " +str(len(output)) +";\n" out_floats = [ '%.3f' % elem for elem in output ] out_str += "float vertices[] = {" +",".join(out_floats) +"};" dest = "path_to_your_header_file/bone.h" f = open(dest, 'w+') f.write(out_str) f.close() print("Created.")
And another updated (May 2017) version which exports the vertices into a .h and .cpp file in the same directory as the .blend file and correctly sets some external variables.
""" Exports the selected object in blender to an float array with vertices and normals. The vertices are rotated into the OpenGL axis system. We do not use vertex indices but rather duplicate each triangle. We create a .h and .cpp file called "Model[ObjectName].h/cpp" and save it into the same location as the .blend file. """ 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.x) output.append(v.y) output.append(v.z) output.append(n.x) output.append(n.y) output.append(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) model_name = o.name; out_header_str = "" \ +"#ifndef MODEL_" +model_name.upper() +"_H\n" \ +"#define MODEL_" +model_name.upper() +"_H\n" \ +"extern int nfloats_" +model_name.lower() +";\n" \ +"extern int nvertices_" +model_name.lower() +";\n" \ +"extern float vertices_" +model_name.lower() +"[];\n" \ +"#endif" out_cpp_str = "" \ +"#include \"Model" +model_name +".h\"\n" \ +"int nfloats_" +model_name.lower() +" = " +str(len(output)) +";\n" \ +"int nvertices_" +model_name.lower() +" = " +str((int(len(output) / 6))) +";\n" out_cpp_floats = [ '%.3f' % elem for elem in output ] out_cpp_str += "float vertices_" +model_name.lower() +"[] = {" +",".join(out_cpp_floats) +"};" header_filepath = bpy.path.abspath("//") +"Model" +model_name +".h" cpp_filepath = bpy.path.abspath("//") +"Model" +model_name +".cpp" f = open(cpp_filepath, 'w+') f.write(out_cpp_str) f.close() f = open(header_filepath, "w+") f.write(out_header_str) f.close() print("Created.")
NAT Types
Building Cabinets
Compiling GStreamer from source on Windows
Debugging CMake Issues
Dual Boot Arch Linux and Windows 10
Mindset Updated Edition, Carol S. Dweck (Book Notes)
How to setup a self-hosted Unifi NVR with Arch Linux
Blender 2.8 How to use Transparent Textures
Compiling FFmpeg with X264 on Windows 10 using MSVC
Blender 2.8 OpenGL Buffer Exporter
Blender 2.8 Baking lightmaps
Blender 2.8 Tips and Tricks
Setting up a Bluetooth Headset on Arch Linux
Compiling x264 on Windows with MSVC
C/C++ Snippets
Reading Chunks from a Buffer
Handy Bash Commands
Building a zero copy parser
Kalman Filter
Saving pixel data using libpng
Compile Apache, PHP and MySQL on Mac 10.10
Fast Pixel Transfers with Pixel Buffer Objects
High Resolution Timer function in C/C++
Rendering text with Pango, Cairo and Freetype
Fast OpenGL blur shader
Spherical Environment Mapping with OpenGL
Using OpenSSL with memory BIOs
Attributeless Vertex Shader with OpenGL
Circular Image Selector
Decoding H264 and YUV420P playback
Fast Fourier Transform
OpenGL Rim Shader
Rendering The Depth Buffer
Delaunay Triangulation
RapidXML
Git Snippets
Basic Shading With OpenGL
Open Source Libraries For Creative Coding
Bouncing particle effect
OpenGL Instanced Rendering
Mapping a texture on a disc
Download HTML page using CURL
Height Field Simulation on GPU
OpenCV
Some notes on OpenGL
Math
Gists to remember
Reverse SSH
Working Set
Consumer + Producer model with libuv
Parsing binary data
C++ file operation snippets
Importance of blur with image gradients
Real-time oil painting with openGL
x264 encoder
Generative helix with openGL
Mini test with vector field
Protractor gesture recognizer
Hair simulation
Some glitch screenshots
Working on video installation
Generative meshes
Converting video/audio using avconv
Auto start terminal app on mac
Export blender object to simple file format