Real mesh plane instead of pseudo plane
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user