McManning / Coherence

Blender viewport renderer using the Unity Engine
MIT License
30 stars 0 forks source link

Add support for Blender instancing #31

Closed McManning closed 3 years ago

McManning commented 3 years ago

See: https://blender.stackexchange.com/a/127507

The tl;dr - objects can share the same mesh data. Editing one obviously edits them all. When this transfers to Unity it doesn't account for this so it transfers a copy per instance - which then also does the same calculations/optimizations per instance when one changes.

Some major issues to tackle:

McManning commented 3 years ago

A good real world use case - the mech sample .blend file that I want to use for demoing is using instanced parts for kitbashing the mech:

image

McManning commented 3 years ago

Looks to be working last night. Had some issues with modifier stacks being applied to all instances incorrectly when I was extracting mesh data from the depsgraph - resolved it with the following (for reference in case I need to figure out why I did this):


import bpy

def on_depsgraph_update(scene, depsgraph):
    for update in depsgraph.updates:
        if type(update.id) == bpy.types.Object and update.id.type == 'MESH':
            obj = bpy.data.objects.get(update.id.name)

            if update.is_updated_geometry:
                eval_obj = obj.evaluated_get(depsgraph)
-               mesh = eval_obj.to_mesh()
+               mesh = eval_obj.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph)

                print('obj={}, mesh={}, modifiers: {}, vertex count: {}'.format(
                    obj.name, 
                    mesh.name, 
                    len(obj.modifiers), 
                    len(mesh.vertices)
                ))

                eval_obj.to_mesh_clear()

bpy.app.handlers.depsgraph_update_post.append(on_depsgraph_update)

If you don't provide preserve_all_layers and the depsgraph to the to_mesh operation, it seems to pull the last evaluated mesh. So if we evaluated one instance that had modifiers and then another that didn't - the one that didn't will still give us the copy with modifiers applied.

One concern I have is about performance though - really don't need to do this extra work/copying if the mesh has no modifiers applied and isn't instanced. Might be able to skip this step for a number of meshes to squeeze a bit more performance out of it. Esentially

McManning commented 3 years ago

Some additional notes on this:

It's been implemented for standard object.type = MESH objects, but not for anything else that is "meshable" (FONT/CURVE/SURFACE). I'm leaving those as just mesh-per-copy for now but it does look like you can create instances of a font, and maybe the others as well.