I need a script to extract some info from selected faces, and I need to output faces as if they are triangles, i. e. as if I used Triangulate tool on these faces, or used something else, I just need my ngons to be a bunch of triangles. Also, it would be great if the original mesh is left unchanged. The faces' info includes vertices positions, uv coordinates, and normals. So far I have managed to get this script:

import bpy
import bmesh

# Copy mesh so that the original is intact
mesh = bmesh.from_edit_mesh(bpy.context.edit_object.data).copy()

# Delete unselected faces
# This is the only way I managed to limit the faces the script works on
bmesh.ops.delete(mesh, geom = [f for f in mesh.faces if not f.select], context = 'FACES')

# Triangulate mesh so that faces are triangles
bmesh.ops.triangulate(mesh, faces = mesh.faces, quad_method = 'BEAUTY', ngon_method = 'BEAUTY')

# Iterate through faces and get info
for face in mesh.faces:
    for vert in (0, 1, 2):
        print('coordinates:', face.verts[vert].co)
        print('uv:', face.loops[vert][mesh.loops.layers.uv[0]].uv)
        print('normal:', face.normal) # oops

You already might see some issues with this script. I probably could have used loops instead of faces, but I am not sure if loops always consist of three vertices. I probably could have used calc_loop_triangles but I gave up on it since I found bmesh.ops.triangulate. I also don't understand the difference between Mesh and BMesh and other types of primitives. They all seem the same yet the scripts I saw on the internet use them differently. Please let me know if there are better ways to code this.

Script works fine, but only when I have flat shading. I added oops comment where I use face normal, instead of vertex split normal. I would like this script to use split normal instead of face normal, since split normal is somewhat universal (changes accordingly in flat/smooth shading). I was not able to find a solution to this problem, because all scripts out there use loops or don't separate selected/unselected faces, or there was some other issue when I tried integrating it in my code.

I am a complete beginner to Blender python.


1 Answer 1


Below a commented code, using bpy.data api, that should correspond to all you asked:

import bpy
from mathutils import Vector

# get current object
o = bpy.context.object

# make a copy (as we'll change data below)
m = o.data.copy()

# calculate split normals
m.use_auto_smooth = True

# calculate triangles loop

# get triangles loop elements corresponding to the selected faces
l_triangles = [lt for lt in m.loop_triangles
    if m.polygons[lt.polygon_index].select]

# get active uv layer
uv_layer = m.uv_layers.active.uv

# loop over the triangles
for lt in l_triangles:
    # get the corresponding polygon and normal
    polygon_index = lt.polygon_index
    polygon = m.polygons[polygon_index]
    polygon_normal = polygon.normal
    # loop over vertices ranks
    for i in range(3):
        # get corresponding vertex index and normal
        vertex_index = lt.vertices[i]
        vertex_normal = Vector(lt.split_normals[i])
        # get uv coordinates
        uv_co = uv_layer[lt.loops[i]].vector
        # print results
        print(polygon_index, polygon_normal, vertex_index, vertex_normal, uv_co)

# delete the mesh copy        
  • $\begingroup$ Awesome! Works great for me, the only problem is that instead of vertices I get their index, do I use m.vertices[vertex_index].co to get the coordinates? $\endgroup$ Jan 14 at 23:39
  • 1
    $\begingroup$ yes, you can for instance do that. $\endgroup$
    – lemon
    Jan 15 at 6:36

You must log in to answer this question.

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