Make bone roll match a face/vertex normal?

I am working on a script that generates bones down an edge or face loop. I have figured out how to create a bone and move its head and tail into position at the top and bottom of a face, or onto a specific vertex. The problem now is how to roll the bone so that it is flat on the face normal (or if on an edge loop, so that it based on the vertex normals.)

Is there some existing way to do this, or any existing addons/scripts that handle this problem? Or do I have to somehow derive the bone’s angle?

Construct the bone matrix

Here is a script that creates a bone at each edge such that the bones y axis is aligned vert 0 to vert 1 and the z axis to the "edge normal" ie the average of the two linked face normals.

Select mesh object in object mode, run script creates an armature with bone on each edge.

import bpy
import bmesh
from mathutils import Vector, Matrix
context = bpy.context
vl = context.view_layer
coll = context.collection
ob = context.object # the mesh
me = ob.data
bm = bmesh.new()
bm.from_mesh(me)
arm = bpy.data.armatures.new("Foo")
arm_obj = bpy.data.objects.new("Foo", arm)
vl.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT')

for e in bm.edges:
eb = arm.edit_bones.new(f"edge{e.index}")
v = e.verts[1].co - e.verts[0].co

y = v.normalized()
z = sum((f.normal for f in e.link_faces), Vector()).normalized()
x = y.cross(z)
M = Matrix((x, y, z)).transposed().to_4x4()
M.translation = e.verts[0].co
eb.matrix = M
eb.tail = e.verts[1].co

bpy.ops.object.mode_set()

• Yes, that looks like the right thing. By flat on the face normal, I meant that the bone has an axis perpendicular to the normal. I get the general idea of your script. Can you explain more how exactly it matches the roll to the normal? – Ascalon May 6 '20 at 22:00
• as explained here blender.stackexchange.com/a/176207/15543 make a 3x3 rotation matrix. Suppose I assume that edge vector and "edge normal" are perp. The face normals are normal to the two linked faces (assumed planes) that intersect at the edge.. If this is True then pretty much just making edit bone x y and z axis point where we want, which takes care of roll. – batFINGER May 6 '20 at 22:17