8
$\begingroup$

Recently we were working to write our own software to load a Wavefront .OBJ file.

The file in question uses the .OBJ file format that Blender 2.73 and below generates which is like this:

# Blender v2.73 (sub 0) OBJ File: ''
# www.blender.org
o Cube_Cube.001
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
s off
f 1 2 3 4

The .OBJ exporter of Blender 2.74, in other hand, creates files like this, which are more closer to the definition that one will find in Wikipedia for example:

# Blender v2.74 (sub 0) OBJ File: ''
# www.blender.org
o Cube
v -1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 -1.000000
vn -1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 0.000000 1.000000
s off
f 2//1 4//1 3//1 1//1

While this is a valid OBJ file, its more involved to parse.

So, the problem is that I would like to write an exporter that uses just a subset of what the .OBJ file format can offer. In this case, just vertices and faces with everything in one line.

I would like to use python inside of Blender to do that but I have no idea on how to start to write this script.

$\endgroup$
4
  • 2
    $\begingroup$ Welcome to the site :) Could you specify what exactly you want our help with? Asking overly broad questions is discouraged here. Try writing the script first, then come back and ask a question if you run into a difficulty (and specify what exactly the difficulty is). $\endgroup$
    – gandalf3
    Jun 15, 2015 at 3:29
  • $\begingroup$ @chicOrtiz I've answered what I think is the bulk of your question, if there are remaining questions either update your question or preferable ask an additional question (separately) which can be answered in a shorter way. Right now (unbeknownst to you perhaps) you have asked at least 4 questions, but I anticipate that it could be more. That's ok, just ask new questions individually, that way we keep information modular and people will find answers to specific questions more rapidly. $\endgroup$
    – zeffii
    Jun 15, 2015 at 6:17
  • $\begingroup$ @gandalf3, simplified the question, was going into a lot of unnecessary details. $\endgroup$
    – ideasman42
    Jun 15, 2015 at 21:22
  • $\begingroup$ Usage example of this simplified .OBJ: LINK $\endgroup$
    – chicOrtiz
    Nov 23, 2016 at 20:15

3 Answers 3

11
$\begingroup$

This is a simple OBJ export script, that this writes valid OBJ files that load back into Blender: verts and faces, (no edges or materials).

import bpy
from bpy import context

filepath = "/tmp/simple_obj.obj"

obj = context.object
mesh = obj.data

with open(filepath, 'w') as f:
    f.write("# OBJ file\n")
    for v in mesh.vertices:
        f.write("v %.4f %.4f %.4f\n" % v.co[:])
    for p in mesh.polygons:
        f.write("f")
        for i in p.vertices:
            f.write(" %d" % (i + 1))
        f.write("\n")

This script can be pasted into Blenders text editor and executed, you will want to modify the output filepath.

$\endgroup$
3
  • $\begingroup$ Just great! Thank you so much for your time Campbell. $\endgroup$
    – chicOrtiz
    Jun 15, 2015 at 23:28
  • $\begingroup$ Post on BlenderArtists: LINK $\endgroup$
    – chicOrtiz
    Jun 17, 2015 at 21:16
  • $\begingroup$ An absolute gem, thank you. $\endgroup$
    – ofekp
    Sep 9, 2022 at 23:48
6
$\begingroup$

This question is actually several questions.

  1. how to write code to generate that string
  2. how to write code that writes this to disk
  3. how to write code that wraps this code as an exporter operator
  4. how to add boilerplate to the operator to make it an add-on

Answers to Question 3 and 4 can be found in Blender's TextEditor, and in the many exporter scripts found in /scripts/addons/.., don't be afraid to read all of them to get a better understanding of the boilerplate code.:

  • TextEditor -> Templates -> Python -> Operator File Export
  • TextEditor -> Templates -> Python -> Operator Simple

I will deal only with 1 and 2 (note that there are quite a few approaches to doing this, with any luck others will give their intepretations too).

import bpy

obj = bpy.context.active_object
mesh = obj.data

filepath_out = "/home/zeffii/Desktop/temp/single_line.obj"
with open(filepath_out, 'w') as ofile:

    begin = "OBJ File: "
    ofile.write(begin)

    for v in mesh.vertices:
        # line = "v {v.x} {v.y} {v.z} " for full precision  
        line = "v {v.x:.4f} {v.y:.4f} {v.z:.4f} "
        line = line.format(v=v.co)
        ofile.write(line)

    for f in mesh.polygons:
        line = "{0} {1} "
        # obj vertex indices for faces start at 1 not 0 like blender.
        indices = [str(i+1) for i in f.vertices[:]]
        line = line.format("f", ' '.join(indices))
        ofile.write(line)

Outputs the following, which is what you were originally after.. on one line:

OBJ File: v -1.0 -1.0 -1.0 v -1.0 -1.0 1.0 v -1.0 1.9393 -1.0 v -1.0 1.9393 1.0 v 1.0 -1.0 -1.0 v 1.0 -1.0 1.0 v 1.0 1.0 -1.0 v 1.0 1.0 1.0 f 1 3 2 0 f 3 7 6 2 f 7 5 4 6 f 5 1 0 4 f 0 2 6 4 f 5 7 3 1 

This code makes a few assumptions,

  • It assumes you only want to export the active object.
  • It assumes the Object's obj.matrix_world is equal to an Identity matrix, and therefore ignores it. For export purposes it may make more sense to apply the matrix first in case you have transforms going on (scale / rotation / translation / sheering), or pass along the matrix in the appropriate form.
  • assumes you only want 4 decimals precision
  • assumes you will eventually be generating a filepath using the exporter, but if you want to know more about paths read the path wiki

here the string formatting mini language uses :.4f to show only 4 decimal places, for web stuff this may be enough, but if you want full precision it's less code:

$\endgroup$
2
  • 1
    $\begingroup$ Zeffii, thank you very much for your answer. It solved the problem, and also now I'm in the right track to learn Python. :) $\endgroup$
    – chicOrtiz
    Jun 15, 2015 at 16:53
  • $\begingroup$ Note, dont think using .replace(",", "") here is great. just format 3 values is better practice. $\endgroup$
    – ideasman42
    Jun 15, 2015 at 19:50
1
$\begingroup$

This is a slight variation of @ideasman42, done by my friend Yorik Van Havre. It writes the file all in the same line. The output can be pasted directly to this HTML file, if someone is interested.

import bpy
from bpy import context

filepath = "/home/chico/Desktop/obj/simple.obj" #Unix filepath template
#filepath = "C:\obj\simple.obj" #Windows filepath template

obj = context.object
mesh = obj.data

with open(filepath, 'w') as f:
    f.write("OBJ File: ")
    for v in mesh.vertices:
        f.write("v %.4f %.4f %.4f " % v.co[:])
    for p in mesh.polygons:
        f.write("f ")
        for i in p.vertices:
            f.write("%d " % (i + 1))
$\endgroup$
9
  • $\begingroup$ Your Html file is using the wrong document type. By the way you might also have a look at three.js. There are a lots of examples available and a course at udacity. Three.js may use the canvas for output as well. $\endgroup$ Jun 16, 2015 at 15:19
  • $\begingroup$ Hello @pink vertex ! Thank you for your input. Do you know if three.js works on hardware that doesn't support WebGL? $\endgroup$
    – chicOrtiz
    Jun 17, 2015 at 17:42
  • 2
    $\begingroup$ Use the canvas renderer if you can not use WebGL. $\endgroup$ Jun 18, 2015 at 16:55
  • $\begingroup$ @pink vertex : Thank you very much for the link! :) $\endgroup$
    – chicOrtiz
    Jun 19, 2015 at 0:47
  • $\begingroup$ Really no problem @poor! Your questioning was legitimate, since I'm starting to post here :) $\endgroup$
    – chicOrtiz
    Jun 20, 2015 at 23:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .