Closed One-sixth closed 1 year ago
Thanks for fixing the bugs 😃 Please check the #73 pull request.
I looked into "rigidbody data loss" and found that the problem is in Blender itself. The following steps also reproduce the problem:
After this, "joint data" also becomes unstable.
I have considered radical fixes, but without fixing Blender itself it is difficult to fix this problem.
@UuuNyaa I checked the code and thought it was okay. About the joint data unstable. I found that just clicking the Update World button then works fine again. This is because after rebuilding the physics, the new RigidBodyConstraints.XXX collection only contains ncc joints. If we check and add origin joints to the new RigidBodyConstraints.XXX collection, we can avoid using Update Wolrd. Or, maybe we can reuse the old RigidBodyWorld and RigidBodyConstraints collection. Because they have the fake_user flag, they are not automatically deleted.
@One-sixth Thank you for your review.
I fixed mmd_tools.rigid_body_world_update operator to add rigid body objects to the new rigid body world collection. Now we can rebuild the physics with the following steps:
@UuuNyaa Thanks to your efforts, I found one thing that could be improved.
I made some improvements that will automatically rebuild the physics.
Due to a bug in Blender, the first play after rebuild physics will crash. Save it before, Then open new Blender and load it again. Then play it and seem work fine.
class UpdateRigidBodyWorld(Operator):
bl_idname = 'mmd_tools.rigid_body_world_update'
bl_label = 'Update Rigid Body World'
bl_description = 'Update rigid body world and references of rigid body constraint according to current scene objects (experimental)'
bl_options = {'REGISTER', 'UNDO'}
@staticmethod
def __get_rigid_body_world_objects():
rigid_body.setRigidBodyWorldEnabled(True)
rbw = bpy.context.scene.rigidbody_world
if bpy.app.version < (2, 80, 0):
if not rbw.group:
rbw.group = bpy.data.groups.new('RigidBodyWorld')
rbw.group.use_fake_user = True
if not rbw.constraints:
rbw.constraints = bpy.data.groups.new('RigidBodyConstraints')
rbw.constraints.use_fake_user = True
return rbw.group.objects, rbw.constraints.objects
if not rbw.collection:
rbw.collection = bpy.data.collections.new('RigidBodyWorld')
rbw.collection.use_fake_user = True
if not rbw.constraints:
rbw.constraints = bpy.data.collections.new('RigidBodyConstraints')
rbw.constraints.use_fake_user = True
if hasattr(bpy.context.scene.rigidbody_world, 'substeps_per_frame'):
bpy.context.scene.rigidbody_world.substeps_per_frame = 1
bpy.context.scene.rigidbody_world.solver_iterations = 60
return rbw.collection.objects, rbw.constraints.objects
def execute(self, context):
scene_objs = set(context.scene.objects)
scene_objs.union(o for x in context.scene.objects if x.instance_type == 'COLLECTION' and x.instance_collection for o in x.instance_collection.objects)
def _update_group(obj, group):
if obj in scene_objs:
if obj not in group.values():
group.link(obj)
return True
elif obj in group.values():
group.unlink(obj)
return False
def _references(obj):
yield obj
if getattr(obj, 'proxy', None):
yield from _references(obj.proxy)
if getattr(obj, 'override_library', None):
yield from _references(obj.override_library.reference)
_find_root = mmd_model.FnModel.find_root
need_rebuild_physics = bpy.context.scene.rigidbody_world is None or bpy.context.scene.rigidbody_world.collection is None or bpy.context.scene.rigidbody_world.constraints is None
rb_objs, rbc_objs = self.__get_rigid_body_world_objects()
objects = bpy.data.objects
table = {}
# Perhaps due to a bug in Blender,
# when bpy.ops.rigidbody.world_remove(),
# Object.rigid_body are removed,
# but Object.rigid_body_constraint are retained.
# Therefore, it must be checked with Object.mmd_type.
for i in (x for x in objects if x.mmd_type == 'RIGID_BODY'):
if not _update_group(i, rb_objs):
continue
rb_map = table.setdefault(_find_root(i), {})
if i in rb_map: # means rb_map[i] will replace i
rb_objs.unlink(i)
continue
for r in _references(i):
rb_map[r] = i
# TODO Modify mmd_rigid to allow recovery of the remaining rigidbody parameters.
# mass, friction, restitution, linear_dumping, angular_dumping
for i in (x for x in objects if x.rigid_body_constraint):
if not _update_group(i, rbc_objs):
continue
rbc, root = i.rigid_body_constraint, _find_root(i)
rb_map = table.get(root, {})
rbc.object1 = rb_map.get(rbc.object1, rbc.object1)
rbc.object2 = rb_map.get(rbc.object2, rbc.object2)
if need_rebuild_physics:
for root in bpy.context.scene.objects:
if root.mmd_type != 'ROOT':
continue
if root.mmd_root.is_built:
from ..bpyutils import activate_layer_collection
with activate_layer_collection(root):
rig = mmd_model.Model(root)
# rig.clean()
rig.build(1.5, 1e-6)
# After rebuild. irst play. Will be crash! But saved it before. Reload after crash. The play can be work.
return { 'FINISHED' }
I opened a blender bug report about rigidbody setting lost. https://developer.blender.org/T101656 From the response, not sure it can be fixed.
@One-sixth I adopted your code snippet. Indeed, in this situation, blender crashes when rebuilding the physics.
I opened a blender bug report about rigidbody setting lost. https://developer.blender.org/T101656 From the response, not sure it can be fixed.
Umm..., there seems to be no rigid body physics area maintainer. The Blender's current physics system would be replaced by a new Nodes & Physics system.
@UuuNyaa I reviewed the code. I think there is no problem. For new physical systems. I think it may take a long time. It's too far away. For the crash problem, I think they may fix it faster, because Blender 3.3 also has a physical update. I also submitted a bug report. https://developer.blender.org/T101681
@One-sixth Thank you for your review. It was released as v2.7.0 🎉
For new physical systems. I think it may take a long time. It's too far away.
I agree with you.
For the crash problem, I think they may fix it faster, because Blender 3.3 also has a physical update.
OK, let's hope the problems are solved.
Great !
Hello, I found 3 new issue. My fix code you can found here. https://github.com/One-sixth/blender_mmd_tools/commit/aa4ae05295d8e61444028d63a8491522a2ad0fb0#diff-8b0a509ad46738648aa4ee1d9579ee6f59712a9b965f1da7c75c23780bbbe75a
bone morph exception and _getVisibilityOfMMDRigArmature exception. Open the link.blend file and you will see two exceptions in the console.
rigidbody data loss after rigidbody_world_remove. Open the ori.blend. Build model physics. Update world. Play 5 frame. Remove the physical environment by bpy.ops.rigidbody.world_remove().![d3](https://user-images.githubusercontent.com/23693633/193462027-d9d300d7-b5eb-4aa0-a18b-5059e1f913c0.png)
Select any MMD rigidbody, you can see the rigidbody object has disappeared.
![d2](https://user-images.githubusercontent.com/23693633/193461991-97dd7fea-875e-43b6-a307-be661c41eda1.png)
This is the test file. 奥托2.zip