I've written a very basic script in Blender that builds a circular set of vertices then rotates and translates these to a rotated face in 3D space (see code below). This works well for any Z rotation however for X or Y rotations it's all over the place.
I know I'm missing a step somewhere but can't see it at the moment. So any help is much appreciated.
To run the code, there simply needs to be a cube in the scene.
The idea is that I build the circle of vertices at (0,0,0) then rotate these to the required face normal (I've chosen face 2 of the cube at random for now), then I translate the vertices to the face location. The main rotation function is at the bottom of the code (rotate_verts_towards_face(..))
NB. This is part of a larger project, so I've written this as a separate script as a demonstration only, so it's rough code.
(results of current code)
Face rotation at 0 degrees Z axis
Face rotation at 45 degrees Z axis
Face rotated at 45 degrees X axis
import bpy
import bmesh
import math
from mathutils import Vector
verts_norm = Vector((0, 0, 1))
verts_center = Vector((0, 0, 0))
# FACE BUILDING
def build_face_verts():
theta = 2 * math.pi / 12
dx = 0
dy = 0
dz = 0
verts = []
for i in range(12):
dx = 1 * math.sin(theta * i)
dy = 1 * math.cos(theta * i)
verts.append(Vector((dx, dy, dz)))
return verts
def update_bm_verts(bm):
bm.verts.index_update()
bm.verts.ensure_lookup_table()
def setup_new_obj(name, context):
obj_name = name
mesh = bpy.data.meshes.new("mesh")
obj = bpy.data.objects.new(obj_name, mesh)
context.scene.collection.objects.link(obj)
context.view_layer.objects.active = obj
obj.select_set(True)
mesh = context.object.data
bm = bmesh.new()
return obj, mesh, bm
def build_face(verts, context):
obj, mesh, bm = setup_new_obj("NEW_FACE", context)
for v in verts:
bm.verts.new(v)
update_bm_verts(bm)
bm.to_mesh(mesh)
bm.free()
# ROTATE AND TRANSLATE
def translate(pt, verts):
for v in verts:
v[0] += pt[0]
v[1] += pt[1]
v[2] += pt[2]
def rotate_verts_towards_face(verts, target, target_norm, target_loc):
mat_world = target.matrix_world
trans_verts = []
# transform face verts to target object space
trans_verts = [mat_world @ v for v in verts]
# build rotation matrix
mat = (
verts_norm.rotation_difference(target_norm).to_matrix().to_4x4()
)
return [mat @ v for v in trans_verts]
target_obj = bpy.data.objects["Cube"]
target_face_norm = target_obj.data.polygons[2].normal
mat_world = target_obj.matrix_world
target_face_norm = mat_world @ target_face_norm
target_location = target_obj.data.polygons[2].center
# rotate verts
r_verts = rotate_verts_towards_face(build_face_verts(), target_obj, target_face_norm, target_location)
# translate verts to face position
translate(target_face_norm, r_verts)
build_face(r_verts, bpy.context)