1
$\begingroup$

I'm trying to obtain the selected face vertex locations for an animated Object as x,y co-ordinates relative to f.calc_center_median() as the origin center [0,0] (assuming a planar face). The way I've approached it at the moment is by moving the origin point to the face center and rotating according to the face, but I'm running into a number of issues...

  1. The vertex locations are still coming through as local, even when multiplied with the matrix world?
  2. Non-uniform scale messes up the face rotation matrix (tried to avoid this by applying the bmesh but that also messes the rotation matrix)
  3. For an 'even edged' face (eg. a cube face) I can't work out how to avoid the x,y rotation from flipping randomly over the duration of the animation?

Any suggestions on fixes, or alternative ways to approach this? This is what I have so far (in the final function I don't want the object to actually move, just moving for testing)...

import bpy
import bmesh
import mathutils

ob = bpy.context.edit_object
frame_start = bpy.context.scene.frame_start
frame_end = bpy.context.scene.frame_end
ob_faces = {} 

for fr in range(frame_start,frame_end):
    bpy.context.scene.frame_set(fr)

    mw = ob.matrix_world
    me = ob.data
    bm = bmesh.new()
    dg = bpy.context.evaluated_depsgraph_get()
    bm.from_object(ob, dg)
    bm.transform(mw)
    bm.normal_update()
    # bm = bmesh.from_edit_mesh(me)

    selverts = [v.co for v in bm.verts if v.select]
    if len(selverts):
        pt = sum(selverts, mathutils.Vector()) / len(selverts)
        #T = Matrix.Translation(-pt)
        bmesh.ops.translate(bm, vec=-pt, verts=bm.verts)
        # mw.translation = mw @ pt
        mw.translation = [0,0,0]

    for f in bm.faces:
        if not f.select:
            continue

        n = f.normal
        t = f.calc_tangent_edge_pair().normalized()
        bt = n.cross(t).normalized()
        M = mathutils.Matrix([t, bt, n]).transposed().to_4x4()
        M.translation = f.calc_center_median()

        ob.rotation_euler = M.inverted().to_euler()
        bmesh.update_edit_mesh(me)

        new_w = ob.matrix_world

        for v in f.verts:
            key = "face_" + str(f.index)
            print (mw @ v.co)
            ob_faces[key] = ob_faces.get(key, []) + [new_w @ v.co]
            # ob_faces[key].append(mw @ v.co)

print("\n", ob_faces)
$\endgroup$
6
  • $\begingroup$ Related blender.stackexchange.com/a/203355/15543 $\endgroup$
    – batFINGER
    Sep 17, 2021 at 19:22
  • $\begingroup$ Thanks, I’m studying through it… when you create the matrix using rotation_difference(up) is that essentially the 2D projection point… setting the face back to flat with normal (0,0,1)? $\endgroup$
    – Dan
    Sep 18, 2021 at 0:51
  • $\begingroup$ @batFINGER (meant to tag you in that previous comment)... I've been thinking through it more and will do some testing. I think I understand now that the applying the rotation_difference when creating the matrix basically resets the rotation. $\endgroup$
    – Dan
    Sep 20, 2021 at 0:15
  • $\begingroup$ Mapping to a space where tri lies in the $XY$ plane, where the normal is $Z$ axis $\endgroup$
    – batFINGER
    Sep 20, 2021 at 10:15
  • $\begingroup$ Feel this is going a bit XY Problem Added an answer to one of your prior questions re using the instancer to get a "consistently" calculated face normal. $\endgroup$
    – batFINGER
    Sep 25, 2021 at 6:04

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.