5
$\begingroup$

I am trying to create a mesh via a Python script and set a texture for it.

My code so far:

def add_mesh(self, coords, uvs, faces, texture, texHeight, texWidth):
  me = bpy.data.meshes.new("myMesh")
  ob = bpy.data.objects.new("myObject", me)

  me.from_pydata(parsedCoords, [], parsedFaces)
  me.update(calc_edges=True)

  mat = self._make_material("myMaterial", (1,1,1), (1,1,1), 1)
  tex = self._make_texture("myTexture", texture, texWidth, texHeight)
  mTex = mat.texture_slots.add()
  mTex.texture_coods = 'UV'
  mTex.use_map_color_diffuse = True
  mTex.diffuse_color_factor = 1.0
  mTex.blend_type = 'MULTIPLY'

  # Missing: Set the uv-coords for the mesh

  me.materials.append(mat)

I use _make_material and _make_texture which are self-defined. But I think they work.

For the missing part I found using the API-documentation following

uv_layer = me.uv_layers.active.data
for poly in me.polygons:
    for loop_ind in range(poly.loop_start, poly.loop_start+ poly.loop_total):
        vInd = me.loops[loop_index].vertex_index
        uv_layer[loop_index].uv = tuple( uvs[vertex_index] )

The passed uvs is a list uv-coordinates as lists. They are in the same order as the vertices.

My problem now is that the uv_layer = me.uv_layers.active.data does not work. It results in AttributeError: 'NoneType' object has no attribute 'data'

I think my mesh has no uv_layer. How do I add one? Is my code correct if I add a uv_layer to the mesh? I am really unsure about it.

Thank you for your help!

Greetings, Dragonseel

$\endgroup$

2 Answers 2

4
$\begingroup$

As Dragonseel mentioned: the bmesh is important. http://web.purplefrog.com/~thoth/blender/python-cookbook/barber-pole.html contains a spiralUVs function which assigns UV coordinates to the faces of a cylinder. It demonstrates the mesh.uv_textures.new(name) function for creating a new UV layer.

Here is the function from that page:

def spiralUVs(mesh, xPlus):
    # add a UV layer called "spiral" and make it slanted.
    mesh.uv_textures.new("spiral")
    bm = bmesh.new()
    bm.from_mesh(mesh)

    uv_layer = bm.loops.layers.uv[0]

    nFaces = len(bm.faces)
    for fi in range(nFaces):
        x0 = fi*2/nFaces
        x1 = (fi+1)*2/nFaces
        bm.faces[fi].loops[0][uv_layer].uv = (x0, 0)
        bm.faces[fi].loops[1][uv_layer].uv = (x1, 0)
        bm.faces[fi].loops[2][uv_layer].uv = (xPlus+x1, 1)
        bm.faces[fi].loops[3][uv_layer].uv = (xPlus+x0, 1)
    bm.to_mesh(mesh)
$\endgroup$
1
  • $\begingroup$ This is best answer I found after 4 hrs worth of search. A decade old stuff that is. A note for future readers: you need bm.verts.ensure_lookup_table() as shown in above link and then it's all set! $\endgroup$
    – jupiterbjy
    Commented Oct 6, 2023 at 9:19
3
$\begingroup$

The only way I found for editing the UV-Coordinates of a mesh is via the BMesh module.

This module can be imported in the script via import bmesh.

Assume the code I wrote in the question I will give my solution for the missing part which edits the uv-coords.

bpy.ops.object.mode_set(mode='EDIT')
bm = bmesh.from_edit_mesh(me)

uv_layer = bm.loops.layers.uv.verify()
bm.faces.layers.tex.verify()

for f in bm.faces:
    for l in f.loops:
        luv = l[uv_layer]
        luv.uv = tuple(uvs[l.vert.index])

bmesh.update_edit_mesh(me)
bpy.ops.object.mode_set(mode='OBJECT')

Note that I only tested to set all the uvs to (0,0) since I have another problem with the uv coordinates. But it worked and my mesh was successfully painted red.

Greetings, Dragonseel

$\endgroup$

You must log in to answer this question.

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