Real mesh plane instead of pseudo plane

This commit is contained in:
pullusb
2023-12-06 18:42:33 +01:00
parent 4c44ff96b3
commit a56a9ea537
3 changed files with 315 additions and 57 deletions
+73 -6
View File
@@ -9,6 +9,30 @@ from bpy_extras.object_utils import world_to_camera_view
from mathutils.geometry import (barycentric_transform, intersect_point_tri,
intersect_point_line, intersect_line_plane, tessellate_polygon)
## context manager to store restore
class attr_set():
'''Receive a list of tuple [(data_path, "attribute" [, wanted value)] ]
entering with-statement : Store existing values, assign wanted value (if any)
exiting with-statement: Restore values to their old values
'''
def __init__(self, attrib_list):
self.store = []
# item = (prop, attr, [new_val])
for item in attrib_list:
prop, attr = item[:2]
self.store.append( (prop, attr, getattr(prop, attr)) )
if len(item) >= 3:
setattr(prop, attr, item[2])
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
for prop, attr, old_val in self.store:
setattr(prop, attr, old_val)
# --- Vector
def triangle_normal(a, b, c):
@@ -67,17 +91,23 @@ def ray_cast_point(point, origin, depsgraph):
return object_hit, np.array(hit_location), tri, tri_indices
def plane_on_bone(bone, arm=None, cam=None, set_rotation=True):
def plane_on_bone(bone, arm=None, cam=None, set_rotation=True, mesh=True):
'''
bone (posebone): reference pose bone
arm (optional: Armature): Armature of the pose bone (if not passed found using bone.id_data)
cam (optional: Camera) : Camera to align plane to (if not passed use scene camera)
set_rotation (bool): rotate the plane on cam view axis according to bone direction in 2d cam space
mesh (bool): create a real mesh ans return it, else return list of plane coordinate
'''
if cam is None:
cam = bpy.context.scene.camera
if arm is None:
arm = bone.id_data
plane = plane_coords()
mat = cam.matrix_world.copy()
if set_rotation:
head_world_coord = arm.matrix_world @ bone.head
mat.translation = head_world_coord
@@ -85,7 +115,7 @@ def plane_on_bone(bone, arm=None, cam=None, set_rotation=True):
## Apply 2d bone rotation facing camera
# Get 2d camera space coords (NDC: normalized device coordinate, 0,0 is bottom-left)
head_2d, tail_2d = utils.get_bone_head_tail_2d(bone, cam=cam)
head_2d, tail_2d = get_bone_head_tail_2d(bone, cam=cam)
vec_from_corner_2d = (tail_2d - head_2d).normalized()
up_vec_2d = Vector((0,1))
# angle = acos(up_vec_2d.dot(vec_from_corner_2d)) ## equivalent but not signed!
@@ -98,15 +128,52 @@ def plane_on_bone(bone, arm=None, cam=None, set_rotation=True):
## Axis camera origin -> pivot
rot_axis = head_world_coord - cam.matrix_world.translation
mat = utils.rotate_matrix_around_pivot(mat, angle, head_world_coord, rot_axis)
mat = rotate_matrix_around_pivot(mat, angle, head_world_coord, rot_axis)
else:
## Use mid bone to better follow movement
mat.translation = arm.matrix_world @ ((bone.tail + bone.head) / 2) # Mid bone
mat_scale = Matrix.Scale(10, 4)
if mesh:
# get/create collection
col = bpy.data.collections.get('interpolation_tool')
if not col:
col = bpy.data.collections.new('interpolation_tool')
if col.name not in bpy.context.scene.collection.children:
bpy.context.scene.collection.children.link(col)
# get/create meshplane
plane = bpy.data.objects.get('interpolation_plane')
if not plane:
plane = create_plane(name='interpolation_plane')
if plane.name not in col.objects:
col.objects.link(plane)
plane.matrix_world = mat
return plane
plane = plane_coords()
mat_scale = Matrix.Scale(10, 4) # maybe move above mesh condition
return matrix_transform(plane, mat @ mat_scale)
def create_plane(name='Plane', collection=None):
'''Create a plane using pydata
collection: link in passed collection, else do not link in scene
'''
x = 1.0
y = 1.0
vert = [(-x, -y, 0.0), (x, -y, 0.0), (-x, y, 0.0), (x, y, 0.0)]
fac = [(0, 1, 3, 2)]
pl_data = bpy.data.meshes.new(name)
pl_data.from_pydata(vert, [], fac)
pl_obj = bpy.data.objects.new(name, pl_data)
# collection = bpy.context.collection
if collection:
collection.objects.link(pl_obj)
return pl_obj
def intersect_with_tesselated_plane(point, origin, face_co):
'''
face_co: World face coordinates