3
$\begingroup$

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()
bm.from_mesh(obj.data)
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.?

$\endgroup$
6
  • $\begingroup$ add Triangulate modifier? $\endgroup$
    – Vader
    Feb 14, 2014 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$ Feb 14, 2014 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, 2014 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$ Feb 14, 2014 at 17:15
  • $\begingroup$ come to chat please chat.stackexchange.com/rooms/8888/the-renderfarm $\endgroup$
    – Vader
    Feb 14, 2014 at 17:17

2 Answers 2

4
$\begingroup$

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

import bpy
import bmesh

ob = bpy.context.object
ob.update_from_editmode()
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()
bm.from_mesh(me)
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]))

bm.free()
del bm

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

$\endgroup$
2
  • $\begingroup$ Would it also be possible to retrieve vertex groups from a bmesh? If yes, could you include that in your answer? $\endgroup$ Feb 14, 2014 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, 2014 at 0:35
3
$\begingroup$

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()
bm.from_mesh(mesh)
bmesh.ops.triangulate(bm, faces=bm.faces)
bm.to_mesh(mesh)
bm.free()
del bm

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

$\endgroup$
2
  • 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, 2014 at 0:42
  • $\begingroup$ Unfortunately this no longer works, since around version 2.8. Lookup evaluated_get method in Blender documentation to see how it's done in the more recent API $\endgroup$
    – kuroi neko
    Jan 9 at 4:17

You must log in to answer this question.

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