Page MenuHome

since the recent depsgraph changes, applying array mods using new_from_object() clears vertex groups
Closed, ResolvedPublic

Description

System Information
Operating system: Linux-4.13.10-041310-generic-x86_64-with-debian-stretch-sid 64 Bits
Graphics card: GeForce GTX 1050/PCIe/SSE2 NVIDIA Corporation 4.5.0 NVIDIA 390.67

Blender Version
Broken: version: 2.80 (sub 69), branch: blender2.7, commit date: 2019-05-17 21:54, hash: rB3b8ae2c08f5c
Worked: before depsgraph changes

Short description of error
Applying an array mod using bpy.data.meshes.new_from_object() will clear vertex groups. The groups still exist but no vertices are assigned.
This happens for arrays with and without caps.
In previous versions, you could set up vertex groups on the main object and the caps, and after applying the mod, the vertex groups would still work as expected on the flattened object.
Applying the modifer from the modifier panel works as expected.

video demo

I think this is one for @Sergey Sharybin (sergey) again.

Exact steps for others to reproduce the error

  • load the blend file above
  • apply mod from the modifier panel and check the vertex group on the result
  • reload and apply the mod via the script, the vertex group is now empty

Details

Event Timeline

Sergey Sharybin (sergey) triaged this task as Normal priority.

The new_from_object() creates mesh from current state of the object, which matches corresponding dependency graph. This state does not include vertex groups because they are not needed by object itself or by any other object referencing it (ignoring vertex group in such cases gives ab big memory saving).
Old behavior of this function was re-evaluating modifier stack of the particular object and forced vertex groups to be included. However, this wasn't reliable either because object modifier stack might depend on vertex groups of another object.

The only reliable way would be to force the entire dependency graph to be evaluated in a way which forces vertex groups to be preserved for the entire dependency hierarchy. This isn't currently possible and could be quite tricky to do.

What is the exact goal you're trying to achieve here? What's the use-case?

MACHIN3 (MACHIN3) added a comment.EditedMay 20 2019, 12:54 PM

My use case is this:
I setup a modular object using 1 base object with one array mods, and 2 cap objects. I prepare the base object and the caps with vertex groups and I want the vertex groups to be merged on the evaluated mesh.
This works perfectly when using the Apply button in the modifier panel, but not using bpy.data.meshes.new_from_object()
To be more specific, here's is how I use this: https://youtu.be/NyZfF8HtTUU?t=669. I use the vertex group to mark specific faces, which need their normals to be adjusted, among other things, after the mods have been applied and the object is joined with another one and integrated into the surface.

If this can't be done anymore, I'll need to use a temporary material, instead of vertex groups. This would only work, because my vertex groups tend to cover faces, however. And so wouldn't work if I only wanted to mark vertices.

However, this wasn't reliable either because object modifier stack might depend on vertex groups of another object.

I think I ran into this with '2d-array plugs'. There are multiple array mods here, 2 on the base object, and 1 each cap or the first array mod on the base. I manged to make it work properly by applying the mods in proper order, caps first.

@Sergey Sharybin (sergey) I have a similar problem with Tissue add-on. In my case I was using a different method, but the issue is the same:
https://devtalk.blender.org/t/ob-to-mesh-problems-with-api-changes/7391/7

What I need to do is to use weight informations in order to affect the tessellation behavior. See example in the old version of blender:
https://youtu.be/XYbD9KaLT3Y?t=671

In order to keep a non-destructive workflow is crucial to have the possibility to keep all modifiers without applying them. As alternative, in the code I can still make a copy of the object and apply all modifiers to it, but in this case I need to change several parts of the code. Just let me know if this is the only possibility.

Thank you for your work!
Alessandro

thinking at a possible turnaround, I've tried this:

import bpy

def convert_object_to_mesh(ob, preserve_status=True):
    if preserve_status:
        # store status
        mode = bpy.context.object.mode
        selected = bpy.context.selected_objects
        active = bpy.context.object
    # change status
    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.select_all(action='DESELECT')
    bpy.context.view_layer.objects.active = ob
    ob.select_set(True)
    # duplicate and convert
    bpy.ops.object.duplicate_move()
    bpy.ops.object.convert(target='MESH')
    new_ob = bpy.context.object
    if preserve_status:
        # restore status
        bpy.ops.object.select_all(action='DESELECT')
        for o in selected: o.select_set(True)
        bpy.context.view_layer.objects.active = active
        bpy.ops.object.mode_set(mode=mode)
    return new_ob
    
ob = bpy.data.objects['Cube']
ob1 = convert_object_to_mesh(ob,True)

Should I convert my add-on using that function or there is a better way to do that?
Thank you

Alessandro

Sergey Sharybin (sergey) closed this task as Resolved.May 27 2019, 11:18 AM

Committed extra changes to API which allows preserving all data layers in rB5dbda3346234.

Unfortunately, i forgot to update commit message and it still states pre-code-review version of argument. The proper name is preserve_all_data_layers.

The script is to be updated in the following way:

active.data = bpy.data.meshes.new_from_object(active.evaluated_get(dg), preserve_all_data_layers=True, depsgraph=dg)

After this weight groups and vertex colors are preserved.

Thanks for the report, closing now.

This comment was removed by Tom Wilson (hedgehog90).

@Tom Wilson (hedgehog90), while the commit message is not mentioning this, but same thing dopes exist for object .to_mesh() as well.

Now the materials of the mesh aren't carried over:
https://developer.blender.org/T65238

active.data = bpy.data.meshes.new_from_object(active.evaluated_get(dg), preserve_all_data_layers=True, depsgraph=dg)

Sorry for the delay, just wanted to confirm, that this is working now. Thanks @Sergey Sharybin (sergey)!