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

物理↔控制骨骼互相影响:
image

Wiggle Bone

https://github.com/shteeve3d/blender-wiggle-2

(此方法已弃用,当骨架有1000多跟骨骼时,比如rigify生成的人:human-metarig,耦合的骨骼,运算很慢)
复制需要物理模拟的控制骨,做2层一样的控制骨,在DEF的需要物理模拟的骨骼中加约束,影响:0.5
image

需要以下脚本来快速找到骨骼约束、被约束的关系:

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异常抖动

世界空间局部空间
image
成功!

批量删除选中的骨骼约束

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帧开始播放模拟

posted @ 2023-06-11 17:14  Nolca  阅读(496)  评论(0编辑  收藏  举报