shteeve3d / blender-wiggle-2

Rewrite of blender-wiggle with new features and physics
GNU General Public License v3.0
585 stars 32 forks source link

Collision does not take wiggle of colliders attached to other wiggle bones into account #51

Open DrakeGator opened 6 months ago

DrakeGator commented 6 months ago

Blender version: 4.0.2

I'm making some wiggly cartoony antennae and I want the bompers on the end to collide with each other.

It seems like the collision implementation doesn't take other bones' wiggles into account, so the bompers collide with a "ghost" of the other mesh, which is where it would be if it weren't wiggling. I added a debug print after this line:

print(b.name + " colliding with " + co.name)

and it prints this to the system console:

Antenna.R.002 colliding with Bomper.L
Antenna.R.002 colliding with Bomper.L
Antenna.R.002 colliding with Bomper.L
Antenna.L.002 colliding with Bomper.R
Antenna.L.002 colliding with Bomper.R
Antenna.L.002 colliding with Bomper.R
Antenna.L.002 colliding with Bomper.R
Antenna.L.002 colliding with Bomper.R
Antenna.L.002 colliding with Bomper.R
Antenna.L.002 colliding with Bomper.R
Antenna.L.002 colliding with Bomper.R

so they really are colliding with the meshes.

I'm not new to programming but new to the blender API so I'm unsure if this is an issue of unpredictable physics update ordering or if this is a shortcoming of the addon code.

Small blend file demonstrating the issue: https://blendswap.com/blend/31356

also I know you're deep in production right now but I also wanted to thank you for making such a great addon!

DrakeGator commented 6 months ago

I tried figuring out how to do it, and I think I did? The idea is that you check if the collider's parent is a wiggle bone, and if so, apply its wiggle matrix and use that as the collider's world matrix instead:

def collider_matrix_world(collider):
    cmw = collider.matrix_world

    if collider.parent and collider.parent.type == 'ARMATURE' and collider.parent_bone:
        parent_bone = collider.parent.pose.bones.get(collider.parent_bone)

        if not parent_bone.wiggle_mute and (parent_bone.wiggle_head or parent_bone.wiggle_tail):
            parent_bone_mw = collider.parent.matrix_world @ parent_bone.matrix
            cmw = parent_bone.wiggle.matrix @ relative_matrix(parent_bone_mw, collider.matrix_world)

    return cmw

Then in the for collider in colliders loop, instead of doing cmw = collider.matrix_world, you do cmw = collider_matrix_world(collider), and similarly in the if co you do collision_point = collider_matrix_world(co) @ cp.

And it works.

I doubt that this is the "right" way to check for the parent bone being a wiggle bone, but if you could let me know if it is (or what the right way is), I could make a PR.