1
$\begingroup$

I was wondering if anyone could help me. I'm hoping to come up with a simple Python script that exports data from an object in a scene.

I've written a little 3d renderer for fun, and my project relies on me manually setting vertices and triangles in script to set up objects. It would be a lot easier if I could just copy and paste from the python console into my script.

So far I've come across this script:

import bpy  

current_obj = bpy.context.active_object  

print("="*40) # printing marker  
for face in current_obj.data.polygons:  
    verts_in_face = face.vertices[:]  
    print("face index", face.index)  
    print("normal", face.normal)  
    for vert in verts_in_face:
        local_point = current_obj.data.vertices[vert].co
        world_point = current_obj.matrix_world * local_point
        print("vert", vert, " vert co", world_point)

However this outputs the vertices in no particular order, and in the format

face index 4
normal <Vector (0.0000, -1.0000, 0.0000)>
vert 8  vert co <Vector (0.0000, -0.0000, -3.0000)>

I'd really like to get it in a format like this:

vertices[0].SetVertex (-1.0, -1.0, -3.0); //vertex coordinates
vertices[1].SetVertex (1.0, -1.0, -3.0);
vertices[2].SetVertex (1.0, 1.0, -3.0);

and

mesh[0].SetTriangle (0, 3, 2); //vertex indices

It would make copy/pasting into my script a lot easier.

Is this possible? Can anyone help me? I've never used Python before and I don't know too much about Blender.

$\endgroup$
1
$\begingroup$

current_obj.data.vertices contains all the vertices of the object. You can read these before you loop over the faces. As you already got the vertex indices of the faces, all is left to do is using the desired format string for your output.

import bpy  

current_obj = bpy.context.active_object  
verts_local = [v.co for v in current_obj.data.vertices.values()]
verts_world = [current_obj.matrix_world * v_local for v_local in verts_local]

print("="*40) # printing marker

for i, vert in enumerate(verts_world):
    print("vertices[{i}].SetVertex ({v[0]}, {v[1]}, {v[2]});".format(i=i, v=vert))

for i, face in enumerate(current_obj.data.polygons):
    verts_indices = face.vertices[:]
    print("mesh[{i}].SetTriangle {v_i};".format(i=i, v_i=verts_indices))

This will generate output like below. But it does not check whether the faces are really triangles and will call for the creation of “triangles” with four or more vertices if your object does contain quads etc.

========================================
vertices[0].SetVertex (0.0, 1.0, -1.0);
vertices[1].SetVertex (0.8660253882408142, -0.5000000596046448, -1.0);
vertices[2].SetVertex (0.0, 0.0, 1.0);
vertices[3].SetVertex (-0.866025447845459, -0.49999991059303284, -1.0);
mesh[0].SetTriangle (0, 2, 1);
mesh[1].SetTriangle (1, 2, 3);
mesh[2].SetTriangle (3, 2, 0);
mesh[3].SetTriangle (0, 1, 3);

If you want to differentiate between triangles, quads and so on then you might want to differentiate the format string based on the length of the vertex list.

N.B.: In my version of Blender, by default the text in the systems console can't be copied. I copied the text above from a text file that was generated by writing the output to a file instead of printing it to the console. Another option could be to start blender from a terminal from which you can copy text.

$\endgroup$
2
  • $\begingroup$ Thanks man, that's brilliant! Very helpful, you're a legend. One more thing though, is it possible to truncate the vertices to something like 5 decimal places? $\endgroup$ Jun 15 '18 at 8:28
  • $\begingroup$ Yes, precision, alignment and similar things can be specified in the format string. E.g. {v[0]:.5} instead of {v[0]} will display up to five decimals. The web page PyFormat.info has a good overview of the Python format string options. $\endgroup$
    – binweg
    Jun 15 '18 at 10:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.