4
$\begingroup$

I have a mesh completely generated using geometry nodes.

I want to assign the vertices procedurally to a vertex group and use it in the armature deform modifier. Is it possible?

I tried to use named attributes but it doesn't work with the armature.

enter image description here

EDIT: My goal is to generate complex meshes with vertices, UV mapping, and armature deformation using only geometry nodes.

$\endgroup$
5
  • $\begingroup$ I think the answer is no. May I recommend to read these posts : get Vertex Group to survive Geometry Nodes and Transfer (float) vertex-attribute to vertex-weight, to allow GeoNodes to control subsequent Armature binding ? $\endgroup$ Commented May 30 at 10:57
  • $\begingroup$ Hello, user111.. Nothing personal, but this does look as if it's very probably a duplicate question. I hope the links provided in the comments, here, give you the answer you're looking for. If they don't, go ahead and edit your question explaining why not, and we'll be happy to re-open it. $\endgroup$
    – Robin Betts
    Commented May 30 at 16:09
  • $\begingroup$ Hi @RobinBetts, I have already read that solution. While it does fix the problem, it is a workaround that cannot always be used. $\endgroup$
    – aarcangeli
    Commented May 30 at 23:14
  • 1
    $\begingroup$ At this point, I think adding, removing, and editing vertex groups is not yet possible using geometry nodes. $\endgroup$
    – aarcangeli
    Commented May 30 at 23:16
  • 1
    $\begingroup$ Hello. @aarcangeli, I've re-opened in response to your edit. As I think you have concluded yourself (?) .. I'm afraid it is unlikely there can be an answer that's an improvement on those linked here at this stage in Blender's evolution. (As a personal opinion, I believe, in the long run, there should be no need for the separate category: 'Vertex Group', and that all modifiers, including 'Armature', will act on integrated Attributes. ... but hat's a long haul.) If your question is turning out to be fruitless, in the light of the other answers, it may be better closed. Let us know. $\endgroup$
    – Robin Betts
    Commented May 31 at 6:30

3 Answers 3

1
$\begingroup$

EDIT: I thought you meant control a vertex group. If you mean create/name them via geometry nodes. Then unfortunately no :/

Yes you can actually. The vertex group just needs to be the same name as the attribute.

enter image description here

enter image description here

If we go into weight paint mode we can see our weights are indeed there

enter image description here

If we set that group in our armature

enter image description here

We can see they are properly deformed by our armature

enter image description here

$\endgroup$
1
  • $\begingroup$ Unfortunately, this method only works if the geometry is not procedural. If you cut the link with the input group and replace it with a procedural node like "Cube" you will notice that the vertex group is deleted. $\endgroup$
    – aarcangeli
    Commented May 31 at 15:57
1
$\begingroup$

I found a workaround that works for me.

I wrote a Python script that generates a new mesh object "SK_Cubes" by copying the final transformed mesh from the object "Cube" and individually applying the attributes.

The first time the operation is executed, it will create a copy of the selected object with the prefix "SK_". If the object has already been created it will simply update it.

The cloned object may have the armature modifier.

import bpy
import bmesh
from bpy.types import (
    Panel,
    PropertyGroup,
)
from bpy.props import (
    PointerProperty,
    StringProperty,
)


def create_object(src, name):
    """ Create a new mesh object with the specified name, and link to the same collections of src object """

    mesh = bpy.data.meshes.new(f"{name}_mesh")
    obj = bpy.data.objects.new(name, mesh)
    obj.location = src.location
    obj.rotation_euler = src.rotation_euler
    obj.scale = src.scale

    for col in src.users_collection:
        col.objects.link(obj)

    return obj


def find_or_create_object(src):
    object_prefix = bpy.context.scene.vgutils_props.object_prefix
    target_name = f"{object_prefix}{src.name}"
    if target_name in bpy.data.objects:
        return bpy.data.objects[target_name]
    else:
        return create_object(src, target_name)


def transfer_evaluated_mesh(src, dest):
    print(f"Transfer mesh from {src.name} to {dest.name}")
    group_prefix = bpy.context.scene.vgutils_props.group_prefix

    # Generate a bmesh from the final transformed mesh
    bm = bmesh.new()
    bm.from_object(src, bpy.context.evaluated_depsgraph_get())
    bm.verts.ensure_lookup_table()

    bm.to_mesh(dest.data)

    # All attribute that starts with "b_" are converted to vertex group in the new mesh
    for attr_name, group in bm.verts.layers.float.items():
        if not attr_name.startswith(group_prefix):
            continue

        group_name = attr_name[len(group_prefix):]

        print(f"  - Copy group {attr_name} to {group_name}")
        if group_name not in dest.vertex_groups:
            target_group = dest.vertex_groups.new(name=group_name)
        else:
            target_group = dest.vertex_groups[group_name]

        for v in bm.verts:
            value = v[group]
            if value > 0:
                target_group.add((v.index,), value, 'REPLACE')
            else:
                target_group.remove((v.index,))

    # Remove all the groups with the "b_" prefix
    bm = bmesh.new()
    bm.from_mesh(dest.data)
    found = True
    while found:
        found = False
        for attr_name, group in list(bm.verts.layers.float.items()):
            if attr_name.startswith(group_prefix):
                bm.verts.layers.float.remove(group)
                found = True
                break
    bm.to_mesh(dest.data)

    print("  + Done!")


# Properties
class VGUtils_Props(PropertyGroup):
    """ Properties for the AutoMirror addon """

    object_prefix: StringProperty(
        name="Object Prefix",
        default="SK_",
    )

    group_prefix: StringProperty(
        name="Group Prefix",
        default="b_",
    )


class VGUtils(bpy.types.Operator):
    bl_idname = "object.vgutils"
    bl_label = "Bake Vertex Groups"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        return all(o.type == "MESH" for o in context.selected_objects)

    def execute(self, context):
        print()
        print("=== Bake Vertex Groups ===")

        object_prefix = bpy.context.scene.vgutils_props.object_prefix
        for obj in bpy.context.selected_objects:
            if obj.type != "MESH":
                continue

            # Find the source and target objects
            if obj.name.startswith(object_prefix):
                src_name = obj.name[len(object_prefix):]
                if src_name not in bpy.data.objects:
                    raise ValueError(f"Source object {src_name} not found")
                src = bpy.data.objects[src_name]
                dest = obj
            else:
                src = obj
                dest = find_or_create_object(obj)

            transfer_evaluated_mesh(src, dest)

        return {'FINISHED'}


class VIEW3D_PT_VGUtils(Panel):
    """ Shows a panel in the "Edit" tab of the 3D View """

    bl_label = "Vertex Group Utils"
    bl_idname = "VIEW3D_PT_VGUtils"
    bl_category = 'Edit'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_options = set()

    @classmethod
    def poll(cls, context):
        return all(o.type == "MESH" for o in context.selected_objects)

    def draw(self, context):
        layout = self.layout
        layout.column(align=True)

        row = layout.row()
        row.operator("object.vgutils")

        vgutils_props = context.scene.vgutils_props
        layout.prop(vgutils_props, "object_prefix")
        layout.prop(vgutils_props, "group_prefix")


def register():
    bpy.utils.register_class(VGUtils)
    bpy.utils.register_class(VIEW3D_PT_VGUtils)
    bpy.utils.register_class(VGUtils_Props)
    bpy.types.Scene.vgutils_props = PointerProperty(type=VGUtils_Props)


def unregister():
    bpy.utils.unregister_class(VGUtils)
    bpy.utils.unregister_class(VIEW3D_PT_VGUtils)
    bpy.utils.unregister_class(VGUtils_Props)


if __name__ == "__main__":
    register()

the addon in action

enter image description here

PROS:

  • it works.

CONS:

  • it requires a manual action.
  • it retains a copy of the mesh in the blend file, making it larger.

$\endgroup$
0
$\begingroup$

I am using solution from https://blenderartists.org/t/can-geometry-nodes-output-a-vertex-group-other-next-modifier-could-see-and-use/1484924

cant post link on comments rep too low

from

Edit. i tested this and seems can only change one single named vertex group. if add another you loose first.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .