135 lines
5.0 KiB
Python
135 lines
5.0 KiB
Python
import blender_node
|
|
|
|
|
|
class Mesh_ModifyShapeKey(blender_node.ObjectOps):
|
|
|
|
CUSTOM_NAME = "Modify Shape Key"
|
|
|
|
EXTRA_INPUT_TYPES = {
|
|
"shape_key_name": ("STRING", {
|
|
# True if you want the field to look like the one on the ClipTextEncode node
|
|
"multiline": False,
|
|
"default": "EyeBlinkLeft", # default value
|
|
}),
|
|
"target_vertex_group": ("STRING", {
|
|
"multiline": False,
|
|
"default": ""
|
|
}),
|
|
"scale_x": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01, "display": "number"}),
|
|
"scale_y": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01, "display": "number"}),
|
|
"offset_x": ("FLOAT", {"default": 0.0, "min": -10.0, "max": 10.0, "step": 0.01, "display": "number"}),
|
|
"offset_y": ("FLOAT", {"default": 0.0, "min": -10.0, "max": 10.0, "step": 0.01, "display": "number"}),
|
|
|
|
"rotate": ("FLOAT", {"default": 0, "min": -360, "max": 360.0, "step": 0.01, "display": "number"}),
|
|
|
|
"origin_offset_x": ("FLOAT", {"default": 0, "min": -10.0, "max": 10.0, "step": 0.01, "display": "number"}),
|
|
"origin_offset_y": ("FLOAT", {"default": 0, "min": -10.0, "max": 10.0, "step": 0.01, "display": "number"}),
|
|
|
|
"transform_radius": ("FLOAT", {"default": 1.0, "min": 0, "max": 1, "step": 0.01, "display": "number"}),
|
|
"falloff": ("FLOAT", {"default": 0, "min": -10.0, "max": 10.0, "step": 0.01, "display": "number"}),
|
|
}
|
|
|
|
def blender_process(self, bpy, BPY_OBJ, shape_key_name, target_vertex_group, scale_x, scale_y, offset_x, offset_y, rotate, origin_offset_x, origin_offset_y, transform_radius, falloff):
|
|
from mathutils import Vector, Matrix
|
|
import math
|
|
|
|
obj = BPY_OBJ
|
|
|
|
# Create new shape key if its not in the object
|
|
if shape_key_name not in BPY_OBJ.data.shape_keys.key_blocks:
|
|
BPY_OBJ.shape_key_add(name=shape_key_name, from_mix=True)
|
|
|
|
# get shape key
|
|
sk = obj.data.shape_keys.key_blocks[shape_key_name]
|
|
# print(obj, sk)
|
|
# sk.interpolation = 'KEY_LINEAR'
|
|
|
|
|
|
|
|
verts = obj.data.vertices
|
|
|
|
# Create a new array of verts with sk as co and verts' groups
|
|
new_verts = []
|
|
for i, vert in enumerate(verts):
|
|
# print(i)
|
|
# print(sk.data[i].co)
|
|
new_vert = {
|
|
'co': sk.data[i].co,
|
|
'groups': vert.groups
|
|
}
|
|
new_verts.append(new_vert)
|
|
verts = new_verts
|
|
|
|
# get vertex group
|
|
|
|
# get the verts in the group
|
|
|
|
if target_vertex_group == '':
|
|
verts_in_group = verts
|
|
else:
|
|
vertex_group = obj.vertex_groups[target_vertex_group]
|
|
verts_in_group = [v for v in verts if vertex_group.index in [
|
|
vg.group for vg in v['groups']]]
|
|
|
|
center = sum((vert['co'] for vert in verts_in_group),
|
|
Vector()) / len(verts_in_group)
|
|
|
|
# apply origin offset
|
|
center.x += origin_offset_x
|
|
center.y += origin_offset_y
|
|
|
|
# Calculate max distance from center to any vertex in the group
|
|
max_distance = max(
|
|
(vert['co'] - center).length for vert in verts_in_group)
|
|
|
|
# Position each vert
|
|
for i, vert in enumerate(verts):
|
|
# return if vert is not in group
|
|
if target_vertex_group != '' and vertex_group.index not in [vg.group for vg in vert['groups']]:
|
|
continue
|
|
# Get vector from center to vertex
|
|
vec = vert['co'] - center
|
|
|
|
# Calculate distance from origin and weight factor
|
|
distance = vec.length
|
|
# weight = max(0, 1 - distance / (max_distance * transform_radius))
|
|
|
|
# if the vertex is outside the transform radius, skip it
|
|
if (distance / max_distance) > transform_radius:
|
|
continue
|
|
|
|
# calculate weight
|
|
weight = max(0, 1 - distance /
|
|
(transform_radius * max_distance)) * falloff
|
|
weight = min(weight, 1)
|
|
|
|
# print(scale_x, scale_y, weight)
|
|
|
|
# Scale vector
|
|
vec.x *= scale_x + (abs(scale_x - 1) * weight)
|
|
vec.y *= scale_y + (abs(scale_y - 1) * weight)
|
|
|
|
# # Offset vector
|
|
vec.x += offset_x + (abs(scale_x - 1) * weight)
|
|
vec.y += offset_y + (abs(scale_y - 1) * weight)
|
|
|
|
# Rotate vector
|
|
# rotate_right_rad = math.radians(rotate_right)
|
|
rotate_rad = math.radians(rotate)
|
|
|
|
# Create rotation matrices for the right and left rotations
|
|
# rotation_matrix_right = Matrix.Rotation(rotate_right_rad, 4, 'X')
|
|
rotation_matrix = Matrix.Rotation(rotate_rad, 4, 'Z')
|
|
|
|
# Apply the rotation matrices to the vector
|
|
# vec.rotate(rotation_matrix_right)
|
|
vec.rotate(rotation_matrix)
|
|
|
|
# Calculate new position
|
|
new_pos = center + vec
|
|
|
|
# Apply new position
|
|
# print(i, vert['co'], new_pos, weight)
|
|
|
|
sk.data[i].co = new_pos
|