blender 使用物理骨骼,受物理影响+不影响主观能动性的"物理妥协骨骼" 插件:wiggle bone / rigid bone
类型上: Mesh网格 ≠ Bone骨骼
骨骼物理
代理骨骼(纯物理模拟) + 驱动器
优点:方便解耦,运算速度快
缺点:碰撞箱得再做一个代理,否则碰撞体积不准确;
应用场景:全身都得进入物理模拟
思路:RIG摆姿势骨(非控制骨)→姿态同步到phy骨架→phy原旋转加上物理模拟的后旋转→映射回RIG控制骨
前提:骨骼位置先对齐,2个骨架对应的骨骼命名一致
可调参数q=False
,此时使用Eular_XYZ运算
import bpy
q=True
#act=bpy.context.selected_pose_bones_from_active_object
act=bpy.data.objects['phy.001'].pose.bones
src_obj=bpy.data.objects['C']
src=src_obj.pose.bones
mode_str='quaternion' if q else 'euler'
rot_str='QUATERNION' if q else 'XYZ'
# QUATERNION XYZ AXIS_ANGLE
axis='xyzw'
for bone in src:
bone.rotation_mode=rot_str
for abone in act:
abone.rotation_mode=rot_str
# QUATERNION XYZ AXIS_ANGLE
abone.driver_remove('rotation_'+mode_str)
# continue
len=4 if q else 3
dri = [abone.driver_add('rotation_'+mode_str, i) for i in range(len)]
i=3 if q else 0
for dr_ in dri:
dr=dr_.driver
try:
transf=dr.variables['Transform']
except:
transf = dr.variables.new()
transf.name = 'Transform'
transf.type = 'TRANSFORMS'
target = transf.targets[0]
target.id=src_obj
target.rotation_mode=rot_str.upper()
target.bone_target = abone.name
target.transform_type = 'ROT_'+axis[i].upper()
target.transform_space='WORLD_SPACE'
# WORLD_SPACE LOCAL_SPACE TRANSFORM_SPACE
dr.use_self=True
if (i!=3):
dr.expression = "(self.rotation_"+mode_str+'.'+axis[i]+"+Transform)/2"
else:
dr.expression = "Transform"
# dr.expression = "copysign(1,Transform)*max(abs(Transform),0.1)"
# It's hard to solve the sign change while crossing the axis, which cause the bone position suddenly changes
i=(i+1)%4
# https://docs.blender.org/api/3.5/bpy.types.DriverTarget.html#bpy.types.DriverTarget.transform_space
代理骨骼+约束器(约束控制骨骼)
已弃用此方法,因为wiggleBone(可能)先于约束器进行运算,导致超过3条链,Mix使用“相加”数值则会太过了,导致不正确的旋转
需要以下bpy脚本,批量添加约束,其中phy是纯粹的物理模拟用的骨骼(可以从metarig复制)
import bpy
cpName='phy'
cp_obj=bpy.data.objects[cpName]
cp_bones=bpy.data.objects[cpName].pose.bones
print(cp_bones)
selected_bones = [bone for bone in bpy.context.selected_pose_bones]
for bone in selected_bones:
# for con in bone.constraints:
print('bc',bone.constraints)
if not bone.constraints:
bone.constraints.new('COPY_ROTATION')
print('YES')
ctmp=bone.constraints["Copy Rotation"]
print('ctmp',ctmp)
ctmp.target = cp_obj
ctmp.subtarget = bone.name
ctmp.target_space="LOCAL"
ctmp.owner_space='LOCAL'
ctmp.influence=0.333
# pose.bones["b_6_0"].constraints["Copy Rotation"].influence
物理↔控制骨骼互相影响:
Wiggle Bone
https://github.com/shteeve3d/blender-wiggle-2
(此方法已弃用,当骨架有1000多跟骨骼时,比如rigify生成的人:human-metarig,耦合的骨骼,运算很慢)
复制需要物理模拟的控制骨,做2层一样的控制骨,在DEF的需要物理模拟的骨骼中加约束,影响:0.5
需要以下脚本来快速找到骨骼约束、被约束的关系:
import bpy
ob = bpy.context.selected_objects[0]
pose = ob.pose
for bonename in pose.bones.keys():
bone = pose.bones[bonename]
for const in bone.constraints:
try:
print(bone.name, '->'+const.subtarget,sep='\t')
except:
pass
解决wiggle异常抖动
把世界空间
改局部空间
成功!
批量删除选中的骨骼约束
import bpy
selected_bones = [bone for bone in bpy.context.selected_pose_bones]
for bone in selected_bones:
for con in bone.constraints:
bone.constraints.remove(con)
bone dynamics + simpliCage代理网格做布料碰撞
没有wiggle bone那么卡,当然没有弹簧特性
https://www.bilibili.com/video/BV1Ye411G74K
rigid bone
https://github.com/Pauan/blender-rigid-body-bones
ps: wiggleBone仅影响旋转
要位移的用rigid bone,但碰撞不好调,容易鬼畜
网格物理+钉固顶点组(不建议)
被钉固的网格顶点,会被上一个修改器修改
布料模拟最蛋疼的地方就是,每次都得从第0帧开始播放模拟