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.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.

Greetings, Dragonseel

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)


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