I have to triangulate the object's mesh because the format I export to only understands triangles. Now I not only want to export geometry but also the uv-mappings for the mesh. Let's call the uv_texture uvTex. The context object is obj What I have done so far:

import bmesh
bm = bmesh.new()
bmesh.ops.triangulate(bm, faces=bm.faces)
# everything is fine so far

Now the problem is that you access the uv-data by iterating through the faces and then through their vertices. So for example uvTex.data[0] belongs to obj.data.faces[0]."vertices[0]" (quotes because it's not really a vertex in this context, it's just an index but you get what I mean).

Triangulating the mesh has changed the order of the vertices so my question is now:

How does one export a triangulated version of an object's mesh, including uv-mappings, without changing the objects geometry, etc.?

  • $\begingroup$ add Triangulate modifier? $\endgroup$ – Vader Feb 14 '14 at 16:59
  • $\begingroup$ that is in no way automated and has to be done by the user, (actually no) but how do I access the modified data without applying it? or should I rewind time after my script finished? enlighten me please $\endgroup$ – WorldSEnder Feb 14 '14 at 17:10
  • $\begingroup$ just add the modifier, on export the modifier will be applies. This is the non-destructive way. Does this do what you want? $\endgroup$ – Vader Feb 14 '14 at 17:13
  • $\begingroup$ it is my own export script, written, not finished, by me. Why should the modifier magically be applied on export? $\endgroup$ – WorldSEnder Feb 14 '14 at 17:15
  • $\begingroup$ come to chat please chat.stackexchange.com/rooms/8888/the-renderfarm $\endgroup$ – Vader Feb 14 '14 at 17:17

You can access the UV and Texture / Image information with bmesh using the custom data layers:

import bpy
import bmesh

ob = bpy.context.object
me = ob.data
vgroups = dict(enumerate(ob.vertex_groups.keys()))
vgroups_weights = [["%s: %.3f" % (vgroups[vg.group], vg.weight) for vg in v.groups] for v in me.vertices]

bm = bmesh.new()
bmesh.ops.triangulate(bm, faces=bm.faces)

uv_layer = bm.loops.layers.uv.active
if uv_layer is None:
    raise Exception("No active UV map (uv)")

uv_tex = bm.faces.layers.tex.active
if uv_tex is None:
    raise Exception("No active UV map (tex)")

for face in bm.faces:
    print("Face %i, Image = %s" % (face.index, getattr(face[uv_tex].image, "name", "")))

    for loop, vert in zip(face.loops, face.verts):
        print(" - Loop for Vertex %i, UV = %r" % (vert.index, loop[uv_layer].uv))
    for vert in face.verts:
        print(" - %s" % ", ".join(vgroups_weights[vert.index]))

del bm

Verts and loops of a face should match (first vertex - first loop etc.)

  • $\begingroup$ Would it also be possible to retrieve vertex groups from a bmesh? If yes, could you include that in your answer? $\endgroup$ – WorldSEnder Feb 14 '14 at 22:40
  • $\begingroup$ No, it's not accessible via bmesh module. But since triangulation doesn't change or add vertices, the BMVerts should be in line with MeshVertexes. Added vertex group name and weight printing to the face loop, although it doesn't make sense to print weights per face-vertex. $\endgroup$ – CodeManX Feb 15 '14 at 0:35

What me and Vader figured out together so far:

You can duplicate the object's data by calling

meshCopy = obj.to_mesh(scene, APPLY_MODIFIERS, 'PREVIEW')

This means that in order to do this you have to know a scene in which context you want to evaluate the modifier, limiting the export a bit but not hitting it hard. APPLY_MODIFIERS is a bool whether to apply modifiers or not so if this is False nothing will be changed. Not though that blender still doesn't accept None as scene so you might consider "cheating" and just handing over bpy.context.scene.

What you get is a perfect copy of object.data meaning that you can now "freely" modify "anything" you want. Instead of using obj.data you just have to use meshCopy now. Also most of the bpy.ops stuff won't work now but most of the time (at all times??) there is a second possibility. For example to triangulate the mesh you do this

import bmesh
bm = bmesh.new()
bmesh.ops.triangulate(bm, faces=bm.faces)
del bm

I hope this helps anyone that may see this question in the future ;)

  • 1
    $\begingroup$ The bmesh module has its own to_mesh() method: bm.from_object() (API Docs). The equivalent would look like: bm.from_object(obj, bpy.context.scene, deform=True, render=False (render=False means 'PREVIEW' quality) $\endgroup$ – CodeManX Feb 15 '14 at 0:42

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.